location(Status|HTTP 1.x) и версия PHP
Как известно, передать HTTP status code в PHP можно двумя способами:
header("Status: 403 Forbidden")header("HTTP/1.1 403 Forbidden")
Проблема в том, что эти способы, кажется, могут работать или не работать в зависимости от разных факторов, прежде всего от того, установлен ли PHP как модуль апача или же как CGI.
Четко я установил следующее:
- PHP5 (любой версии, проверено многократно), установленый как CGI-приложение, нормально работает со
Status:.... - PHP 4.4.0, установленный как модуль аппача, нормальмо работает с
HTTP/..., наStatus:...— возвращает200и добавляет заголовокStatusв неизменном виде. - PHP 5.1.4 CGI на
HTTP/1.1 403 Forbiddenвыдает ответHTTP/1.х 403 Ok.
Интересует, прежде всего, как себя поведет PHP5, установленый как модуль апача. Кто-нибудь тут может это проверить?
А также — от каких еще факторов (версия апача, опрерационка, температура за окном, etc) зависит такое поведение PHP. Сам тестил под видной, Apache/1.3.33.
Проверил на PHP 5.1.4/CGI под FreeBSD, Apache 1.3.37. Результат совершенно аналогичен испытаниям под виндой. Так что, по-видимому, от операционки не зависит.
Главный вопрос остается в силе: как поведет себя PHP5, установленый как модуль апача, с каждым из этих заголовков? У меня самого его сейчас нет, к сожалению, под рукой.
Status: — это (более-менее) стандартный способ выдачи статусного заголовка для CGI-скриптов. Т.е. не только PHP, но и любая другая программа в CGI-режиме может выдать эту строку, и Апач сам из неё сделает правильный статус. Так что в CGI-mode Status: гарантированно должен работать.
Что касается PHP как модуля, то тут уже надо смотреть. Но вообще, Status: в модуле работать не обязан.
как поведет себя PHP5, установленый как модуль апача, с каждым из этих заголовков?
- header("Status: 403 Forbidden");
HTTP/1.0 200 OK Date: Sat, 02 Sep 2006 11:54:40 GMT Server: Apache/1.3.33 (Win32) PHP/5.0.4 X-Powered-By: PHP/5.0.4 Status: 403 Forbidden Keep-Alive: timeout=15, max=100 Connection: Keep-Alive Transfer-Encoding: chunked Content-Type: text/html
- header("HTTP/1.1 403 Forbidden");
HTTP/1.0 403 Forbidden Date: Sat, 02 Sep 2006 11:56:39 GMT Server: Apache/1.3.33 (Win32) PHP/5.0.4 X-Powered-By: PHP/5.0.4 Keep-Alive: timeout=15, max=100 Connection: Keep-Alive Transfer-Encoding: chunked Content-Type: text/html
Владимир Михайленко[досье], спасибо.
Правда, за это время я успел поставить себе другой аппач, на него mod_php5, и проверить на нем. PHP 5.1.2, результат тот же. Окончательный вывод: такое поведение не зависит от версии PHP.
Таблица установки заголовков
| header() | "Status: 403 Forbidden" | "HTTP/1.1 403 Forbidden" |
|---|---|---|
| mod_php | HTTP/1.0 200 OK | HTTP/1.x 403 Forbidden |
| Status: 403 Forbidden | ||
| CGI | HTTP/1.x 403 Forbidden | HTTP/1.x 403 Ok |
Вывод: Для CGI используем Status, для модуля — HTTP.
P.S. Кстати, существует ли оффициальный способ отличить одно от другого изнутри скрипта? Я сам пока использую function_exists('apache_get_version'). Если нету — значит это CGI. У этого способа тот недостаток, что существует, хотя и очень маленькая, вероятность того, что юзер вздумает для CGI-версии проэмулировать apache_get_version своими силами...
P.P.S. А вообще — для верности надо бы еще все это дело под Apache 2 проверить...
Eugene Efremov[досье]
Юзайте php_sapi_name()
define( 'STATUS', (php_sapi_name() == 'cgi')? "Status: " : "HTTP/1.1 " ); ... header(STATUS . "403 Forbidden");
и будет Вам щастье :)
Что касается последнего:
CGI HTTP/1.x 403 Forbidden => HTTP/1.x 403 Ok
Насколько я понимаю, главное, что возвращается правильный числовой статус, reason phrase ("Forbidden", "OK" и т.п.) вроде всегда просто для информации, и особого значения не имеет. Хотя некрасиво, конечно. Похожее обсуждение — http://bugs.php.net/bug.php?id=27345
Александр Лукьянов[досье], спасибо!
В завершенее дискуссии — небольшая библиотечка для этого дела:
class XHttpStatus
{
protected static $status = array
(
100 => '100 Continue',
101 => '101 Switching Protocols',
102 => '102 Processing',
200 => '200 OK',
201 => '201 Created',
202 => '202 Accepted',
203 => '203 Non-Authoritative Information',
204 => '204 No Content',
205 => '205 Reset Content',
206 => '206 Partial Content',
207 => '207 Multi Status',
226 => '226 IM Used',
300 => '300 Multiple Choices',
301 => '301 Moved Permanently',
302 => '302 Found',
303 => '303 See Other',
304 => '304 Not Modified',
305 => '305 Use Proxy',
306 => '306 (Unused)',
307 => '307 Temporary Redirect',
400 => '400 Bad Request',
401 => '401 Unauthorized',
402 => '402 Payment Required',
403 => '403 Forbidden',
404 => '404 Not Found',
405 => '405 Method Not Allowed',
406 => '406 Not Acceptable',
407 => '407 Proxy Authentication Required',
408 => '408 Request Timeout',
409 => '409 Conflict',
410 => '410 Gone',
411 => '411 Length Required',
412 => '412 Precondition Failed',
413 => '413 Request Entity Too Large',
414 => '414 Request-URI Too Long',
415 => '415 Unsupported Media Type',
416 => '416 Requested Range Not Satisfiable',
417 => '417 Expectation Failed',
420 => '420 Policy Not Fulfilled',
421 => '421 Bad Mapping',
422 => '422 Unprocessable Entity',
423 => '423 Locked',
424 => '424 Failed Dependency',
426 => '426 Upgrade Required',
449 => '449 Retry With',
500 => '500 Internal Server Error',
501 => '501 Not Implemented',
502 => '502 Bad Gateway',
503 => '503 Service Unavailable',
504 => '504 Gateway Timeout',
505 => '505 HTTP Version Not Supported',
506 => '506 Variant Also Varies',
507 => '507 Insufficient Storage',
509 => '509 Bandwidth Limit Exceeded',
510 => '510 Not Extended'
);
static public function get_str($code)
{
return self::$status[$code];
}
static public function set($code)
{
// CGI or mod_php ?
$header = (php_sapi_name() == 'cgi') ? 'HTTP/1.1 ' : 'Status: ';
header($header.self::$status[$code]);
}
}
Думаю, этот список заголовков может быть кому-нибудь полезным :-)
P.S. Единственное, что осталось проверить — это то, как это дело ведет себя под вторым апачем. Хотя, думаю, там особых отличий не будет...
![[logo]](/site/images/logo.jpg)