PHP: Jak wysłać kod odpowiedzi HTTP?

254

Mam skrypt PHP, który musi odpowiadać za pomocą kodów odpowiedzi HTTP (kodów stanu), takich jak HTTP 200 OK lub jakiś kod 4XX lub 5XX.

Jak mogę to zrobić w PHP?

Paulo Coghi - Przywróć Monikę
źródło

Odpowiedzi:

461

Właśnie znalazłem to pytanie i pomyślałem, że potrzebuje bardziej kompleksowej odpowiedzi:

Począwszy od PHP 5.4 istnieją trzy metody osiągnięcia tego:

Samodzielne tworzenie kodu odpowiedzi (PHP> = 4.0)

Ta header()funkcja ma specjalny przypadek użycia, który wykrywa linię odpowiedzi HTTP i pozwala zastąpić ją niestandardową

header("HTTP/1.1 200 OK");

Wymaga to jednak specjalnego traktowania (szybkiego) CGI PHP:

$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");

Uwaga: Zgodnie z HTTP RFC The fraza powodem może być dowolny ciąg niestandardowy (zgodne ze standardem), ale ze względu na kompatybilność klienta ja nie polecam umieszczenie tam losowy ciąg.

Uwaga: php_sapi_name() wymaga PHP 4.0.1

Trzeci argument funkcji nagłówka (PHP> = 4.3)

Oczywiście przy pierwszym wariancie jest kilka problemów. Myślę, że największym z nich jest to, że jest częściowo przeanalizowane przez PHP lub serwer WWW i słabo udokumentowane.

Od wersji 4.3 headerfunkcja ma trzeci argument, który pozwala nieco wygodnie ustawić kod odpowiedzi, ale użycie go wymaga, aby pierwszy argument był niepustym ciągiem. Oto dwie opcje:

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

Polecam drugi . Pierwszy robi pracę na wszystkich przeglądarkach I zostały przetestowane, ale niektóre przeglądarki niewielki lub roboty sieciowe mogą mieć problem z linii nagłówka, który zawiera tylko dwukropek. Nazwa pola nagłówka w 2. miejscu. wariant nie jest oczywiście w żaden sposób ustandaryzowany i można go zmodyfikować, wybrałem po prostu miejmy nadzieję opisową nazwę.

funkcja http_response_code (PHP> = 5.4)

http_response_code()Funkcja została wprowadzona w PHP 5.4, i to wszystko o wiele łatwiejsze.

http_response_code(404);

To wszystko.

Zgodność

Oto funkcja, którą przygotowałem, gdy potrzebowałem kompatybilności poniżej 5.4, ale chciałem funkcjonalności „nowej” http_response_codefunkcji. Wierzę, że PHP 4.3 to więcej niż wystarczająca kompatybilność wsteczna, ale nigdy nie wiadomo ...

// 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;
    }
}
podwójny
źródło
10
Mogę potwierdzić, że header('X-PHP-Response-Code: 404', true, 404);działa poprawnie w PHP-FPM (FastCGI)
Josh
@dualed (1) nie headers_sent()zawsze będzie prawdziwe zaraz po wywołaniu header()? (2) Czy kiedykolwiek znalazłeś coś takiego jak http_response_text () w świecie 5.4? Przynajmniej stary nagłówek () może wpływać na tekst po kodzie stanu.
Bob Stein
@ BobStein-VisiBone (1) headers_sent() jest prawdą, jeśli nie możesz dodać więcej nagłówków, ponieważ treść została już wysłana, a nie jeśli dodałeś nagłówek. (2) Przepraszamy, nie. Inne języki mają jednak lepszą obsługę
dualed
1
@Perry powód, dla którego nie sugeruję zrobienia tego, jest taki sam, dlaczego nie sugeruję, aby był to tylko dwukropek. PHP może traktować to inaczej w różnych wersjach, ponieważ nie jest zdefiniowane, co dzieje się z takim „nagłówkiem”, może całkowicie zawieść - nie ustawiając ani nagłówka ani statusu, lub może dodać nieprawidłowy nagłówek (standard protokołu HTTP 1.1 wymaga dwukropka )
podwójny
8
Spędziłem godziny zdając sobie sprawę, że http_response_code(a może bardziej ogólnie modyfikowanie nagłówka) już nie działa po echoczymś. Mam nadzieję, że to pomoże.
Neptilo
40

Niestety znalazłem rozwiązania przedstawione przez @dualed mają różne wady.

  1. Używanie substr($sapi_type, 0, 3) == 'cgi'nie jest enogh do wykrywania szybkiego CGI. Podczas korzystania z PHP-FPM FastCGI Process Manager php_sapi_name()zwraca fpm, a nie cgi

  2. Fasctcgi i php-fpm ujawniają kolejny błąd wspomniany przez @Josh - używanie header('X-PHP-Response-Code: 404', true, 404);działa poprawnie pod PHP-FPM (FastCGI)

  3. header("HTTP/1.1 404 Not Found");może się nie powieść, gdy protokołem nie jest HTTP / 1.1 (tj. „HTTP / 1.0”). Aktualny protokół musi zostać wykryty przy użyciu $_SERVER['SERVER_PROTOCOL'](dostępny od PHP 4.1.0

  4. Istnieją co najmniej 2 przypadki, gdy wywołanie http_response_code()powoduje nieoczekiwane zachowanie:

    • Gdy PHP napotka kod odpowiedzi HTTP, którego nie rozumie, PHP zastąpi kod innym, który zna z tej samej grupy. Na przykład „Serwer 521 nie działa” zastępuje się przez „Błąd wewnętrzny serwera 500”. Wiele innych nietypowych kodów odpowiedzi z innych grup 2xx, 3xx, 4xx jest obsługiwanych w ten sposób.
    • Na serwerze z funkcją php-fpm i nginx funkcja http_response_code () MOŻE zmienić kod zgodnie z oczekiwaniami, ale nie komunikat. Może to spowodować na przykład dziwny nagłówek „404 OK”. Ten problem jest również wspomniany na stronie PHP w komentarzu użytkownika http://www.php.net/manual/en/function.http-response-code.php#112423

W celach informacyjnych znajduje się pełna lista kodów statusu odpowiedzi HTTP (ta lista zawiera kody ze standardów internetowych IETF, a także inne RFC IETF. Wiele z nich NIE jest obecnie obsługiwanych przez funkcję PHP http_response_code): http: //en.wikipedia .org / wiki / List_of_HTTP_status_codes

Możesz łatwo przetestować ten błąd, dzwoniąc:

http_response_code(521);

Serwer wyśle ​​kod odpowiedzi HTTP „500 Internal Server Error”, co spowoduje nieoczekiwane błędy, jeśli na przykład niestandardowa aplikacja kliencka dzwoni do serwera i oczekuje dodatkowych kodów HTTP.


Moje rozwiązanie (dla wszystkich wersji PHP od 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);
}

