Use multiple PHP versions at the same time!
Soup-up your dev environment with Fast CGI process Manager: PHP-FPM! Say you have already set yourself up with a web development environment following Andy Miller’s macOs dev setup guides part one and part two. However one can grow tired of pulling that daily PHP version switch. The question is: Is there a way to run multiple instances of PHP side by side? Yes! There is a way. Let’s find out how:
Standard
Firstly, a quick recap on how things are currently wired up and how apache is capable of rendering a php file using x-httpd-php, and mod_php.
- The apache_core enables apache to map the <FilesMatch "\.php$"> to be handled by the SetHandler application/x-httpd-php. Notice that this application is under apache and is not stand alone.
- Apache then knows what module to load as a single php apache module as defined in /usr/local/etc/httpd/httpd.conf. For example a php5 module definition is something like:
LoadModule php5_module/usr/local/opt/php@5.6/lib/httpd/modules/libphp5.so
- Moreover, when dealing with a PHP file, apache will use CGI by launching a process -> initializing the environment -> digesting the request -> returning the result. In a nutshell FCGI is the protocol that web servers (like apache) use to delegate work to other processes
Souped-up
We are going to no longer use the mod_php and instead replace it with stand-alone php-fpm processes. In other words php-fpm is a php daemon that's configured to listen and respond to the FCGI protocol This means that we need to start/stop php independently of apache. The proxy_fcgi_module is used so that the SetHandler can connect to the php-fpm socket. I m going to go through this step by step for adding the php version 5.6 later you can follow the same steps to set up other php versions.
Step 1 - proxy_mod
Add the proxy modules: In your /usr/local/etc/httpd/httpd.conf find the commented lines below and uncomment:
LoadModule proxy_module lib/httpd/modules/mod_proxy.so
LoadModule proxy_fcgi_module lib/httpd/modules/mod_proxy_fcgi.so
Step 2 : Configure PHP-FPM
Copy the listen path: In your /usr/local/etc/php/5.6/php-fpm.conf find the listen path and copy it someplace safe. We have to point our vhost to this listen path in the next step
listen = /usr/local/var/run/php56-fpm.sock
Set up your log paths: In the same file /usr/local/etc/php/5.6/php-fpm.conf look for both Error_log & Access_log. Uncomment and set:
error_log = /Users/YOURNAME/sites/log/5.6/php-fpm.log
access.log = /Users/YOURNAME/sites/log/5.6/$pool.access.log
Set your User/Group: Again In the same file /usr/local/etc/php/5.6/php-fpm.conf look for user and group. Change them from _www to whatever user and group you have set your apache to:
user = YOUR_APACHE_USER
group = YOUR_APACHE_GROUP
Step 3: Re-configure your Vhost
Add a new ServerAlias: In /usr/local/etc/httpd/extra/httpd-vhosts.conf add a server alias that is version specific. In this case php56 seems reasonably simple and clear. (note that this depends on the dnsmsq wildcard in this example my host is *.test)
ServerAlias *.php56.test
Redefine your SetHandler: As mentioned we will use the proxy handling. Change the application/x-httpd-php to the following: ( with respect to VirtualDocumentRoot beings set to /Users/YOURNAME/sites/%1/public_html ). This has to match the listen path you gathered in step 2. Note that I d like to pass the socket to a designated port on the fcgi side ie: 8056 for 5.6 version.
SetHandler "proxy:unix:/usr/local/var/run/php56-fpm.sock|fcgi://localhost:8056"
Add Directory specifications:
<Directory "/Users/YOURNAME/sites/*/public_html">
DirectoryIndex index.php index.html
Options Indexes MultiViews FollowSymLinks
Require all granted
AllowOverride All
</Directory>
Step 4 : Run php-fpm
Fire up your php-fpm: Running the php-fpm with flag -D will force the process to run in the background
/usr/local/opt/php\@5.6/sbin/php-fpm -D
Test your local. You can verify the php-fpm process on Activity Monitor.
Step 5 : Repeat the steps 2 - 4 for other versions of PHP (7.x). In this case 7.2.
full vhost:
<VirtualHost *:80>
ServerAlias *.php72.test
VirtualDocumentRoot /Users/YOURNAME/sites/%1/public_html
<FilesMatch "\.php$">
SetHandler "proxy:unix:/usr/local/var/run/php72-fpm.sock|fcgi://localhost:8072"
</FilesMatch>
<Directory "/Users/YOURNAME/sites/*/public_html">
DirectoryIndex index.php index.html
Options Indexes MultiViews FollowSymLinks
Require all granted
AllowOverride All
</Directory>
</VirtualHost>
Error handling: change the /usr/local/etc/php/7.2/php-fpm.conf
error_log = /Users/YOURNAME/sites/log/7.2/php-fpm.log
access.log = /Users/YOURNAME/sites/log/7.2/$pool.access.log
Fire up your php-fpm:
/usr/local/opt/php\@5.67.2/sbin/php-fpm -D
And now Restart apache and test away.
Last thing to do is to add the start scripts for your php-fpm to your startup login items.
A quick note: There are other ways you could route your php version. One way that was not mentioned above is to place the web projects in different folder bins and instead of setting your ServerAlias rather configure the Directory.
Conclusion
Move your dev environment from mod_php to php-fpm and not only you easily can switch between projects without the hassle for reconfiguring your apache but also enjoy the high performance.
As a reminder, this post focuses on local development environment and assumes that security and heavy request load are both not a concern. Although you can find the perfect balance for your production servers with the right tweaks as well as a security in mind; I d leave that discussion out for another post. Just incase if memory is a concern you can always tune your memory usage so it won't deprive other processes. Happy deving!