Configuring Apache to use PHP in CGI mode

The PHP documentation helpfully describes how to install Apache 2 and PHP 5 using the shared module mode, but I needed to run PHP in CGI mode so that it matched the setup on someone else's system. The PHP manual wasn't a lot of use, and I hunted around for hours looking for tips on how to configure Apache to use PHP for parsing PHP files using the PHP CGI executable. I finally got it working, so I'm including the recipe here to help anyone else who needs a guide.

This document will describe the whole process for someone using Linux, including configuring and compiling from source code. If you just need help with the Apache httpd.conf configuration, jump to the configuring Apache section near the end. I was using Apache 2.2.9 and PHP 5.2.5, on Ubuntu Linux 8.04. The general process should be very similar for people using other software versions and different distributions of Linux, but bear in mind your default installation file paths may vary from those mentioned below.

Install Apache and PHP

Download the source code

First of all, download the source code for the version of Apache you want from, and download the source code for the version of PHP you want from and save them into your home directory.

Decompress and unpack the tarballs like so (replacing 2.X.YY and 5.V.WW with the version numbers you have):

gunzip httpd-2.X.YY.tar.gz
tar -xvf httpd-2.X.YY.tar
gunzip php-5.V.WW.tar.gz
tar -xvf php-5.V.WW.tar

Compile and install Apache

Now change into the newly-created Apache directory and configure the build you want. Note that mod_rewrite is not built by default, so you might want to enable that. Once you've run the configure command with all the options you need, run make and then make install (which needs admininstrator rights).

cd httpd-2.X.YY
./configure --enable-rewrite
sudo make install

Now it's a good idea to configure the basic settings in httpd.conf (which is located at /usr/local/apache2/conf/httpd.conf in Ubuntu 8.04) and test that Apache is installed properly.

Compile and install PHP CGI

Change into the recently-created PHP directory and configure the build you want. Note that almost every module and feature you add to your configure command will have to have been installed on your system previously.

For instance, if you choose to add --with-mcrypt to your configure command, you need to make sure that the mcrypt files are installed on your system before you run the configure command. This is easy in Ubuntu. Just load Synaptic Package Manager and search for mcrypt. Then you need to install the mcrypt packages that end in "-dev", as these are the development files that allow mcrypt to be compiled into other programs such as PHP. So, for mcrypt, installing the libmcrypt-dev package should do the job. If you need to be really precise with software versions, you may need to download the development files for each piece of software and configure, compile and install them manually.

If you're sure that a dependency has been installed, but configure is failing when it gets to that dependency, you may need to tell the configure option which directory to look in for that software. Most of the time, it seems to be enough to distinguish between /usr and /usr/local, but I have to admit that I haven't been able to find clear guidance on exactly what the directory path given to a configure option needs to be.

Because you often don't realise that your system is missing a vital package until after you've run the configure command, it might be a good idea to create a script file that contains your custom configure command, so you can run it easily without too much typing.

Once you've crafted your configure command, and all of the necessary dependencies are installed, run your configure command and then compile and install PHP. The following worked for me once I had all the necessary dependencies installed to their default locations (the ↪ symbol means that the line should be continued as part of the previous line):

cd ~/php-5.V.WW/
./configure --disable-pdo --enable-bcmath --enable-calendar--with-curl=/usr/ --with-freetype-dir=/usr/ --with-gd--with-jpeg-dir=/usr/ --with-libxml-dir=/usr/--with-mcrypt=/usr/local/ --with-mysql=/usr/local/--with-mysqli=/usr/local/bin/mysql_config --with-png-dir=/usr/--with-ttf --with-xpm-dir=/usr/ --with-zlib--with-zlib-dir=/usr
make test
sudo make install

Even though configure should check for dependencies, it's possible that a missing dependency won't be noticed until you run the make command. If make fails, you might need to run make clean to clear up the mess before starting over again.

Running make test is optional, but it provides useful information to the developers of PHP, so it's worth doing. Note that you will see a number of test failures, but it should be a very small percentage of the number of tests.

PHP should now be built and installed on your system. Time to tell Apache what to do with it.

Configuration files

Configuring Apache to use the PHP CGI

To get Apache to use the PHP CGI for files with the .php extension, you need to tell Apache where to find the php-cgi executable, which is installed to /usr/local/bin/php-cgi by default. You also need to give Apache permission to execute files in that location. Add the following to an appropriate place in your httpd.conf file (default location /usr/local/apache2/conf/httpd.conf):

# CUSTOM: Add PHP 5 parsing (via CGI) handler and action
ScriptAlias /local-bin /usr/local/bin
AddHandler application/x-httpd-php5 php
Action application/x-httpd-php5 /local-bin/php-cgi
<Directory "/usr/local/bin">
    Order allow,deny
    Allow from all

The ScriptAlias directive tells Apache that the /usr/local/bin directory can be used to execute scripts. The AddHandler directive tells Apache that whenever it encounters a file with a .php extension, it should mark it as having a MIME type of application/x-httpd-php5. The Action directive tells Apache that whenever it encounters a file of type application/x-httpd-php5 it should pass it to the script /usr/local/bin/php-cgi and capture the output. And the Directory block tells Apache that it should give all requests permission to access the /usr/local/bin folder where php-cgi is.

It is important to note that the /usr/local/bin directory contains far more than just php-cgi, so it's probably much safer to move php-cgi to its own directory and then configure Apache to use that separate directory instead.

Check that the options in php.ini (default location is /usr/local/bin/php.ini) are suitable. Then start the Apache server with the following command:

/usr/local/apache2/bin/apachectl start

and test to make sure that files ending with .php are parsed using PHP and not simply being served with their PHP source code on show.

Selective PHP parsing using .htaccess

If you need to make it possible to enable PHP parsing using .htaccess files, then open your httpd.conf file and find the <Directory> block for your document root. Check to see if there's already an AllowOverride directive for it. If there is, make sure that FileInfo is a permitted option. If there's not, then add AllowOverride FileInfo, plus any other options you want to permit .htaccess files to control. The documentation on the Apache website does a very good job of describing the options and directives available. Rememeber that you'll need to restart Apache to see the effect of changes to httpd.conf.

Once inside an .htaccess file, you can enable PHP parsing with the SetHandler directive. For instance, if you only wanted to add PHP parsing to one file called list-threads.html you could add this to the .htaccess file for the directory that contains list-threads.html:

<Files "list-threads.html">
    SetHandler application/x-httpd-php5

The SetHandler directive above tells Apache to treat all the files described by the <Files> block as if they have a MIME type of application/x-httpd-php5 which, combined with the Action directive we added to httpd.conf, will cause Apache to hand the file to php-cgi for processing with PHP.