PHP: ¿Cómo enviar el código de respuesta HTTP?

254

Tengo un script PHP que necesita responder con códigos de respuesta HTTP (códigos de estado), como HTTP 200 OK, o algún código 4XX o 5XX.

¿Cómo puedo hacer esto en PHP?

Paulo Coghi - Restablece a Mónica
fuente

Respuestas:

461

Acabo de encontrar esta pregunta y pensé que necesitaba una respuesta más completa:

A partir de PHP 5.4 hay tres métodos para lograr esto:

Ensamblar el código de respuesta por su cuenta (PHP> = 4.0)

La header()función tiene un caso de uso especial que detecta una línea de respuesta HTTP y le permite reemplazarla por una personalizada

header("HTTP/1.1 200 OK");

Sin embargo, esto requiere un tratamiento especial para PHP (rápido) 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");

Nota: Según el RFC de HTTP , la frase de razón puede ser cualquier cadena personalizada (que se ajuste al estándar), pero en aras de la compatibilidad del cliente , no recomiendo colocar una cadena aleatoria allí.

Nota: php_sapi_name() requiere PHP 4.0.1

Tercer argumento para la función de encabezado (PHP> = 4.3)

Obviamente, hay algunos problemas al usar esa primera variante. Creo que lo más importante es que está parcialmente analizado por PHP o el servidor web y mal documentado.

Desde 4.3, la headerfunción tiene un tercer argumento que le permite configurar el código de respuesta de manera cómoda, pero su uso requiere que el primer argumento sea una cadena no vacía. Aquí hay dos opciones:

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

Recomiendo el segundo . El primero hace el trabajo en todos los navegadores que he probado, pero algunos navegadores menores o rastreadores web puede tener un problema con una línea de cabecera que sólo contiene dos puntos. El nombre del campo de encabezado en el segundo. Por supuesto, la variante no está estandarizada de ninguna manera y podría modificarse, simplemente elegí un nombre descriptivo con suerte.

Función http_response_code (PHP> = 5.4)

La http_response_code()función se introdujo en PHP 5.4 y facilitó mucho las cosas .

http_response_code(404);

Eso es todo.

Compatibilidad

Aquí hay una función que he preparado cuando necesitaba compatibilidad por debajo de 5.4 pero quería la funcionalidad de la función "nueva" http_response_code. Creo que PHP 4.3 es más que suficiente compatibilidad con versiones anteriores, pero nunca se sabe ...

// 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;
    }
}
dualed
fuente
10
Puedo confirmar que header('X-PHP-Response-Code: 404', true, 404);funciona correctamente bajo PHP-FPM (FastCGI)
Josh
@dualed (1) no headers_sent()siempre sería cierto justo después de llamar header()? (2) ¿alguna vez has encontrado algo como http_response_text () en el mundo 5.4? Al menos el encabezado anterior () puede afectar el texto después del código de estado.
Bob Stein
@ BobStein-VisiBone (1) headers_sent() es verdadero si no puede agregar más encabezados porque el contenido ya se envió, no si ha agregado un encabezado. (2) Lo siento, no. Otros idiomas tienen un mejor soporte embargo
dualed
1
@Perry La razón por la que no sugiero hacer esto es la misma por la que no sugiero el de solo dos puntos. PHP puede manejar esto de manera diferente en todas las versiones, ya que no está definido qué sucede con ese "encabezado", puede fallar por completo, no establecer el encabezado o el estado, o puede agregar un encabezado no válido (el estándar de protocolo http 1.1 requiere dos puntos )
dualed
8
Pasé horas dándome cuenta de que http_response_code(y quizás más generalmente modificando el encabezado) ya no funciona después de echoalgo. Espero eso ayude.
Neptilo
40

