Jak wysłać błąd 500 Internal Server Error ze skryptu PHP

81

Muszę wysłać „500 Internal Server Error” ze skryptu PHP pod pewnymi warunkami. Skrypt ma być wywoływany przez aplikację innej firmy. Skrypt zawiera kilka die("this happend")instrukcji, dla których muszę wysłać 500 Internal Server Errorkod odpowiedzi zamiast zwykłego 200 OK. Skrypt strony trzeciej ponownie wyśle ​​żądanie pod pewnymi warunkami, które obejmują nieotrzymanie 200 OKkodu odpowiedzi.

Druga część pytania: muszę skonfigurować mój skrypt w następujący sposób:

<?php
    custom_header( "500 Internal Server Error" );

    if ( that_happened ) {
        die( "that happened" )
    }

    if ( something_else_happened ) {
        die( "something else happened" )
    }

    update_database( );

    // the script can also fail on the above line
    // e.g. a mysql error occurred

    remove_header( "500" );
?>

Muszę wysłać 200nagłówek dopiero po wykonaniu ostatniej linii.

Edytować

Pytanie poboczne: czy mogę wysłać dziwne nagłówki 500, takie jak te:

HTTP/1.1 500 No Record Found
HTTP/1.1 500 Script Generated Error (E_RECORD_NOT_FOUND)
HTTP/1.1 500 Conditions Failed on Line 23

Czy takie błędy zostaną zarejestrowane przez serwer WWW?

Salman A
źródło
nie jest możliwe, gdy
wyślesz
1
Boczne pytanie: to całkowicie uzasadnione. Przyczyna Zwroty nie są przeznaczone do użytku maszynowego i mogą być dowolne. Liczy się tylko trzycyfrowy kod statusu. (RFC2616 6.1.1: „Podane tutaj wyrażenia powodujące są jedynie zaleceniami - MOGĄ zostać zastąpione lokalnymi odpowiednikami bez wpływu na protokół.”)
Piskvor opuścił budynek

Odpowiedzi:

171
header($_SERVER['SERVER_PROTOCOL'] . ' 500 Internal Server Error', true, 500);
Core Xii
źródło
FYI, to rozwiązanie wysyła X-Pad: unikaj nagłówka błędu przeglądarki w niektórych wersjach Apache. stackoverflow.com/questions/8711584/… . http_response_code()pomija ten nagłówek.
Anthony Rutledge
3
To działa nawet, jeśli nagłówek nie jest na początku (na przykład dowód pracy), dobra robota.
Jestem sobą
Fajnie, a co jeśli chcesz wyprowadzić plik json zamiast 500 wewnętrznego błędu serwera?
tblancog
44

PHP 5.4 ma funkcję o nazwie http_response_code , więc jeśli używasz PHP 5.4, możesz po prostu zrobić:

http_response_code(500);

Napisałem polyfill dla tej funkcji (Gist), jeśli używasz wersji PHP poniżej 5.4.


Aby odpowiedzieć na kolejne pytanie, dokument RFC dotyczący protokołu HTTP 1.1 mówi:

Podane tutaj frazy powodu są jedynie zaleceniami - MOGĄ zostać zastąpione lokalnymi odpowiednikami bez wpływu na protokół.

Oznacza to, że możesz użyć dowolnego tekstu (z wyłączeniem powrotu karetki lub wysuwów wiersza) po samym kodzie i to zadziała. Ogólnie rzecz biorąc, zwykle istnieje lepszy kod odpowiedzi do użycia. Na przykład, zamiast używać 500 dla braku rekordu, możesz wysłać 404 (nie znaleziono), a dla czegoś takiego jak „warunki nie powiodły się” (zgaduję, że błąd walidacji), możesz wysłać coś takiego jak 422 (nieprzetworzone jednostka).

inxilpro
źródło
Ważne jest, aby pamiętać, że ta funkcja również nie działa już po rozpoczęciu drukowania!
rob74
@ rob74 Prawda - gdy PHP zacznie wysyłać dane wyjściowe, wszystkie funkcje związane z nagłówkami przestaną działać. Jeśli nie masz pewności, czy będziesz musiał zmienić kod odpowiedzi, zanim zaczniesz wysyłać dane wyjściowe, buforowanie danych wyjściowych jest dobrym rozwiązaniem.
inxilpro
34

Możesz użyć następującej funkcji, aby wysłać zmianę statusu:

