*/ function app_public_page_view_labels(): array { return [ 'landing' => 'Startseite', 'prices' => 'Preise', 'register' => 'Registrierung', 'login' => 'Login', 'privacy' => 'Datenschutz', 'imprint' => 'Impressum', 'terms' => 'AGB', 'dpa' => 'AVV', 'withdrawal_information' => 'Widerrufsbelehrung', ]; } /** * Erhoeht ausschliesslich einen aggregierten Tageszaehler. Es werden keine * Request-Metadaten gelesen oder gespeichert. Schreibfehler duerfen eine * oeffentliche Seite nicht unbenutzbar machen, etwa waehrend eines Deploys, * bei dem die Migration wenige Sekunden nach dem Code eingespielt wird. */ function app_record_public_page_view(string $pageKey, ?PDO $pdo = null): void { // Ein explizit injiziertes PDO ist nur fuer den CLI-Regressionstest // vorgesehen. Normale CLI-Aufrufe sollen keine Seitenansicht erzeugen. if (($pdo === null && PHP_SAPI === 'cli') || ($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'GET') { return; } if (!array_key_exists($pageKey, app_public_page_view_labels())) { throw new InvalidArgumentException('Unbekannter öffentlicher Seitenschlüssel.'); } try { $stmt = ($pdo ?? app_db_pdo())->prepare( 'INSERT INTO public_page_views (view_date, page_key, view_count) VALUES (CURRENT_DATE, ?, 1) ON DUPLICATE KEY UPDATE view_count = view_count + 1' ); $stmt->execute([$pageKey]); } catch (Throwable $e) { error_log('Anonymer Seitenzähler konnte nicht aktualisiert werden: ' . $e->getMessage()); } } /** * @return array{ * totals: array{today: int, last_30_days: int, all_time: int}, * pages: list * } */ function app_public_page_view_summary(PDO $pdo): array { $totalsRow = $pdo->query( 'SELECT COALESCE(SUM(CASE WHEN view_date = CURRENT_DATE THEN view_count ELSE 0 END), 0) AS today, COALESCE(SUM(CASE WHEN view_date >= CURRENT_DATE - INTERVAL 29 DAY THEN view_count ELSE 0 END), 0) AS last_30_days, COALESCE(SUM(view_count), 0) AS all_time FROM public_page_views' )->fetch() ?: []; $pageRows = $pdo->query( 'SELECT page_key, COALESCE(SUM(CASE WHEN view_date = CURRENT_DATE THEN view_count ELSE 0 END), 0) AS today, COALESCE(SUM(CASE WHEN view_date >= CURRENT_DATE - INTERVAL 29 DAY THEN view_count ELSE 0 END), 0) AS last_30_days, COALESCE(SUM(view_count), 0) AS all_time FROM public_page_views GROUP BY page_key ORDER BY all_time DESC, page_key ASC' )->fetchAll(); $labels = app_public_page_view_labels(); $pages = []; foreach ($pageRows as $row) { $pageKey = (string)$row['page_key']; $pages[] = [ 'page_key' => $pageKey, 'label' => $labels[$pageKey] ?? $pageKey, 'today' => (int)$row['today'], 'last_30_days' => (int)$row['last_30_days'], 'all_time' => (int)$row['all_time'], ]; } return [ 'totals' => [ 'today' => (int)($totalsRow['today'] ?? 0), 'last_30_days' => (int)($totalsRow['last_30_days'] ?? 0), 'all_time' => (int)($totalsRow['all_time'] ?? 0), ], 'pages' => $pages, ]; }