db.driver */ require_once __DIR__ . '/../database/sqlite_schema.php'; function config(): array { static $config = null; if ($config === null) { $config = require __DIR__ . '/../config/config.php'; // Nur für Tests: einzelne Werte überschreiben (wirkt ausschließlich mit DESKHUB_TESTING=1) if (getenv('DESKHUB_TESTING') === '1' && ($extra = json_decode((string) getenv('DESKHUB_CONFIG_JSON'), true)) && is_array($extra)) { $config = array_replace_recursive($config, $extra); } // Nur für Tests: Datenbankangaben (zum Beispiel eine MySQL-Testdatenbank) überschreiben alles andere, auch wenn der Test selbst DESKHUB_CONFIG_JSON setzt if (getenv('DESKHUB_TESTING') === '1' && ($testDbJson = json_decode((string) getenv('DESKHUB_TEST_DB_JSON'), true)) && is_array($testDbJson)) { $config['db'] = array_replace($config['db'] ?? [], $testDbJson); } // Nur für die Testläufe (tests/run_all.php setzt DESKHUB_TESTS_FORCE_SQLITE): nie die in config/config.php eingetragene Datenbank // (zum Beispiel die Produktiv-MySQL) benutzen, sondern SQLite. In Test-Webservern nur mit einer vom Test gesetzten Datenbankdatei. if (getenv('DESKHUB_TESTS_FORCE_SQLITE') === '1') { $testDb = getenv('DESKHUB_SQLITE_PATH'); if (PHP_SAPI === 'cli' || ($testDb !== false && $testDb !== '' && $testDb !== ':memory:')) { $config['db']['driver'] = 'sqlite'; $config['db']['sqlite_path'] = $testDb !== false && $testDb !== '' ? $testDb : ':memory:'; } } } return $config; } /** * Die Datenbank ist nicht eingerichtet: Mit vorhandenem Installer dorthin weiterleiten, sonst eine verständliche Meldung. * Auf der Kommandozeile (Cron, Skripte) wird ein Fehler geworfen. */ function app_not_installed(): never { $message = 'DeskHub ist noch nicht eingerichtet: Die Datenbank fehlt. Bitte die Installation unter /install/ abschließen.'; if (PHP_SAPI === 'cli') throw new RuntimeException($message); $installerOpen = is_file(__DIR__ . '/../install/index.php') && !is_file(__DIR__ . '/../install/.installed'); if ($installerOpen && !headers_sent()) { header('Location: /install/'); exit; } http_response_code(503); header('Content-Type: text/plain; charset=utf-8'); exit($message . " "); } function get_db(): PDO { static $pdo = null; if ($pdo !== null) { return $pdo; } $cfg = config()['db']; if ($cfg['driver'] === 'sqlite') { $dbPath = $cfg['sqlite_path']; $needInit = !file_exists($dbPath) || filesize($dbPath) === 0; // Eine SQLite-Datenbank wird nie nebenbei angelegt (z. B. durch den ersten Seitenaufruf mit einer mitgelieferten Konfiguration): // Das macht allein der Installer, wenn SQLite gewählt wurde. Nur Tests und Entwickler, die den Pfad ausdrücklich per // DESKHUB_SQLITE_PATH angeben, dürfen eine neue Datenbank erzeugen lassen. if ($needInit && $dbPath !== ':memory:' && (string) getenv('DESKHUB_SQLITE_PATH') === '') { app_not_installed(); } $pdo = new PDO('sqlite:' . $dbPath); $pdo->exec('PRAGMA journal_mode = WAL;'); $pdo->exec('PRAGMA foreign_keys = ON;'); if ($needInit) { $schemaFile = __DIR__ . '/../database/schema.sql'; if (!file_exists($schemaFile)) { throw new \RuntimeException("Schema-Datei nicht gefunden: $schemaFile"); } $sql = file_get_contents($schemaFile); $pdo->exec(convert_schema_to_sqlite($sql)); } } else { $dsn = sprintf('mysql:host=%s;dbname=%s;charset=utf8mb4', $cfg['host'], $cfg['name']); $pdo = new PDO($dsn, $cfg['user'], $cfg['pass'], [ PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4", ]); } $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); // Ausstehende Schema-Migrationen automatisch einspielen. // Bereits angewendete werden übersprungen → Einstellungen bleiben erhalten. $migrateFile = __DIR__ . '/../database/migrate.php'; if (file_exists($migrateFile)) { require_once $migrateFile; $migrationResult = run_migrations($pdo); if ($migrationResult['errors']) { throw new RuntimeException('Datenbankmigration fehlgeschlagen: ' . implode('; ', $migrationResult['errors'])); } } return $pdo; } /** Liefert NOW() als DATETIME-String, kompatibel zu beiden Treibern */ function db_now(): string { return date('Y-m-d H:i:s'); } /** SQL-Datum-Differenz (Stunden addieren), kompatibel zu beiden Treibern -> wird in PHP berechnet */ function add_hours(string $datetime, int $hours): string { $ts = strtotime($datetime) + ($hours * 3600); return date('Y-m-d H:i:s', $ts); }