42
votes

How can i trigger 500 Internal Server Error or 404 Page Not Found Apache errors in PHP?

For 500 Internal Server Error i have tried following code :

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

But it shows me a blank page. How can i show the error in Apache's default format?

Please guide..

10
At first glance I thought this would be trivial to solve. But it appears it's actually not. So +1GordonM
Just to throw it out there for everyone: I was thinking you could just include Apache's original error document out of the shared files (/usr/share/httpd/error/HTTP_INTERNAL_SERVER_ERROR.html.var for me) and exit the PHP script. But I'm having a huge problem: how would you go about processing the .html.var file? In Apache it's set as AddHandler type-map var but I can't figure out anything that would be useful in PHP.animuson♦

10 Answers

19
votes

You could just copy the Apache error documents into your web root (or symlink them in) and use header() to set the error codes and with those documents as output. That's probably best unless you have a compelling reason not to. But in case that won't work for you, there are some alternatives (albeit, hacky alternatives).

For 500, just put a bug in your code.

<?php throw new Exception('Nooooooooooooooo!'); ?>

The PHP script will raise an exception, resulting in a regular Apache 500 error page. (But be aware of the caveat that this will only result in an Apache error if the PHP init setting display_errors is set to 0. In most development configurations, this is not the case. In most production configurations, this is the case. If you don't know your production server's setting, you'll have to just test this to see if it works.)

For 404, I think the best you can do is redirect to a non-existent page. It's not exactly the same thing, but might do for your purposes.

<?php header("Location: /i-dont-think-therefore-i-am-not"); ?>

In most browsers, the users won't actually see the redirect, they will just get silently and quickly redirected to a non-existent page, resulting in a regular Apache 404 error. Of course, the url will have changed and some users might notice that. If that's not acceptable, you can perhaps achieve similar results using Apache mod_rewrite to rewrite the url backend to a non-existent location.

To respond to several comments: Setting the response code via header() (or some other way) will not result in the standard Apache error document. It will simply return that response code with your own output. This is intentional behavior, designed so that you can have custom error documents, or otherwise set response codes as the HTTP spec dictates on any request. If you want the Apache error documents, you have to either forge them (as per my initial suggestion of simply copying the error documents to your web root), or you'll have to trick Apache into returning them (as per my backup suggestion).

13
votes

After such a knowledge-full discussion, i think there is no php code can display the by default 500 Internal Server Error. The solution is :
1. Create a folder named http500 next to the php file.
2. Create a .htaccess file in it and add following code :

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} -d
    RewriteRule ^])(.(*/
    RewriteRule ^])((a-zA
</IfModule>
  1. PHP redirect code :

header('location : http500/');

6
votes
function ISE()
{
  header('HTTP/1.1 500 Internal Server Error', true, 500);
  trigger_error('ISE function called.', E_USER_ERROR);//if you are logging errors?
}

However, you will need output buffering ON to be able to use php header() function after you use any output function like echo.

4
votes

I know this is an old thread however...

You could render an iframe element into your view, and then set its height and width to 100% in the event of the error you are preparing to handle.

<?php header("HTTP/1.0 500 Internal Server Error"); http_response_code(500); ?>

<iframe src="page_displaying_apache_screenshot_fullscreen.html"></iframe>

THAT SAID

I truly think that the best modern solution for this would be something like:

<?php
header("HTTP/1.0 500 Internal Server Error");
http_response_code(500);
?>
<div class="panel-body">
    <h1>Error!</h1>
     <p>
         <?php

         // Then, in the view if your in dev env, print exception and stack trace
         if ($env === 'dev') 
         {
             throw new Exception('Uh oh! Something broke while adding a new user the db.');
         }
         else 
         {
             echo "Hold your butts, an error has occured.";
             die();
         }
         ?>
     </p>
   </div>

This would result in a proper error code for all users, and also a stack trace for dev if you set the $env variable to 'dev' on your dev stack. What the user sees with this, using PHP 5.4 installed with yum using CENTOS7 by default

No redirect, no hackery, secure unless you need to expose an error it won't. :)

3
votes

I'm probably quite late, but this solution should work

header("HTTP/1.0 500 Internal Server Error");
include("/path-to-public-html/errors/500.php");
die();

This will trigger a 500 ISE response, and show the default 500 error page, then stop the script. Obviously you will need to to modify the location of the included file

2
votes

you simply cannot trigger apache error pages from php code without hackery redirection as proposed by ben lee because error document redirection is handled by another layer of your application's stack (specifically, apache's mod_core).
when your script runs, it's too late.

the trickery of getting an error page by throwing an exception heavily depends on your php.ini's settings about error handling and verbosity.

http_response_code()currently only exists in php's svn thus it's not available in most production environments which are supposed to run an official release version.

my advice is to properly implement a custom error and exception handler via set_error_handler() and set_exception_handler(), respectively, use header() to send the client proper http status information and (if needed) generate error pages.

2
votes

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.

0
votes

Apparently there is a function called http_response_code that will let you set the response code appropriately. If that doesn't work (there's a note in the documentation about it possibly being only in SVN) then the header function can take an optional response code argument:

header("HTTP/1.0 ...", true, 404);

This should signal Apache correctly.

0
votes

On PHP 5.5 => "header("tester.php",true,500);" where tester.php does not exist. It works and takes me to my 500 page :)

Unfortunately none of the other methods listed here worked for me for one reason or the other.

0
votes

reason for Internal Server error 500. Iopen httpd.conf text file and edit it fixed my error just change my serverName localhost 81 instead of 80.