Desafortunadamente, encontré que las soluciones presentadas por @dualed tienen varios defectos.

  1. Usar substr($sapi_type, 0, 3) == 'cgi'no es suficiente para detectar CGI rápido. Al usar PHP-FPM FastCGI Process Manager, php_sapi_name()devuelve fpm no cgi

  2. Fasctcgi y php-fpm exponen otro error mencionado por @Josh: el uso header('X-PHP-Response-Code: 404', true, 404);funciona correctamente en PHP-FPM (FastCGI)

  3. header("HTTP/1.1 404 Not Found");puede fallar cuando el protocolo no es HTTP / 1.1 (es decir, 'HTTP / 1.0'). El protocolo actual debe detectarse usando $_SERVER['SERVER_PROTOCOL'](disponible desde PHP 4.1.0

  4. Hay al menos 2 casos cuando la llamada http_response_code()produce un comportamiento inesperado:

    • Cuando PHP encuentra un código de respuesta HTTP que no comprende, PHP reemplazará el código con uno que conozca del mismo grupo. Por ejemplo, "el servidor web 521 está inactivo" se reemplaza por "500 Error interno del servidor". Muchos otros códigos de respuesta poco comunes de otros grupos 2xx, 3xx, 4xx se manejan de esta manera.
    • En un servidor con php-fpm y nginx, la función http_response_code () PUEDE cambiar el código como se esperaba pero no el mensaje. Esto puede dar como resultado un encabezado extraño "404 OK", por ejemplo. Este problema también se menciona en el sitio web de PHP por un comentario del usuario http://www.php.net/manual/en/function.http-response-code.php#112423

Para su referencia, aquí está la lista completa de códigos de estado de respuesta HTTP (esta lista incluye códigos de los estándares de Internet IETF, así como otros RFC de IETF. Muchos de ellos NO son compatibles actualmente con la función PHP http_response_code): http: //en.wikipedia .org / wiki / List_of_HTTP_status_codes

Puede probar fácilmente este error llamando a:

http_response_code(521);

El servidor enviará el código de respuesta HTTP "500 Internal Server Error", lo que provocará errores inesperados si, por ejemplo, tiene una aplicación cliente personalizada que llama a su servidor y espera algunos códigos HTTP adicionales.


Mi solución (para todas las versiones de PHP desde 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);
}

Conclusión

La implementación de http_response_code () no admite todos los códigos de respuesta HTTP y puede sobrescribir el código de respuesta HTTP especificado con otro del mismo grupo.

La nueva función http_response_code () no resuelve todos los problemas involucrados, pero empeora las cosas al introducir nuevos errores.

La solución de "compatibilidad" ofrecida por @dualed no funciona como se esperaba, al menos bajo PHP-FPM.

Las otras soluciones ofrecidas por @dualed también tienen varios errores. La detección rápida de CGI no maneja PHP-FPM. Se debe detectar el protocolo actual.

Cualquier prueba y comentario son apreciados.

Grigore Madalin
fuente
21

desde PHP 5.4 puede usar http_response_code()para obtener y establecer el código de estado del encabezado.

Aquí un ejemplo:

<?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());
?>

Aquí está el documento de esta función en php.net:

http_response_code

Seyed Ali Roshan
fuente
En mi experiencia, esta es la mejor respuesta.
Desaliñado
¿Por qué usar var_dump ()?
Tomás González el
Pero, ¿por qué var_dump () en lugar de echo? ¿Puede el resultado no ser adecuado para un eco simple? O incluso print_r (). var_dump () parece tan inadecuado para el código de producción ...
Tomas Gonzalez
@TomasGonzalez no es gran cosa, solo quería mostrarte qué hay en él imprimiendo todo con var_dump () y estás en lo cierto, no son importantes
Seyed Ali Roshan
OK veo. Lo que me llamó la atención es que en los documentos oficiales, el ejemplo también usa var_dump (). Así que tenía curiosidad sobre la razón para hacerlo. Podría haber habido algo que me faltaba. php.net/manual/en/function.http-response-code.php
Tomás González
10

Agregue esta línea antes de cualquier salida del cuerpo, en caso de que no esté utilizando el almacenamiento en búfer de salida.

header("HTTP/1.1 200 OK");

Reemplace la parte del mensaje ('OK') con el mensaje apropiado y el código de estado con su código según corresponda (404, 501, etc.)

sparkey0
fuente
2
¿El mensaje que ponemos (para cambiar el OK) puede ser algo?
FMaz008
Esto funcionó para mí. Estaba trabajando en un formulario de contacto en un sitio web con PHP 5.3. Y esta solución funcionó para mí. Le dará un texto de respuesta y este código HTTP para una solicitud AJAX realizada fallará. Eso es todo lo que quería.
Surjith SM
7

