New version

This commit is contained in:
2026-01-24 01:42:46 +01:00
parent 6063ae4193
commit f3f24cebba
68 changed files with 3136 additions and 407 deletions

View File

@@ -1 +1,123 @@
<?php // TODO
<?php
declare(strict_types=1);
namespace App;
final class Database
{
public static function createPdo(Config $config): ?\PDO
{
if (!$config->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;
}
}