function header_status($statusCode) {
    static $status_codes = null;

    if ($status_codes === null) {
        $status_codes = array (
            100 => 'Continue',
            101 => 'Switching Protocols',
            102 => 'Processing',
            200 => 'OK',
            201 => 'Created',
            202 => 'Accepted',
            203 => 'Non-Authoritative Information',
            204 => 'No Content',
            205 => 'Reset Content',
            206 => 'Partial Content',
            207 => 'Multi-Status',
            300 => 'Multiple Choices',
            301 => 'Moved Permanently',
            302 => 'Found',
            303 => 'See Other',
            304 => 'Not Modified',
            305 => 'Use Proxy',
            307 => 'Temporary Redirect',
            400 => 'Bad Request',
            401 => 'Unauthorized',
            402 => 'Payment Required',
            403 => 'Forbidden',
            404 => 'Not Found',
            405 => 'Method Not Allowed',
            406 => 'Not Acceptable',
            407 => 'Proxy Authentication Required',
            408 => 'Request Timeout',
            409 => 'Conflict',
            410 => 'Gone',
            411 => 'Length Required',
            412 => 'Precondition Failed',
            413 => 'Request Entity Too Large',
            414 => 'Request-URI Too Long',
            415 => 'Unsupported Media Type',
            416 => 'Requested Range Not Satisfiable',
            417 => 'Expectation Failed',
            422 => 'Unprocessable Entity',
            423 => 'Locked',
            424 => 'Failed Dependency',
            426 => 'Upgrade Required',
            500 => 'Internal Server Error',
            501 => 'Not Implemented',
            502 => 'Bad Gateway',
            503 => 'Service Unavailable',
            504 => 'Gateway Timeout',
            505 => 'HTTP Version Not Supported',
            506 => 'Variant Also Negotiates',
            507 => 'Insufficient Storage',
            509 => 'Bandwidth Limit Exceeded',
            510 => 'Not Extended'
        );
    }

    if ($status_codes[$statusCode] !== null) {
        $status_string = $statusCode . ' ' . $status_codes[$statusCode];
        header($_SERVER['SERVER_PROTOCOL'] . ' ' . $status_string, true, $statusCode);
    }
}

Możesz go używać jako takiego:

<?php
header_status(500);

if (that_happened) {
    die("that happened")
}

if (something_else_happened) {
    die("something else happened")
}

update_database();

header_status(200);
Andrew Moore
źródło
21
Oszczędność kilku bajtów pamięci rzadko jest dobrym powodem do pisania kodu aplikacji internetowej w taki czy inny sposób.
Dan Grossman,
1
nie przegapisz ;po die()?
henrywright
2
Brakuje Twojej listy 418 => "Jestem czajniczkiem" patrz: en.wikipedia.org/wiki/Hyper_Text_Coffee_Pot_Control_Protocol
Louis Loudog Trottier
16

Możesz po prostu wstawić:

header("HTTP/1.0 500 Internal Server Error");

w twoich warunkach, takich jak:

if (that happened) {
    header("HTTP/1.0 500 Internal Server Error");
}

Jeśli chodzi o zapytanie do bazy danych, możesz to zrobić w następujący sposób:

$result = mysql_query("..query string..") or header("HTTP/1.0 500 Internal Server Error");

Pamiętaj, że musisz umieścić ten kod przed jakimkolwiek tagiem html (lub wyjściem).

Ruel
źródło
11
Upewnij się, że zakończysz / die / return / coś po wywołaniu funkcji header (). PHP będzie dalej wykonywać kod - co prawdopodobnie nie jest pożądane.
David Goodwin
8

Możesz to uprościć w ten sposób:

if ( that_happened || something_else_happened )
{
    header('X-Error-Message: Incorrect username or password', true, 500);
    die;
}

Zwróci następujący nagłówek:

HTTP/1.1 500 Internal Server Error
...
X-Error-Message: Incorrect username or password
...

Dodano: Jeśli chcesz dokładnie wiedzieć, co poszło nie tak, zrób coś takiego:

if ( that_happened )
{
    header('X-Error-Message: Incorrect username', true, 500);
    die('Incorrect username');
}

if ( something_else_happened )
{
    header('X-Error-Message: Incorrect password', true, 500);
    die('Incorrect password');
}
David Kuridža
źródło
5
Co teraz 'x'ma być?
Core Xii
1
+1 Pamiętaj, że pierwszy parametr w headermusi być niepustym ciągiem znaków. To 'x'nie ma znaczenia.
theazureshadow
1
@Core Xii, pierwszy parametr nie może być zerowy, jak wskazał @theazureshadow. Krótko mówiąc, wywołanie nagłówka („coś”, prawda, 500) spowoduje zwrócenie poprawnego nagłówka „HTTP / 1.0 500 Internal Server Error”. Możesz mnie nazwać leniwym, ale łatwiej jest po prostu przekazać kod błędu niż obsłużyć właściwy nagłówek :) Zajrzyj na php.net/manual/en/function.header.php, aby uzyskać więcej informacji.
David Kuridža
Podręcznik nie jest na ten temat zbyt jasny. Więc mówisz, że jeśli wymusisz kod statusu, PHP automatycznie nadpisze argument ciągu do jego prawidłowej wartości? Dlaczego więc instrukcja miałaby mówić, że obowiązuje to tylko wtedy, gdy łańcuch nie jest pusty?
Core Xii
1
Zauważ, że w niektórych konfiguracjach PHP (tej, której używa mój dostawca hostingu na przykład, ale nie w mojej konfiguracji lokalnej) ta sztuczka nie zadziała! Apache nie rozpoznaje „x” jako prawidłowego ciągu nagłówka i zakończy się niepowodzeniem z błędem „Zniekształcony nagłówek”.
mjsarfatti
2

Twój kod powinien wyglądać następująco:

<?php
if ( that_happened ) {
    header("HTTP/1.0 500 Internal Server Error");
    die();
}

if ( something_else_happened ) {
    header("HTTP/1.0 500 Internal Server Error");
    die();
}

// Your function should return FALSE if something goes wrong
if ( !update_database() ) {
    header("HTTP/1.0 500 Internal Server Error");
    die();
}

// the script can also fail on the above line
// e.g. a mysql error occurred


header('HTTP/1.1 200 OK');
?>

Zakładam, że przerywasz wykonanie, jeśli coś pójdzie nie tak.

Sébastien VINCENT
źródło