Wniosek

Implementacja http_response_code () nie obsługuje wszystkich kodów odpowiedzi HTTP i może zastąpić określony kod odpowiedzi HTTP innym kodem z tej samej grupy.

Nowa funkcja http_response_code () nie rozwiązuje wszystkich związanych z tym problemów, ale sprawia, że ​​najgorsze jest wprowadzanie nowych błędów.

Rozwiązanie „kompatybilności” oferowane przez @dualed nie działa zgodnie z oczekiwaniami, przynajmniej w PHP-FPM.

Inne rozwiązania oferowane przez @dualed również zawierają różne błędy. Szybkie wykrywanie CGI nie obsługuje PHP-FPM. Aktualny protokół musi zostać wykryty.

Wszelkie testy i komentarze są mile widziane.

Grigore Madalin
źródło
21

od PHP 5.4 możesz używać http_response_code()do pobierania i ustawiania kodu statusu nagłówka.

tutaj przykład:

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

oto dokument tej funkcji w php.net:

http_response_code

Seyed Ali Roshan
źródło
Z mojego doświadczenia wynika, że ​​jest to najlepsza odpowiedź.
Scruffy
Dlaczego warto korzystać z var_dump ()?
Tomas Gonzalez
Ale dlaczego var_dump () zamiast echa? Czy wynik może nie nadawać się do zwykłego echa? Lub nawet print_r (). var_dump () wydaje się więc nieodpowiedni do kodu produkcyjnego ...
Tomas Gonzalez
@TomasGonzalez to nie jest wielka sprawa, chciałem tylko pokazać ci, co jest w tym, drukując wszystko za pomocą var_dump () i masz rację, że nie są ważne
Seyed Ali Roshan
Dobra, widzę. To, co zwróciło moją uwagę, to fakt, że w oficjalnych dokumentach przykład używa również var_dump (). Byłem więc ciekawy, dlaczego tak się stało. Mogło być coś, czego mi brakowało. php.net/manual/en/function.http-response-code.php
Tomas Gonzalez
10

Dodaj ten wiersz przed jakimkolwiek wyjściem treści, w przypadku, gdy nie używasz buforowania wyjściowego.

header("HTTP/1.1 200 OK");

Zastąp część komunikatu („OK”) odpowiednią wiadomością, a kod stanu odpowiednim kodem (404, 501 itp.)

sparkey0
źródło
2
Czy przesłana przez nas wiadomość (aby zastąpić OK) może być czymkolwiek?
FMaz008,
To zadziałało dla mnie. Pracowałem nad formularzem kontaktowym na stronie internetowej z PHP 5.3. I to rozwiązanie zadziałało dla mnie. Daje tekst odpowiedzi i ten kod HTTP dla funkcji zakończonej niepowodzeniem żądania AJAX. To wszystko, czego chciałem.
Surjith SM
7

Jeśli jesteś tutaj, ponieważ Wordpress podaje 404 podczas ładowania środowiska, powinno to rozwiązać problem:

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

Problem jest spowodowany wysłaniem nagłówka Status: 404 Not Found. Musisz to zmienić. Będzie to również działać:

define('WP_USE_THEMES', false);
require('../wp-blog-header.php');
header("HTTP/1.1 200 OK");
header("Status: 200 All rosy");
jaggedsoft
źródło
nagłówek („HTTP / 1.1 200 OK”); http_response_code (201); nagłówek („Status: 200 Wszystkie różowe”); // praca
alpc,
6

Dzięki funkcji nagłówka . W sekcji dotyczącej pierwszego parametru znajduje się przykład.

Quentin
źródło
2

Jeśli twoja wersja PHP nie zawiera tej funkcji:

<?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
źródło
1

Możemy uzyskać inną wartość zwracaną od http_response_code przez dwa różne środowiska:

  1. Środowisko serwera WWW
  2. Środowisko CLI

W środowisku serwera WWW zwróć poprzedni kod odpowiedzi, jeśli podałeś kod odpowiedzi lub jeśli nie podasz kodu odpowiedzi, zostanie wydrukowana bieżąca wartość. Wartość domyślna to 200 (OK).

W środowisku CLI wartość true zostanie zwrócona, jeśli podałeś kod odpowiedzi, a false, jeśli nie podasz kodu odpowiedzi.

Przykład środowiska zwracającego wartość parametru Response_code dla środowiska serwera WWW:

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

Przykład środowiska CLI wartości zwracanej kodu odpowiedzi:

var_dump(http_response_code()); // bool(false)
var_dump(http_response_code(501)); // bool(true)
var_dump(http_response_code()); // int(501)
GaziAnis
źródło