I’m writing an authentication script in PHP, to be called as an API, that needs to return 200only in the case that it approves the request, and403(Forbidden) or500` otherwise.
The problem I’m running into is that php returns 200 in the case of error conditions, outputting the error as html instead. How can I make absolutely sure that php will return an HTTP 500 code unless I explicitly return the HTTP 200 or HTTP 403 myself? In other words, I want to turn any and all warning or error conditions into 500s, no exceptions, so that the default case is rejecting the authentication request, and the exception is approving it with a 200 code.
I’ve fiddled with set_error_handler() and error_reporting(), but so far no luck. For example, if the code outputs something before I send the HTTP response code, PHP naturally reports that you can’t modify header information after outputting anything. However, this is reported by PHP as a 200 response code with html explaining the problem. I need even this kind of thing to be turned into a 500 code.
Is this possible in PHP? Or do I need to do this at a higher level like using mod_rewrite somehow? If that’s the case, any idea how I’d set that up?
I’m writing an authentication script in PHP, to be called as an API, that needs to return 200only in the case that it approves the request, and403(Forbidden) or500` otherwise.
The problem I’m running into is that php returns 200 in the case of error conditions, outputting the error as html instead. How can I make absolutely sure that php will return an HTTP 500 code unless I explicitly return the HTTP 200 or HTTP 403 myself? In other words, I want to turn any and all warning or error conditions into 500s, no exceptions, so that the default case is rejecting the authentication request, and the exception is approving it with a 200 code.
I’ve fiddled with set_error_handler() and error_reporting(), but so far no luck. For example, if the code outputs something before I send the HTTP response code, PHP naturally reports that you can’t modify header information after outputting anything. However, this is reported by PHP as a 200 response code with html explaining the problem. I need even this kind of thing to be turned into a 500 code.
Is this possible in PHP? Or do I need to do this at a higher level like using mod_rewrite somehow? If that’s the case, any idea how I’d set that up?
(PHP 5 >= 5.4.0, PHP 7, PHP 
http_response_code — Get or Set the HTTP response code
Description
http_response_code(int $response_code = 0): int|bool
Parameters
-
response_code -
The optional
response_codewill set the response code.
Return Values
If response_code is provided, then the previous
status code will be returned. If response_code is not
provided, then the current status code will be returned. Both of these
values will default to a 200 status code if used in a web
server environment.
false will be returned if response_code is not
provided and it is not invoked in a web server environment (such as from a
CLI application). true will be returned if
response_code is provided and it is not invoked in a
web server environment (but only when no previous response status has been
set).
Examples
Example #1 Using http_response_code() in a web server environment
<?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());
?>
The above example will output:
Example #2 Using http_response_code() in a CLI environment
<?php// Get the current default response code
var_dump(http_response_code());// Set a response code
var_dump(http_response_code(201));// Get the new response code
var_dump(http_response_code());
?>
The above example will output:
bool(false) bool(true) int(201)
See Also
- header() — Send a raw HTTP header
- headers_list() — Returns a list of response headers sent (or ready to send)
craig at craigfrancis dot co dot uk ¶
11 years ago
If your version of PHP does not include this function:
<?phpif (!function_exists('http_response_code')) {
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;
}
}
?>
In this example I am using $GLOBALS, but you can use whatever storage mechanism you like... I don't think there is a way to return the current status code:
https://bugs.php.net/bug.php?id=52555
For reference the error codes I got from PHP's source code:
http://lxr.php.net/opengrok/xref/PHP_5_4/sapi/cgi/cgi_main.c#354
And how the current http header is sent, with the variables it uses:
http://lxr.php.net/opengrok/xref/PHP_5_4/main/SAPI.c#856
Stefan W ¶
9 years ago
Note that you can NOT set arbitrary response codes with this function, only those that are known to PHP (or the SAPI PHP is running on).
The following codes currently work as expected (with PHP running as Apache module):
200 – 208, 226
300 – 305, 307, 308
400 – 417, 422 – 424, 426, 428 – 429, 431
500 – 508, 510 – 511
Codes 0, 100, 101, and 102 will be sent as "200 OK".
Everything else will result in "500 Internal Server Error".
If you want to send responses with a freestyle status line, you need to use the `header()` function:
<?php header("HTTP/1.0 418 I'm A Teapot"); ?>
Thomas A. P. ¶
7 years ago
When setting the response code to non-standard ones like 420, Apache outputs 500 Internal Server Error.
This happens when using header(0,0,420) and http_response_code(420).
Use header('HTTP/1.1 420 Enhance Your Calm') instead.
Note that the response code in the string IS interpreted and used in the access log and output via http_response_code().
Anonymous ¶
10 years ago
Status codes as an array:
<?php
$http_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", 306 => "(Unused)", 307 => "Temporary Redirect", 308 => "Permanent 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", 418 => "I'm a teapot", 419 => "Authentication Timeout", 420 => "Enhance Your Calm", 422 => "Unprocessable Entity", 423 => "Locked", 424 => "Failed Dependency", 424 => "Method Failure", 425 => "Unordered Collection", 426 => "Upgrade Required", 428 => "Precondition Required", 429 => "Too Many Requests", 431 => "Request Header Fields Too Large", 444 => "No Response", 449 => "Retry With", 450 => "Blocked by Windows Parental Controls", 451 => "Unavailable For Legal Reasons", 494 => "Request Header Too Large", 495 => "Cert Error", 496 => "No Cert", 497 => "HTTP to HTTPS", 499 => "Client Closed Request", 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", 508 => "Loop Detected", 509 => "Bandwidth Limit Exceeded", 510 => "Not Extended", 511 => "Network Authentication Required", 598 => "Network read timeout error", 599 => "Network connect timeout error");
?>
Source: Wikipedia "List_of_HTTP_status_codes"
Anonymous ¶
9 years ago
You can also create a enum by extending the SplEnum class.
<?php/** HTTP status codes */
class HttpStatusCode extends SplEnum {
const __default = self::OK;
const
SWITCHING_PROTOCOLS = 101;
const OK = 200;
const CREATED = 201;
const ACCEPTED = 202;
const NONAUTHORITATIVE_INFORMATION = 203;
const NO_CONTENT = 204;
const RESET_CONTENT = 205;
const PARTIAL_CONTENT = 206;
const MULTIPLE_CHOICES = 300;
const MOVED_PERMANENTLY = 301;
const MOVED_TEMPORARILY = 302;
const SEE_OTHER = 303;
const NOT_MODIFIED = 304;
const USE_PROXY = 305;
const BAD_REQUEST = 400;
const UNAUTHORIZED = 401;
const PAYMENT_REQUIRED = 402;
const FORBIDDEN = 403;
const NOT_FOUND = 404;
const METHOD_NOT_ALLOWED = 405;
const NOT_ACCEPTABLE = 406;
const PROXY_AUTHENTICATION_REQUIRED = 407;
const REQUEST_TIMEOUT = 408;
const CONFLICT = 408;
const GONE = 410;
const LENGTH_REQUIRED = 411;
const PRECONDITION_FAILED = 412;
const REQUEST_ENTITY_TOO_LARGE = 413;
const REQUESTURI_TOO_LARGE = 414;
const UNSUPPORTED_MEDIA_TYPE = 415;
const REQUESTED_RANGE_NOT_SATISFIABLE = 416;
const EXPECTATION_FAILED = 417;
const IM_A_TEAPOT = 418;
const INTERNAL_SERVER_ERROR = 500;
const NOT_IMPLEMENTED = 501;
const BAD_GATEWAY = 502;
const SERVICE_UNAVAILABLE = 503;
const GATEWAY_TIMEOUT = 504;
const HTTP_VERSION_NOT_SUPPORTED = 505;
}
Rob Zazueta ¶
10 years ago
The note above from "Anonymous" is wrong. I'm running this behind the AWS Elastic Loadbalancer and trying the header(':'.$error_code...) method mentioned above is treated as invalid HTTP.
The documentation for the header() function has the right way to implement this if you're still on < php 5.4:
<?php
header("HTTP/1.0 404 Not Found");
?>
viaujoc at videotron dot ca ¶
2 years ago
Do not mix the use of http_response_code() and manually setting the response code header because the actual HTTP status code being returned by the web server may not end up as expected. http_response_code() does not work if the response code has previously been set using the header() function. Example:
<?php
header('HTTP/1.1 401 Unauthorized');
http_response_code(403);
print(http_response_code());
?>
The raw HTTP response will be (notice the actual status code on the first line does not match the printed http_response_code in the body):
HTTP/1.1 401 Unauthorized
Date: Tue, 24 Nov 2020 13:49:08 GMT
Server: Apache
Connection: Upgrade, Keep-Alive
Keep-Alive: timeout=5, max=100
Transfer-Encoding: chunked
Content-Type: text/html; charset=UTF-8
403
I only tested it on Apache. I am not sure if this behavior is specific to Apache or common to all PHP distributions.
Anonymous ¶
11 years ago
If you don't have PHP 5.4 and want to change the returned status code, you can simply write:
<?php
header(':', true, $statusCode);
?>
The ':' are mandatory, or it won't work
divinity76 at gmail dot com ¶
3 years ago
if you need a response code not supported by http_response_code(), such as WebDAV / RFC4918's "HTTP 507 Insufficient Storage", try:
<?php
header($_SERVER['SERVER_PROTOCOL'] . ' 507 Insufficient Storage');
?>
result: something like
HTTP/1.1 507 Insufficient Storage
Richard F. ¶
10 years ago
At least on my side with php-fpm and nginx this method does not change the text in the response, only the code.
<?php// HTTP/1.1 404 Not Found
http_response_code(404);?>
The resulting response is HTTP/1.1 404 OK
Steven ¶
8 years ago
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.
stephen at bobs-bits dot com ¶
9 years ago
It's not mentioned explicitly, but the return value when SETTING, is the OLD status code.
e.g.
<?php
$a
= http_response_code();
$b = http_response_code(202);
$c = http_response_code();var_dump($a, $b, $c);// Result:
// int(200)
// int(200)
// int(202)
?>
Chandra Nakka ¶
6 years ago
On PHP 5.3 version, If you want to set HTTP response code. You can try this type of below trick :)
<?php
header
('Temporary-Header: True', true, 404);
header_remove('Temporary-Header');?>
yefremov {dot} sasha () gmail {dot} com ¶
8 years ago
@craig at craigfrancis dot co dot uk@ wrote the function that replaces the original. It is very usefull, but has a bug. The original http_response_code always returns the previous or current code, not the code you are setting now. Here is my fixed version. I also use $GLOBALS to store the current code, but trigger_error() instead of exit. So now, how the function will behave in the case of error lies on the error handler. Or you can change it back to exit().
if (!function_exists('http_response_code')) {
function http_response_code($code = NULL) {
$prev_code = (isset($GLOBALS['http_response_code']) ? $GLOBALS['http_response_code'] : 200);
if ($code === NULL) {
return $prev_code;
}
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:
trigger_error('Unknown http status code ' . $code, E_USER_ERROR); // exit('Unknown http status code "' . htmlentities($code) . '"');
return $prev_code;
}
$protocol = (isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0');
header($protocol . ' ' . $code . ' ' . $text);
$GLOBALS['http_response_code'] = $code;
// original function always returns the previous or current code
return $prev_code;
}
}
Anonymous ¶
5 years ago
http_response_code() does not actually send HTTP headers, it only prepares the header list to be sent later on.
So you can call http_reponse_code() to set, get and reset the HTTP response code before it gets sent.
Test code:
<php
http_response_code(500); // set the code
var_dump(headers_sent()); // check if headers are sent
http_response_code(200); // avoid a default browser page
Kubo2 ¶
7 years ago
If you want to set a HTTP response code without the need of specifying a protocol version, you can actually do it without http_response_code():
<?php
header
('Status: 404', TRUE, 404);?>
zweibieren at yahoo dot com ¶
8 years ago
The limited list given by Stefan W is out of date. I have just tested 301 and 302 and both work.
divinity76 at gmail dot com ¶
6 years ago
warning, it does not check if headers are already sent (if it is, it won't *actually* change the code, but a subsequent call will imply that it did!!),
you might wanna do something like
function ehttp_response_code(int $response_code = NULL): int {
if ($response_code === NULL) {
return\ http_response_code();
}
if (\headers_sent()) {
throw new\ Exception('tried to change http response code after sending headers!');
}
return\ http_response_code($response_code);
}
PHP фатальные ошибки возвращаются в качестве кода состояния 200 для HTTP-клиента. Как я могу заставить его вернуть код состояния 500 (Внутренняя ошибка сервера)?
header("HTTP/1.1 500 Internal Server Error");
Это именно та проблема, с которой я вчера столкнулся, и нашел решение следующим образом:
1) прежде всего, вам нужно уловить PHP фатальные ошибки, которые являются ошибкой E_ERROR. при возникновении этой ошибки скрипт будет хранить ошибку и прекратить выполнение. вы можете получить сохраненную ошибку, вызвав функцию error_get_last ().
2) до завершения сценария всегда будет вызываться функция обратного вызова register_shutdown_function (). поэтому вам необходимо зарегистрировать обработчик ошибок с помощью этой функции, чтобы сделать то, что вы хотите, в этом случае вернуть заголовок 500 и настроенную внутреннюю страницу ошибок (необязательно).
function my_error_handler() { $last_error = error_get_last(); if ($last_error && $last_error['type']==E_ERROR) { header("HTTP/1.1 500 Internal Server Error"); echo '...';//html for 500 page } } register_shutdown_function('my_error_handler');
Примечание. Если вы хотите поймать собственный тип ошибки, который начинается с E_USER *, вы можете использовать функцию set_error_handler () для регистрации обработчика ошибок и запускать ошибку с помощью функции trigger_error, однако этот обработчик ошибок не может обрабатывать тип ошибки E_ERROR. см. объяснение на php.net о обработчике ошибок
Я использовал «set_exception_handler» для обработки исключений uncaught.
function handleException($ex) { error_log("Uncaught exception class=" . get_class($ex) . " message=" . $ex->getMessage() . " line=" . $ex->getLine()); ob_end_clean(); # try to purge content sent so far header('HTTP/1.1 500 Internal Server Error'); echo 'Internal error'; } set_exception_handler('handleException');
Невозможно обрабатывать PHP E_ERROR каким-либо образом в соответствии с документацией PHP: http://www.php.net/manual/en/function.set-error-handler.php
Также нельзя обрабатывать «E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING и большую часть E_STRICT» в соответствии с этой ссылкой.
Вы можете предоставить обработчик для другой ошибки, предупреждения и уведомлений, включая E_USER_ERROR, но это действительно не так полезно, как кажется, поскольку эта ошибка только умышленно бросается программистом с помощью trigger_error ().
И, конечно же, вы можете поймать любое исключение (даже те, которые бросают собственные PHP-функции).
Я согласен, что это проблема. Серверы НЕ должны возвращать 200 OK, когда код приложения сбой и ожоги.
Вам придется поймать заброшенную ошибку с помощью try / catch, а затем использовать этот блок catch для отправки заголовка () с ошибкой 500.
try { ...badcode... throw new Exception('error'); } catch (Exception $e) { header("Status: 500 Server Error"); var_dump($e->getMessage()); }
Если фатальное исключение не окружено блоками try {} catch, вы должны зарегистрировать глобальный обработчик и использовать register_shutdown_function() чтобы проверить наличие ошибки на конце скрипта.
Никогда не забудьте установить header("HTTP/1.1 200 OK", true, 200); как последняя строка любого пути выполнения:
//first things first: header("HTTP/1.1 500 Internal Server Error", true, 500); //Application code, includes, requires, etc. [...] //somewhere something happens //die(); throw new Exception("Uncaught exception!"); //last things last, only reached if code execution was not stopped by uncaught exception or some fatal error header("HTTP/1.1 200 OK", true, 200);
В PHP 5.4 вы можете заменить вышеописанную функцию header гораздо лучше http_response_code(200) или http_response_code(500) .
Трудная вещь при работе с фатальными ошибками (ошибки компиляции, например отсутствующая точка с запятой) заключается в том, что сценарий не будет выполнен, поэтому он не поможет установить код состояния в этом скрипте. Однако, когда вы включаете или требуете сценарий, исполняемый скрипт будет выполнен независимо от ошибок во включенном скрипте. При этом я прихожу к этому решению:
рок-твердое тело-script.php:
// minimize changes to this script to keep it rock-solid http_response_code(500); // PHP >= 5.4 require_once("script-i-want-to-guard-for-errors.php");
скрипт-я-хочу-к-охранником-для-errors.php:
// do all the processsing // don't produce any output // you might want to use output buffering http_response_code(200); // PHP >= 5.4 // here you can produce the output
Направьте свой звонок на rock-solid-script.php, и вы готовы к работе.
Мне бы лучше было установить код состояния по умолчанию на 500 в .htaccess. Это кажется мне более элегантным, но я не могу найти способ его снять. Я попробовал флаг RewriteRule R, но это предотвращает выполнение php вообще, так что это бесполезно.
Стандартная конфигурация PHP возвращает 500 при возникновении ошибки! Просто убедитесь, что ваш display_errors = выключен. Вы можете имитировать его с помощью:
ini_set('display_errors', 0); noFunction();
По умолчанию директива display_errors отключена по умолчанию.
I know this is an old thread, but when I searched on Google, it jumps out as the first answer. I was trying to figure out how to do it these days, so I think I should post my workaround from 2018.
As you all have known, no, you cannot simply trigger Apache’s error pages from PHP. There’s no way doing it. So the best workaround I could find, after some research, is to use a PHP function to display the custom error pages, which is called from both what you specified in Apache, and the page that you want to trigger 500 Internal Server Error.
Here is my conf of Apache:
ErrorDocument 400 /error.php
ErrorDocument 401 /error.php
ErrorDocument 403 /error.php
ErrorDocument 404 /error.php
ErrorDocument 500 /error.php
As you could see, all 4xx and 500 errors are redirected to a same php file. Why I’m not using separate files for each code is another question, which has nothing to do with your question here, so let’s forget it and focus on error.php for now.
Here are some lines of error.php:
<?php
require_once("error_page.php");
$relative_path = "";
$internal_server_error = FALSE;
if (isset($_SERVER['REDIRECT_URL']) && $_SERVER['REDIRECT_URL'] != "")
{
$relative_path = $_SERVER['REDIRECT_URL'];
$internal_server_error = (http_response_code() >= 500);
}
else if (isset($_SERVER['REQUEST_URI']))
{
$relative_path = $_SERVER['REQUEST_URI'];
}
ErrorPage::GenerateErrorPage($internal_server_error, $relative_path);
?>
In short, it receives HTTP status code from Apache via http_response_code(), and simply categorize the status code into two categories: Internal Server Error and Non-Internal Server Error. It then passes the category to ErrorPage::GenerateErrorPage() which actually generates contents of the error page.
In ErrorPage::GenerateErrorPage(), I do something like this:
<?php
http_response_code($internal_server_error ? 500 : 404);
?>
at the beginning of the function, so that there won’t be any annoying “headers already sent”. This function will generate a fully functional error page with correct (or what we expected, at least) HTTP status code. After setting the HTTP status code, as you may guess, one of two prepared contents will be generated by following php codes, one for 500, another for 404.
Now let’s go back to your question.
You want to trigger exactly the same error page as Apache does, and now you can simply call the ErrorPage::GenerateErrorPage() from wherever you want, as long as you give it correct parameters (TRUE for 500, FALSE for 404 in my case).
Obviously, because that the Apache error pages are generated by the same function ErrorPage::GenerateErrorPage(), we can guarantee that what you trigger wherever is exactly what you would expect from Apache error pages.
Here is my example of a trigger page:
<?php
ob_start();
require_once("error_page.php");
try
{
// Actual contents go here
phpInfo();
throw new Exception('test exception');
}
catch (Exception $e)
{
ob_clean();
ErrorPage::GenerateErrorPage(TRUE);
ob_end_flush();
exit();
}
ob_end_flush();
?>
The reason I use ob_start() and ob_clean() is that, in this way, I can clear anything output before the exception occurs, and send a pure 500 Internal Server Error page that looks exactly the same as Apache gives, without any content on the trigger page (phpInfo() in this case). ob_start() and ob_clean() also make sure that there won’t be “headers already sent”, because nothing will ever be sent unless you call ob_end_flush().
The solution above is concluded from what I researched these days. It is so far so good for me, but I’m not sure if it is the correct way to do it. Any comments, questions, thoughts, suggestions and improvements are welcomed.
