331 votes

PHP : Comment envoyer le code de réponse HTTP ?

J'ai un script PHP qui doit répondre avec des codes de réponse HTTP (codes de statut), comme HTTP 200 OK, ou un code 4XX ou 5XX.

Comment puis-je faire cela en PHP ?

564voto

dualed Points 3564

Je viens de trouver cette question et j'ai pensé qu'elle nécessitait une réponse plus complète :

A partir de PHP 5.4 Il existe trois méthodes pour y parvenir :

Assemblage du code de réponse par vous-même (PHP >= 4.0)

Le site header() a un cas d'utilisation spécial qui détecte une ligne de réponse HTTP et vous permet de la remplacer par une ligne personnalisée.

header("HTTP/1.1 200 OK");

Cependant, cela nécessite un traitement spécial pour le PHP (Fast)CGI :

$sapi_type = php_sapi_name();
if (substr($sapi_type, 0, 3) == 'cgi')
    header("Status: 404 Not Found");
else
    header("HTTP/1.1 404 Not Found");

Note : Selon le RFC HTTP le phrase de motivation peut être n'importe quelle chaîne personnalisée (conforme à la norme), mais pour des raisons de compatibilité avec le client, j'ai décidé d'utiliser l'option ne pas recommande d'y mettre une chaîne aléatoire.

Note : php_sapi_name() nécessite PHP 4.0.1

3ème argument de la fonction d'en-tête (PHP >= 4.3)

L'utilisation de cette première variante pose évidemment quelques problèmes. Le plus important est qu'elle est partiellement analysée par PHP ou le serveur web et qu'elle est mal documentée.

Depuis 4.3, le header possède un troisième argument qui vous permet de définir le code de réponse de manière assez confortable, mais son utilisation nécessite que le premier argument soit une chaîne non vide. Voici deux options :

header(':', true, 404);
header('X-PHP-Response-Code: 404', true, 404);

Je recommande le 2ème . Le premier fait fonctionnent sur tous les navigateurs que j'ai testés, mais certains navigateurs mineurs ou crawlers web peuvent avoir un problème avec une ligne d'en-tête qui ne contient que deux points. Le nom du champ d'en-tête dans la 2ème variante n'est bien sûr pas standardisé et peut être modifié, j'ai juste choisi un nom descriptif.

Fonction http_response_code (PHP >= 5.4)

Le site http_response_code() a été introduite en PHP 5.4, et a rendu les choses plus faciles. beaucoup plus facile.

http_response_code(404);

C'est tout.

Compatibilité

Voici une fonction que j'ai créée lorsque j'avais besoin d'une compatibilité avec une version inférieure à la 5.4 mais que je souhaitais bénéficier des fonctionnalités de la "nouvelle" version. http_response_code fonction. Je pense que PHP 4.3 offre une compatibilité ascendante plus que suffisante, mais on ne sait jamais...

// For 4.3.0 <= PHP <= 5.4.0
if (!function_exists('http_response_code'))
{
    function http_response_code($newcode = NULL)
    {
        static $code = 200;
        if($newcode !== NULL)
        {
            header('X-PHP-Response-Code: '.$newcode, true, $newcode);
            if(!headers_sent())
                $code = $newcode;
        }       
        return $code;
    }
}

52voto

Grigore Madalin Points 31

Malheureusement, j'ai trouvé que les solutions présentées par @dualed ont plusieurs défauts.

1. Utiliser substr($sapi_type, 0, 3) == 'cgi' n'est pas suffisant pour détecter les CGI rapides. Lorsque vous utilisez le gestionnaire de processus PHP-FPM FastCGI, php_sapi_name() retourne fpm et non cgi...

2. Fasctcgi et php-fpm exposent un autre bug mentionné par @Josh - l'utilisation de header('X-PHP-Response-Code : 404', true, 404) ; fonctionne correctement sous PHP-FPM (FastCGI)

