dbEnabled) { return null; } $db = $config->db; $driver = (string)($db['driver'] ?? ''); if ($driver === '') { throw new \RuntimeException('DB enabled but config/db.php missing "driver"'); } $dsn = match ($driver) { 'mysql' => self::buildMysqlDsn($db), 'pgsql' => self::buildPgsqlDsn($db), 'sqlite' => self::buildSqliteDsn($db), default => throw new \RuntimeException('Unsupported PDO driver: ' . $driver), }; try { $pdo = new \PDO( $dsn, // sqlite braucht user/pass nicht, PDO ignoriert es aber; wir geben leer zurück (string)($db['user'] ?? ''), (string)($db['password'] ?? ''), (array)($db['options'] ?? []) ); // Optional: PostgreSQL schema/search_path setzen if ($driver === 'pgsql' && !empty($db['schema'])) { // Minimaler Schutz gegen Injection über schema $schema = preg_replace('/[^a-zA-Z0-9_]/', '', (string)$db['schema']); if ($schema !== '') { $pdo->exec('SET search_path TO ' . $schema); } } return $pdo; } catch (\PDOException $e) { // In Prod würdest du loggen; hier minimal http_response_code(500); echo 'Database connection error.'; exit; } } private static function buildMysqlDsn(array $db): string { if (empty($db['dbname'])) { throw new \RuntimeException('MySQL config missing "dbname"'); } $charset = (string)($db['charset'] ?? 'utf8mb4'); // Unix socket takes precedence if (!empty($db['unix_socket'])) { return sprintf( 'mysql:unix_socket=%s;dbname=%s;charset=%s', (string)$db['unix_socket'], (string)$db['dbname'], $charset ); } $host = (string)($db['host'] ?? 'localhost'); $port = (int)($db['port'] ?? 3306); return sprintf( 'mysql:host=%s;port=%d;dbname=%s;charset=%s', $host, $port, (string)$db['dbname'], $charset ); } private static function buildPgsqlDsn(array $db): string { if (empty($db['dbname'])) { throw new \RuntimeException('PostgreSQL config missing "dbname"'); } $host = (string)($db['host'] ?? 'localhost'); $port = (int)($db['port'] ?? 5432); // Hinweis: charset gehört bei pgsql nicht in den DSN return sprintf( 'pgsql:host=%s;port=%d;dbname=%s', $host, $port, (string)$db['dbname'] ); } private static function buildSqliteDsn(array $db): string { // SQLite kann :memory: oder einen Pfad nutzen $path = (string)($db['path'] ?? ''); if ($path === '') { // Default: Memory-DB $path = ':memory:'; } // Wenn es ein Pfad ist, stelle sicher, dass das Verzeichnis existiert. if ($path !== ':memory:') { $dir = \dirname($path); if ($dir && !is_dir($dir)) { @mkdir($dir, 0775, true); } } return 'sqlite:' . $path; } }