Apache 2.4.10 on Windows. I have a stable Zend Framework 1 PHP application. I just decided to add an
ErrorDocument directive to
.htaccess. I'm completely baffled by the three different behaviors I get with 404's, depending on how they're triggered.
My .htaccess file contains:
ErrorDocument 404 "Page not found" RedirectMatch 404 /uploads/(.*/)?private/
If I simply type a url for a non-existent page in the address bar, I get the error page produced by Zend Framework's
If I enter
/uploads/private/foo (matching the
RedirectMatch), then I get the
ErrorDocument output, as expected.
But if in my PHP code I do
then I get the browser's standard error page. This is the one I totally fail to understand. If I use the Network tab in Chrome Developer tools, I can see that all three requests give a 404 status. I guess I can imagine that the Zend Framework's error handling setup would trap the non-existent url, and do its thing, bypassing the
ErrorDocument processing. But I don't understand how an immediate
exit from PHP code with a status of 404 would get past the
What PHP code could I write to trigger the
Based on the answer from Tim Fountain, I should provide more context: As noted above, my ZF
ErrorController page is set up to look the way I want - I see that page when I enter a URL for a non-existent page. In this particular situation, I'm actually running code from a WordPress
mu-plugin (WP is installed below the ZF
public directory). The
.htaccess file naturally does not direct requests for existing files below
public to ZF. Requests for anything below
public/wp instead go to
mu-plugin bootstraps ZF (but does not call the bootstrap's
run() method) and then examines the request. If it's not permitted (according to ZF's Auth session variables), I want to give a 404 (not 403). Previously, I did this by actually redirecting to a non-existent URL, and that showed the
ErrorController page just fine - but it also left the address bar displaying the non-existent URL. I decided to add the
ErrorDocument directive so that the address bar would still show the URL typed by the user. In my actual code, I did not have a simple string on the directive, but rather this URL:
/default/error/error?error_handler[type]=404. I changed it to a simple string just to make sure there wasn't something about the URL causing a problem. Note that when I enter a URL for something within a
private directory triggering the
RedirectMatch, I do see the ZF
ErrorController page, so I know that the URL in itself is not a problem. I just wanted to reduce the complexity for this posting.
Tim's answer says that my problem code is sending an empty 404 page directly to the browser, and the browser is changing it to explanatory text. That's clearly what's happening!
Does this mean my problem is that I need to produce some non-zero-length page content and use
header() to set the status, because
http_response_code() sends empty content directly to the browser? But what's unclear in his answer is why the
ErrorDocument directive would be bypassed.
The request URL causing this behavior is
.../public. This is not rewritten by
.htaccess to go to ZF, but goes directly to
public/wp/index.php. In which case I would have thought that the
ErrorDocument would be triggered...
Or wait, maybe Tim's point isn't really about ZF Error handling, but that from Apache's point of view, the incoming request was satisfied (by going to
public/wp/index.php and running PHP), so it's up to the PHP code to handle it, I can't get back to Apache's
ErrorDocument after that! I guess I had a really fundamental misunderstanding of how ErrorDocument works. I need to figure out some way to invoke the
ErrorController code directly to display the page I want with a 404 status! Duh!
I guess I'll accept Tim's answer, though if he wants to clarify/generalize his point about when
ErrorDocument processing comes into play, that would be nice :-)
Just to wrap this up. I accepted Tim's answer because it revealed my fundamental misunderstanding of how the Apache
ErrorDocument directive works. But it didn't directly show me how to solve the problem I was experiencing, with discovering that I wanted to return a 404 status using my Zend Framework custom status page, but I was running in a WordPress query having bootstrapped ZF without having started the MVC application running under the bootstrap. I had no experience mucking around with ZFs front controller, but after digging into the documents a bit, I came up with this solution, which has the exact same effect as the full
ErrorDocument directive I had wanted to trip.
$error_url = $this->serverUrl() . '/default/error/error?error_handler[type]=404'; $request = new Zend_Controller_Request_Http($error_url); $front = Zend_Controller_Front::getInstance(); $front->returnResponse(true); $response = $front->dispatch($request); $response->setRawHeader('HTTP/1.1 404 Not Found'); $response->sendResponse(); exit(0);