Як надіслати 500 помилок внутрішньої помилки сервера із сценарію PHP


81

Мені потрібно надіслати "500 внутрішніх помилок сервера" зі сценарію PHP за певних умов. Сценарій повинен викликатися стороннім додатком. Сценарій містить пару die("this happend")тверджень, для яких мені потрібно надіслати 500 Internal Server Errorкод відповіді замість звичайного 200 OK. Сторонній сценарій повторно надішле запит за певних умов, які включають не отримання 200 OKкоду відповіді.

Друга частина запитання: мені потрібно налаштувати свій сценарій так:

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

Мені потрібно надіслати 200заголовок лише після того, як був виконаний останній рядок.

Редагувати

Побічне запитання: чи можу я надіслати дивні 500 заголовків, таких як ці:

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

Чи реєструватиме такі помилки веб-сервер?


неможливо виконати, коли ви надіслали заголовок і видалите заголовок пізніше
ajreal

1
Сторонне запитання щодо Re: Це цілком законно. Причина Фрази не призначені для споживання машиною, і ними може бути що завгодно. Важливий лише тризначний код стану. (RFC2616 6.1.1: "Перелічені тут фрази є лише рекомендаціями - їх МОЖЕ замінити місцевими еквівалентами, не впливаючи на протокол.")
Пісквор залишив будівлю

Відповіді:


171
header($_SERVER['SERVER_PROTOCOL'] . ' 500 Internal Server Error', true, 500);

FYI, це рішення надсилає X-Pad: уникайте заголовка помилки браузера в деяких версіях Apache. stackoverflow.com/questions/8711584/… . http_response_code()опускає цей заголовок.
Ентоні Ратледж,

3
Це навіть працює, якщо заголовок не на початку (наприклад, як доказ роботи), хороша робота.
я я

Класно, а якщо потрібно вивести json замість 500 Внутрішня помилка сервера?
tblancog

44

PHP 5.4 має функцію http_response_code , тому, якщо ви використовуєте PHP 5.4, ви можете просто зробити:

http_response_code(500);

Я написав поліфіл для цієї функції (Gist), якщо у вас запущена версія PHP під 5.4.


Щоб відповісти на ваше подальше запитання, HTTP 1.1 RFC говорить:

Викладені тут фрази причини є лише рекомендаціями - їх МОЖЕ замінити місцевими відповідниками, не впливаючи на протокол.

Це означає, що ви можете використовувати будь-який потрібний текст (за винятком повернень каретки або подач рядків) після самого коду, і він буде працювати. Як правило, однак, як правило, є кращий код відповіді для використання. Наприклад, замість того, щоб використовувати 500 для жодного запису, ви можете надіслати 404 (не знайдено), а для чогось типу "умови не вдалося" (я здогадуюсь про помилку перевірки), ви можете надіслати щось на зразок 422 (не обробляється сутність).


Важливо пам’ятати, що ця функція також вже не працює, як тільки розпочнеться вихід!
rob74

@ rob74 Правда - як тільки PHP почне надсилати вихідні дані, всі функції, пов'язані із заголовком, більше не працюватимуть. Якщо ви не впевнені, чи доведеться вам змінювати код відповіді перед тим, як почати надсилати вихідні дані, тоді буферизація виводу є хорошим рішенням.
inxilpro

34

Ви можете використовувати наступну функцію, щоб надіслати зміну стану:

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

Ви можете використовувати його як такий:

<?php
header_status(500);

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

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

update_database();

header_status(200);

21
Збереження пари байт пам’яті рідко буває вагомою причиною так чи інакше писати код веб-програми.
Ден Гроссман,

1
ти не пропускаєш ;після die()?
henrywright

2
У вашому списку відсутній 418 => "я чайник" див .: en.wikipedia.org/wiki/Hyper_Text_Coffee_Pot_Control_Protocol
Луї Лудог Троттьє

16

Ви можете просто поставити:

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

у ваших умовах, таких як:

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

Що стосується запиту до бази даних, ви можете зробити це так:

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

Слід пам’ятати, що цей код потрібно розміщувати перед будь-яким тегом html (або результатом).


11
Переконайтесь, що ви вийшли / померли / повернули / щось після виклику заголовка (). PHP буде продовжувати виконувати код - що, мабуть, не бажано.
Девід Гудвін,

8

Ви можете спростити це так:

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

Він поверне наступний заголовок:

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

Додано: Якщо вам потрібно точно знати, що пішло не так, зробіть щось подібне:

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

5
Тепер що 'x'має бути?
Core Xii

1
+1 Зверніть увагу, що першим параметром у headerмає бути непустий рядок. Що це 'x'насправді не має значення.
theazureshadow

1
@Core Xii, перший параметр не повинен бути нульовим, як зазначив @theazureshadow. Коротше кажучи, викликавши заголовок ('something', true, 500), буде повернено правильний заголовок "HTTP / 1.0 500 Internal Server Error". Ви можете назвати мене ледачим, але простіше просто передати код помилки, ніж обробляти фактичний рядок заголовка :) Подивіться на php.net/manual/en/function.header.php, щоб отримати докладнішу інформацію.
David Kuridža

У посібнику це не дуже зрозуміло. Отже, ви говорите, що якщо ви примусите код стану, PHP автоматично перепише аргумент рядка до його правильного значення? Тоді чому в посібнику буде сказано, що воно набирає чинності, лише якщо рядок не порожній?
Core Xii

1
Зверніть увагу, що в деяких конфігураціях PHP (той, який мій хостинг-провайдер використовує для exapmle, але не в моїй локальній установці), цей трюк не спрацює! Apache не розпізнає "x" як правильний рядок заголовка і не зможе з помилкою "Неправильний заголовок".
mjsarfatti

2

Ваш код повинен виглядати так:

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

Я припускаю, що ви зупините виконання, якщо щось піде не так.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.