Pages d'erreur personnalisées
OxPHP sert des pages d'erreur HTML personnalisées pour les réponses 4xx et 5xx. Chaque page est lue depuis le disque une seule fois au démarrage et servie depuis la mémoire, de sorte qu'aucune E/S disque ne se produit pendant le traitement des requêtes.
Fonctionnement
- Chargement au démarrage. Au démarrage, OxPHP lit le répertoire indiqué par
ERROR_PAGES_DIRet charge en mémoire chaque fichier{status}.htmlvalide. - Règles de nommage. Les fichiers doivent être nommés avec un code de statut HTTP numérique compris dans la plage 400–599 (par exemple,
404.html,503.html). Les fichiers portant un nom non numérique, un code de statut hors de cette plage (y compris200.html) ou une extension autre que.htmlsont ignorés silencieusement. - Remplacement du corps. Lorsqu'OxPHP génère une réponse 4xx ou 5xx, il vérifie s'il existe une page d'erreur préchargée correspondante. Si c'est le cas, OxPHP ne remplace que le corps et les en-têtes qui le décrivent :
Content-Typeest défini àtext/html; charset=utf-8,Content-Lengthà la taille de la page, et les en-têtes liés au corps d'origine (Content-Encoding,ETag,Last-Modified) sont supprimés afin qu'ils ne puissent ni étiqueter à tort ni revalider le remplacement (par exemple, un corps d'erreur PHP compressé parob_gzhandlerne laissera pas la page HTML marquéeContent-Encoding: gzip). Les en-têtes qui décrivent la sémantique de la réponse plutôt que le corps sont conservés dans la page personnalisée :Content-Rangesur un416 Range Not Satisfiable,Retry-Aftersur un529 Site is overloaded, etAllowsur un405 Method Not Allowed. - Repli. Si le répertoire n'existe pas ou ne peut pas être lu au démarrage, OxPHP enregistre un avertissement et continue sans pages d'erreur personnalisées. Les réponses d'erreur se replient sur des corps en texte brut jusqu'à ce que le répertoire soit corrigé et le serveur redémarré.
Configuration
| Variable | Valeur par défaut | Description |
|---|---|---|
ERROR_PAGES_DIR |
(non défini) | Répertoire contenant les fichiers HTML des pages d'erreur personnalisées. Les fichiers doivent être nommés {status}.html pour les codes de statut 400–599. Lorsqu'elle n'est pas définie, les réponses d'erreur utilisent des corps en texte brut |
Exemples de pages
Chaque page d'erreur est un fichier HTML autonome nommé {status}.html. Gardez-les avec des styles en ligne et sans ressources externes : une requête secondaire qui échouerait casserait sinon la page d'erreur elle-même.
Modèle réutilisable
Copiez ceci dans chaque {status}.html et modifiez le <title>, le <h1> et le <p> :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>500 — Internal Server Error</title>
<style>
body { font-family: system-ui, sans-serif; text-align: center; padding: 4rem 1rem; color: #333; }
h1 { font-size: 2rem; margin-bottom: 0.5rem; }
p { color: #666; }
</style>
</head>
<body>
<h1>Something went wrong</h1>
<p>Please try again in a moment.</p>
</body>
</html>Codes de statut à fournir
OxPHP remplace le corps de chaque 4xx ou 5xx qui atteint le pipeline de réponse. Voici les codes qu'il renvoie de lui-même, fournissez donc un fichier pour chacun :
| Fichier | Statut | Quand OxPHP le renvoie |
|---|---|---|
400.html |
Bad Request | Une requête QUERY (RFC 10008) envoyée sans en-tête Content-Type |
404.html |
Not Found | Aucun fichier ou route correspondant ; un dotfile bloqué (.env, .git/) ; une requête .php directe en mode Framework ; le repli par défaut de PHP_DENY_PATHS |
413.html |
Payload Too Large | Le corps de la requête dépasse la taille maximale |
416.html |
Range Not Satisfiable | Un en-tête Range non satisfiable sur un fichier statique (Content-Range est conservé) |
500.html |
Internal Server Error | Une erreur PHP non interceptée ou fatale |
503.html |
Service Unavailable | Drainage gracieux pendant l'arrêt |
504.html |
Gateway Timeout | La requête a dépassé REQUEST_TIMEOUT_SECONDS |
529.html |
Site is overloaded | La file d'attente des requêtes est pleine à QUEUE_CAPACITY (Retry-After est conservé) |
Tout autre 4xx ou 5xx fonctionne de la même manière : ajoutez un 403.html, un 451.html, et ainsi de suite pour les codes que renvoie votre application PHP, ou pour un statut PHP_DENY_FALLBACK personnalisé. La seule exception est le 429 du limiteur de débit, qui est produit avant l'exécution de ce gestionnaire et utilise toujours son corps par défaut (voir la note ci-dessous).
Exemples prêts à l'emploi
Une page 404 minimale :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>404 - Page Not Found</title>
<style>
body { font-family: system-ui, sans-serif; text-align: center; padding: 4rem 1rem; color: #333; }
h1 { font-size: 2rem; margin-bottom: 0.5rem; }
p { color: #666; }
</style>
</head>
<body>
<h1>Page Not Found</h1>
<p>The page you requested does not exist.</p>
</body>
</html>Une page de maintenance 503 avec rafraîchissement automatique :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="refresh" content="30">
<title>503 - Service Unavailable</title>
<style>
body { font-family: system-ui, sans-serif; text-align: center; padding: 4rem 1rem; color: #333; }
h1 { font-size: 2rem; margin-bottom: 0.5rem; }
p { color: #666; }
</style>
</head>
<body>
<h1>Service Unavailable</h1>
<p>We are performing maintenance. This page will refresh automatically.</p>
</body>
</html>Dépannage
Les pages d'erreur personnalisées n'apparaissent pas
Vérifiez qu'ERROR_PAGES_DIR est défini et que les fichiers sont nommés correctement.
Vérification : Confirmez le chemin du répertoire actif et qu'OxPHP a bien enregistré des lignes « Loaded custom error page » au démarrage :
docker logs my-app 2>&1 | grep "error page"Correctif : Assurez-vous que le chemin du répertoire est correct, que les fichiers sont nommés {status}.html et que le conteneur dispose d'un accès en lecture au répertoire.
Avertissement au démarrage concernant un répertoire de pages d'erreur manquant
OxPHP enregistre un avertissement et continue sans pages d'erreur personnalisées si le répertoire ERROR_PAGES_DIR n'existe pas ou ne peut pas être lu. Les réponses d'erreur utilisent alors des corps en texte brut. Vérifiez que le volume est correctement monté dans Docker :
docker run --rm -v ./errors:/var/www/errors:ro \
-e ERROR_PAGES_DIR=/var/www/errors \
ghcr.io/oxphp/oxphp:0.10.0Une réponse 429 affiche toujours le corps par défaut
Certaines réponses générées avant l'exécution du pipeline de réponse — comme les rejets liés à la limitation de débit — ne sont pas traitées par le gestionnaire de pages d'erreur. La réponse 429 Too Many Requests du limiteur de débit utilise son corps par défaut, qu'un fichier 429.html soit présent ou non.
Exemple Docker
services:
app:
image: ghcr.io/oxphp/oxphp:0.10.0
ports:
- "8080:8080"
volumes:
- ./src:/var/www/html:ro
- ./errors:/var/www/errors:ro
environment:
ERROR_PAGES_DIR: "/var/www/errors"
ENTRY_FILE: "index.php"Structure du répertoire :
project/
src/
public/
index.php
errors/
400.html
403.html
404.html
500.html
503.html
504.html
529.htmlBonnes pratiques
- Gardez les pages d'erreur autonomes avec du CSS en ligne. Ne référencez pas de feuilles de style ou de scripts externes : ces requêtes secondaires pourraient elles-mêmes échouer.
- Incluez une balise
<meta http-equiv="refresh" content="30">dans503.htmlafin que les utilisateurs réessaient automatiquement une fois la maintenance terminée. - Gardez les pages d'erreur légères. Chaque page chargée est conservée en mémoire pendant toute la durée de vie du processus serveur.
Les pages d'erreur personnalisées s'appliquent aux réponses qui transitent par le pipeline de requêtes normal. La réponse 429 Too Many Requests du limiteur de débit est générée avant l'exécution du gestionnaire de pages d'erreur et utilise son corps par défaut en texte brut.
Voir aussi
- Routage — comment les réponses 404 sont générées pour les chemins sans correspondance
- Limitation de débit — comportement de la limitation de débit et réponses 429
- Référence de configuration — référence complète des variables d'environnement