marcus welz

Bootstrapping Zend Framework via ErrorDocument 404

Posted on May 4, 2010

Traditionally Zend Framework applications are bootstrapped using mod_rewrite as recommended in the manual and various tutorials. For non-Apache servers such nginx, similar methods are provided. But it's also possible to use Apache's ErrorDocument configuration to kick off a Zend Framework based application. This comes in handy if the web application requires many Apache aliases and other legacy configurations that make it tedious or performance inefficient to use mod_rewrite. In such a case Apache is configured to just "serve" per its configuration and anything that results in a 404 because a file wasn't found will be redirected to the Zend Framework bootstrap file.

In order to get that working all you need in your httpd.conf or .htaccess is:

ErrorDocument 404 /index.php

Now, when you try to hit a URL such as 'http://example.com/hello/world', the file is not found, and Apache's error handler will kick in, and call index.php, which should be the ZF bootstrap file. And as long as you have a HelloController with worldAction() method, it should be invoked as you'd expect. There are, however, a number of pitfalls that need to be taken into consideration otherwise you'll soon run into strange issues.

The Modified Apache Context

Right off the bat, the first problem is that the query string is no longer accessible the regular way. $_GET is empty. So if you call http://example.com/hello/world?foo=bar and you expect to be able to grab that with $this->_getParam('foo') you'll be disappointed, because it's not there. $_GET is blank, and therefore, the Zend_Controller_Request_Abstract class logic to populate the parameters and query string interaction is broken. This is corrected by plugging Zend_Controller_Request_Apache404 into the Front Controller which is supposed to provide the compatibility with Apache 404s.

Somewhere in your bootstrap mechanism you'll want to have:

Zend_Controller_Front::getInstance()->setRequest(new Zend_Controller_Request_Apache404());

This will populate $_GET with data from the REQUEST_QUERY_STRING server environment variable, which Apache sets up. Well, it should anyway. Unfortunately as of version 1.10.4 the Zend_Controller_Request_Apache404 class has a bug in it, and it tries to access REQUEST_QUERYSTRING instead. This has been reported as a bug. As a workaround, you can either modify the class, copy and paste it into a new class, or copy $_SERVER['REQUEST_QUERY_STRING'] into $_SERVER['REQUEST_QUERYSTRING'].

GET requests aren't the only issue. POST variables are also not accessible (with Apache 2.0+). And unfortunately Apache provides no alternate environment variable that contains the POST context. Makes sense, since POSTs may be multi-part bodies and can be a bit more complex. In this case, mod_actions saves the day by providing a way of calling a particularly script depending on the type of HTTP action. In this case, we'll route all POST actions to index.php.

Script POST /index.php

The pitfall here is that you can no longer submit a POST to anything other than the Zend Framework bootstrap file. So if you were planning on running legacy PHP side by side with your ZF application, you'll have to resort to additional Apache configuration in order to make that fly.

Not as immediately apparent is the issue of having all your pages served with status code 404. Remember, the app is bootstrapped using Apache's 404 error handler. The Zend Framework currently doesn't set any headers by default as it assumes the default response code to be 200. So because PHP doesn't set anything, Apache will use its own 404 status code with your regular application body as content, so it'll probably still show up in most browsers. However, automated tools and search engines will freak out and probably not index your site at all. This has also been reported as a bug.

Considering the various issues that I've encountered it's almost safe to assume that nobody else has really tried bootstrapping a Zend Framework web application using the Apache404 handler. Some of these problems would have probably surfaced and been remedied by now.

Print This Post Print This Post