Exception:
Array
(
    [message] => Call to undefined function mysqli_report()
    [file] => /home/www/vvveb/www/system/db/mysqli.php
    [line_no] => 120
    [line] => 		\mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);	 // <==

    [lines] => Array
        (
            [0] => 	public function connect(string $host = DB_HOST, string $dbname = DB_NAME, string $user = DB_USER, string $pass = DB_PASS, ?int $port = DB_PORT, string $prefix = DB_PREFIX): ?\mysqli {

            [1] => 		//connect to database

            [2] => 		if (self :: $link) {

            [3] => 			return self :: $link;

            [4] => 		}

            [5] => 		$this->prefix = $prefix;

            [6] => 

            [7] => 		\mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);	 // <==

            [8] => 

            [9] => 		try {

            [10] => 			self :: $link = new \mysqli($host, $user, $pass, $dbname, $port);

            [11] => 		} catch (\mysqli_sql_exception $e) {

            [12] => 			$errorMessage = str_replace($pass, '*****', $e->getMessage());

            [13] => 

        )

    [trace] => #0 /home/www/vvveb/www/system/db/mysqli.php(441): Vvveb\System\Db\Mysqli->connect()
#1 /home/www/vvveb/www/storage/model/app/settingsql.mysqli.php(308): Vvveb\System\Db\Mysqli->execute()
#2 /home/www/vvveb/www/system/setting.php(143): Vvveb\Sql\SettingSQL->getMulti()
#3 /home/www/vvveb/www/system/functions/settings.php(36): Vvveb\System\Setting->get()
#4 /home/www/vvveb/www/plugins/insert-scripts/plugin.php(66): Vvveb\getSetting()
#5 /home/www/vvveb/www/plugins/insert-scripts/plugin.php(80): InsertScriptsPlugin->app()
#6 /home/www/vvveb/www/plugins/insert-scripts/plugin.php(85): InsertScriptsPlugin->__construct()
#7 /home/www/vvveb/www/system/extensions/plugins.php(354): include('...')
#8 /home/www/vvveb/www/system/core/startup.php(512): Vvveb\System\Extensions\Plugins::loadPlugins()
#9 /home/www/vvveb/www/index.php(170): Vvveb\System\Core\start()
#10 /home/www/vvveb/www/public/index.php(28): include('...')
#11 {main}
    [code] => Array
        (
            [0] =>  

            [2] => /**

            [3] =>  * Vvveb

            [4] =>  *

            [5] =>  * Copyright (C) 2022  Ziadin Givan

            [6] =>  *

            [7] =>  * This program is free software: you can redistribute it and/or modify

            [8] =>  * it under the terms of the GNU Affero General Public License as

            [9] =>  * published by the Free Software Foundation, either version 3 of the

            [10] =>  * License, or (at your option) any later version.

            [11] =>  *

            [12] =>  * This program is distributed in the hope that it will be useful,

            [13] =>  * but WITHOUT ANY WARRANTY; without even the implied warranty of

            [14] =>  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

            [15] =>  * GNU Affero General Public License for more details.

            [16] =>  *

            [17] =>  * You should have received a copy of the GNU Affero General Public License

            [18] =>  * along with this program.  If not, see .

            [19] =>  *

            [20] =>  */

            [21] => 

            [22] => namespace Vvveb\System\Db;

            [23] => 

            [24] => use Vvveb\System\Event;

            [25] => 

            [26] => class Mysqli extends DBDriver {

            [27] => 	/** @var ?\MySQLi The shared database connection (singleton per process). */

            [28] => 	private static ?\mysqli $link = null;

            [29] => 

            [30] => 	/** @var int Number of rows affected by the last query. */

            [31] => 	public int $affected_rows = 0;

            [32] => 

            [33] => 	/** @var ?int The auto-increment ID generated by the last INSERT. */

            [34] => 	public ?int $insert_id = null;

            [35] => 

            [36] => 	/** @var string Identifier quote character for MySQL. */

            [37] => 	public string $quote  = '`';

            [38] => 

            [39] => 	/** @var string Table name prefix. */

            [40] => 	public string $prefix = ''; //'vv_';

            [41] => 

            [42] => 	/**

            [43] => 	 * Get the MySQL server version as an integer.

            [44] => 	 *

            [45] => 	 * @return int|null The server version (e.g. 80031) or null if not connected.

            [46] => 	 */

            [47] => 	public static function version(): ?int {

            [48] => 		if (self :: $link) {

            [49] => 			return mysqli_get_server_version(self :: $link);

            [50] => 		}

            [51] => 

            [52] => 		return null;

            [53] => 	}

            [54] => 

            [55] => 	/**

            [56] => 	 * Get the MySQL server version string.

            [57] => 	 *

            [58] => 	 * @return string|null The version string (e.g. '8.0.31') or null if not connected.

            [59] => 	 */

            [60] => 	public static function info(): ?string {

            [61] => 		if (self :: $link) {

            [62] => 			return mysqli_get_server_info(self :: $link);

            [63] => 		}

            [64] => 

            [65] => 		return null;

            [66] => 	}

            [67] => 

            [68] => 	/**

            [69] => 	 * Get the error message from the last MySQL operation.

            [70] => 	 *

            [71] => 	 * @return string|null The error message, or null if not connected.

            [72] => 	 */

            [73] => 	public function error(): ?string {

            [74] => 		if (self :: $link) {

            [75] => 			return self :: $link->error;

            [76] => 		}

            [77] => 

            [78] => 		return null;

            [79] => 	}

            [80] => 

            [81] => 	/**

            [82] => 	 * Get the error code from the last MySQL operation.

            [83] => 	 *

            [84] => 	 * @return int|null The error code, or null if not connected.

            [85] => 	 */

            [86] => 	public function errorCode(): ?int {

            [87] => 		if (self :: $link) {

            [88] => 			return self :: $link->errno;

            [89] => 		}

            [90] => 

            [91] => 		return null;

            [92] => 	}

            [93] => 

            [94] => 	public function __construct() {}

            [95] => 

            [96] => 	/**

            [97] => 	 * Connect to the MySQL database.

            [98] => 	 *

            [99] => 	 * Uses a singleton pattern — returns the existing connection if already open.

            [100] => 	 * Throws an exception with a sanitised error message on failure.

            [101] => 	 *

            [102] => 	 * @param string   $host   Database host.

            [103] => 	 * @param string   $dbname Database name.

            [104] => 	 * @param string   $user   Database user.

            [105] => 	 * @param string   $pass   Database password.

            [106] => 	 * @param int|null $port   Database port.

            [107] => 	 * @param string   $prefix Table name prefix.

            [108] => 	 *

            [109] => 	 * @throws \Exception On connection failure.

            [110] => 	 *

            [111] => 	 * @return ?\MySQLi The database connection, or null on failure.

            [112] => 	 */

            [113] => 	public function connect(string $host = DB_HOST, string $dbname = DB_NAME, string $user = DB_USER, string $pass = DB_PASS, ?int $port = DB_PORT, string $prefix = DB_PREFIX): ?\mysqli {

            [114] => 		//connect to database

            [115] => 		if (self :: $link) {

            [116] => 			return self :: $link;

            [117] => 		}

            [118] => 		$this->prefix = $prefix;

            [119] => 

            [120] => 		\mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);	 // <==

            [121] => 

            [122] => 		try {

            [123] => 			self :: $link = new \mysqli($host, $user, $pass, $dbname, $port);

            [124] => 		} catch (\mysqli_sql_exception $e) {

            [125] => 			$errorMessage = str_replace($pass, '*****', $e->getMessage());

            [126] => 

            [127] => 			throw new \Exception($errorMessage, $e->getCode());

            [128] => 		}

            [129] => 

            [130] => 		// check if a connection established

            [131] => 		if (\mysqli_connect_errno()) {

            [132] => 			$error        = mysqli_connect_error();

            [133] => 			$errorMessage = str_replace($pass, '*****', $error);

            [134] => 

            [135] => 			throw new \Exception($errorMessage, mysqli_connect_errno());

            [136] => 		}

            [137] => 

            [138] => 		//sync database time

            [139] => 		//$this->execute('SET `time_zone` = :zone', ['zone' => $this->escape(date('P'))]);

            [140] => 

            [141] => 		return self :: $link;

            [142] => 	}

            [143] => 

            [144] => 	/**

            [145] => 	 * Get all columns for a table used for sanitizing input.

            [146] => 	 *

            [147] => 	 * @param string $tableName The table name to introspect.

            [148] => 	 * @param bool   $comment   Whether to include the column comment field.

            [149] => 	 *

            [150] => 	 * @return array|false

            [151] => 	 *                                                                                                                      Associative array keyed by column name, or false on failure.

            [152] => 	 */

            [153] => 	public function getColumnsMeta(string $tableName, bool $comment = false): array|false {

            [154] => 		$sql =

            [155] => 		'SELECT COLUMN_NAME as name, COLUMN_DEFAULT as d, IS_NULLABLE  as n, DATA_TYPE as t, EXTRA as e, CHARACTER_MAXIMUM_LENGTH as l'

            [156] => 		. ($comment ? ', COLUMN_COMMENT as c' : '') .

            [157] => 		' FROM `INFORMATION_SCHEMA`.`COLUMNS`

            [158] => 		WHERE `TABLE_SCHEMA`= "' . DB_NAME . '"

            [159] => 			AND `TABLE_NAME`="' . $tableName . '"';

            [160] => 

            [161] => 		if ($result = $this->query($sql)) {

            [162] => 			//$columns = $result->fetch_all(MYSQLI_ASSOC);

            [163] => 			$columns = [];

            [164] => 

            [165] => 			while ($row = $result->fetch_assoc()) {

            [166] => 				$columns[$row['name']] = $row;

            [167] => 			}

            [168] => 

            [169] => 			// free result set

            [170] => 			$result->close();

            [171] => 

            [172] => 			return $columns;

            [173] => 		}

            [174] => 

            [175] => 		return false;

            [176] => 	}

            [177] => 

            [178] => 	/**

            [179] => 	 * Get all table names in the database.

            [180] => 	 *

            [181] => 	 * @param string $db The database name.

            [182] => 	 *

            [183] => 	 * @return array|false List of table names, or false on failure.

            [184] => 	 */

            [185] => 	public function getTableNames(string $db = DB_NAME): array|false {

            [186] => 		$sql = "SELECT table_name as name

            [187] => 			FROM information_schema.tables

            [188] => 			WHERE table_schema = '$db' ORDER BY table_name";

            [189] => 

            [190] => 		if ($result = $this->query($sql)) {

            [191] => 			//$names = $result->fetch_all(MYSQLI_ASSOC);

            [192] => 			$names = [];

            [193] => 

            [194] => 			while ($row = $result->fetch_assoc()) {

            [195] => 				$names[] = $row['name'];

            [196] => 			}

            [197] => 

            [198] => 			// free result set

            [199] => 			$result->close();

            [200] => 

            [201] => 			return $names;

            [202] => 		}

            [203] => 

            [204] => 		return false;

            [205] => 	}

            [206] => 

            [207] => 	/**

            [208] => 	 * Select a different database on the current connection.

            [209] => 	 *

            [210] => 	 * @param string $db The database name.

            [211] => 	 *

            [212] => 	 * @return bool True on success, false on failure.

            [213] => 	 */

            [214] => 	public function select_db(string $db): bool {

            [215] => 		return self :: $link->select_db($db);

            [216] => 	}

            [217] => 

            [218] => 	/**

            [219] => 	 * Execute a raw SQL query.

            [220] => 	 *

            [221] => 	 * Automatically connects if not connected. Updates affected_rows and insert_id.

            [222] => 	 *

            [223] => 	 * @param string $sql The SQL query to execute.

            [224] => 	 *

            [225] => 	 * @throws \Exception On query failure.

            [226] => 	 *

            [227] => 	 * @return bool|\mysqli_result Query result or true for success, false on failure.

            [228] => 	 */

            [229] => 	public function query(string $sql): bool|\mysqli_result {

            [230] => 		if (!self :: $link) {

            [231] => 			$this->connect();

            [232] => 		}

            [233] => 

            [234] => 		if (LOG_SQL_QUERIES) {

            [235] => 			error_log($sql);

            [236] => 		}

            [237] => 

            [238] => 		try {

            [239] => 			$result = self :: $link->query($sql);

            [240] => 		} catch (\mysqli_sql_exception $e) {

            [241] => 			$message = $e->getMessage() . "\n" . $sql . "\n - " . print_r(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1), true);

            [242] => 

            [243] => 			throw new \Exception($message, $e->getCode());

            [244] => 		}

            [245] => 

            [246] => 		if ($result) {

            [247] => 			$this->affected_rows = self :: $link->affected_rows;

            [248] => 			$this->insert_id     = self :: $link->insert_id;

            [249] => 		}

            [250] => 

            [251] => 		return $result;

            [252] => 	}

            [253] => 

            [254] => 	/**

            [255] => 	 * Execute multiple SQL statements in a single call.

            [256] => 	 *

            [257] => 	 * @param string $sql The SQL statements to execute (semicolon-separated).

            [258] => 	 *

            [259] => 	 * @return bool True on success, false on failure.

            [260] => 	 */

            [261] => 	public function multi_query(string $sql): bool {

            [262] => 		if (!self :: $link) {

            [263] => 			$this->connect();

            [264] => 		}

            [265] => 

            [266] => 		$result = self :: $link->multi_query($sql);

            [267] => 

            [268] => 		if ($result) {

            [269] => 			$this->affected_rows = self :: $link->affected_rows;

            [270] => 			$this->insert_id     = self :: $link->insert_id;

            [271] => 		}

            [272] => 

            [273] => 		return $result;

            [274] => 	}

            [275] => 

            [276] => 	/**

            [277] => 	 * Escape a value for safe inclusion in a SQL query.

            [278] => 	 *

            [279] => 	 * Strings are escaped with real_escape_string. Null values become 'null'.

            [280] => 	 * All other types are returned as-is.

            [281] => 	 *

            [282] => 	 * @param mixed $string The value to escape.

            [283] => 	 *

            [284] => 	 * @return mixed The escaped value.

            [285] => 	 */

            [286] => 	public function escape(mixed $string): mixed {

            [287] => 		if (is_string($string)) {

            [288] => 			return self :: $link->real_escape_string($string);

            [289] => 		}

            [290] => 

            [291] => 		if (is_null($string)) {

            [292] => 			return 'null';

            [293] => 		}

            [294] => 

            [295] => 		return $string;

            [296] => 	}

            [297] => 

            [298] => 	/**

            [299] => 	 * Escape a string value for use in a SQL literal.

            [300] => 	 *

            [301] => 	 * @param string $string The string to escape.

            [302] => 	 *

            [303] => 	 * @return string The escaped string.

            [304] => 	 */

            [305] => 	public function escapeLiteral(string $string): string {

            [306] => 		return $this->escape($string);

            [307] => 	}

            [308] => 

            [309] => 	/**

            [310] => 	 * Generate a MySQL-compatible LIMIT clause.

            [311] => 	 *

            [312] => 	 * @param int|string $start Offset (0-based).

            [313] => 	 * @param int|string $limit Maximum number of rows.

            [314] => 	 *

            [315] => 	 * @return string The LIMIT clause (e.g. 'LIMIT 0, 10').

            [316] => 	 */

            [317] => 	public function sqlLimit(int|string $start, int|string $limit): string {

            [318] => 		return "LIMIT $start, $limit";

            [319] => 	}

            [320] => 

            [321] => 	/**

            [322] => 	 * Fetch a single row from a statement or result set.

            [323] => 	 *

            [324] => 	 * @param \mysqli_stmt|\mysqli_result $stmt The statement or result to fetch from.

            [325] => 	 *

            [326] => 	 * @return array The fetched row, or empty array if no rows.

            [327] => 	 */

            [328] => 	public function fetchArray(\mysqli_stmt|\mysqli_result $stmt): array {

            [329] => 		$data      = [];

            [330] => 		$statement = ($stmt instanceof \mysqli_stmt);

            [331] => 

            [332] => 		if ($statement) {

            [333] => 			$this->store_result();

            [334] => 			$result = $stmt->get_result();

            [335] => 		} else {

            [336] => 			$result = $stmt;

            [337] => 		}

            [338] => 

            [339] => 		if ($result) {

            [340] => 			$result = $result->fetch_array(MYSQLI_ASSOC);

            [341] => 

            [342] => 			if ($result) {

            [343] => 				$data = $result;

            [344] => 

            [345] => 				if ($statement && $stmt->more_results()) {

            [346] => 					$stmt->next_result();

            [347] => 				}

            [348] => 			}

            [349] => 		}

            [350] => 

            [351] => 		return $data;

            [352] => 	}

            [353] => 

            [354] => 	/**

            [355] => 	 * Fetch all rows from a statement or result set.

            [356] => 	 *

            [357] => 	 * @param \mysqli_stmt|\mysqli_result $stmt The statement or result to fetch from.

            [358] => 	 *

            [359] => 	 * @return array> All result rows.

            [360] => 	 */

            [361] => 	public function fetchAll(\mysqli_stmt|\mysqli_result $stmt): array {

            [362] => 		$data      = [];

            [363] => 		$statement = ($stmt instanceof \mysqli_stmt);

            [364] => 

            [365] => 		if ($statement) {

            [366] => 			$this->store_result();

            [367] => 			$result = $stmt->get_result();

            [368] => 		} else {

            [369] => 			$result = $stmt;

            [370] => 		}

            [371] => 

            [372] => 		if ($result) {

            [373] => 			$data = $result->fetch_all(MYSQLI_ASSOC);

            [374] => 		}

            [375] => 

            [376] => 		return $data;

            [377] => 	}

            [378] => 

            [379] => 	/**

            [380] => 	 * Store the result of the last query in the client-side buffer.

            [381] => 	 *

            [382] => 	 * @return \mysqli_result|false The stored result, or false on failure.

            [383] => 	 */

            [384] => 	public function store_result(): \mysqli_result|false {

            [385] => 		return self :: $link->store_result();

            [386] => 	}

            [387] => 

            [388] => 	/**

            [389] => 	 * Check if the current statement has more result sets.

            [390] => 	 *

            [391] => 	 * @return bool True if more results are available.

            [392] => 	 */

            [393] => 	public function more_results(): bool {

            [394] => 		return self :: $link->more_results();

            [395] => 	}

            [396] => 

            [397] => 	/**

            [398] => 	 * Move to the next result set in a multi-query.

            [399] => 	 *

            [400] => 	 * @return bool True on success, false on failure.

            [401] => 	 */

            [402] => 	public function next_result(): bool {

            [403] => 		return self :: $link->next_result();

            [404] => 	}

            [405] => 

            [406] => 	/**

            [407] => 	 * Close the database connection.

            [408] => 	 *

            [409] => 	 * @return ?bool True on success, null if not connected.

            [410] => 	 */

            [411] => 	public function close(): ?bool {

            [412] => 		if ((self :: $link instanceof \mysqli)/* && self :: $link->ping()*/) {

            [413] => 			return self :: $link->close();

            [414] => 		}

            [415] => 

            [416] => 		return null;

            [417] => 	}

            [418] => 

            [419] => 	/**

            [420] => 	 * Prepare and execute a parameterized query.

            [421] => 	 *

            [422] => 	 * Fires an Event::trigger hook before execution. Converts named parameters

            [423] => 	 * to positional placeholders, binds parameters, and executes the statement.

            [424] => 	 * Updates affected_rows and insert_id on success.

            [425] => 	 *

            [426] => 	 * @param string                $sql        The SQL query with :named parameters.

            [427] => 	 * @param array  $params     Named parameter values.

            [428] => 	 * @param array $paramTypes Optional explicit type overrides.

            [429] => 	 *

            [430] => 	 * @throws \Exception On prepare or execute failure.

            [431] => 	 *

            [432] => 	 * @return ?\mysqli_stmt The executed statement, or null on failure.

            [433] => 	 */

            [434] => 	public function execute(string $sql, array $params = [], array $paramTypes = []): ?\mysqli_stmt {

            [435] => 		[$sql, $params] = Event::trigger(__CLASS__, __FUNCTION__, $sql, $params);

            [436] => 		//save orig sql for debugging info

            [437] => 		$origSql = $sql;

            [438] => 

            [439] => 		if (!self :: $link) {

            [440] => 			$this->connect();

            [441] => 		}

            [442] => 

            [443] => 		[$parameters, $types] = $this->paramsToQmark($sql, $params, $paramTypes);

            [444] => 

            [445] => 		try {

            [446] => 			$stmt = self::$link->prepare($sql);

            [447] => 		} catch (\mysqli_sql_exception $e) {

            [448] => 			$message = $e->getMessage() . "\n" . $this->debugSql($origSql, $params, $paramTypes) . "\n - " . $origSql . "\n - " . print_r(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1), true);

            [449] => 

            [450] => 			throw new \Exception($message, $e->getCode());

            [451] => 		}

            [452] => 

            [453] => 		if ($stmt && !empty($types)) {

            [454] => 			array_unshift($parameters, $types);

            [455] => 

            [456] => 			//hack for php 7.x bind_param "expected to be a reference, value given" stupid warning

            [457] => 			$referenceArray = [];

            [458] => 

            [459] => 			foreach ($parameters as $key => $value) {

            [460] => 				$referenceArray[$key] = &$parameters[$key];

            [461] => 			}

            [462] => 

            [463] => 			@call_user_func_array([$stmt, 'bind_param'], $referenceArray);

            [464] => 		}

            [465] => 

            [466] => 		if (LOG_SQL_QUERIES) {

            [467] => 			error_log($this->debugSql($origSql, $params, $paramTypes));

            [468] => 		}

            [469] => 

            [470] => 		if ($stmt) {

            [471] => 			try {

            [472] => 				if ($stmt->execute()) {

            [473] => 					$this->affected_rows = self :: $link->affected_rows;

            [474] => 					$this->insert_id     = self :: $link->insert_id;

            [475] => 

            [476] => 					return $stmt;

            [477] => 				} else {

            [478] => 					error_log(print_r($stmt, true));

            [479] => 					error_log($this->debugSql($sql, $params, $paramTypes));

            [480] => 				}

            [481] => 			} catch (\mysqli_sql_exception $e) {

            [482] => 				$message = $e->getMessage() . "\n" . $origSql . "\n" . $this->debugSql($origSql, $params, $paramTypes) . "\n" . print_r($parameters, true) . $types . "\n" . print_r(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1), true);

            [483] => 

            [484] => 				throw new \Exception($message, $e->getCode());

            [485] => 			}

            [486] => 		} else {

            [487] => 			error_log(print_r($stmt, true));

            [488] => 			error_log($this->debugSql($origSql, $params, $paramTypes));

            [489] => 		}

            [490] => 

            [491] => 		return $stmt;

            [492] => 	}

            [493] => }

        )

)