PDO::ERRMODE_EXCEPTION, PDO::ATTR_TIMEOUT => 3]); } else { $path = (string) ($db['sqlite_path'] ?? ''); if ($path === '' || !is_file($path)) return false; $pdo = new PDO('sqlite:' . $path, null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]); } return (int) $pdo->query('SELECT COUNT(*) FROM staff')->fetchColumn() > 0; } catch (Throwable $e) { return false; // keine nutzbare Datenbank: Erstinstallation ist in Ordnung } })(); $alreadyInstalled = file_exists(LOCK_FILE) || $existingInstallation; $errors = []; $success = false; // --------------------------------------------------------------- // Anforderungsprüfung // --------------------------------------------------------------- $checks = [ ['label' => 'PHP-Version 8.1 oder neuer (gefunden: ' . PHP_VERSION . ')', 'ok' => version_compare(PHP_VERSION, '8.1.0', '>=')], ['label' => 'PDO-Erweiterung', 'ok' => extension_loaded('pdo')], ['label' => 'PDO MySQL-Treiber (für Produktivbetrieb)', 'ok' => extension_loaded('pdo_mysql'), 'optional' => true], ['label' => 'PDO SQLite-Treiber (optional, für lokale Tests)', 'ok' => extension_loaded('pdo_sqlite'), 'optional' => true], ['label' => 'mbstring-Erweiterung', 'ok' => extension_loaded('mbstring')], ['label' => 'IMAP-Erweiterung (optional, nur für E-Mail-zu-Ticket)', 'ok' => extension_loaded('imap'), 'optional' => true], ['label' => 'Verzeichnis config/ ist beschreibbar', 'ok' => is_writable(ROOT_DIR . '/config')], ['label' => 'Verzeichnis uploads/ ist beschreibbar', 'ok' => is_writable(ROOT_DIR . '/uploads')], ['label' => 'Verzeichnis database/ ist beschreibbar', 'ok' => is_writable(ROOT_DIR . '/database')], ]; $requiredOk = true; foreach ($checks as $c) { if (empty($c['optional']) && !$c['ok']) { $requiredOk = false; } } // --------------------------------------------------------------- // Installation durchführen // --------------------------------------------------------------- if ($_SERVER['REQUEST_METHOD'] === 'POST' && !$alreadyInstalled && $requiredOk) { if (empty($_SESSION['install_csrf']) || !hash_equals($_SESSION['install_csrf'], $_POST['csrf_token'] ?? '')) { $errors[] = 'Ungültige Anfrage (Sitzung abgelaufen). Bitte die Seite neu laden und erneut versuchen.'; } else { $driver = ($_POST['driver'] ?? '') === 'mysql' ? 'mysql' : 'sqlite'; $siteName = trim($_POST['site_name'] ?? '') ?: 'DeskHub Support'; $siteUrl = rtrim(trim($_POST['site_url'] ?? ''), '/'); $adminName = trim($_POST['admin_name'] ?? ''); $adminEmail = trim($_POST['admin_email'] ?? ''); $adminPass = $_POST['admin_password'] ?? ''; $adminPass2 = $_POST['admin_password2'] ?? ''; if ($siteUrl === '') $errors[] = 'Bitte die URL der Installation angeben (z.B. https://support.firma.de).'; if ($adminName === '') $errors[] = 'Bitte einen Namen für das Admin-Konto angeben.'; if (!filter_var($adminEmail, FILTER_VALIDATE_EMAIL)) $errors[] = 'Bitte eine gültige Admin-E-Mail-Adresse angeben.'; if (strlen($adminPass) < 8) $errors[] = 'Das Admin-Passwort muss mindestens 8 Zeichen lang sein.'; if ($adminPass !== $adminPass2) $errors[] = 'Die beiden Passwörter stimmen nicht überein.'; if (!extension_loaded('pdo_' . $driver)) $errors[] = "Die PHP-Erweiterung pdo_{$driver} ist nicht installiert."; $dbConfig = [ 'driver' => $driver, 'host' => 'localhost', 'name' => 'deskhub', 'user' => 'deskhub_user', 'pass' => 'change_me', 'sqlite_path' => ROOT_DIR . '/database/deskhub.sqlite', ]; if ($driver === 'mysql') { $dbConfig['host'] = trim($_POST['db_host'] ?? 'localhost') ?: 'localhost'; $dbConfig['name'] = trim($_POST['db_name'] ?? ''); $dbConfig['user'] = trim($_POST['db_user'] ?? ''); $dbConfig['pass'] = $_POST['db_pass'] ?? ''; if ($dbConfig['name'] === '' || $dbConfig['user'] === '') { $errors[] = 'Bitte Datenbankname und Datenbankbenutzer angeben.'; } } $pdo = null; if (!$errors) { try { if ($driver === 'mysql') { $dsn = sprintf('mysql:host=%s;dbname=%s;charset=utf8mb4', $dbConfig['host'], $dbConfig['name']); $pdo = new PDO($dsn, $dbConfig['user'], $dbConfig['pass']); } else { @unlink($dbConfig['sqlite_path']); $pdo = new PDO('sqlite:' . $dbConfig['sqlite_path']); $pdo->exec('PRAGMA foreign_keys = ON;'); } $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch (Throwable $e) { $errors[] = 'Datenbankverbindung fehlgeschlagen: ' . $e->getMessage(); } } if (!$errors && $pdo) { try { $sql = file_get_contents(ROOT_DIR . '/database/schema.sql'); if ($driver === 'sqlite') { $sql = convert_schema_to_sqlite($sql); } $pdo->exec($sql); // Vordefiniertes Demo-Admin-Konto entfernen und durch das hier // eingegebene, echte Admin-Konto ersetzen. $pdo->exec("DELETE FROM staff WHERE email = 'admin@example.com'"); $stmt = $pdo->prepare( 'INSERT INTO staff (name, email, password_hash, role, department_id, is_active, created_at) VALUES (?,?,?,?,?,1,?)' ); $stmt->execute([$adminName, $adminEmail, password_hash($adminPass, PASSWORD_DEFAULT), 'admin', 1, date('Y-m-d H:i:s')]); // ── Initiale Einstellungen in die DB seeden ─────────────────────── // Alle Kerneinstellungen sofort in der settings-Tabelle anlegen, // damit sie Updates überleben (config.php wird beim Update nie // überschrieben, aber so sind die Werte auch bei Neuinstallationen // sofort über get_setting() abrufbar). // Sicherer, zufälliger App-Key – direkt hier generieren, damit er // sowohl in die DB (überlebt Updates) als auch in config.php geschrieben wird. $appKey = bin2hex(random_bytes(32)); $installSettings = [ 'app_key' => $appKey, // ← in DB: überlebt Updates 'display_name' => $siteName, 'site_url' => $siteUrl, 'timezone' => 'Europe/Berlin', 'smtp_from_email' => $adminEmail, 'smtp_from_name' => $siteName, 'mail_enabled' => '0', 'helpdesk_status' => 'online', 'kb_enabled' => '1', 'ticket_ratings_enabled' => '1', 'staff_session_timeout' => '30', 'retention_enabled' => '0', 'retention_months' => '24', 'ip_anonymize' => '0', 'upload_allowed_extensions' => 'png, jpg, jpeg, gif, pdf, txt, log, docx, xlsx, zip', 'upload_max_size_mb' => '10', ]; $upsertSql = $driver === 'sqlite' ? 'INSERT OR REPLACE INTO settings (setting_key, setting_value) VALUES (?, ?)' : 'INSERT INTO settings (setting_key, setting_value) VALUES (?, ?) ON DUPLICATE KEY UPDATE setting_value = VALUES(setting_value)'; foreach ($installSettings as $k => $v) { $pdo->prepare($upsertSql)->execute([$k, $v]); } // Alle vorhandenen Migrationsdateien sofort als "eingespielt" markieren, // da das Schema gerade frisch erstellt wurde. $migrTable = $driver === 'sqlite' ? "CREATE TABLE IF NOT EXISTS schema_migrations (migration VARCHAR(255) PRIMARY KEY, applied_at DATETIME NOT NULL DEFAULT (datetime('now')))" : "CREATE TABLE IF NOT EXISTS schema_migrations (migration VARCHAR(255) PRIMARY KEY, applied_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"; $pdo->exec($migrTable); $insertMigr = $driver === 'sqlite' ? 'INSERT OR IGNORE INTO schema_migrations (migration) VALUES (?)' : 'INSERT IGNORE INTO schema_migrations (migration) VALUES (?)'; foreach (glob(ROOT_DIR . '/database/migrations/*.sql') ?: [] as $mf) { $pdo->prepare($insertMigr)->execute([basename($mf)]); } } catch (Throwable $e) { $errors[] = 'Fehler beim Einrichten der Datenbank: ' . $e->getMessage(); } } if (!$errors) { $configArray = [ 'app_key' => $appKey, 'db' => $dbConfig, 'site' => [ 'name' => $siteName, 'url' => $siteUrl, 'admin_email' => $adminEmail, 'timezone' => 'Europe/Berlin', ], 'mail' => [ 'enabled' => false, 'from_email' => $adminEmail, 'from_name' => $siteName, ], 'imap' => [ 'enabled' => false, 'mailbox' => '{imap.example.com:993/imap/ssl}INBOX', 'user' => 'support@example.com', 'pass' => 'change_me', 'default_department_id' => 1, 'default_priority_id' => 2, ], 'uploads' => [ 'max_size_bytes' => 10 * 1024 * 1024, 'allowed_extensions' => ['png','jpg','jpeg','gif','pdf','txt','log','docx','xlsx','zip'], 'path' => ROOT_DIR . '/uploads', ], ]; $php = " DeskHub – Installation
🔒

Bereits installiert

Eingerichtet am

⚠️ Bitte das Verzeichnis install/ vom Server löschen, um diese Seite zu deaktivieren.

Zum Wiederholen: install/.installed löschen

✅

Installation abgeschlossen!

DeskHub wurde erfolgreich eingerichtet.


🗑️ Wichtig: Löschen Sie jetzt das Verzeichnis install/ vom Server, damit niemand die Installation wiederholen kann.
1 Systemvoraussetzungen
✗ Nicht alle Pflichtvoraussetzungen erfüllt. Bitte die rot markierten Punkte beheben und die Seite neu laden.
✗
2 Konfiguration
🗄️ Datenbank

Die Datenbank muss bereits existieren (leer) — Tabellen werden automatisch angelegt.

🌐 Website
Wird in E-Mail-Links verwendet. Kein abschließendes /
👤 Administrator-Konto