web-dev-qa-db-fra.com

La directive .htaccess ErrorDocument ne récupère pas les erreurs 404 déclenchées par PHP http_response_code (404)

Apache 2.4.10 sur Windows. J'ai une application stable Zend Framework 1 PHP. J'ai juste décidé d'ajouter une directive ErrorDocument à .htaccess. Je suis complètement déconcerté par les trois comportements différents des 404, en fonction de la manière dont ils sont déclenchés.

Mon fichier .htaccess contient:

ErrorDocument 404 "Page not found"
RedirectMatch 404 /uploads/(.*/)?private/

Si je tape simplement une URL pour une page inexistante dans la barre d'adresse, j'obtiens la page d'erreur produite par ErrorController de Zend Framework.

Si je saisis /uploads/private/foo (correspondant à RedirectMatch), la sortie ErrorDocument est alors produite, comme prévu.

Mais si dans mon PHP code je le fais

http_response_code(404);
exit(0);

alors j'obtiens la page d'erreur standard du navigateur. C'est celui que je ne comprends pas du tout. Si j'utilise l'onglet Réseau dans Chrome Outils de développement, je peux voir que les trois demandes donnent un statut 404. J'imagine que je peux imaginer que la configuration de traitement des erreurs du Zend Framework piège l'URL inexistante et fasse son travail, en contournant le traitement de ErrorDocument. Mais je ne comprends pas comment un code exit immédiat de PHP avec un statut de 404 passerait au-delà de ErrorDocument.

Quel code PHP pourrais-je écrire pour déclencher la directive ErrorDocument?

MODIFIER:

Basé sur la réponse de Tim Fountain , je devrais fournir plus de contexte: comme indiqué ci-dessus, ma page ZF ErrorController est configurée pour regarder de la manière que je veux - je vois cette page lorsque j'entre une URL pour une page inexistante. Dans cette situation particulière, je suis en train d'exécuter du code à partir d'un WordPress mu-plugin (WP est installé sous le répertoire ZF public). Le fichier .htaccess ne dirige naturellement pas les demandes de fichiers existants situés sous public vers ZF. Les demandes pour tout ce qui se trouve en dessous de public/wp vont plutôt à public/wp/index.php Le mu-plugin bootstraps ZF (mais n'appelle pas la méthode run() de l'amorce) puis examine la demande. Si ce n'est pas autorisé (selon les variables de session Auth de ZF), je souhaite donner un 404 (et non 403). Auparavant, je le faisais en redirigeant réellement vers une URL inexistante, ce qui montrait parfaitement la page ErrorController, mais elle laissait également la barre d'adresse affichant l'URL inexistante. J'ai décidé d'ajouter la directive ErrorDocument afin que la barre d'adresse affiche toujours l'URL saisie par l'utilisateur. Dans mon code actuel, je n'avais pas une simple chaîne sur la directive, mais plutôt cette URL: /default/error/error?error_handler[type]=404. Je l'ai changée en une simple chaîne pour m'assurer que l'URL ne posait aucun problème. Notez que lorsque j'entre une URL pour quelque chose dans un répertoire private déclenchant la RedirectMatch, je vois la page ZF ErrorController, alors je sais que l'URL en elle-même n'est pas un problème. Je voulais juste réduire la complexité de cette publication.

La réponse de Tim indique que mon code problème envoie une page 404 vide directement au navigateur et que celui-ci le modifie en texte explicatif. C'est clairement ce qui se passe!

Cela signifie-t-il que mon problème est que je dois produire un contenu de page de longueur non nulle et utiliser header() pour définir le statut, car http_response_code() envoie un contenu vide directement au navigateur? Mais ce qui n'est pas clair dans sa réponse, c'est pourquoi la directive ErrorDocument serait ignorée.

L'URL de la demande à l'origine de ce problème est http://www.example.com/wp/foo. La DocumentRoot est .../public. Ceci n'est pas réécrit par .htaccess pour aller à ZF, mais va directement à public/wp/index.php. Dans ce cas, j'aurais pensé que la ErrorDocument serait déclenchée ...

EDIT 2:

Ou attendez, peut-être que l'argument de Tim ne concerne pas vraiment la gestion des erreurs ZF, mais que du point de vue d'Apache, la demande entrante était satisfaite (en accédant à public/wp/index.php et en exécutant PHP), donc c'est à la PHP code pour le gérer, je ne peux pas revenir à ErrorDocument d'Apache après cela! Je suppose que j'avais un malentendu fondamental sur le fonctionnement de ErrorDocument. Je dois trouver un moyen d'invoquer le code ErrorController directement pour afficher la page que je souhaite avec le statut 404! Duh!

J'imagine que j'accepterai la réponse de Tim, même s'il souhaite clarifier/généraliser son propos sur le moment où le traitement de ErrorDocument entre en jeu, ce serait bien :-)

EDIT 3:

Juste pour conclure. J'ai accepté la réponse de Tim parce qu'elle révélait mon malentendu fondamental sur le fonctionnement de la directive Apache ErrorDocument. Mais cela ne m'a pas directement montré comment résoudre le problème que je rencontrais, mais j'ai découvert que je voulais retourner un statut 404 à l'aide de ma page d'état personnalisée Zend Framework, mais que je courais dans une requête WordPress amorcez ZF sans avoir démarré l'application MVC qui s'exécute sous l'amorçage. Je n'avais aucune expérience avec le contrôleur frontal de ZF, mais après avoir fouillé un peu dans les documents, j'ai proposé cette solution, qui a exactement le même effet que la directive complète ErrorDocument que je voulais déclencher.

$error_url = $this->serverUrl() . '/default/error/error?error_handler[type]=404';
$request = new Zend_Controller_Request_Http($error_url);
$front = Zend_Controller_Front::getInstance();
$front->returnResponse(true);
$response = $front->dispatch($request);
$response->setRawHeader('HTTP/1.1 404 Not Found');
$response->sendResponse();
exit(0);
2
sootsnoot

Vraisemblablement, dans vos règles htaccess, vous avez également une règle de réécriture pour router toutes les requêtes vers Zend Framework. À ce stade, Apache (et ErrorDocument) ne sont pas vraiment visibles, car vous lui avez dit que vous souhaitiez que les requêtes soient traitées par PHP.

Quand tu fais:

http_response_code(404);
exit(0);

vous envoyez une page 404 vide au navigateur. De nombreux navigateurs sont configurés pour afficher leur propre page 404 conviviale si la taille de la page 404 reçue du serveur est inférieure à X octets. (Juste pour une meilleure expérience utilisateur.)

Zend Framework devrait intercepter cela et utiliser sa propre page d'erreur en fonction de vous mettez ce code PHP (et éventuellement sur la base de certaines options de configuration).

Je vous suggérerais de mettre à jour la page Zend Framework ErrorController afin qu'elle soit comme vous le souhaitez. Je ne crois pas qu'il y ait un moyen de transférer le traitement de la demande à Apache (pour ainsi dire).

2
Tim Fountain