PHPFarm – How to run multiple versions of PHP on the same computer

http://thejibe.com/blog/14/02/phpfarm

http://www.fastcgi.com/drupal/node/5?q=node/10

My past blog posts on installing PHP 5.2.x on recent versions of Ubuntu still get a surprising number of hits, so I thought it was time for an update and to discuss PHPFarm (https://github.com/cweiske), which allows multiple versions of PHP to be run concurrently on the same machine. It is what I currently use on my development laptop in order to switch quickly between PHP versions.

PHPFarm was created by Christian Weiske primarily for the PEAR continuous integration machine.  It makes compiling, configuring, and running multiple versions of PHP on the same computer about as easy as possible. Each instance of PHP can have its own compile options, pear/pecl modules, and php.ini. Additionally, you can configure apache (or your favourite web server) to use different instances of PHP on a per-site basis; so if for instance you are migrating a Drupal 5 site forward to Drupal 7, you can run the old site on PHP 5.2 and the new one on PHP 5.4 on the same development machine. Similarly, if you are updating a server between PHP versions this allows you to test the site on the new version on your development system, and correct any issues before they become a problem. Not everyone needs this sort of flexibility, but if you do, PHPFarm is the best option I’ve found.

In the instructions below I will be using examples from a debian based distribution, which includes Ubuntu and Mint. If you use a different distribution the commands will be different–but the steps will be the same.

Set-Up

The first step is to get the tools required for building (compiling) PHP. On a debian based distro this can be done with:

apt-get build-essential

Next you need to get the PHP build dependencies. The actual dependencies that you will need will vary with the compile options you use, but a good starting place is to get all of the build dependencies for the stock PHP that comes with your distribution. This can be done with:

apt-get build-dep php5

Now you are ready to get the scripts that make up PHPFarm. You do this by cloning the git repository. You will want to give some thought to where you want to clone the repository as it will house both the source and compiled binary copies of your PHP instances. Personally I put it in /opt/phpfarm:

git clone https://github.com/cweiske/phpfarm.git /opt/phpfarm

At this point you should have all of the dependencies that you will need for a standard vanilla PHP build, however if you require support for additional libraries you will need to install them now. Using mcrypt as an example, you can check it’s requirements on the PHP site (http://ca3.php.net/manual/en/mcrypt.requirements.php) and ensure that you have libmcrypt installed. In most cases your distribution will have a packaged version of the required library so you won’t need to compile it yourself. To install libmcrypt on debian you would use the command `apt-get install libmcrypt`

Compile Options

Now that you have your build tools, PHP dependencies, and PHPFarm, you are almost ready to compile PHP.  The last task is to sort out the compile options.

For a vanilla PHP you don’t need to specify any compile options, however this will leave you with a PHP that doesn’t have support for many of the things you need for running Drupal (or most other web applications)–such as support for databases, GD, curl, bzip2, etc. Fortunately PHPFarm makes specifying compile options very easy. Looking in the PHPFarm src directory (/opt/phpfarm/src in my example) you will find a file named options.sh. The comments at the top of this file explain how to specify compile options. Basically, you create a text file that contains your compile options and, depending on how you name the file, it will be applied to either all of your PHP builds or to specific PHP versions.

For example: a text file named custom-options.sh will be applied to all of your PHP builds, while one named custom-options-5.sh will only be applied to PHP 5.x.x builds, one named custom-options-5.3.sh will only be applied to PHP 5.3.x, and finally one named custom-options-5.3.22.sh will only be applied to PHP 5.3.22.

The following is the custom-options-5.3.sh file that I use for my standard drupal development environment on 64bit Ubuntu 12.04:

configoptions="\ --with-libdir=lib64 \ --enable-memory-limit \ --with-regex=php \ --enable-sysvsem \ --enable-sysvshm \ --enable-sysvmsg \ --enable-track-vars \ --enable-trans-sid \ --with-bz2 \ --enable-ctype \ --without-gdbm \ --with-iconv \ --enable-filepro \ --enable-shmop \ --with-libxml-dir=/usr \ --with-kerberos=/usr \ --with-openssl \ --enable-dbx \ --with-system-tzdata \ --with-mysql=/usr \ --with-mysqli=/usr/bin/mysql_config \ --enable-pdo \ --with-pdo-mysql=/usr \ --enable-fastcgi \ --enable-force-cgi-redirect \ --with-curl \ --enable-bcmath \ --enable-calendar \ --enable-exif \ --enable-ftp \ --with-gd \ --with-jpeg-dir=/usr \ --with-png-dir \ --with-freetype-dir=/usr \ --with-t1lib \ --with-zlib-dir=/usr \ --with-gettext=/usr \ --enable-mbstring \ --with-mcrypt=/usr \ --with-mhash \ --with-mime-magic \ --enable-soap \ --enable-sockets \ --with-tidy \ --enable-wddx \ --with-xsl=/usr \ --with-zip \ --with-zlib \ --enable-zip \

You will notice that in some cases it is necessary to provide a path with the particular compile option. Unfortunately, I am aware of no hard and fast rule that will let you know when the path is required, though if there is a problem you will get an error message curing the compile process that will tell you which library it can’t find. Rather than the path pointing directly to the library or to the library directory, it should typically point to the directory below the lib directory. For instance with gettext from above, the path given is /usr and the path to the library on ubuntu is /usr/lib/libgettestlib.so.

Compile Time

With any custom compile options set up, you are now ready to compile php:

./compile.sh 5.3.22

This will download php 5.3.22 and build it, using any custom compile options you have set up.

The compile process can take a long time, especially if you have a slower computer. During the compile process there will be a large volume of text that goes by on your screen. You may see the occasional warning message, typically these can be safely ignored. If there is a significant error the process will stop and there will be an error message that should give you some indication of what went wrong. Typically this will have to do with a missing dependency and/or the compile script not being able to find the required library. This can be fixed by making sure the library is installed and then providing the path in the custom options file.

When the compilation is complete you will find the php install in the inst directory within PHPFarm (/opt/phpfarm/inst in my example) and within there the bin directory, which will include symlinks to your compiled php files.

Apache Set-Up

Enable the fastcgi module. On debian based systems this can be done with:

a2enmod fastcgi

Configure a FastCgiServer for your php

Add a file to /etc/apache2/conf.d where you will put your FastCgiServer configuration.  A good name for this file might be php-cgisetup.conf.  The following is an example of the configuration to put in this file:

#php-cgi setup #used for multiple php versions FastCgiServer /var/www/cgi-bin/php-cgi-5.3.22 -idle-timeout 240 FastCgiServer /var/www/cgi-bin/php-cgi-5.4.12 ScriptAlias /cgi-bin-php/ /var/www/cgi-bin/

In the example above you will see that I have a configuration for PHP 5.3.22 and PHP 5.4.12.  You will want to have a line in here for each version of PHP that you create with PHPFarm.  You will also see that I have added an -idle-timeout configuration to php-5.3.22 of 240 seconds, this is not typically necessary, however if you do need to add any options to the FactCgiServer this is where you would do that.

Finally, we need to create the file /var/www/cgi-bin/php-cgi-5.3.22. Here is a sample for that file:

#!/bin/sh PHP_FCGI_CHILDREN=3 export PHP_FCGI_CHILDREN PHP_FCGI_MAX_REQUESTS=5000 export PHP_FCGI_MAX_REQUESTS exec /opt/phpfarm/inst/bin/php-cgi-5.3.22

If you wanted to move the php.ini file to somewhere other than /opt/phpfarm/inst/php-5.3.22/lib/php.ini (using my PHPFarm install location as an example) you could do that in this file by adding lines such as the following:

PHPRC="/etc/php5/cgi/5.3.22/" export PHPRC

This would cause a php.ini file at /etc/php5/cgi/5.3.22/php.ini to be loaded instead.

The next step is to set up an apache VirtualHost stanza to use phpfarm:

<VirtualHost *:80> ServerName yourawesomewebsite.com DocumentRoot /absolute/path/to/your/website/document/root <Directory />   Options FollowSymLinks   AllowOverride All   AddHandler php-cgi .php   Action php-cgi /cgi-bin-php/php-cgi-5.3.22 </Directory> ErrorLog /var/log/apache2/error.log LogLevel warn CustomLog /var/log/apache2/access.log combined </VirtualHost>

The two key lines being the `AddHandler php-cgi .php` and `Action php-cgi /cgi-bin-php/php-cgi-5.3.22`.  These tell apache to use the php-cgi handler for files that end with .php and that the php-cgi handler should use php-cgi-5.3.22.

Now, with all of this in place, you are ready to (re)start apache to load the configuration changes and to use a browser to go to the website you just configured.  Congratulations, you are now using PHPFarm!

Adding Another Version of PHP

If you now wanted to use a different version of PHP you could compile the new version with ./compile.sh 5.4.23 (as an example) and then update /etc/apache2/conf.d/php-cgisetup.conf to add a line for 5.4.23 and create /var/www/cgi-bin/php-cgi-5.4.23 based off of the earlier one.  You can then switch a site between PHP versions just by editing it’s VirtualHost configuration and restarting apache:

<VirtualHost *:80> ServerName yourawesomewebsite.com DocumentRoot /absolute/path/to/your/website/document/root <Directory />   Options FollowSymLinks   AllowOverride All   AddHandler php-cgi .php   # Action php-cgi /cgi-bin-php/php-cgi-5.3.22 # Commented out   Action php-cgi /cgi-bin-php/php-cgi-5.4.23 </Directory> ErrorLog /var/log/apache2/error.log LogLevel warn CustomLog /var/log/apache2/access.log combined </VirtualHost>

Getting Fancy – One site, two versions of PHP

It is even possible to run the same site on two different versions of PHP at the same time by setting up two VirtualHost configurations with the same DocumentRoot, but different ServerName and Action configurations:

<VirtualHost *:80> ServerName yourawesomewebsite53.com DocumentRoot /absolute/path/to/your/website/document/root <Directory />   Options FollowSymLinks   AllowOverride All   AddHandler php-cgi .php   Action php-cgi /cgi-bin-php/php-cgi-5.3.22 </Directory> ErrorLog /var/log/apache2/error.log LogLevel warn CustomLog /var/log/apache2/access.log combined </VirtualHost> <VirtualHost *:80> ServerName yourawesomewebsite54.com DocumentRoot /absolute/path/to/your/website/document/root <Directory />   Options FollowSymLinks   AllowOverride All   AddHandler php-cgi .php   Action php-cgi /cgi-bin-php/php-cgi-5.4.23 </Directory> ErrorLog /var/log/apache2/error.log LogLevel warn CustomLog /var/log/apache2/access.log combined </VirtualHost>

This can be extremely helpful for testing, for instance when you are preparing to move a site to a server with a different version of PHP.