3. header("HTTP/1.1 404 Not Found") ; peut échouer si le protocole n'est pas HTTP/1.1 (c'est-à-dire 'HTTP/1.0'). Le protocole actuel doit être détecté à l'aide de $_SERVER['SERVER_PROTOCOL'] (disponible depuis PHP 4.1.0).

4. Il y a au moins deux cas où l'appel à http_response_code() entraîne un comportement inattendu :

  • Lorsque PHP rencontre un code de réponse HTTP qu'il ne comprend pas, il le remplace par un code du même groupe qu'il connaît. Par exemple, "521 Web server is down" est remplacé par "500 Internal Server Error". Beaucoup d'autres codes de réponse peu communs des autres groupes 2xx, 3xx, 4xx sont traités de cette façon.
  • Sur un serveur avec php-fpm et nginx, la fonction http_response_code() PEUT changer le code comme prévu mais pas le message. Cela peut donner lieu à un étrange en-tête "404 OK" par exemple. Ce problème est également mentionné sur le site de PHP par un commentaire d'utilisateur http://www.php.net/manual/en/function.http-response-code.php#112423

Pour votre référence, voici la liste complète des codes d'état des réponses HTTP (cette liste comprend des codes provenant des normes Internet de l'IETF ainsi que d'autres RFC de l'IETF. Beaucoup d'entre eux ne sont actuellement PAS supportés par la fonction PHP http_response_code) : http://en.wikipedia.org/wiki/List_of_HTTP_status_codes

Vous pouvez facilement tester ce bogue en appelant :

http_response_code(521);

Le serveur enverra le code de réponse HTTP "500 Internal Server Error", ce qui entraînera des erreurs inattendues si vous avez, par exemple, une application client personnalisée qui appelle votre serveur et attend des codes HTTP supplémentaires.


Ma solution (pour toutes les versions de PHP depuis 4.1.0) :

$httpStatusCode = 521;
$httpStatusMsg  = 'Web server is down';
$phpSapiName    = substr(php_sapi_name(), 0, 3);
if ($phpSapiName == 'cgi' || $phpSapiName == 'fpm') {
    header('Status: '.$httpStatusCode.' '.$httpStatusMsg);
} else {
    $protocol = isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0';
    header($protocol.' '.$httpStatusCode.' '.$httpStatusMsg);
}

Conclusion

L'implémentation de http_response_code() ne prend pas en charge tous les codes de réponse HTTP et peut remplacer le code de réponse HTTP spécifié par un autre du même groupe.

La nouvelle fonction http_response_code() ne résout pas tous les problèmes en cause mais aggrave la situation en introduisant de nouveaux bogues.

La solution de "compatibilité" proposée par @dualed ne fonctionne pas comme prévu, du moins sous PHP-FPM.

Les autres solutions proposées par @dualed présentent également divers bugs. La détection rapide des CGI ne gère pas PHP-FPM. Le protocole actuel doit être détecté.

Tous les tests et commentaires sont appréciés.

13voto

sparkey0 Points 544

Ajoutez cette ligne avant toute sortie du corps, dans le cas où vous n'utilisez pas de tampon de sortie.

header("HTTP/1.1 200 OK");

Remplacez la partie message ('OK') par le message approprié, et le code d'état par votre code selon le cas (404, 501, etc.)

7voto

jagged software Points 20

Si vous êtes ici parce que Wordpress donne 404's lors du chargement de l'environnement, ceci devrait résoudre le problème :

define('WP_USE_THEMES', false);
require('../wp-blog-header.php');
status_header( 200 );
//$wp_query->is_404=false; // if necessary

Le problème est dû au fait qu'il envoie un Status : 404 Not Found. Vous devez le contourner. Ceci fonctionnera également :

define('WP_USE_THEMES', false);
require('../wp-blog-header.php');
header("HTTP/1.1 200 OK");
header("Status: 200 All rosy");

5voto

Quentin Points 325526

Avec le en-tête fonction. Il y a un exemple dans la section sur le premier paramètre qu'elle prend.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X