web-dev-qa-db-fra.com

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

J'ai un script PHP qui doit fournir des réponses avec des codes de réponse HTTP (codes d'état), tels que HTTP 200 OK, ou du code 4XX ou 5XX.

Comment puis-je faire cela en PHP?

221
Paulo Coghi

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

A partir de PHP 5.4 , il existe trois méthodes pour accomplir cela:

Assembler vous-même le code de réponse (PHP> = 4.0)

La fonction header() a un cas d'utilisation spécial qui détecte une ligne de réponse HTTP et vous permet de le remplacer par un autre personnalisé.

header("HTTP/1.1 200 OK");

Cependant, cela nécessite un traitement spécial pour 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");

Remarque: Selon le HTTP RFC , la phrase de motif peut être toute chaîne personnalisée (conforme à la norme), mais dans un souci de compatibilité client, je ne recommande pas de placer une chaîne aléatoire à cet emplacement.

Note: php_sapi_name() requiert PHP 4.0.1

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

Il existe évidemment quelques problèmes lors de l’utilisation de cette première variante. Le plus important dont je pense est qu'il est en partie analysé par PHP ou par le serveur Web et mal documenté.

Depuis la version 4.3, la fonction header a 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 2e . Le premier fonctionne sur tous les navigateurs que j'ai testés, mais certains navigateurs mineurs ou robots d'exploration de sites 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 le 2e. La variante n’est bien sûr pas standardisée et peut être modifiée, j’ai simplement choisi un nom descriptif, espérons-le.

fonction http_response_code (PHP> = 5.4)

La fonction http_response_code() a été introduite dans PHP 5.4, et rend les choses beaucoup plus faciles .

http_response_code(404);

C'est tout.

Compatibilité

Voici une fonction que j’ai concoctée lorsque j’avais besoin d’une compatibilité inférieure à 5.4 mais que je voulais la fonctionnalité de la "nouvelle" fonction http_response_code. Je pense que PHP 4.3 est une compatibilité ascendante, 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;
    }
}
418
dualed

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

  1. Utiliser substr($sapi_type, 0, 3) == 'cgi' ne permet pas de détecter rapidement les CGI. Lorsque vous utilisez PHP-FPM FastCGI Process Manager, php_sapi_name() renvoie fpm not cgi

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

  3. header("HTTP/1.1 404 Not Found"); peut échouer lorsque 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 2 cas où l'appel de http_response_code() entraîne un comportement inattendu:

    • Lorsque PHP rencontre un code de réponse HTTP qu'il ne comprend pas, PHP remplacera le code par un code connu du même groupe. Par exemple, "Le serveur Web 521 est en panne" est remplacé par "500 Erreur interne du serveur". De nombreux 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 entraîner un étrange en-tête "404 OK" par exemple. Ce problème est également mentionné sur le site Web PHP par un commentaire d'utilisateur http://www.php.net/manual/en/function.http-response-code.php#11242

Pour votre information, voici la liste complète des codes d'état de réponse HTTP (cette liste inclut les codes des standards Internet IETF ainsi que d'autres RFC IETF. Nombre d'entre eux ne sont PAS actuellement pris en charge par la fonction PHP http_response_code): - http://en.wikipedia.org/wiki/List_of_HTTP_status_codes

Vous pouvez facilement tester ce bug en appelant:

http_response_code(521);

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


Ma solution (pour toutes les versions de PHPdepuis 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 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, mais aggrave le problème 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 CGI rapide ne gère pas PHP-FPM. Le protocole actuel doit être détecté.

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

37
Grigore Madalin

depuis PHP 5.4, vous pouvez utiliser http_response_code() pour obtenir et définir le code d'état de l'en-tête.

voici un exemple:

<?php

// Get the current response code and set a new one
var_dump(http_response_code(404));

// Get the new response code
var_dump(http_response_code());
?>

voici le document de cette fonction dans php.net:

http_response_code

16
Seyed Ali Roshan

Ajoutez cette ligne avant toute sortie du corps, si vous n'utilisez pas la mise en mémoire tampon de sortie.

header("HTTP/1.1 200 OK");

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

8
sparkey0

Si vous êtes ici à cause de Wordpress donnant 404 lors du chargement de l'environnement, cela 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û à l'envoi d'un en-tête Status: 404 Not Found. Vous devez passer outre cela. Cela fonctionnera également:

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

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

6
Quentin
header("HTTP/1.1 200 OK");
http_response_code(201);
header("Status: 200 All rosy");

http_response_code (200); ne fonctionne pas car test d'alerte 404 https://developers.google.com/speed/pagespeed/insights/

2
alpc

Nous pouvons obtenir une valeur de retour différente de http_response_code via les deux environnements différents:

  1. Environnement de serveur Web
  2. Environnement CLI

Sur l'environnement du serveur Web, renvoyez le code de réponse précédent si vous avez fourni un code de réponse ou si vous ne fournissez aucun code de réponse, la valeur actuelle sera alors imprimée. La valeur par défaut est 200 (OK).

Dans l'environnement CLI, la valeur true sera renvoyée si vous avez fourni un code de réponse et false si vous ne fournissez aucun code de réponse.

Exemple d'environnement de serveur Web avec la valeur renvoyée par Response_code:

var_dump(http_respone_code(500)); // int(200)
var_dump(http_response_code()); // int(500)

Exemple d'environnement CLI de la valeur renvoyée par Response_code:

var_dump(http_response_code()); // bool(false)
var_dump(http_response_code(501)); // bool(true)
var_dump(http_response_code()); // int(501)
1
GaziAnis