commit basic
This commit is contained in:
123
src/App/Database.php
Executable file
123
src/App/Database.php
Executable file
@@ -0,0 +1,123 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user