PHP: Como enviar código de resposta HTTP?

254

Eu tenho um script PHP que precisa responder com códigos de resposta HTTP (status-codes), como HTTP 200 OK ou algum código 4XX ou 5XX.

Como posso fazer isso em PHP?

Paulo Coghi - Restabelecer Monica
fonte

Respostas:

461

Acabei de encontrar esta pergunta e achei que precisava de uma resposta mais abrangente:

No PHP 5.4, existem três métodos para fazer isso:

Montando o código de resposta por conta própria (PHP> = 4.0)

A header()função possui um caso de uso especial que detecta uma linha de resposta HTTP e permite substituí-la por uma personalizada

header("HTTP/1.1 200 OK");

No entanto, isso requer tratamento especial para o PHP CGI (rápido):

$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: De acordo com o HTTP RFC , a frase de razão pode ser qualquer sequência personalizada (que esteja em conformidade com o padrão), mas, para fins de compatibilidade do cliente , não recomendo colocar uma sequência aleatória lá.

Nota: php_sapi_name() requer PHP 4.0.1

Terceiro argumento para a função de cabeçalho (PHP> = 4,3)

Obviamente, existem alguns problemas ao usar essa primeira variante. O maior dos quais eu acho é que ele é parcialmente analisado pelo PHP ou pelo servidor da Web e mal documentado.

Desde 4.3, a headerfunção possui um terceiro argumento que permite definir o código de resposta de maneira confortável, mas usá-lo exige que o primeiro argumento seja uma sequência não vazia. Aqui estão duas opções:

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

Eu recomendo o segundo . O primeiro faz o trabalho em todos os navegadores que eu testei, mas alguns navegadores menores ou rastreadores da web pode ter um problema com uma linha de cabeçalho que contém apenas dois pontos. O nome do campo de cabeçalho no 2º. é claro que a variante não é padronizada de nenhuma maneira e pode ser modificada. Acabei de escolher um nome que se espera ser descritivo.

função http_response_code (PHP> = 5.4)

A http_response_code()função foi introduzida no PHP 5.4 e facilitou muito as coisas .

http_response_code(404);

Isso é tudo.

Compatibilidade

Aqui está uma função que eu criei quando precisava de compatibilidade abaixo da versão 5.4, mas queria a funcionalidade da função "nova" http_response_code. Eu acredito que o PHP 4.3 é mais do que suficiente compatibilidade com versões anteriores, mas você nunca 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;
    }
}
dualizado
fonte
10
Posso confirmar que header('X-PHP-Response-Code: 404', true, 404);funciona corretamente em PHP-FPM (FastCGI)
Josh
@dualed (1) nem headers_sent()sempre é verdade depois de ligar header()? (2) alguma vez encontrou algo como http_response_text () no mundo 5.4? Pelo menos o cabeçalho antigo () pode afetar o texto após o código de status.
Bob Stein
@ BobStein-VisiBone (1) headers_sent() é verdadeiro se você não puder adicionar mais cabeçalhos porque o conteúdo já foi enviado, não se você tiver adicionado um cabeçalho. (2) Desculpe, não. Outros idiomas têm melhor suporte
dualed
1
@ Perry, a razão pela qual eu não sugiro fazer isso é o mesmo porque eu não sugiro o cólon. O PHP pode lidar com isso de maneira diferente em todas as versões, pois não está definido o que acontece com esse "cabeçalho", pode falhar completamente - não definir cabeçalho ou status ou adicionar um cabeçalho inválido (o padrão do protocolo http 1.1 requer dois pontos )
dualed
8
Passei horas percebendo que http_response_code(e talvez mais geralmente modificando o cabeçalho) não funciona mais depois de você echoalguma coisa. Espero que ajude.
Neptilo 24/10
40

Infelizmente, encontrei as soluções apresentadas pela @dualed com várias falhas.

  1. O uso substr($sapi_type, 0, 3) == 'cgi'não é suficiente para detectar CGI rápido. Ao usar o FastCGI Process Manager do PHP-FPM, php_sapi_name()retorna fpm não cgi

  2. Fasctcgi e php-fpm expõem outro bug mencionado por @Josh - o uso header('X-PHP-Response-Code: 404', true, 404);funciona corretamente no PHP-FPM (FastCGI)

  3. header("HTTP/1.1 404 Not Found");pode falhar quando o protocolo não é HTTP / 1.1 (ou seja, 'HTTP / 1.0'). O protocolo atual deve ser detectado usando $_SERVER['SERVER_PROTOCOL'](disponível desde o PHP 4.1.0

  4. Existem pelo menos 2 casos ao chamar http_response_code()resultam em comportamento inesperado:

    • Quando o PHP encontra um código de resposta HTTP que ele não entende, o PHP substituirá o código por um que ele conheça do mesmo grupo. Por exemplo, "521 Web server in down" é substituído por "500 Internal Server Error". Muitos outros códigos de resposta incomuns de outros grupos 2xx, 3xx, 4xx são tratados dessa maneira.
    • Em um servidor com php-fpm e nginx, a função http_response_code () PODE alterar o código conforme o esperado, mas não a mensagem. Isso pode resultar em um cabeçalho "404 OK" estranho, por exemplo. Esse problema também é mencionado no site PHP por um comentário do usuário http://www.php.net/manual/en/function.http-response-code.php#112423

Para sua referência aqui, há a lista completa de códigos de status de resposta HTTP (esta lista inclui códigos dos padrões da Internet IETF e de outras RFCs da IETF. Muitos deles NÃO são atualmente suportados pela função http_response_code do PHP): http: //en.wikipedia .org / wiki / List_of_HTTP_status_codes

Você pode facilmente testar esse bug chamando:

http_response_code(521);

O servidor enviará o código de resposta HTTP "500 Internal Server Error", resultando em erros inesperados se você tiver, por exemplo, um aplicativo cliente personalizado ligando para o servidor e esperando alguns códigos HTTP adicionais.


Minha solução (para todas as versões do 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);
}

