Running multiple php versions on a single Apache install

This is a very strange topic: even though a cursory google search using the words “multiple php versions apache” spits out a considerable amount of informative howtos and blog entries, when I recently mentioned in a mailing list that it is in fact quite easy to have multiple php installs running in parallel using Apache virtual hosts, I immediately received a private request for my configuration.
Well, here it is, along with a few details on how to set up the complete environment.

The desired goal is having “alot” of php installations running in parallel, so that php scripts can be quickly tested against as many versions of php as possible. It is very useful f.e. when

  • you are migrating an existing app from php 4 to version 5
  • you are deploying your applications on a large base of servers where different versions of php are installed, but develop all the different apps on the same workstation
  • you develop a popular open source php library or shrink wrapped application, and want to make sure that it runs smoothly in every possible user setup
  • you want to test an application against different sets of php.ini configurations, to check for possible problems in areas such as output buffering, opcode caches etc…
  • you are into integration testing

There are many different setups that can be used to achieve this result (a big list is available on Gentoo docs, courtesy of Andreas Korthaus).
My preferred setup is: use a single apache instance, with a single php version installed as module, and many versions installed as cgi applications. Advantages:

  • no need to rename any php file to run it with different php versions
  • no need to restart the webserver or run any kind of script to switch php version
  • uses less memory than multiple apache installs

The main disadvantages are:

  • only 1 php version can run as an apache module, the others must limit themselves to cgi
  • a very misbehaved php application can in rare cases hog or crash the webserver, and it will have to be reset before testing with other php versions

The instructions below are geared to a windows environment with Apache 2, but converting them to linux is left as trivial exercise for the sysadmin.

  • Step1: download all the zip versions of php you need, and dump them somewhere on your disk. I usually name the directories “C:/php5” (stores always the latest php version), “C:/php4” (last version in the php 4 branch), “C:/php506” and so on
  • Step 2: install your apache server. Make sure that you know where the httpd.conf file is located
  • Step 3: for every php install, make sure you have a separate, working php.ini file. I prefer to keep the ini file in the same directory where the php exe is located. There are at least two settings that should be different for every php version:
    1. error_log: it is always a good idea to have a separate log file for every php version
    2. extension_dir: to make sure you are loading the php extensions from the correct path, I usually use the absolute path of the extensions dir (such as C:/php5/extensions or C:/php4/ext)
  • Step 4: (windows only): make sure you do not have any version of php4ts.dll or php5ts.dll inside your windows or system32 directories
  • Step 5: (windows only): make sure you do not have any of the dlls that come with php inside your windows or system32 directories. It will help avoiding the problem commonly known as “dll hell”
  • Step 5a: (windows only): if you are going to run any install of php 4 as cgi, copy the dlls that you find inside the “dlls” dir into the main php directory (eg. from C:/php4/dlls/ to C:/php4/). This is needed so that the php.exe executable, run as cgi app, can pick up the correct version of the dll libraries, and not the version from a different php install. If you are going to run php5 as cgi app, there is no problem, since the php.exe file and the required dlls are already in the same directory
  • Step 5b: (windows only): if you are going to run at least one php install as an apache module (php version 5 in this tutorial), you need to make sure that all the dll files it needs can be found at runtime. The difference from step 5a above is that, when running as an apache module, the process running is in fact apache.exe, not php.exe, and as such it will not, by default, search into c:/php for any dll to open, but look instead inside C:/Program Files/Apache2/Apache/bin. This problem will only become apparent when you enable in php.ini an extension that needs an extra dll, such as curl that depends on ssleay.dll. There are a couple of different solutions to this:
    1. Put the dir to your php-as-apache-module install in the PATH environment var. This does not interfere with the other versions of php run as cgi, since the windows mechanism for opening dll files is to look in the exe file dir first, and in the path second. Otoh it might interfere if you run php scripts from a dos prompt
    2. Copy the dll files from the php install (all those that are in the top dir and are whose name does not start by php for version 5, all those found in the ‘dlls’ dir for php4) into the apache/bin directory
  • Step 6: decide if you are going to use name-based or ip based virtual hosting. If you do not know what I am talking about, go read the Apache docs. If you are lazy, and it is fine for you to have the different php versions responding on different ports (beware of firewalls!), just keep on reading
  • Step 7: Stop the apache server, and edit the httpd.conf file. I prefer to keep all the php settings in a separate file, and include it in the main file like this:
    Include conf/phpvhosts.conf

    The content of the file phpvhosts.conf follows. It is set up to have the “main” virtual host listening on the standard apache port (as specified by the Listen directive in httpd.conf) with php 5, and two virtual hosts running two versions of php4 on ports 8447 and 8423. You guessed it, the port number matches the corresponding php version, so it is easy to remember. The comments inside the file itself are quite explicative.

    # Port-based virtual hosting: every php install uses a vhost on a different port
    Listen 8447
    Listen 8423
    
    ### BASE virtualhost
    ### set up the main php version we're using
    <VirtualHost *:80>
        LoadModule php5_module "E:/php5/php5apache2_2.dll"
        PHPIniDir "E:/php5"
        php_value extension_dir "E:/php5/ext/"
        AddType application/x-httpd-php .php
        AddType application/x-httpd-php-source .phps
    </VirtualHost>
    
    <VirtualHost *:8447>
        # it would be handy to use php_value directives, but CGI versions of php will not grok them,
        # so we rely on different php.ini
        SetEnv PHPRC "E:/php4/"
        ScriptAlias /php447/ "E:/php4/"
        Action application/x-httpd-php447 "/php447/php.exe"
        AddType application/x-httpd-php447 .php .inc
        # apache 2.2 denies access to the php cgi executable, unless it is explicitly granted
        <Directory "E:/php4/">
          <Files "php.exe">
            Allow from all
          </Files>
        </Directory>
    </VirtualHost>
    
    <VirtualHost *:8423>
        SetEnv PHPRC "E:/php423/"
        ScriptAlias /php423/ "E:/php423/"
        Action application/x-httpd-php423 "/php423/php.exe"
        AddType application/x-httpd-php423 .php .inc
        <Directory "E:/php423/">
          <Files "php.exe">
            Allow from all
          </Files>
        </Directory>
    </VirtualHost>

    Restart Apache

  • Step 8: there is no step 8! Well… if you wanna check out if everything works, just set up a phpinfo.php file in your webserver root dir and access http://localhost/phpinfo.php, http://localholhost:8423/phpinfo.php and http://localholhost:84447/phpinfo.php to see if everything is fine
  • Some of considerations:

    • There are a lot of other configurations that you normally have to set up in httpd.conf. Of interest to php users is, for example, DirectoryIndex
    • To use port 80 for all php versions and switch to name based virtual hosting, you will have to comment out the two Listen directives and modify the VirtualHost directives in the file above. You will most likely also need to add some aliases to your ip address in C:/winnt/system32/drivers/etc/hosts
    • the above config file has been tested to work with both apache 2.0 and 2.2. It should not be hard to make a version for Apache 1.3 (in fact I suspect this one would just work)
    • Setting up separate Apache 1 and Apache 2 install is pretty trivial on windows (you just have to take care to have the first server installed shut down while you install the second, so that the port 80 is free; you can edit the config file to avoid port conflict later). If your primary goal is testing your app in as many different setups as possible, having 5 php installs on apache 2 and 5 on apache 1 is a good start. Plus, you can have two version of php running as apache modules
    • Arnold Daniels has a blog entry on how to set up multiple php versions using different apache instances It is geared towards linux installs. Jamie Burns has a similar blog entry, aimed at windows
    • Thierry Bothorel uses a slightly different setup
    • Ernie has yet another windows setup
    • Skiffie beat me by publishing a tutorial almost identical to this one more than 6 months ago…
    • … while a french version of this same setup has been published one and half year ago

    In the next installments: how to set up multiple php versions in IIS, and how to set up unit testing to take advantage of the php versions galore.

    Edited 2007/08/06: changed bullet point 5 adding more info about where to put dll files

