0, 'path' => '/', 'domain' => '', // Standard: aktuelle Domain 'secure' => $secure, 'httponly' => true, 'samesite' => 'Lax', ]); session_start(); } // --- Sprache ermitteln / speichern --- function auth_get_lang(): string { if (!empty($_GET['lang'])) { $_SESSION['lang'] = $_GET['lang']; } if (!empty($_SESSION['lang'])) { return $_SESSION['lang']; } return 'en'; } // --- CSRF-Token --- function auth_csrf_token(): string { if (empty($_SESSION['csrf_token'])) { $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); } return $_SESSION['csrf_token']; } function auth_verify_csrf(?string $token): bool { if (empty($token) || empty($_SESSION['csrf_token'])) { return false; } return hash_equals($_SESSION['csrf_token'], $token); } // --- PDO Helper --- function auth_pdo(): PDO { // $pdo kommt aus config/db.php global $pdo; if (!$pdo instanceof PDO) { throw new RuntimeException('Database connection not available.'); } return $pdo; } // --- Aktueller User --- function auth_current_user(): ?array { if (!empty($_SESSION['user_cache']) && is_array($_SESSION['user_cache'])) { return $_SESSION['user_cache']; } if (empty($_SESSION['user_id'])) { return null; } $pdo = auth_pdo(); $stmt = $pdo->prepare('SELECT * FROM users WHERE id = :id LIMIT 1'); $stmt->execute([':id' => $_SESSION['user_id']]); $user = $stmt->fetch(PDO::FETCH_ASSOC); if (!$user) { return null; } $_SESSION['user_cache'] = $user; return $user; } function auth_require_login(): void { if (!auth_current_user()) { $lang = auth_get_lang(); header('Location: /login.php?lang=' . urlencode($lang)); exit; } } // --- Avatar-Helfer --- function auth_user_initials(array $user): string { $name = $user['full_name'] ?? ''; if (trim($name) === '') { $name = $user['username'] ?? $user['email'] ?? 'U'; } $parts = preg_split('/\s+/', trim($name)); $initials = strtoupper(mb_substr($parts[0], 0, 1)); if (count($parts) > 1) { $initials .= strtoupper(mb_substr(end($parts), 0, 1)); } return $initials; } function auth_user_avatar_url(array $user): ?string { if (!empty($user['avatar_path'])) { return '/uploads/avatars/' . ltrim($user['avatar_path'], '/'); } return null; } // --- Registrierung --- function auth_register_user( string $email, string $username, string $fullName, string $password, string $passwordConfirm, string $preferredLang ): array { $pdo = auth_pdo(); $errors = []; $email = trim($email); $username = trim($username); $fullName = trim($fullName); if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { $errors['email'] = 'Bitte eine gültige E-Mail-Adresse eingeben.'; } if ($username === '' || !preg_match('/^[a-zA-Z0-9_.-]{3,32}$/', $username)) { $errors['username'] = 'Username muss 3–32 Zeichen lang sein und darf nur Buchstaben, Zahlen, ., _, - enthalten.'; } if (mb_strlen($fullName) < 3) { $errors['full_name'] = 'Bitte einen vollständigen Namen angeben.'; } if (mb_strlen($password) < 10) { $errors['password'] = 'Passwort muss mindestens 10 Zeichen lang sein.'; } if ($password !== $passwordConfirm) { $errors['password_confirm'] = 'Passwörter stimmen nicht überein.'; } $allowedLangs = ['de', 'en', 'it', 'fr']; if (!in_array($preferredLang, $allowedLangs, true)) { $preferredLang = 'en'; } // E-Mail / Username bereits vergeben? if (!$errors) { $stmt = $pdo->prepare('SELECT email, username FROM users WHERE email = :email OR username = :username LIMIT 1'); $stmt->execute([ ':email' => $email, ':username' => $username, ]); $existing = $stmt->fetch(PDO::FETCH_ASSOC); if ($existing) { if (strcasecmp($existing['email'], $email) === 0) { $errors['email'] = 'Diese E-Mail-Adresse wird bereits verwendet.'; } if (strcasecmp($existing['username'], $username) === 0) { $errors['username'] = 'Dieser Username ist bereits vergeben.'; } } } if ($errors) { return ['success' => false, 'errors' => $errors]; } $hash = password_hash($password, PASSWORD_DEFAULT); $now = (new DateTimeImmutable('now', new DateTimeZone('UTC')))->format('Y-m-d H:i:s'); $stmt = $pdo->prepare(' INSERT INTO users (email, username, full_name, password_hash, preferred_lang, created_at, updated_at) VALUES (:email, :username, :full_name, :password_hash, :preferred_lang, :created_at, :updated_at) '); $stmt->execute([ ':email' => $email, ':username' => $username, ':full_name' => $fullName, ':password_hash' => $hash, ':preferred_lang'=> $preferredLang, ':created_at' => $now, ':updated_at' => $now, ]); $userId = (int)$pdo->lastInsertId(); $_SESSION['user_id'] = $userId; unset($_SESSION['user_cache']); // neu laden beim nächsten Zugriff $_SESSION['lang'] = $preferredLang; return ['success' => true, 'errors' => []]; } // --- Login --- function auth_login(string $login, string $password): array { $pdo = auth_pdo(); $errors = []; $login = trim($login); if ($login === '' || $password === '') { $errors['login'] = 'Bitte Zugangsdaten vollständig ausfüllen.'; return ['success' => false, 'errors' => $errors]; } $stmt = $pdo->prepare(' SELECT * FROM users WHERE email = :login OR username = :login LIMIT 1 '); $stmt->execute([':login' => $login]); $user = $stmt->fetch(PDO::FETCH_ASSOC); if (!$user || !password_verify($password, $user['password_hash'])) { $errors['login'] = 'E-Mail/Username oder Passwort ist falsch.'; return ['success' => false, 'errors' => $errors]; } $_SESSION['user_id'] = (int)$user['id']; unset($_SESSION['user_cache']); if (!empty($user['preferred_lang'])) { $_SESSION['lang'] = $user['preferred_lang']; } // Option: Password-Rehash, wenn Algorithmus veraltet if (password_needs_rehash($user['password_hash'], PASSWORD_DEFAULT)) { $newHash = password_hash($password, PASSWORD_DEFAULT); $upd = $pdo->prepare('UPDATE users SET password_hash = :hash WHERE id = :id'); $upd->execute([':hash' => $newHash, ':id' => $user['id']]); } return ['success' => true, 'errors' => []]; } // --- Profil aktualisieren (Name, Sprache) --- function auth_update_profile(int $userId, string $fullName, string $preferredLang): array { $pdo = auth_pdo(); $errors = []; $fullName = trim($fullName); if (mb_strlen($fullName) < 3) { $errors['full_name'] = 'Bitte einen gültigen Namen angeben.'; } $allowedLangs = ['de', 'en', 'it', 'fr']; if (!in_array($preferredLang, $allowedLangs, true)) { $preferredLang = 'en'; } if ($errors) { return ['success' => false, 'errors' => $errors]; } $now = (new DateTimeImmutable('now', new DateTimeZone('UTC')))->format('Y-m-d H:i:s'); $stmt = $pdo->prepare(' UPDATE users SET full_name = :full_name, preferred_lang = :preferred_lang, updated_at = :updated_at WHERE id = :id '); $stmt->execute([ ':full_name' => $fullName, ':preferred_lang'=> $preferredLang, ':updated_at' => $now, ':id' => $userId, ]); unset($_SESSION['user_cache']); $_SESSION['lang'] = $preferredLang; return ['success' => true, 'errors' => []]; } // --- Logout --- function auth_logout(): void { $_SESSION = []; if (ini_get('session.use_cookies')) { $params = session_get_cookie_params(); setcookie(session_name(), '', time() - 42000, $params['path'], $params['domain'], $params['secure'], $params['httponly']); } session_destroy(); }