Как отправить 500 ошибок внутреннего сервера с PHP скрипт

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

Вторая часть вопроса: мне нужно настроить мой script следующим образом:

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

Будут ли регистрироваться такие ошибки на веб-сервере?

Ответ 1

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

Ответ 2

Вы можете использовать следующую функцию для отправки изменения статуса:

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

Ответ 3

PHP 5.4 имеет функцию http_response_code, поэтому, если вы используете PHP 5.4, вы можете просто сделать:

http_response_code(500);

Я написал polyfill для этой функции (Gist), если вы используете версию PHP под 5.4.


Чтобы ответить на ваш последующий вопрос, HTTP 1.1 RFC говорит:

Приведенные здесь фразы являются только рекомендациями - они МОГУТ быть заменены локальными эквивалентами, не влияя на протокол.

Это означает, что вы можете использовать любой текст, который вы хотите (за исключением возвратов каретки или строк) после самого кода, и он будет работать. Обычно, как правило, лучше использовать код ответа. Например, вместо использования 500 для не найденной записи вы можете отправить 404 (не найден), а для чего-то вроде "условия не удались" (я предполагаю ошибка проверки), вы можете отправить что-то вроде 422 (необработанный объект).

Ответ 4

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

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 (или выходом).

Ответ 5

Вы можете упростить его следующим образом:

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

Ответ 6

Ваш код должен выглядеть так:

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

Я предполагаю, что вы прекратите выполнение, если что-то пойдет не так.