5

In order to include the right file and display an error page if an error occurs, I have the following code (very simplified) :

$page = 'examplePage.php';
$page404 = '404.php';

if (file_exists($page))
{
    require($page);
}
else if (file_exists($page404))
{
    require($page404);
}
else
{
    // Tell the browser to display his default page
}

?>

To summarize :

  • If I have the file, I include it.

  • If I don't have the file, i include the error file.

  • What if the error file does not exist too ?

I would like it to be rendered as the default error page of the browser.

I already achieved this with Internet Explorer by sending an empty content with the HTTP error. The problem is that the other browsers don't act the same, they all display a blank page.

Is there any way to tell browsers to display their own error page ? (not only 404, but all errors : 304, 500 etc)

Thank you.

Edit : I forgot to tell you that I have the complete control on the headers I send and on the content sent in response.

Edit 2 : here is some code

// possible paths to retrieve the file
$possiblePaths = array(
    $urlPath,
    D_ROOT.$urlPath,
    D_PAGES.$urlPath.'.php',
    D_PAGES.$urlPath.'/index.php',
    $urlPath.'.php'
);

foreach ($possiblePaths as $possiblePath)
    if (file_exists($possiblePath) && !is_dir($possiblePath))
    {
        if (!is_readable($possiblePath))
        {
            Response::setCode(403); // calls the header(403)
            self::$filePath = self::getErrorPage(403);
        }
        else
            self::$filePath = $possiblePath;
        break;
    }

if (self::$filePath === null) // no file found => 404
{
    Response::setCode(404); // call the header(404)
    self::$filePath = self::getErrorPage(404); 
}


public static function _getErrorPage($code)
{
    if (is_readable(D_ERRORS.$code.'.php')) // D_ERRORS is the error directory, it contains files like 404.php, 403.php etc
        return D_ERRORS.$code.'.php';
    else
    {
        /*-------------------------------------------------*/
        /* Here i go if the error file is not found either */
        /*-------------------------------------------------*/

        if ($code >= 400)
            Response::$dieResponse = true; // removes all output, only leaves the http header
        return null;
    }
}
?>

And here is when I print the content :

    <?php
    if (self::$dieResponse)
    {
        self::$headers = array(); // no more headers
        self::$content = ''; // no more response
    }
    http_response_code(self::$code); // HTTP code
    foreach (self::$headers as $key => $value)
        header($key.': '.implode(';', $value)); // sends all headers
    echo self::$content;
    ?>

Edit : here are some screenshots to explain what I want.

This is what i've got in IE :

Internet Explorer

This is exactly what i want.

Now, in all the other browsers, I've got a blank page. I don't want a blank page.

I want, for example, Chrome to display this : Chrome

Heru-Luin
  • 1,832
  • 1
  • 15
  • 25
  • 1
    If your error page itself is missing, don't you have bigger problems than what the user's seeing? – ceejayoz Jun 04 '14 at 19:28
  • 1
    Just a note: the _browser_ has nothing to do with the 404 (or any other) error page. It's all on the _server_. If there is an error condition seen on the server, it will look for the associated error page listed under **ErrorDocument** in .htaccess, then for custom documents (e.g., /404.shtml), and finally, use its own default page. The browser simply displays whatever the server decided to send it. – Phil Perry Jun 04 '14 at 19:40
  • ceejayoz : not a problem, in this case, it just means that I don't have a specific file to display for this error. PhilPerry : true, but wrong. The server rules, but browsers have default error pages. This is also why the 404 page does not look the same in different browsers. Fred-ii- : i can't use apache directives. He may 404 things that are not 404 (if the file does not exists on my server, it does not mean that there is no file to load). – Heru-Luin Jun 04 '14 at 19:59
  • 1
    Note: Not all pages are standard webbrowser, many are standard server (eg Apache, Nginx, lighttpd, etc) – Guilherme Nascimento Jun 04 '14 at 23:04
  • @GuilhermeNascimento I didn't know this. If you know a way to trigger these pages, I'm all opened. – Heru-Luin Jun 05 '14 at 00:59
  • Hi! My answer solve your problem? If so check as "correct", if not tell me what is missing. – Guilherme Nascimento Apr 12 '15 at 15:11
  • In this case, I need to trigger the standard server page. Any ideas ? – Heru-Luin Apr 14 '15 at 13:51

4 Answers4

2

Default error pages

Web Browsers shows default error pages if content is blank, eg. create a empty PHP file (error.php) and put this:

<?php
   $status = http_response_code();
   switch ($status) {
     case 404:
     case 500:
        exit;//terminate script execution
     break;
     ...
   }

In .htaccess put:

ErrorDocument 400 /error.php
ErrorDocument 500 /error.php

