PHP: Jak wysłać kod odpowiedzi HTTP?


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;
    }
}

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.


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


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.)


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

nagłówek („HTTP / 1.1 200 OK”); http_response_code (201); nagłówek („Status: 200 Wszystkie różowe”); // praca
alpc,



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;
    }

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)
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.