I'm having the following situation, I'm developing an API. I rewrite all traffic to one PHP script named: route.php, using mod_rewrite like:

1: RewriteEngine On
2: RewriteCond %{REQUEST_FILENAME} -f [OR]
3: RewriteCond %{REQUEST_FILENAME} -d
4: RewriteRule ^.* route.php [L]

Other files should not be accessible, that's why I am using a whitelist for accessing route.php only. Therefor I use this:

order allow,deny
<FilesMatch "route\.php">
    allow from all

I would like to send all 1xx, 2xx (except 200), 4xx, and if possible 5xx HTTP status codes to a PHP script (let's say error.php?code=404 that shows the dynamic error page for that statuscode. In this case I probably have to allow access to error.php also in the FilesMatch part.

I found partly what I want, described in this article, but I can't implement or manage to get it working the way I described above.

My purpose is for the error.php to show a JSON output (dynamically based on the statuscode) like {'statusCode':'404','status':'Not Found'} including all common (security) HTTP headers I use.

1 Answer 1


This question didn't get much attention and I managed to answer the question myself. So hereby my answer. This is possible in the following way. Any improvement is welcome.

Below should be in the .htaccess file:

order allow,deny
deny from all
<FilesMatch "^route\.php$">
    # replace with IP that is allowed to access the Matched files
    allow from

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

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteRule ^route.php/(.*)$ index.php [L]
<IfModule !mod_rewrite.c>
    ErrorDocument 403 /error.php?code=403

The following should be in the error.php file:

if (!function_exists('http_response_code_text'))
    function http_response_code_text($code = 403)
        $text = 'Forbidden';
        switch ($code)
            case 400: $text = 'Bad Request'; break;
            case 401: $text = 'Unauthorized'; break;
            case 403: $text = 'Forbidden'; break;
            case 404: $text = 'Not Found'; break;
            case 500: $text = 'Internal Server Error'; break;
                $text = 'Forbidden';
        return $text;

$code = 403;
    $code = (int) $_GET['code'];

$text = http_response_code_text($code);
echo json_encode(array('httpStatusCode' => $code, 'httpStatusText' => $text));

This doesn't seem to work for all HTTP error codes, like 414 "Request-URI Too Long" and always falls back to 403 Forbidden.

  • There are several error codes that you simply can't trap in "userland" code (such as 414 and most types of 500 - which is just a generic error state). You don't necessarily need to explicitly pass the status code to your script. The $_SERVER['REDIRECT_STATUS'] should also contain this information (which is not set at all for direct requests, but "200" after a successful rewrite). The ErrorDocument directive in the <IfModule !mod_rewrite.c> container would seem to be superfluous?
    – MrWhite
    Jul 13, 2016 at 22:31

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .