PHP: How to Send Http Response Code

PHP: How to send HTTP response code?

I just found this question and thought it needs a more comprehensive answer:

As of PHP 5.4 there are three methods to accomplish this:

Assembling the response code on your own (PHP >= 4.0)

The header() function has a special use-case that detects a HTTP response line and lets you replace that with a custom one

header("HTTP/1.1 200 OK");

However, this requires special treatment for (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");

Note: According to the HTTP RFC, the reason phrase can be any custom string (that conforms to the standard), but for the sake of client compatibility I do not recommend putting a random string there.

Note: php_sapi_name() requires PHP 4.0.1

3rd argument to header function (PHP >= 4.3)

There are obviously a few problems when using that first variant. The biggest of which I think is that it is partly parsed by PHP or the web server and poorly documented.

Since 4.3, the header function has a 3rd argument that lets you set the response code somewhat comfortably, but using it requires the first argument to be a non-empty string. Here are two options:

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

I recommend the 2nd one. The first does work on all browsers I have tested, but some minor browsers or web crawlers may have a problem with a header line that only contains a colon. The header field name in the 2nd. variant is of course not standardized in any way and could be modified, I just chose a hopefully descriptive name.

http_response_code function (PHP >= 5.4)

The http_response_code() function was introduced in PHP 5.4, and it made things a lot easier.

http_response_code(404);

That's all.

Compatibility

Here is a function that I have cooked up when I needed compatibility below 5.4 but wanted the functionality of the "new" http_response_code function. I believe PHP 4.3 is more than enough backwards compatibility, but you never know...

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

Best way to send HTTP response code in PHP

To answer your question about what is the difference, I found this comment in the PHP docs (thanks Steven):

http_response_code is basically a shorthand way of writing a http
status header, with the added bonus that PHP will work out a suitable
Reason Phrase to provide by matching your response code to one of the
values in an enumeration it maintains within
php-src/main/http_status_codes.h. Note that this means your response
code must match a response code that PHP knows about. You can't create
your own response codes using this method, however you can using the
header method.

In summary - The differences between http_response_code and header
for setting response codes:

  1. Using http_response_code will cause PHP to match and apply a Reason Phrase from a list of Reason Phrases that are hard-coded into
    the PHP source code.

  2. Because of point 1 above, if you use http_response_code you must set a code that PHP knows about. You can't set your own custom code,
    however you can set a custom code (and Reason Phrase) if you use the
    header method.


I was curious about how some popular frameworks send the header in a standard response:

Symfony (and Laravel, by inheritance) sets the raw header:

// status
header(sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText), true, $this->statusCode);

Zend Framework 2 also sets the raw header:

public function renderStatusLine()
{
$status = sprintf(
'HTTP/%s %d %s',
$this->getVersion(),
$this->getStatusCode(),
$this->getReasonPhrase()
);
return trim($status);
}

And so does Yii

protected function sendHeaders()
{
if (headers_sent()) {
return;
}
$statusCode = $this->getStatusCode();
header("HTTP/{$this->version} $statusCode {$this->statusText}");
// ...

How to send a status code in PHP, without maintaining an array of status names?

There is a new function for this in PHP >= 5.4.0 http_response_code

Simply do http_response_code(404).

If you have a lower PHP version try header(' ', true, 404); (note the whitespace in the string).

If you want to set the reason phrase as well try:

header('HTTP/ 433 Reason Phrase As You Wish');

Setting HTTP response status code in PHP using header('HTTP/1.1 status-code')?

The message is sent, even if you don't provide it.

In the PHP source code, we can see how it works.

In sapi/litespeed/lsapi_main.c, a list of code/message is stored.

static const http_error http_error_codes[] = {
{100, "Continue"},
{101, "Switching Protocols"},
{200, "OK"},
// ...
{403, "Forbidden"},
{404, "Not Found"},
// ...
{0, NULL}
};

Then, in the sapi_lsapi_send_headers_like_cgi(), from sapi_lsapi_send_headers(), the status is converted to integer and message is found in the http_error structure (many lines ommited below) :

if (SG(sapi_headers).http_response_code != 200)
{
// ...
if (SG(sapi_headers).http_status_line &&
(s = strchr(SG(sapi_headers).http_status_line, ' ')) != 0 &&
(s - SG(sapi_headers).http_status_line) >= 5 &&
strncasecmp(SG(sapi_headers).http_status_line, "HTTP/", 5) == 0
) {
len = slprintf(buf, sizeof(buf), "Status:%s", s);
response_status = atoi((s + 1));
}
// ...
http_error *err = (http_error*)http_error_codes;
while (err->code != 0) {
if (err->code == SG(sapi_headers).http_response_code) {
break;
}
err++;
}
if (err->msg) {
len = slprintf(buf, sizeof(buf), "Status: %d %s", SG(sapi_headers).http_response_code, err->msg);
} else {
len = slprintf(buf, sizeof(buf), "Status: %d", SG(sapi_headers).http_response_code);
}
//...

Then the function LSAPI_SetRespStatus_r() hold this information and finally, the function LSAPI_FinalizeRespHeaders_r() send the finalized header informations.

The most interesting line is (store the message from the http_error) :

len = slprintf(buf, sizeof(buf), "Status: %d %s", SG(sapi_headers).http_response_code, err->msg);

For information, see also the simple structure of http_error :

typedef struct _http_error {
int code;
const char* msg;
} http_error;

How to set http response status code and message in php

You are probably looking for...

$arr = array('message' => 'blah'); //etc

header('HTTP/1.1 201 Created');
echo json_encode($arr);

Set Response Status Code

PHP <=5.3

The header() function has a parameter for status code. If you specify it, the server will take care of it from there.

header('HTTP/1.1 401 Unauthorized', true, 401);

PHP >=5.4

See Gajus' answer: https://stackoverflow.com/a/14223222/362536

Returning http status codes with a rest api

You could re-think your code this way

public function actionTest()
{
try {
// Here: everything went ok. So before returning JSON, you can setup HTTP status code too
$rtn = array("id", "3", "name", "John");
http_response_code(200);
print json_encode($rtn);
}
catch (SomeException $ex) {
$rtn = array("id", "3", "error", "something wrong happened");
http_response_code(500);
print json_encode($rtn);
}
}

Basically, before stream the output (the JSON data), you can set the HTTP status code by http_response_code($code) function.

And about your additional question in comment, yes, printing the JSON data is the correct way.

php - send HTTP status BEFORE the code executes

PHP can certainly do it, but it's a little bit tricky.

ignore_user_abort(true);
header("Content-Length: 0");
header("Connection: Close");
flush();
session_write_close();

// do something that takes very long

This is the minimal code you need. If you don't have a session you can leave off the last call.

Once you've closed the connection you can't send updates though, so if you want to do something with error reporting you'll have to find another way.



Related Topics



Leave a reply



Submit