Darwinweb

Using PHP with Ruby on Rails under Lighttpd

August 20, 2006     

I’m in the process of transitioning an old PHP site to Ruby on Rails. Most of the site will be recreated extremely quickly, but there are a couple pieces of behind-the-scenes administrative code that works great in PHP and has no reason to be ported. I’m not ready to deploy yet, but I want to be able to test everything locally, so that means getting Lighttpd, Rails, and PHP playing together nicely. The process turned out to be not that difficult, here are the steps I took:

Compile Lighttpd

References:

Dan Benjamin’s article is all you’ll need to build Lighttpd along with Ruby, Rails and MySQL. His tutorials are quick, easy, and I like his philosophy of building things yourself in /usr/local instead of using Fink or DarwinPorts.

Once lighttpd is up and running Rails will use it automatically instead of Webrick which means better performance at development time.

Compile PHP

References:

You need to compile a CGI/FastCGI copy of PHP for use with Lighttpd. The built-in PHP is an Apache module and will not work with Lighttpd (as far as I know).

I compiled a fairly vanilla version of PHP. The only tricky part was getting GD compiled in the first place. There are nearly infinite options that can be compiled with PHP, so I’ll leave you to figure out exactly what you need. The important part was compiling the FastCGI compatible binary. In order to do that I simply added the following lines (taken from the Lighttpd-PHP wiki page):

--enable-fastcgi \
--enable-discard-path \
--enable-force-redirect

Configuring Lighttpd

References:

The Lighttpd PHP tutorial gave me all the information I needed, but there was one snag integrating it into the Rails lighttpd.conf file. If you had lighttpd installed when you generated your Rails application structure then there should be a config/lighttpd.conf file. This file already has a fastcgi.server section, so you need to append the PHP config to the end. This is what mine looks like:

fastcgi.server = ( 
  ".fcgi" => ( 
    "localhost" => (
      "min-procs"       => 1, 
      "max-procs"       => 1,
      "socket"          => CWD + "/tmp/sockets/fcgi.socket",
      "bin-path"        => CWD + "/public/dispatch.fcgi",
      "bin-environment" => ( "RAILS_ENV" => "development" ))), 
  ".php" => (
    "localhost" => (
      "bin-path" => "/usr/local/bin/php",
      "socket" => "/tmp/php.socket",
      "broken-scriptfilename" => "enable")))

The main difference here is that the tutorial omits the localhost scope from the .php declaration. I’m not sure why its necessary, but my PHP files weren’t being parsed without it.

The broken-scriptfilename option is specifically required to for PHP_SELF and PATH_INFO to be available to PHP scripts (according to the FastCGI module docs). The other half was in the php.ini file.

PHP Configuration

By default, Mac OS X looks for a php.ini (configuration) file at /private/etc/php.ini. Mine looks something like this:

[PHP]
include_path=".:/Users/me/Sites/lib:/usr/local/lib/php"
default_charset="utf8"
error_reporting=E_ALL&~E_NOTICE

post_max_size = "64M"
upload_max_filesize = "64M"

#Fix PHP_SELF and PATH_INFO
cgi.fix_pathinfo = 1

The last bit combines with the lighttpd config to make PHP_SELF and PATH_INFO work. The rest is just stuff that I find convenient.

Once all these steps are complete you should be able to fire up script/server and run any PHP files in your public directory. If you try this and run into any snags, please drop me a note and I’ll post an addendum.

Mark says…
August 26, 2006 at 12:14AM

Do you know if it’s possible to use .php files OUTSIDE of the public directory? I need to use a php upload handler script, and ideally, I’d route to it via dispatch.fcgi. Unfortunately, rails keeps looking for a .rhtml file. Is there a rails config that will allow it to ‘see’ php files in app/views/controller_name/ ? Any thoughts? Thanks

Gabe da Silveira says…
August 27, 2006 at 5:05AM

Rails would have to be capable of invoking PHP as a CGI with the environment intact. I wouldn’t even know where to begin to tackle this, but ultimately I don’t think it makes sense. A view is invoked by a controller, so you would have a Ruby controller calling a PHP view. Where would the instance variables go? What would the PHP environment look like? It would just cause confusion.

The best solution to your problem is to put your PHP files in public and just use redirects as necessary to move between Rails and PHP. Dispatch.fcgi is a ruby script, once you are there the web server is done setting up CGI environments for the request. I’m not sure if there’s a way to setup the CGI environment and propogate it down to a PHP script, but it would be some serious Rails hacking, and I’m not sure what the benefit would be.