fehlerseiten
This commit is contained in:
@@ -206,6 +206,93 @@ function dd($value): void
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Zeigt eine sauber gestaltete Fehlerseite für 40x-Status-Codes mit Erklärung.
|
||||
*
|
||||
* @param int $statusCode Client-Error-Status (400–499)
|
||||
* @param string $explanation Optionale Zusatzinfo zur Problemursache
|
||||
* @param string[] $tips Handlungsvorschläge für Benutzer (optional)
|
||||
*/
|
||||
function renderClientError(int $statusCode, string $explanation = '', array $tips = []): void
|
||||
{
|
||||
if ($statusCode < 400 || $statusCode >= 500) {
|
||||
$statusCode = 400;
|
||||
}
|
||||
|
||||
$reasons = [
|
||||
400 => 'Ungültige Anfrage',
|
||||
401 => 'Nicht authentifiziert',
|
||||
403 => 'Zugriff verweigert',
|
||||
404 => 'Seite nicht gefunden',
|
||||
405 => 'Methode nicht erlaubt',
|
||||
408 => 'Anfrage abgelaufen',
|
||||
429 => 'Zu viele Anfragen',
|
||||
];
|
||||
|
||||
$reason = $reasons[$statusCode] ?? 'Clientseitiger Fehler';
|
||||
$defaultExplanation = match ($statusCode) {
|
||||
400 => 'Die Anfrage konnte aufgrund fehlender oder falscher Daten nicht verstanden werden.',
|
||||
401 => 'Bitte melden Sie sich an oder verwenden gültige Zugangsdaten.',
|
||||
403 => 'Sie besitzen keinen Zugriff auf diesen Bereich.',
|
||||
404 => 'Die angeforderte Ressource existiert nicht oder wurde verschoben.',
|
||||
405 => 'Diese Aktion ist auf dem Server nicht erlaubt.',
|
||||
408 => 'Die Anfrage hat zu lange gedauert; bitte erneut versuchen.',
|
||||
429 => 'Sie senden zu viele Anfragen in kurzer Zeit.',
|
||||
default => 'Die Anfrage kann nicht verarbeitet werden; überprüfen Sie die Eingaben.',
|
||||
};
|
||||
|
||||
$message = $explanation !== '' ? $explanation : $defaultExplanation;
|
||||
|
||||
http_response_code($statusCode);
|
||||
|
||||
$css = <<<CSS
|
||||
body { font-family: 'Segoe UI', system-ui, sans-serif; margin: 0; background: #0b1220; color: #e0e7ff; }
|
||||
.page { min-height: 100vh; display: flex; justify-content: center; align-items: center; padding: 2rem; }
|
||||
.card { max-width: 640px; background: linear-gradient(145deg, #16213d, #0d0f1f); border: 1px solid rgba(224,231,255,0.2); border-radius: 1rem; box-shadow: 0 20px 45px rgba(0,0,0,0.45); padding: 2rem; }
|
||||
h1 { margin: 0 0 0.5rem; font-size: clamp(2.5rem, 3vw, 3.5rem); }
|
||||
p { margin: 0 0 1rem; line-height: 1.6; color: rgba(224,231,255,0.9); }
|
||||
.badge { display: inline-flex; align-items: center; padding: 0.25rem 0.75rem; border-radius: 999px; font-size: 0.85rem; background: rgba(255,255,255,0.08); color: #a5b4fc; margin-bottom: 1rem; }
|
||||
ul { margin: 1rem 0 0; padding-left: 1.25rem; color: rgba(224,231,255,0.85); }
|
||||
a { color: #7dd3fc; text-decoration: none; }
|
||||
a:hover { text-decoration: underline; }
|
||||
CSS;
|
||||
|
||||
$rendered = strtr(<<<'HTML'
|
||||
<!doctype html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>Fehler {{code}}</title>
|
||||
<style>{{css}}</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="page">
|
||||
<section class="card">
|
||||
<div class="badge">{{status}}</div>
|
||||
<h1>{{code}} · {{reason}}</h1>
|
||||
<p>{{message}}</p>
|
||||
{{tips}}
|
||||
<p>Zurück zur Startseite: <a href="/">Dashboard</a></p>
|
||||
</section>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
HTML, [
|
||||
'{{code}}' => e((string)$statusCode),
|
||||
'{{reason}}' => e($reason),
|
||||
'{{status}}' => e(sprintf('%d Fehler', $statusCode)),
|
||||
'{{message}}' => e($message),
|
||||
'{{css}}' => $css,
|
||||
'{{tips}}' => count($tips) === 0
|
||||
? ''
|
||||
: '<ul>' . implode('', array_map(fn($tip) => '<li>' . e($tip) . '</li>', $tips)) . '</ul>',
|
||||
]);
|
||||
|
||||
echo $rendered;
|
||||
exit;
|
||||
}
|
||||
|
||||
/* =========================
|
||||
* Sonstiges
|
||||
* ========================= */
|
||||
|
||||
Reference in New Issue
Block a user