Apache's ErrorDocument directive does not redirect
Asked Answered
V

2

14

I have a bunch of ErrorDocument directives in my .htaccess file in order to catch almost all the possible errors Apache can throw at a user, and to redirect said user to my error controller which would then render the error in a more user friendly manner. However, it does not seem work.

For instance, when I enter an invalid URL like mysite.com/""##$##$! I always get Apache's default 403 error message, instead of a redirect to my errors.php file. Below is the directive I'm using. Do I need to do anything else to make it work? (AllowOverride All is set)

   ErrorDocument 403 /errors.php

If this is the wrong way to approach absolute custom error handling, please let me know, I would appreciate a nudge in the right direction.

Thank you!

Edit: Oh, just thought I'd mention this. I wrote my own MVC structure for redirecting the request, and it works well. From within PHP, if a user requests a nonexistant URL, my own 404 error will fire just fine (or whatever other error I have defined). So basically, if I enter mysite.com/!!!! into the URL, it will work and I get a 404. However, whenever I start a request with the double quote character, the default Apache 403 error fires. Odd. Also, a 500 error will fail to redirect to errors.php as well, and will simply return a default Apache 500 screen (for instance, when testing with header("HTTP/1.0 500 Internal Server Error");die();).

Edit 3: I just tried placing ErrorDocument 200 "message" in my .htaccess file and nothing happened, any page I open opens normally. Worst case scenario, this should get stuck in an infinite loop. Best case scenario, it should output "message". It did neither, it simply ignored ErrorDocument. Apache's Access Log notes a normal 200 OK header, and yet it was completely ignored by .htaccess.

Voltmeter answered 23/4, 2011 at 16:12 Comment(11)
You are getting a 403 for an invalid URL? That is odd, you should get a 404. (The ErrorDocument syntax looks okay, though.)Prophets
Maybe it is hitting a 403 while trying to access errors.php? Do you have all permissions properly set?Prophets
Yes, permissions are fine. I even tried putting a string instead of the file, something like "blah", because Errordocument should output the message if it gets anything non-url, right? That does not work either.Voltmeter
The .htaccess file is in the web root? Strange. Are you 100% sure you have no AllowOverride directive somewhere else in the conf file, contradicting the first one? It's happened to me.Prophets
I have AllowOverride All set on the entire htdocs folder, but I'll double check. I also updated the question with some more info. And yes, it is in the web root, .htaccess works well with the URL renaming and redirecting and whatnot. Huh..Voltmeter
Just triple checked. There is no AllowOverride defined anywhere else other than in the httpd.conf, and there it's set to the entire htdocs folder. I'm guessing my URL renaming wouldn't work either if it wasn't set to All properly, so that must work. Any thoughts..?Voltmeter
@Voltmeter hmm, it might be worth investigating why you are getting 403s instead of 404s. Do you have some RewriteRules in place?Prophets
I do, yes. Mind you, I only get 403 if I start the URL with a double quote character. Other times, PHP handles the 404 as defined in my MVC. I will post the rewrite rule in the original question.Voltmeter
@Voltmeter aaah! In that case, this might be Apache's security kicking in to prevent an injection attack. An unencoded " is, after all, invalid in a URL. It could be that this is not circumventable... This is only my speculation though.Prophets
I see, I did not know of this automatic defense measure. Still, should it not redirect me to my ErrorDocument 403 directive whatever the reason for the error? Also, why does simulating an error 500 also give me the default Apache 500 screen and not errors.php (or a custom message I provide)?Voltmeter
Strange. That makes it look more like the ErrorDocument directive isn't working at all - I don't know why!Prophets
M
28

A few different mis-conceptions in the question. The following PHP code:

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

Will never trigger an Apache error page - it's triggering your browser's default error page. Once control has been given over to PHP, it does not go back to Apache for error handling.

ErrorDocument only works for error codes, not success codes. It's in the docs

Syntax: ErrorDocument error-code document

http://httpd.apache.org/docs/current/mod/core.html#errordocument

If you were mistaking one kind of browser error page for a server error, then that might be the cause of your main problem too. Unless your custom error handler outputs a certain amount of data, some browsers will always show their own error pages. Make sure your output is at least a few kilobytes in size.

The cause of your problem is most likely just Apache's built-in behavior combined with your choice of test URLs. From the ErrorDocument docs:

Although most error messages can be overriden, there are certain circumstances where the internal messages are used regardless of the setting of ErrorDocument. In particular, if a malformed request is detected, normal request processing will be immediately halted and the internal error message returned. This is necessary to guard against security problems caused by bad requests.


Edit: How to simulate a 500 error in Apache. My first thought was syntax errors in .htaccess, but this wont trigger custom error handlers. The easiest way I found was to enable CGI in .htaccess by adding these lines:

ErrorDocument 500 /500.php
Options +ExecCGI
AddHandler cgi-script .pl

And then adding a perl script that crashes:

#!/usr/bin/perl
safasfdsfdd_(*EYFIUOBAF(_*AS^FD_(*AWHD{

You will need to make sure the perl script is executable by apache's user. This shows my custom 500 handler.

However, you're very unlikely to ever trigger an Apache 500 when using PHP, so this probably isn't a useful test.

Mastiff answered 30/4, 2011 at 2:34 Comment(6)
I see, now this is very useful! So what would be the best way to simulate a real apache 500 error?Voltmeter
Edited the answer to include a section on simulating a 500. Please accept the answer!Mastiff
Good stuff, thanks. I'll think about some other scenarios. Until then, I think it's best if I just handle all the errors PHP can catch in PHP itself. The reason for simulating it was just to see if my error controller gets called properly when an error occurs, so I can put that area of my server configuration behind me and focus on developing further. Thanks for all the insight!Voltmeter
So I guess there is no clean way to get Apache to catch error status generated by PHP, e.g. similar to fastcgi_intercept_errors on in Nginx :(Precessional
Thanks a lot for the answer! The broken perl script did the trick.Dehumidifier
Some days you just have to love SO even more. Was going in circles about this - came up to this one. Excellent!Nonconformity
B
-10

I just use .htaccess for all custom error pages

ErrorDocument 401 /error/PHP/server-error.php?error=401

ErrorDocument 403 /error/PHP/server-error.php?error=403

ErrorDocument 404 /error/PHP/server-error.php?error=404

ErrorDocument 500 /error/PHP/server-error.php?error=500

ErrorDocument 503 /error/PHP/server-error.php?error=503
Burgeon answered 6/7, 2011 at 1:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.