0, 'path' => '/', 'secure' => request_is_https(), 'httponly' => true, 'samesite' => 'Lax', ]); session_start(); } // Sicherheits-Header header('X-Content-Type-Options: nosniff'); header('X-Frame-Options: DENY'); header('Referrer-Policy: strict-origin-when-cross-origin'); header("Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https://api.qrserver.com; font-src 'self'; connect-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self';"); header('Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=()'); // HSTS nur bei echtem HTTPS senden if (request_is_https()) { header('Strict-Transport-Security: max-age=31536000; includeSubDomains'); } // PHP-Fehler nie im Browser ausgeben (Produktion) @ini_set('display_errors', '0'); @ini_set('log_errors', '1'); // "Eingebauter" Ersatz für echte Server-Cronjobs (siehe includes/pseudo_cron.php). // Bewusst auf JEDER Seite (nicht nur im Mitarbeiterbereich): auch Kundenportal-Besuche // (Ticket einreichen, Status prüfen, Login, KB) halten die Hintergrund-Jobs am Laufen – // genau wie bei WordPress' wp-cron.php reicht dafür jeder Seitenaufruf, nicht nur ein // eingeloggter Mitarbeiter. Läuft NACH dem Senden der Antwort, verlangsamt also nichts. pseudo_cron_schedule_background(); // Aktive Plugins laden (Fehler in Plugins werden isoliert, siehe includes/plugins.php). plugins_boot(); // Mehrsprachigkeit: bei einer anderen Sprache als Deutsch (oder im Sammelmodus) wird die fertige Seite übersetzt (includes/i18n.php). i18n_start(); // DB-kompatibler SQL-Ausdruck für Domain-Teil einer E-Mail function sql_email_domain(string $col): string { $driver = config()['db']['driver'] ?? 'sqlite'; return $driver === 'mysql' ? "SUBSTRING_INDEX($col,'@',-1)" : "SUBSTR($col, INSTR($col,'@')+1)"; }