12 thoughts on “Running multiple php versions on a single Apache install”

  1. Pingback: /home/kOoLiNuS
  2. In step 3 you mentioned that each php version should have it’s own php.ini file in the same directory as it’s php.exe. Sounds good, but how to tell those executables to use them and not to use %windir&%\php.ini?

    My http.conf allows only one PHPIniDir. Defining another one in a VirtualHost gives: Only first PHPINIDir directive honored per configuration tree – subsequent ones ignored.

  3. @Hb: I only use one single PHPIniDir directive. It is used by the phpversion that is run as an Apache module. All the other php versions are running as cgi applications, and as such would ignore PHPIniDir anyway. For those, I use SetEnv PHPRC “path to ini file” instead, as you can see in my httpd.conf example. I have tried with apache 2.0 and 2.2, and I have had no problems so far…

  4. An alternative setup using PHP as CGI. You can run as many versions as you want on one address/port…

    ScriptAlias /php-4/ “c:/php/4.4.9”
    ScriptAlias /php-5/ “c:/php/5.3”

    # default to php 5
    AddType application/x-httpd-php .php
    Action application/x-httpd-php “/php-5/php.exe”

    # app that needs php 4

    Action application/x-httpd-php “/php-4/php.exe”

  5. Hi,

    Thanks for showing this way. I didn’t now one could put settings like that in vhosts.

    I would like to configure so that files with extension .php runs one version of PHP and files with the extension .php53 runs version 5.3.

    Any thought on that?

    Best,
    Jon

  6. Hi,

    I am new to php and for apache. I have doe the setup for multiple versions of php as mentioned above, but when i tried to access the application with another version of php using different port number am getting below error.

    Forbidden
    You don’t have permission to access /php423/php.exe/dcs/index.php on this server.

    Kindly help me out if you know the solution.

  7. I have the probloem that I have 2 versions of PHP, one is 5.6.20, the official, and the other that is 5.6.13.

    The official is at /usr/bin and the other is at /opt/php5-6/bin/php. The problem is that websites are using 5.6.13 instead of 5.6.20. How can I change this?

    Thanks
    Jaime

  8. @Jaime in this day and age, I would run php as php-fpm, and connect it to Apache using mod_proxy_fcgi.
    You can easily set up 2 php-fpm processes, listening on different ports.
    Then you can use apache mod_proxy_fcgi to proxy to the correct fpm ‘daemon’ based on vhost, path or what you prefer

Leave a Reply

Your email address will not be published. Required fields are marked *