host = $config['host']; $this->user = $config['user']; $this->password = $config['password']; $this->database = $config['database']; if (isset($config['port']) && is_numeric($config['port'])) { $this->port = (int)$config['port']; } if (isset($config['ssl_mode']) && is_string($config['ssl_mode']) && $config['ssl_mode'] !== '') { $this->ssl_mode = $config['ssl_mode']; } } public static function getPDO(): \PDO { global $CONFIG_DB; $port = $CONFIG_DB['port'] ?? 3306; $dsn = "mysql:host={$CONFIG_DB['host']};port={$port};dbname={$CONFIG_DB['database']};charset=utf8mb4"; return new \PDO($dsn, $CONFIG_DB['user'], $CONFIG_DB['password'], [ \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION, \PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC, \PDO::ATTR_EMULATE_PREPARES => false, ]); } public function testConnection(): bool { try { $conn = new mysqli($this->host, $this->user, $this->password, $this->database, $this->port); if ($conn->connect_error) { return false; } $this->conn = $conn; return true; } catch (Exception) { return false; } } public function connect(): void { global $response; try { // Enable error reporting for mysqli to catch connection issues via exceptions mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT); $this->conn = new mysqli($this->host, $this->user, $this->password, $this->database, $this->port); if ($this->conn->connect_error) { throw new Exception($this->conn->connect_error); } } catch (Exception $e) { if ($response) { $response->internal_server_error("Database connection failed: " . $e->getMessage()); } else { throw $e; } } } public function escape_string(string $string): string { return $this->conn->real_escape_string($string); } public function close(): void { if (!isset($this->conn)) { return; } try { $this->conn->close(); } catch (\Throwable) { } } public function get(string $table, int $id) { $sql = "SELECT * FROM $table WHERE id = $id"; $result = $this->query($sql); return $this->fetch_assoc($result); } public function query(string $sql): \mysqli_result|bool { // If the connection is not established, connect return $this->conn->query($sql); } public function fetch_assoc($result) { return $result->fetch_assoc(); } public function list_objects(string $table): array { $sql = "SELECT * FROM $table"; $result = $this->query($sql); return $this->fetch_all($result); } public function fetch_all($result) { return $result->fetch_all(MYSQLI_ASSOC); } public function list_objects_paginated(string $table, int $page, int $limit): array { $offset = ($page - 1) * $limit; $sql = "SELECT * FROM $table LIMIT $limit OFFSET $offset"; $result = $this->query($sql); return $this->fetch_all($result); } public function count_objects(string $table): int { $sql = "SELECT COUNT(*) FROM $table"; $result = $this->query($sql); return $result->fetch_row()[0]; } public function insert_id(): int { return $this->conn->insert_id; } public function conn(): mysqli { return $this->conn; } public function prepare(string $sql): false|\mysqli_stmt { return $this->conn->prepare($sql); } public function num_rows(\mysqli_result|bool $result): int|string { return $result->num_rows; } public function getUsername() { return $this->user; } public function getPassword() { return $this->password; } public function getHost() { return $this->host; } public function getDatabase() { return $this->database; } public function backupDatabase(string $path): bool { // Save the database to the path // Build a safe mysqldump command with configurable SSL (MariaDB-compatible flags) $mode = strtoupper(trim($this->ssl_mode)); // Map ssl_mode to MariaDB client flags // DISABLED => --skip-ssl (no TLS) // PREFERRED => (no flag; client decides) // REQUIRED/VERIFY_* => --ssl (enable TLS without strict verification unless CA materials provided) $sslFlag = ''; switch ($mode) { case 'DISABLED': $sslFlag = '--skip-ssl'; break; case 'PREFERRED': $sslFlag = ''; break; case 'REQUIRED': case 'VERIFY_CA': case 'VERIFY_IDENTITY': default: $sslFlag = '--ssl'; break; } $host = escapeshellarg($this->host); $user = escapeshellarg($this->user); $pass = escapeshellarg($this->password); $db = escapeshellarg($this->database); $port = (int)$this->port; $outfile = escapeshellarg($path); $sslPart = $sslFlag !== '' ? ($sslFlag . ' ') : ''; $command = "mysqldump {$sslPart}-h $host -P $port -u $user --password=$pass $db > $outfile 2>&1"; exec($command, $output, $return); // Check if the command was successful return $return === 0; } public function getView(string $view): array { $sql = "SELECT * FROM $view"; $result = $this->query($sql); return $this->fetch_all($result); } /** * Generate a fake ID for a table. * Fake ids are not stored in the database, they are generated on every request starting from -1. * This is useful for testing purposes. * @see orders_o::simulateOrderFromXLVask() * @param string $table * @return int */ public function getNextFakeId(string $table): int { // This is a static variable that will be shared across all instances of the class static $fakeId = 0; // Start from 0 and decrement on each call $fakeId--; return $fakeId; } }