When teaching PHP to newcomers, I have found that (honestly to my surprise) one of the biggest barriers you have to cross is setting the stack up to serve PHP files properly, especially when it comes to Zend Framework apps and other rewrite rule based MVC applications. Even with strong development background, the idea of setting up Web Server configuration to get things working seems foreign to many.
Even as an experienced developer with good knowledge of the LAMP stack setup, setting up new vhosts and other configuration for each new project is sometimes a pain in the ass.
There are of course good news – starting from PHP 5.4, the Command Line Interface (CLI) version of PHP comes with a build-in Web server that can be used to serve PHP apps in development. This Web server is very easy to use – you just fire it up in the right place and it works, serving your PHP files. While it is by no means a viable production solution (it is a sequential, no-concurrency server meaning it will only serve one request at a time), it is very convenient for development purposes.
While it “just works” for simple “1-to-1 URL <-> File” apps, it can work almost as easily for rewrite based MVC apps, including Zend Framework 1.x and 2.x apps and probably for other frameworks as well.
As a start, here is how you launch the Built-in Web server (assuming you have PHP 5.4 in your PATH):
$ php -S localhost:8080
The -S flag means “start the built-in server and listen on localhost port 8080″ (which of course can be changed, but usually in development you want it listening to local requests only). You can always hit Ctrl+C to quit the server.
This tells PHP to treat the current directory as the document root, and serve files as they are requested – basically if $_SERVER['REQUEST_URI'] matches a local file it will be served (static file extensions are identified and sent as-is, while other files are parsed as PHP files and are executed). If the request URI does not match a local file, a 404 error will be returned.
This works well for simple no-rewrite apps – but what about more complex MVC apps? That’s easy to – all you have to do is give the Web server a file which will be used as a catch-all “router” script, so in a ZF app for example, you can do the following:
$ php -S localhost:8080 public/index.php
Of course, you could write a complex plugin to intercept such requests and handle them from within ZF, serving static content using, for example, PHP’s readfile() function. But this seems like a huge overhead for something which is only needed in development environments (in production, you will have the proper rewrite rules set up for your production-grade web server of choice, of course).
My solution came from reading a little bit more about the built-in Web server. It turns out that if the router script returns FALSE, the web server will fall back to serving the file directly, as if no router script was specified in the command line. So I wrote this tiny little wrapper PHP script that I now use in my ZF app. You can even include it in the source tree as it is a virtually harmless file to have even in a production environment:
Save this file in your project as public/builtin-ws-wrapper.php and then run the built-in Web server like so:
$ php -S localhost:8080 public/builtin-ws-wrapper.php
In a way very similar to how the recommended ZF rewrite rules work, the script checks if the file being requested is a real file (and is under the document root) and if so returns FALSE – this tells the built-in Web server to handle it from here. Otherwise, it simply includes the framework’s main entry file, index.php, and lets Zend Framework take care of the rest.