91

I need to send "500 Internal Server Error" from an PHP script under certain conditions. The script is supposed to be called by a third party app. The script contains a couple of die("this happend") statements for which I need to send the 500 Internal Server Error response code instead of the usual 200 OK. The third party script will re-send the request under certain conditions which include not receiving the 200 OK response code.

Second part of the question: I need to setup my script like this:

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

I need to send 200 header only after the last line has been executed.

Edit

A side question: can I send strange 500 headers such as these:

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

Will such errors get logged by the webserver?

2
  • is not doable when u sent header and remove header later
    – ajreal
    Commented Nov 12, 2010 at 7:39
  • 2
    Re side question: That's entirely legit. Reason Phrases are not intended for machine consumption and they can be anything. It's only the three-digit Status Code that matters. (RFC2616 6.1.1: "The reason phrases listed here are only recommendations -- they MAY be replaced by local equivalents without affecting the protocol.") Commented Oct 15, 2019 at 9:52

6 Answers 6

185
header($_SERVER['SERVER_PROTOCOL'] . ' 500 Internal Server Error', true, 500);
4
  • FYI, this solution sends the X-Pad: avoid browser bug header in some versions of Apache. stackoverflow.com/questions/8711584/… . http_response_code() omits this header. Commented Jun 4, 2015 at 12:44
  • 3
    That even works if the header isn't at the beginning, (such as a proof of working), good job.
    – i am me
    Commented Nov 30, 2015 at 19:56
  • Cool, what if want output a json instead a 500 Internal server error?
    – tblancog
    Commented Nov 17, 2020 at 15:00
  • The preferred version is now http_response_code to avoid to stuck on a specific protocol. Commented Mar 28, 2021 at 21:10
59

PHP 5.4 has a function called http_response_code, so if you're using PHP 5.4 you can just do:

http_response_code(500);

I've written a polyfill for this function (Gist) if you're running a version of PHP under 5.4.


To answer your follow-up question, the HTTP 1.1 RFC says:

The reason phrases listed here are only recommendations -- they MAY be replaced by local equivalents without affecting the protocol.

That means you can use whatever text you want (excluding carriage returns or line feeds) after the code itself, and it'll work. Generally, though, there's usually a better response code to use. For example, instead of using a 500 for no record found, you could send a 404 (not found), and for something like "conditions failed" (I'm guessing a validation error), you could send something like a 422 (unprocessable entity).

2
  • It's important to keep in mind that this function also doesn't work anymore once output has started!
    – rob74
    Commented Mar 19, 2015 at 13:47
  • @rob74 True — once PHP has started to send output, all header-related functions will no longer work. If you're not sure if you're going to have to change the response code before you start sending output, then output buffering is a good solution.
    – inxilpro
    Commented Mar 19, 2015 at 14:06
34

You may use the following function to send a status change:

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

You may use it as such:

<?php
header_status(500);

if (that_happened) {
    die("that happened")
}

if (something_else_happened) {
    die("something else happened")
}

update_database();

header_status(200);
3
16

You can just put:

header("HTTP/1.0 500 Internal Server Error");

inside your conditions like:

if (that happened) {
    header("HTTP/1.0 500 Internal Server Error");
}

As for the database query, you can just do that like this:

$result = mysql_query("..query string..") or header("HTTP/1.0 500 Internal Server Error");

You should remember that you have to put this code before any html tag (or output).

1
  • 11
    Make sure you exit/die/return/something after calling header(). PHP will carry on executing code - which is probably not desirable. Commented Aug 1, 2013 at 13:44
7

You can simplify it like this:

if ( that_happened || something_else_happened )
{
    header('X-Error-Message: Incorrect username or password', true, 500);
    die;
}

It will return following header:

HTTP/1.1 500 Internal Server Error
...
X-Error-Message: Incorrect username or password
...

Added: If you need to know exactly what went wrong, do something like this:

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');
}
11
  • 5
    Now what is 'x' supposed to be?
    – Core Xii
    Commented Nov 12, 2010 at 6:49
  • 1
    +1 Note that the first parameter in header must be a non-empty string. That it is 'x' doesn't really matter. Commented Nov 12, 2010 at 6:49
  • 1
    @Core Xii, first parameter must not be null as @theazureshadow pointed out. In short, by calling header('something', true, 500), the correct header "HTTP/1.0 500 Internal Server Error" will be returned. You may call me lazy, but it's easier to just pass the error code than to handle actual header string :) Take a look at php.net/manual/en/function.header.php for more details. Commented Nov 12, 2010 at 6:54
  • The manual isn't very clear about this. So you're saying that if you force the status code, PHP overwrites the string argument to its correct value automatically? Then why would the manual say that it only takes effect if the string isn't empty?
    – Core Xii
    Commented Nov 12, 2010 at 7:25
  • 1
    Note that in some PHP configurations (the one my hosting provider uses for exapmle, but not my local setup) this trick won't work! Apache does not recognize "x" as a correct header string and will fail with a "Malformed header" error.
    – mjsarfatti
    Commented Nov 28, 2012 at 12:58
3

Your code should look like:

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

I assume you stop execution if something goes wrong.

Not the answer you're looking for? Browse other questions tagged or ask your own question.