How to Send a Status Code in PHP, Without Maintaining an Array of Status Names

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;

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

Is there a built in list of http response codes and their DESCRIPTIONS in Laravel or Symfony?

Edited:
This code will return http error description:
\Illuminate\Http\Response::$statusTexts["404"]

Use a Custom Status Code with CakePHP 2.x

It's cool that you lookup the API but just keep reading:

Queries & sets valid HTTP response codes & messages.

/**
* Queries & sets valid HTTP response codes & messages.
*
* @param int|array $code If $code is an integer, then the corresponding code/message is
* returned if it exists, null if it does not exist. If $code is an array, then the
* keys are used as codes and the values as messages to add to the default HTTP
* codes. The codes must be integers greater than 99 and less than 1000. Keep in
* mind that the HTTP specification outlines that status codes begin with a digit
* between 1 and 5, which defines the class of response the client is to expect.
* Example:
*
* httpCodes(404); // returns array(404 => 'Not Found')
*
* httpCodes(array(
* 381 => 'Unicorn Moved',
* 555 => 'Unexpected Minotaur'
* )); // sets these new values, and returns true
*
* httpCodes(array(
* 0 => 'Nothing Here',
* -1 => 'Reverse Infinity',
* 12345 => 'Universal Password',
* 'Hello' => 'World'
* )); // throws an exception due to invalid codes
*
* For more on HTTP status codes see: http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6.1
*
* @return mixed associative array of the HTTP codes as keys, and the message
* strings as values, or null of the given $code does not exist.
* @throws CakeException If an attempt is made to add an invalid status code
*/

If you plan to use none standard codes with an API I would return the code in a x-header instead or within the response like Jsend does it for example.

Representing a status array within a PHP class

Using the ReflectionClass

I like you second example; it's a very simple and effective way to make an enum type (sort of). Actually, some of the pretty big php ORMs out there, like Doctrine operate using a similar pattern. The one thing I like to do to improve scalability is to use the ReflectionClass. This will allow you to add new values in the form of constants without having to change the function that returns the list of values. I would also refactor the code to check if the value is valid in the enum class as well to keep a better separation of concerns between the two classes

class User {
private $status_id;

public function setStatus($status_id) {
if (UserStatuses::isStatus($status_id)) {
$this->status_id = $status_id;
}
else {
throw new Exception('invalid status');
}
}
}

class UserStatuses {
const USER_STATUS_ACTIVE = 1;
const USER_STATUS_INACTIVE = 2;
const USER_STATUS_CANCELLED = 3;

public static function statusList() {
$oClass = new ReflectionClass(__CLASS__);
return $oClass->getConstants();
}

public static function isUserStatus($int) {
return in_array($int, self::statusList());
}
}

PHP - for get_headers($url, 1), are the keys for status codes *always* integers?

The PHP C source code for that function looks like this:

        if (!format) {
no_name_header:
add_next_index_str(return_value, zend_string_copy(Z_STR_P(hdr)));
} else {
char c;
char *s, *p;

if ((p = strchr(Z_STRVAL_P(hdr), ':'))) {
... omitted ...
} else {
goto no_name_header;
}
}

In other words, it tests if there's a : in the header, and if so proceeds to index it by its name (omitted here). If there's no : or if you did not request to $format the result, no_name_header kicks in and it adds it to the return_value without explicit index.

So, yes, the status lines should always be numerically indexed. Unless the server puts a : into the status line, which would be unusual. Note that RFC 2616 does not explicitly prohibit the use of : in the reason phrase part of the status line:

Status-Line    = HTTP-Version SP Status-Code SP Reason-Phrase CRLF

Reason-Phrase = *<TEXT, excluding CR, LF>

TEXT = <any OCTET except CTLs,
but including LWS>

There is no standardised reason phrase which contains a ":", but you never know, you may encounter exotic servers in the wild which defy convention here…

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

Laravel won't obey status code

You can't return responses from controller constructors - it just doesn't fit with the flow of the request lifecycle in Laravel.

There's two ways to do this. You can either:

a) Setup a response filter that handles whatever functionality it is you're trying to achieve or
b) Force a controller ACTION to return a response. This would be done like so:

class Api_Controller extends Base_Controller
{
public $restful = true;

public function get_index()
{
return Response::json($test, 400);
}
}

It DOES work - you're just doing it incorrectly :)

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


Related Topics



Leave a reply



Submit