Warning: mysqli::__construct(): php_network_getaddresses: getaddrinfo for mysql failed: Try again in /var/www/html/system/db/mysqli.php on line 295 Exception:
Array
(
    [message] => php_network_getaddresses: getaddrinfo for mysql failed: Try again
    [file] => /var/www/html/system/db/mysqli.php
    [line_no] => 299
    [line] => 			throw new \Exception($errorMessage, $e->getCode());	 // <==

    [lines] => Array
        (
            [0] => 

            [1] => 		try {

            [2] => 			self :: $link = new \Mysqli(/*'p:' . */$host, $user, $pass, $dbname, $port);

            [3] => 			//self :: $link = $this;

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

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

            [6] => 

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

            [8] => 		}

            [9] => 

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

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

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

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

        )

    [trace] => #0 /var/www/html/system/db/mysqli.php(615): Vvveb\System\Db\Mysqli->connect()
#1 /var/www/html/storage/model/app/productsql.mysqli.php(6895): Vvveb\System\Db\Mysqli->execute('SELECT  pd.*,pr...', Array, Array)
#2 /var/www/html/app/component/products.php(179): Vvveb\Sql\ProductSQL->getAll(Array)
#3 /var/www/html/system/component/component.php(206): Vvveb\Component\Products->results()
#4 /var/www/html/system/component/component.php(134): Vvveb\System\Component\Component->loadComponents()
#5 /var/www/html/system/component/component.php(91): Vvveb\System\Component\Component->__construct(Object(Vvveb\System\Core\View), false, NULL, NULL)
#6 /var/www/html/system/core/view.php(523): Vvveb\System\Component\Component::getInstance(Object(Vvveb\System\Core\View), false, NULL)
#7 /var/www/html/system/core/response.php(161): Vvveb\System\Core\View->render(true, true)
#8 /var/www/html/system/core/frontcontroller.php(287): Vvveb\System\Core\Response->output()
#9 /var/www/html/system/core/frontcontroller.php(337): Vvveb\System\Core\FrontController::call('Vvveb\\Controlle...', 'index', '/var/www/html/a...')
#10 /var/www/html/system/core/frontcontroller.php(426): Vvveb\System\Core\FrontController::redirect('Index', 'index')
#11 /var/www/html/system/core/startup.php(514): Vvveb\System\Core\FrontController::dispatch(Array)
#12 /var/www/html/index.php(170): Vvveb\System\Core\start()
#13 /var/www/html/public/index.php(28): include('/var/www/html/i...')
#14 {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] => /**

            [27] =>  * Polyfill for mysqli_result when native fetch_all is missing on mysqli_stmt.

            [28] =>  *

            [29] =>  * Wraps a prepared statement and provides fetch_all, fetch_assoc, and fetchRow

            [30] =>  * methods by binding result columns and iterating through the statement.

            [31] =>  */

            [32] => class mysqli_result {

            [33] => 	/** @var \mysqli_stmt The underlying prepared statement. */

            [34] => 	private \mysqli_stmt $stmt;

            [35] => 

            [36] => 	/** @var ?\mysqli_result Metadata for the statement result. */

            [37] => 	private ?\mysqli_result $meta = null;

            [38] => 	

            [39] => 	/** @var array row. */

            [40] => 	private $row = [];

            [41] => 

            [42] => 	/**

            [43] => 	 * @param \mysqli_stmt $stmt The prepared statement to wrap.

            [44] => 	 */

            [45] => 	public function __construct(\mysqli_stmt $stmt) {

            [46] => 		$this->stmt = $stmt;

            [47] => 

            [48] => 		$this->stmt->store_result();

            [49] => 		$meta = $this->stmt->result_metadata();

            [50] => 		if ($meta) {

            [51] => 			$this->row  = [];

            [52] => 			/*

            [53] => 			for ($i = 0;$i < $meta->field_count; $i++) {

            [54] => 				$field = $meta->fetch_field_direct($i);

            [55] => 				$name = $field->name;

            [56] => 				$this->row[$name] = [];

            [57] => 				$params[] = &$this->row[$name];

            [58] => 			}

            [59] => 			*/

            [60] => 			

            [61] => 			while ($field = $meta->fetch_field()) {

            [62] => 				$name = $result = preg_replace('/[^a-zA-Z0-9_-]+/', '', $field->name);

            [63] => 				$this->row[$name] = [];

            [64] => 				$params[] = &$this->row[$name];

            [65] => 			}

            [66] => 

            [67] => 			call_user_func_array([$this->stmt, 'bind_result'], $params);

            [68] => 		}

            [69] => 	}

            [70] => 

            [71] => 	/**

            [72] => 	 * Fetch all rows as an associative array (delegates to fetch_assoc).

            [73] => 	 *

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

            [75] => 	 */

            [76] => 	public function fetch_all(): array {

            [77] => 		return $this->fetch_assoc();

            [78] => 	}

            [79] => 

            [80] => 	/**

            [81] => 	 * Fetch all rows as an associative array (delegates to fetch_assoc).

            [82] => 	 *

            [83] => 	 * @param int $resulttype Ignored — always returns associative.

            [84] => 	 *

            [85] => 	 * @return array>|null All result rows.

            [86] => 	 */

            [87] => 	public function fetch_array(int $resulttype): ?array {

            [88] => 		if ($result = $this->stmt->fetch()) {

            [89] => 			//dereference

            [90] => 			foreach ($this->row as $key => $value) {

            [91] => 				if ($resulttype == MYSQLI_ASSOC) {

            [92] => 					$row[$key] = $value;

            [93] => 				} else {

            [94] => 					$row[] = $value;

            [95] => 				}

            [96] => 			}

            [97] => 

            [98] => 			return $row;

            [99] => 		} else {

            [100] => 			//$this->stmt->close();

            [101] => 			return $result;

            [102] => 		}

            [103] => 	}

            [104] => 

            [105] => 	/**

            [106] => 	 * Fetch all rows as an associative array by binding result columns.

            [107] => 	 *

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

            [109] => 	 */

            [110] => 	public function fetch_assoc(): array {

            [111] => 		$result = [];

            [112] => 		while ($return = $this->stmt->fetch()) {

            [113] => 			$c = [];

            [114] => 

            [115] => 			$row = $this->row;

            [116] => 			foreach ($row as $key => $val) {

            [117] => 				$c[$key] = $val;

            [118] => 			}

            [119] => 			$result[] = $c;

            [120] => 		}

            [121] => 

            [122] => 		return $result;

            [123] => 	}

            [124] => 

            [125] => 	/**

            [126] => 	 * Stub for interface compatibility — does nothing.

            [127] => 	 *

            [128] => 	 * @return void

            [129] => 	 */

            [130] => 	public function fetch_field(): void {

            [131] => 	}

            [132] => 

            [133] => 	/**

            [134] => 	 * Stub for interface compatibility — does nothing.

            [135] => 	 *

            [136] => 	 * @return void

            [137] => 	 */

            [138] => 	public function fetch_fields(): void {

            [139] => 	}

            [140] => 

            [141] => 	/**

            [142] => 	 * Fetch all rows as an associative array (alias for fetch_assoc).

            [143] => 	 *

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

            [145] => 	 */

            [146] => 	public function fetchRow(): array {

            [147] => 		if ($result = $this->stmt->fetch()) {

            [148] => 			//dereference

            [149] => 			foreach ($this->row as $key => $value) {

            [150] => 				$row[$key] = $value;

            [151] => 			}

            [152] => 			return $row;

            [153] => 		} else {

            [154] => 			//$this->stmt->close();

            [155] => 			return $result;

            [156] => 		}

            [157] => 	}

            [158] => 	

            [159] => 	private function destroy() {

            [160] => 		$this->stmt->close();

            [161] => 	}

            [162] => }

            [163] => 

            [164] => /**

            [165] =>  * MySQL database driver using the mysqli extension.

            [166] =>  *

            [167] =>  * Provides connection management, query execution with prepared statements,

            [168] =>  * result fetching, escaping, and schema introspection for MySQL/MariaDB.

            [169] =>  */

            [170] => class Mysqli extends DBDriver {

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

            [172] => 	private static ?\MySQLi $link = null;

            [173] => 

            [174] => 	/** @var ?\mysqli_stmt The current prepared statement, if any. */

            [175] => 	private ?\mysqli_stmt $stmt = null;

            [176] => 

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

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

            [179] => 

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

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

            [182] => 

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

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

            [185] => 

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

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

            [188] => 

            [189] => 	/**

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

            [191] => 	 *

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

            [193] => 	 */

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

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

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

            [197] => 		}

            [198] => 

            [199] => 		return null;

            [200] => 	}

            [201] => 

            [202] => 	/**

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

            [204] => 	 *

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

            [206] => 	 */

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

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

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

            [210] => 		}

            [211] => 

            [212] => 		return null;

            [213] => 	}

            [214] => 

            [215] => 	/**

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

            [217] => 	 *

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

            [219] => 	 */

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

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

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

            [223] => 		}

            [224] => 

            [225] => 		return null;

            [226] => 	}

            [227] => 

            [228] => 	/**

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

            [230] => 	 *

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

            [232] => 	 */

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

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

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

            [236] => 		}

            [237] => 

            [238] => 		return null;

            [239] => 	}

            [240] => 

            [241] => 	/**

            [242] => 	 * Wrap a mysqli_stmt in a mysqli_result polyfill for fetch_all support.

            [243] => 	 *

            [244] => 	 * @param \mysqli_stmt $stmt The prepared statement.

            [245] => 	 *

            [246] => 	 * @return mysqli_result The polyfilled result object.

            [247] => 	 */

            [248] => 	public function get_result(\mysqli_stmt $stmt): mysqli_result {

            [249] => 		$result = new mysqli_result($stmt);

            [250] => 

            [251] => 		return $result;

            [252] => 	}

            [253] => 

            [254] => 	/**

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

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

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

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

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

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

            [261] => 	 */

            [262] => 	public function __construct(string $host = DB_HOST, string $dbname = DB_NAME, string $user = DB_USER, string $pass = DB_PASS, int|null $port = DB_PORT,  string $prefix = DB_PREFIX) {

            [263] => 		//return $this->connect($host, $dbname, $user, $pass, $port,  $prefix);

            [264] => 	}

            [265] => 

            [266] => 	/**

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

            [268] => 	 *

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

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

            [271] => 	 *

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

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

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

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

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

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

            [278] => 	 *

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

            [280] => 	 *

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

            [282] => 	 */

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

            [284] => 		//mysqli_report(MYSQLI_REPORT_OFF);

            [285] => 		//connect to database

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

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

            [288] => 		}

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

            [290] => 

            [291] => 		\mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);

            [292] => 

            [293] => 		try {

            [294] => 			self :: $link = new \Mysqli(/*'p:' . */$host, $user, $pass, $dbname, $port);

            [295] => 			//self :: $link = $this;

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

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

            [298] => 

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

            [300] => 		}

            [301] => 

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

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

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

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

            [306] => 

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

            [308] => 		}

            [309] => 

            [310] => 		if ((! self :: $link instanceof \MySQLi)) {

            [311] => 			throw new \Exception('Mysqli not an object', mysqli_connect_errno());

            [312] => 		}

            [313] => 

            [314] => 		//sync database time

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

            [316] => 

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

            [318] => 	}

            [319] => 

            [320] => 	/**

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

            [322] => 	 *

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

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

            [325] => 	 *

            [326] => 	 * @return array|false

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

            [328] => 	 */

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

            [330] => 		$sql =

            [331] => 		'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'

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

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

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

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

            [336] => 

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

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

            [339] => 			$columns = [];

            [340] => 

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

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

            [343] => 			}

            [344] => 

            [345] => 			/* free result set */

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

            [347] => 

            [348] => 			return $columns;

            [349] => 		} else {

            [350] => 		}

            [351] => 

            [352] => 		return false;

            [353] => 	}

            [354] => 

            [355] => 	/**

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

            [357] => 	 *

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

            [359] => 	 *

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

            [361] => 	 */

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

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

            [364] => 			FROM information_schema.tables 

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

            [366] => 

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

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

            [369] => 			$names = [];

            [370] => 

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

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

            [373] => 			}

            [374] => 

            [375] => 			/* free result set */

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

            [377] => 

            [378] => 			return $names;

            [379] => 		} else {

            [380] => 		}

            [381] => 

            [382] => 		return false;

            [383] => 	}

            [384] => 

            [385] => 	/**

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

            [387] => 	 *

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

            [389] => 	 *

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

            [391] => 	 */

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

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

            [394] => 	}

            [395] => 

            [396] => 	/**

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

            [398] => 	 *

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

            [400] => 	 *

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

            [402] => 	 *

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

            [404] => 	 *

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

            [406] => 	 */

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

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

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

            [410] => 		}

            [411] => 

            [412] => 		if (LOG_SQL_QUERIES) {

            [413] => 			error_log($sql);

            [414] => 		}

            [415] => 

            [416] => 		try {

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

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

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

            [420] => 

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

            [422] => 		}

            [423] => 

            [424] => 		if ($result) {

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

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

            [427] => 		}

            [428] => 

            [429] => 		return $result;

            [430] => 	}

            [431] => 

            [432] => 	/**

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

            [434] => 	 *

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

            [436] => 	 *

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

            [438] => 	 */

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

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

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

            [442] => 		}

            [443] => 

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

            [445] => 

            [446] => 		if ($result) {

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

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

            [449] => 		}

            [450] => 

            [451] => 		return $result;

            [452] => 	}

            [453] => 

            [454] => 	/**

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

            [456] => 	 *

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

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

            [459] => 	 *

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

            [461] => 	 *

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

            [463] => 	 */

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

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

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

            [467] => 		}

            [468] => 

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

            [470] => 			return 'null';

            [471] => 		}

            [472] => 

            [473] => 		return $string;

            [474] => 	}

            [475] => 

            [476] => 	/**

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

            [478] => 	 *

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

            [480] => 	 *

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

            [482] => 	 */

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

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

            [485] => 	}

            [486] => 

            [487] => 	/**

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

            [489] => 	 *

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

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

            [492] => 	 *

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

            [494] => 	 */

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

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

            [497] => 	}

            [498] => 

            [499] => 	/**

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

            [501] => 	 *

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

            [503] => 	 *

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

            [505] => 	 */

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

            [507] => 		$data      = [];

            [508] => 		$statement = (get_class($stmt) === 'mysqli_stmt');

            [509] => 

            [510] => 		if ($statement) {

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

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

            [513] => 		} else {

            [514] => 			$result = $stmt;

            [515] => 		}

            [516] => 

            [517] => 		if ($result) {

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

            [519] => 

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

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

            [522] => 			}

            [523] => 		}

            [524] => 

            [525] => 		return $data;

            [526] => 	}

            [527] => 

            [528] => 	/**

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

            [530] => 	 *

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

            [532] => 	 *

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

            [534] => 	 */

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

            [536] => 		$data      = [];

            [537] => 		$statement = (get_class($stmt) === 'mysqli_stmt');

            [538] => 

            [539] => 		if ($statement) {

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

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

            [542] => 		} else {

            [543] => 			$result = $stmt;

            [544] => 		}

            [545] => 

            [546] => 		if ($result) {

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

            [548] => 		}

            [549] => 

            [550] => 		return $data;

            [551] => 	}

            [552] => 

            [553] => 	/**

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

            [555] => 	 *

            [556] => 	 * @return ?\mysqli_result The stored result, or null on failure.

            [557] => 	 */

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

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

            [560] => 	}

            [561] => 

            [562] => 	/**

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

            [564] => 	 *

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

            [566] => 	 */

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

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

            [569] => 	}

            [570] => 

            [571] => 	/**

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

            [573] => 	 *

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

            [575] => 	 */

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

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

            [578] => 	}

            [579] => 

            [580] => 	/**

            [581] => 	 * Close the database connection.

            [582] => 	 *

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

            [584] => 	 */

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

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

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

            [588] => 		}

            [589] => 

            [590] => 		return null;

            [591] => 	}

            [592] => 

            [593] => 	/**

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

            [595] => 	 *

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

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

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

            [599] => 	 *

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

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

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

            [603] => 	 *

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

            [605] => 	 *

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

            [607] => 	 */

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

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

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

            [611] => 		$origSql = $sql;

            [612] => 

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

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

            [615] => 		}

            [616] => 

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

            [618] => 

            [619] => 		try {

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

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

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

            [623] => 

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

            [625] => 		}

            [626] => 

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

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

            [629] => 

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

            [631] => 			$referenceArray = [];

            [632] => 

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

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

            [635] => 			}

            [636] => 

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

            [638] => 		}

            [639] => 

            [640] => 		if (LOG_SQL_QUERIES) {

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

            [642] => 		}

            [643] => 

            [644] => 		if ($stmt) {

            [645] => 			try {

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

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

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

            [649] => 

            [650] => 					return $stmt;

            [651] => 				} else {

            [652] => 					error_log(print_r($stmt, 1));

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

            [654] => 				}

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

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

            [657] => 

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

            [659] => 			}

            [660] => 		} else {

            [661] => 			error_log(print_r($stmt, 1));

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

            [663] => 		}

            [664] => 

            [665] => 		return $stmt;

            [666] => 	}

            [667] => 

            [668] => 	/**

            [669] => 	 * Bind a parameter value to the current prepared statement.

            [670] => 	 *

            [671] => 	 * @param string|int  $param The parameter index or name.

            [672] => 	 * @param mixed       $value The value to bind.

            [673] => 	 * @param int|null    $type  The PDO type constant, or null for auto-detection.

            [674] => 	 *

            [675] => 	 * @return void

            [676] => 	 */

            [677] => 	public function bind(string|int $param, mixed $value, ?int $type = null): void {

            [678] => 		// TODO: bindValue() is PDO-only; store bindings for later use if needed

            [679] => 	}

            [680] => }

        )

)