Si está aquí porque Wordpress le da 404 cuando carga el entorno, esto debería solucionar el problema:

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

El problema se debe a que envía un encabezado Estado: 404 No encontrado. Tienes que anular eso. Esto también funcionará:

define('WP_USE_THEMES', false);
require('../wp-blog-header.php');
header("HTTP/1.1 200 OK");
header("Status: 200 All rosy");
jaggedsoft
fuente
encabezado ("HTTP / 1.1 200 OK"); http_response_code (201); encabezado ("Estado: 200 Todo color de rosa"); // trabajo
alpc
6

Con la función de encabezado . Hay un ejemplo en la sección sobre el primer parámetro que toma.

Quentin
fuente
2

Si su versión de PHP no incluye esta función:

<?php

function http_response_code($code = NULL) {
        if ($code !== NULL) {
            switch ($code) {
                case 100: $text = 'Continue';
                    break;
                case 101: $text = 'Switching Protocols';
                    break;
                case 200: $text = 'OK';
                    break;
                case 201: $text = 'Created';
                    break;
                case 202: $text = 'Accepted';
                    break;
                case 203: $text = 'Non-Authoritative Information';
                    break;
                case 204: $text = 'No Content';
                    break;
                case 205: $text = 'Reset Content';
                    break;
                case 206: $text = 'Partial Content';
                    break;
                case 300: $text = 'Multiple Choices';
                    break;
                case 301: $text = 'Moved Permanently';
                    break;
                case 302: $text = 'Moved Temporarily';
                    break;
                case 303: $text = 'See Other';
                    break;
                case 304: $text = 'Not Modified';
                    break;
                case 305: $text = 'Use Proxy';
                    break;
                case 400: $text = 'Bad Request';
                    break;
                case 401: $text = 'Unauthorized';
                    break;
                case 402: $text = 'Payment Required';
                    break;
                case 403: $text = 'Forbidden';
                    break;
                case 404: $text = 'Not Found';
                    break;
                case 405: $text = 'Method Not Allowed';
                    break;
                case 406: $text = 'Not Acceptable';
                    break;
                case 407: $text = 'Proxy Authentication Required';
                    break;
                case 408: $text = 'Request Time-out';
                    break;
                case 409: $text = 'Conflict';
                    break;
                case 410: $text = 'Gone';
                    break;
                case 411: $text = 'Length Required';
                    break;
                case 412: $text = 'Precondition Failed';
                    break;
                case 413: $text = 'Request Entity Too Large';
                    break;
                case 414: $text = 'Request-URI Too Large';
                    break;
                case 415: $text = 'Unsupported Media Type';
                    break;
                case 500: $text = 'Internal Server Error';
                    break;
                case 501: $text = 'Not Implemented';
                    break;
                case 502: $text = 'Bad Gateway';
                    break;
                case 503: $text = 'Service Unavailable';
                    break;
                case 504: $text = 'Gateway Time-out';
                    break;
                case 505: $text = 'HTTP Version not supported';
                    break;
                default:
                    exit('Unknown http status code "' . htmlentities($code) . '"');
                    break;
            }
            $protocol = (isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0');
            header($protocol . ' ' . $code . ' ' . $text);
            $GLOBALS['http_response_code'] = $code;
        } else {
            $code = (isset($GLOBALS['http_response_code']) ? $GLOBALS['http_response_code'] : 200);
        }
        return $code;
    }
Abdo-Host
fuente
1

Podemos obtener diferentes valores de retorno de http_response_code a través de los dos entornos diferentes:

  1. Entorno de servidor web
  2. Entorno CLI

En el entorno del servidor web, devuelva el código de respuesta anterior si proporcionó un código de respuesta o si no proporciona ningún código de respuesta, se imprimirá el valor actual. El valor predeterminado es 200 (OK).

En CLI Environment, se devolverá verdadero si proporcionó un código de respuesta y falso si no proporciona ningún código de respuesta.

Ejemplo de entorno de servidor web del valor de retorno de Response_code:

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

Ejemplo del entorno de CLI del valor de retorno de Response_code:

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