Custom error pages

  1. Using HTTP status

    You can use http_response_code() for GET current HTTP status, .htaccess file content:

    ErrorDocument 400 /error.php
    ErrorDocument 401 /error.php
    ErrorDocument 403 /error.php
    ErrorDocument 404 /error.php
    ErrorDocument 500 /error.php
    ErrorDocument 503 /error.php
    

    Page error.php:

    <?php
       $status = http_response_code();
       switch ($status) {
         case '400':
          echo 'Custom error 400';
         break;
         case '404':
          echo 'Custom error 404';
         break;
         ...
       }
    
  2. Using GET param

    ErrorDocument 400 /error.php?status=400
    ErrorDocument 401 /error.php?status=401
    ErrorDocument 403 /error.php?status=403
    ErrorDocument 404 /error.php?status=404
    ErrorDocument 500 /error.php?status=500
    ErrorDocument 503 /error.php?status=503
    

    Page error.php:

    <?php
       $status = empty($_GET['status']) ? NULL : $_GET['status'];
       switch ($status) {
         case '400':
          echo 'Custom error 400';
         break;
         case '404':
          echo 'Custom error 404';
         break;
         ...
       }
    

Related: How to enable mod_rewrite for Apache 2.2

Community
  • 1
  • 1
Guilherme Nascimento
  • 7,990
  • 6
  • 41
  • 107
  • I can't, i'm already in the PHP script and I'm using a router to get the files. Sometimes the page "example.php" will use a script which is in "scripts/example.php", placing ErrorDocuments would not let me handle what is an arror and what is not. – Heru-Luin Jun 04 '14 at 19:47
  • This does not answer my question though. I already know how to set a custom ErrorDocument, my question is when the 404.php file itself does not exist. – Heru-Luin Jun 04 '14 at 21:24
  • Although you have not understood what I proposed, so I'll have a formulate another response. – Guilherme Nascimento Jun 04 '14 at 21:28
  • I don't want to display a custom page, I want to display the browser's default page. – Heru-Luin Jun 04 '14 at 21:38
  • 1
    Send `header($_SERVER['SERVER_PROTOCOL'] . ' 404 Not Found');` without content (eg. without `echo ...;`). Note: Not all pages are standard browser, many are standard server (eg Apache, Nginx, lighttpd, etc) – Guilherme Nascimento Jun 04 '14 at 23:03
  • Why the downvote? Explain so I can improve the answer. – Guilherme Nascimento May 28 '15 at 17:38
  • Browsers do not show default error pages if the content is blank (only IE does this). I'm already fine with IE, so it doesn't help. For the other part (ErrorDocument), I already handle this in PHP. The reason I don't use ErrorDocument in the .htaccess is because not all URLs correspond to a file on the server. To check if a document is found or not, I need to check several things in PHP and on my database. For example if I ask for the page "test.php", it is possible that the file "test.php" doesn't exist on the server, but I still have content (other than an error page) to display. – Heru-Luin May 29 '15 at 09:11
1

If you need to have it display its default 404 page, before any output, do this:

header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found");

See here: http://www.php.net/manual/en/function.header.php

So, for your code, you could modify it to:

$page = 'examplePage.php';
$page404 = '404.php';

if (file_exists($page))
{
    require($page);
}
else if (file_exists($page404))
{
    require($page404);
}
else
{
    header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found");
}

?>

Note the following warning that header stuff has to be done before any other output:

Remember that header() must be called before any actual output is sent, either by normal HTML tags, blank lines in a file, or from PHP. It is a very common error to read code with include, or require, functions, or another file access function, and have spaces or empty lines that are output before header() is called. The same problem exists when using a single PHP/HTML file.

Jonathan M
  • 16,131
  • 8
  • 49
  • 88
1

I asked similar question before a while ago Access apache errordocument directive from PHP

Upshot was either redirect the user to a generic 404 page (so the address changes) Header("Location: $uri_404"); or curl your own 404 page and echo it, like so:

Header('Status: 404 Not Found');

$uri_404 = 'http://'
    . $_SERVER['HTTP_HOST']
    . ($_SERVER['HTTP_PORT'] ? (':' . $_SERVER['HTTP_PORT']) : '')
    . '/was-nowhere-to-be-seen';
$curl_req = curl_init($uri);
curl_setopt($curl_req, CURLOPT_MUTE, true);
$body = curl_exec($curl_req);
print $body;
curl_close($curl_req);

Code credit to @RoUS

Community
  • 1
  • 1
aland
  • 1,562
  • 2
  • 22
  • 39
  • Sorry on further reading you are asking for the default 'browser' 404 page. I don't think such a thing exists (except in IE). – aland Jun 04 '14 at 20:35
0

Maybe you could try:

header('HTTP/1.0 404 Not Found');
  • Better to use `header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found");` since you don't know what protocol was used – Jonathan M Jun 04 '14 at 19:30