PHP: Как отправить код ответа HTTP?

254

У меня есть PHP-скрипт, который должен давать ответы с помощью HTTP-кодов ответов (кодов состояния), таких как HTTP 200 OK или код 4XX или 5XX.

Как я могу сделать это в PHP?

Пауло Коги - Восстановить Монику
источник

Ответы:

461

Я только нашел этот вопрос и подумал, что нужен более полный ответ:

Начиная с PHP 5.4, есть три способа сделать это:

Сборка кода ответа самостоятельно (PHP> = 4.0)

header()Функция имеет специальный потребительной случай , который определяет линию ответа HTTP и позволяет заменить , что с пользовательской один

header("HTTP/1.1 200 OK");

Однако для этого требуется (Fast) 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");

Примечание: Согласно HTTP RFC , фраза причины может быть любой произвольной строкой (которая соответствует стандарту), но ради совместимости с клиентом я не рекомендую помещать туда случайную строку.

Примечание: php_sapi_name() требуется PHP 4.0.1

3-й аргумент функции заголовка (PHP> = 4.3)

Очевидно, есть несколько проблем при использовании этого первого варианта. Самым большим из них, на мой взгляд, является то, что он частично анализируется PHP или веб-сервером и плохо документирован.

Начиная с 4.3, headerфункция имеет 3-й аргумент, который позволяет вам несколько удобно установить код ответа, но для его использования требуется, чтобы первый аргумент был непустой строкой. Вот два варианта:

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

Я рекомендую второй . Первый делает работу на все браузеры я тестировал, но некоторые незначительные браузеры или веб - сканеры могут иметь проблемы с линией заголовка , который содержит только двоеточие. Имя поля заголовка во 2-м. вариант, конечно, никак не стандартизирован и может быть изменен, я просто выбрал, надеюсь, описательное имя.

Функция http_response_code (PHP> = 5.4)

http_response_code()Функция была введена в PHP 5.4, и он сделал вещи намного проще.

http_response_code(404);

Вот и все.

Совместимость

Вот функция, которую я приготовил, когда мне требовалась совместимость ниже 5,4, но мне нужна была функциональность «новой» http_response_codeфункции. Я считаю, что PHP 4.3 более чем достаточно для обратной совместимости, но вы никогда не знаете ...

// 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;
    }
}
dualed
источник
10
Я могу подтвердить, что header('X-PHP-Response-Code: 404', true, 404);работает правильно под PHP-FPM (FastCGI)
Джош
@dualed (1) не headers_sent()всегда будет правдой сразу после звонка header()? (2) когда-нибудь найти что-то вроде http_response_text () в мире 5.4? По крайней мере старый header () может влиять на текст после кода состояния.
Боб Стейн
@ BobStein-VisiBone (1) headers_sent() имеет значение true, если вы не можете добавить больше заголовков, потому что контент уже отправлен, а не если вы добавили заголовок. (2) Извините, нет. Другие языки имеют лучшую поддержку
dualed
1
@Перри, причина, по которой я не предлагаю делать это, та же самая, почему я не предлагаю только двоеточие. PHP может обрабатывать это по-разному во всех версиях, так как не определено, что происходит с таким «заголовком», он может полностью потерпеть неудачу - не устанавливая ни заголовок, ни статус, или он может добавить недопустимый заголовок (стандарт протокола http 1.1 требует двоеточия )
сдал
8
Я потратил часы, осознавая, что http_response_code(и, возможно, в целом изменение заголовка) больше не работает после того, как вы echoчто-то сделали. Надеюсь, поможет.
Нептило
40

К сожалению, я обнаружил, что решения, представленные @dualed, имеют различные недостатки.

  1. Использование substr($sapi_type, 0, 3) == 'cgi'не достаточно, чтобы обнаружить быстрый CGI. При использовании PHP-FPM FastCGI Process Manager php_sapi_name()возвращает fpm, а не cgi

  2. Fasctcgi и php-fpm раскрывают еще одну ошибку, упомянутую @Josh - использование header('X-PHP-Response-Code: 404', true, 404);работает правильно под PHP-FPM (FastCGI)

  3. header("HTTP/1.1 404 Not Found");может произойти сбой, если протокол не HTTP / 1.1 (т. е. «HTTP / 1.0»). Текущий протокол должен быть обнаружен с помощью $_SERVER['SERVER_PROTOCOL'](доступно с PHP 4.1.0

  4. Существует как минимум 2 случая, когда вызов http_response_code()приводит к неожиданному поведению:

    • Когда PHP встречает код ответа HTTP, который он не понимает, PHP заменит код на тот, который он знает из той же группы. Например, «521 веб-сервер не работает» заменяется на «500 Internal Server Error». Многие другие необычные коды ответов из других групп 2xx, 3xx, 4xx обрабатываются таким образом.
    • На сервере с функциями php-fpm и nginx http_response_code () МОЖЕТ изменить ожидаемый код, но не сообщение. Это может привести к странному заголовку «404 OK», например. Эта проблема также упоминается на веб-сайте PHP в комментарии пользователя http://www.php.net/manual/en/function.http-response-code.php#112423.

Для справки здесь приведен полный список кодов состояния ответа HTTP (этот список включает коды из интернет-стандартов IETF, а также других RFC IETF. Многие из них в настоящее время НЕ поддерживаются функцией PHP http_response_code): http: //en.wikipedia .org / вики / List_of_HTTP_status_codes

Вы можете легко проверить эту ошибку, позвонив:

http_response_code(521);

Сервер отправит HTTP-код ответа «500 Internal Server Error», что приведет к непредвиденным ошибкам, если у вас есть, например, пользовательское клиентское приложение, вызывающее ваш сервер и ожидающее дополнительные HTTP-коды.


Мое решение (для всех версий PHP начиная с 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);
}