Conclusão

A implementação http_response_code () não suporta todos os códigos de resposta HTTP e pode substituir o código de resposta HTTP especificado por outro do mesmo grupo.

A nova função http_response_code () não resolve todos os problemas envolvidos, mas piora a introdução de novos bugs.

A solução de "compatibilidade" oferecida pelo @dualed não funciona como esperado, pelo menos no PHP-FPM.

As outras soluções oferecidas pelo @dualed também possuem vários bugs. A detecção rápida de CGI não suporta PHP-FPM. O protocolo atual deve ser detectado.

Quaisquer testes e comentários são apreciados.

Grigore Madalin
fonte
21

desde o PHP 5.4, você pode usar http_response_code()para obter e definir o código de status do cabeçalho.

aqui um exemplo:

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

aqui está o documento dessa função no php.net:

http_response_code

Seyed Ali Roshan
fonte
Na minha experiência, esta é a melhor resposta.
Desalinhado
Por que usar var_dump ()?
Tomas Gonzalez
Mas por que var_dump () em vez de echo? O resultado pode não ser adequado para um eco simples? Ou mesmo print_r (). var_dump () parece não ser adequado para o código de produção ...
Tomas Gonzalez
@ TomasGonzalez não é grande coisa, eu só queria mostrar o que há nele imprimindo tudo com var_dump () e certo, eles não são importantes
Seyed Ali Roshan
OK eu vejo. O que chamou minha atenção é que, nos documentos oficiais, o exemplo usa var_dump () também. Então, eu estava curioso sobre o motivo disso. Poderia ter algo que estava faltando. php.net/manual/en/function.http-response-code.php
Tomas Gonzalez
10

Adicione esta linha antes de qualquer saída do corpo, caso você não esteja usando o buffer de saída.

header("HTTP/1.1 200 OK");

Substitua a parte da mensagem ('OK') pela mensagem apropriada e o código de status pelo código conforme apropriado (404, 501, etc.)

sparkey0
fonte
2
A mensagem que colocamos (para substituir o OK) pode ser alguma coisa?
precisa saber é o seguinte
Isso funcionou para mim. Eu estava trabalhando em um formulário de contato em um site com PHP 5.3. E esta solução funcionou para mim. Ele fornecerá o texto de resposta e esse código HTTP para uma função de falha de solicitação AJAX concluída. Era tudo o que eu queria.
Surjith SM
7

Se você está aqui por causa do Wordpress dando 404 ao carregar o ambiente, isso deve resolver o problema:

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

O problema é devido ao envio de um cabeçalho Status: 404 não encontrado. Você tem que substituir isso. Isso também funcionará:

define('WP_USE_THEMES', false);
require('../wp-blog-header.php');
header("HTTP/1.1 200 OK");
header("Status: 200 All rosy");
jaggedsoft
fonte
cabeçalho ("HTTP / 1.1 200 OK"); http_response_code (201); cabeçalho ("Status: 200 Todos rosados"); // work
alpc 7/08/19
6

Com a função de cabeçalho . Há um exemplo na seção sobre o primeiro parâmetro necessário.

Quentin
fonte
2

Se sua versão do PHP não incluir esta função:

<?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
fonte
1

Podemos obter valores de retorno diferentes de http_response_code por meio de dois ambientes diferentes:

  1. Ambiente do servidor Web
  2. Ambiente CLI

No ambiente do servidor da web, retorne o código de resposta anterior se você forneceu um código de resposta ou quando não fornece nenhum código de resposta, ele imprimirá o valor atual. O valor padrão é 200 (OK).

No CLI Environment, true será retornado se você forneceu um código de resposta e false se você não fornecer nenhum response_code.

Exemplo do valor de retorno do ambiente do servidor Web do Response_code:

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

Exemplo de valor de retorno do ambiente CLI do 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
fonte