(string)env_get($vars, 'DB_SERVERNAME', 'localhost'), 'port' => (int)env_get($vars, 'DB_PORT', '3306'), 'user' => (string)env_get($vars, 'DB_USERNAME', ''), 'pass' => (string)env_get($vars, 'DB_PASSWORD', ''), 'db' => 'FabianWebsite', // Registrierung optional abschaltbar 'allow_register' => ((string)env_get($vars, 'ADMINER_ALLOW_REGISTER', '1')) !== '0', ]; return $cfg; } function adminer_app_pdo() { $cfg = adminer_app_config(); if ($cfg['host'] === '' || (int)$cfg['port'] <= 0 || $cfg['user'] === '' || $cfg['db'] === '') { throw new RuntimeException('DB_* ist in .env nicht vollständig gesetzt (für Admin-Login-User-Store).'); } $dsn = sprintf('mysql:host=%s;port=%d;dbname=%s;charset=utf8mb4', $cfg['host'], (int)$cfg['port'], $cfg['db']); return new PDO($dsn, $cfg['user'], $cfg['pass'], [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ]); } function adminer_validate_username($u) { $u = trim((string)$u); if ($u === '') return [false, 'Benutzername darf nicht leer sein.']; if (strlen($u) < 3) return [false, 'Benutzername ist zu kurz (min. 3 Zeichen).']; if (strlen($u) > 50) return [false, 'Benutzername ist zu lang (max. 50 Zeichen).']; if (!preg_match('/^[A-Za-z0-9_.-]+$/', $u)) return [false, 'Nur Buchstaben, Zahlen, Punkt, Unterstrich und Minus sind erlaubt.']; return [true, null]; } function adminer_app_bootstrap() { $pdo = adminer_app_pdo(); $pdo->exec( 'CREATE TABLE IF NOT EXISTS adminer_users (' . 'id INT AUTO_INCREMENT PRIMARY KEY,' . 'username VARCHAR(190) NOT NULL UNIQUE,' . 'password_hash VARCHAR(255) NOT NULL,' . 'is_admin TINYINT(1) NOT NULL DEFAULT 0,' . 'created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP' . ') ENGINE=InnoDB DEFAULT CHARSET=utf8mb4' ); // Migration: falls Tabelle bereits existiert (alte Version ohne is_admin) try { $col = $pdo->query("SHOW COLUMNS FROM adminer_users LIKE 'is_admin'")->fetch(); if (!$col) { $pdo->exec('ALTER TABLE adminer_users ADD COLUMN is_admin TINYINT(1) NOT NULL DEFAULT 0'); } } catch (Throwable $e) { // Wenn ALTER scheitert, lieber deutlich machen throw new RuntimeException('Konnte adminer_users nicht migrieren (is_admin): ' . $e->getMessage()); } // Optional: auto-seed from .env ADMINER_APP_SEED_USER/PASS $vars = env_load(dirname(__DIR__) . '/.env'); $seedUser = env_get($vars, 'ADMINER_APP_SEED_USER', ''); $seedPass = env_get($vars, 'ADMINER_APP_SEED_PASS', ''); if ($seedUser !== '' && $seedPass !== '') { $stmt = $pdo->prepare('SELECT id FROM adminer_users WHERE username = ?'); $stmt->execute([(string)$seedUser]); $id = $stmt->fetchColumn(); if (!$id) { $hash = password_hash((string)$seedPass, PASSWORD_DEFAULT); $ins = $pdo->prepare('INSERT INTO adminer_users (username, password_hash, is_admin) VALUES (?, ?, 1)'); $ins->execute([(string)$seedUser, $hash]); } else { // sicherstellen, dass Seed-User Admin ist $upd = $pdo->prepare('UPDATE adminer_users SET is_admin = 1 WHERE id = ?'); $upd->execute([(int)$id]); } } } function adminer_app_is_logged_in() { adminer_app_session_start(); if (PHP_SAPI === 'cli') { return false; } return !empty($_SESSION['adminer_app']['ok']); } function adminer_app_logout() { adminer_app_session_start(); if (PHP_SAPI === 'cli') { return; } unset($_SESSION['adminer_app']); } function adminer_app_try_login($username, $password) { $username = trim((string)$username); $password = (string)$password; if ($username === '' || $password === '') { return ['ok' => false, 'error' => 'Bitte Benutzername und Passwort eingeben.']; } $pdo = adminer_app_pdo(); $stmt = $pdo->prepare('SELECT id, password_hash, is_admin FROM adminer_users WHERE username = ?'); $stmt->execute([$username]); $row = $stmt->fetch(); if (!$row || empty($row['password_hash']) || !password_verify($password, (string)$row['password_hash'])) { return ['ok' => false, 'error' => 'Login fehlgeschlagen.']; } // Erst nach Verifizierung erlauben if (empty($row['is_admin'])) { return ['ok' => false, 'error' => 'Dein Konto ist noch nicht verifiziert. Bitte lasse dich von einem Server-Administrator freischalten.']; } adminer_app_session_start(); if (PHP_SAPI !== 'cli') { $_SESSION['adminer_app'] = [ 'ok' => true, 'username' => $username, 'uid' => (int)$row['id'], 'is_admin' => (bool)$row['is_admin'], ]; } return ['ok' => true, 'error' => null]; } function adminer_app_allow_register() { $cfg = adminer_app_config(); return !empty($cfg['allow_register']); } function adminer_app_try_register($username, $password, $password2) { if (!adminer_app_allow_register()) { return ['ok' => false, 'error' => 'Registrierung ist deaktiviert.']; } list($ok, $msg) = adminer_validate_username($username); if (!$ok) return ['ok' => false, 'error' => $msg]; $password = (string)$password; $password2 = (string)$password2; if (strlen($password) < 8) { return ['ok' => false, 'error' => 'Passwort ist zu kurz (min. 8 Zeichen).']; } if ($password !== $password2) { return ['ok' => false, 'error' => 'Passwörter stimmen nicht überein.']; } $pdo = adminer_app_pdo(); // Unique check $stmt = $pdo->prepare('SELECT id FROM adminer_users WHERE username = ?'); $stmt->execute([trim((string)$username)]); if ($stmt->fetchColumn()) { return ['ok' => false, 'error' => 'Benutzername ist bereits vergeben.']; } // Standard: unverifiziert (is_admin=0) $hash = password_hash($password, PASSWORD_DEFAULT); $ins = $pdo->prepare('INSERT INTO adminer_users (username, password_hash, is_admin) VALUES (?, ?, 0)'); $ins->execute([trim((string)$username), $hash]); return ['ok' => true, 'error' => null]; }