Вывод

Реализация http_response_code () не поддерживает все коды ответов HTTP и может перезаписать указанный код ответа HTTP другим кодом из той же группы.

Новая функция http_response_code () не решает все связанные с этим проблемы, а усугубляет ситуацию, создавая новые ошибки.

Решение «совместимости», предлагаемое @dualed, не работает должным образом, по крайней мере, в PHP-FPM.

Другие решения, предлагаемые @dualed, также имеют различные ошибки. Быстрое обнаружение CGI не обрабатывает PHP-FPM. Текущий протокол должен быть обнаружен.

Любые тесты и комментарии приветствуются.

Григорий Мадалин
источник
21

начиная с PHP 5.4 вы можете использовать http_response_code()для получения и установки кода статуса заголовка.

вот пример:

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

вот документ этой функции в php.net:

http_response_code

Сейед Али Рошан
источник
По моему опыту, это лучший ответ.
Скраффи
Зачем использовать var_dump ()?
Томас Гонсалес
Но почему var_dump () вместо echo? Может ли результат не подходить для простого эха? Или даже print_r (). var_dump (), кажется, не подходит для производственного кода ...
Томас Гонсалес
@ TomasGonzalez, это не так уж важно, я просто хотел показать вам, что в нем, распечатав все с помощью var_dump (), и вы правы, что они не важны
Сейед Али Рошан
Да я вижу. Что привлекло мое внимание, так это то, что в официальных документах пример использует var_dump (). Так что мне было интересно узнать причину этого. Там могло быть что-то, чего мне не хватало. php.net/manual/en/function.http-response-code.php
Томас Гонсалес
10

Добавьте эту строку перед любым выводом тела, если вы не используете буферизацию вывода.

header("HTTP/1.1 200 OK");

Замените часть сообщения («ОК») соответствующим сообщением, а код состояния - соответствующим образом (404, 501 и т. Д.).

sparkey0
источник
2
Разве сообщение, которое мы помещаем (чтобы заменить OK), может быть чем-нибудь?
FMaz008
Это сработало для меня. Я работал над формой контакта на веб-сайте с PHP 5.3. И это решение сработало для меня. Он выдаст текст ответа и этот HTTP-код для функции неудачного завершения запроса AJAX. Это все, что я хотел.
Surjith SM
7

Если вы находитесь здесь из-за того, что Wordpress дает 404 при загрузке среды, это должно решить проблему:

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

Проблема связана с отправкой заголовка Status: 404 Not Found. Вы должны переопределить это. Это также будет работать:

define('WP_USE_THEMES', false);
require('../wp-blog-header.php');
header("HTTP/1.1 200 OK");
header("Status: 200 All rosy");
jaggedsoft
источник
заголовок («HTTP / 1.1 200 OK»); http_response_code (201); заголовок («Статус: все 200 розовых»); // работа
alpc
6

С функцией заголовка . В разделе приведен пример первого параметра, который он принимает.

Quentin
источник
2

Если ваша версия PHP не включает эту функцию:

<?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;
    }
Абдо-Host
источник
1

Мы можем получить другое возвращаемое значение из http_response_code через две разные среды:

  1. Среда веб-сервера
  2. Среда CLI

В среде веб-сервера верните предыдущий код ответа, если вы указали код ответа или если вы не указали код ответа, тогда будет напечатано текущее значение. Значение по умолчанию - 200 (ОК).

В среде CLI значение true будет возвращено, если вы предоставили код ответа, и значение false, если вы не предоставите код ответа.

Пример среды веб-сервера возвращаемого значения кода ответа:

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

Пример среды CLI возвращаемого значения Response_code:

var_dump(http_response_code()); // bool(false)
var_dump(http_response_code(501)); // bool(true)
var_dump(http_response_code()); // int(501)
GaziAnis
источник