Part 4 – Installing PHP
October 30, 2024
!Series: Local Environment Apache PHP
In this section, we will be adding PHP to our demo websites—a different version for each site.
Downloading PHP
Since we’re going to have two different versions of PHP, it makes sense to have a new folder just for our PHP versions. I’ll create a new folder in the Development folder called PHP. All of our PHP versions will live inside that directory.
Now we need the files to run PHP. I am going to be downloading a version of PHP 8 and a version of PHP 7, but you can use any two different versions. The current version will be available on the main downloads page of the PHP site. We want to get files from the Windows downloads.
You will have the option of downloading the thread safe or non-thread safe version. I don’t fully understand the details behind this at this point. As far as I can tell, you need to use thread safe version for running PHP in specific contexts. For our purposes, the non-thread safe version works fine. Download the ZIP file for the version of Windows you have (either x64 or x86).
PHP 7 is out of support, so we will need to go to the archives page to download that. At the time of writing, that link is at the bottom of the left sidebar. (I assume it’s buried because using old versions of PHP poses a major security risk, and you probably shouldn’t do it for real websites.)
The archives page is pretty old-school, but we can scroll down to the last listed version of PHP 7, which was PHP 7.4.9. NTS stands for “not thread safe”, so I downloaded the file named php-7.4.9-nts-Win32-vc15-x64.zip
.
Once you’ve downloaded the files, extract them. I’m going to shorten the names a little bit to just include the version. Now, let’s move them into our PHP folder, which for me is C:\Development\PHP
.
PHP Configuration
PHP comes with two different configuration files, one with the recommended settings for a development environment (called php.ini-development) and one with the recommended settings for production (called php.ini-production). We won’t change any of these settings at this point, but we do need to use one of the two files to be our configuration file. Because this is for a local development environment, we will use the development settings.
In each PHP folder, copy and paste the file php.ini-development, and then rename it to php.ini. PHP will automatically load settings from the file with that name when it starts.
Installing the FastCGI Module
When we first looked at the Apache main configuration file in Part 3, we mentioned that Apache uses modules to handle more complicated functionality. In order to run multiple versions of PHP, we will need to add an additional module. This module is called mod_fcgid.
Very generally, a Common Gateway Interface or CGI lets web servers like Apache connect with other programs. In our case, it will let Apache work with PHP. FastCGI is meant to be a faster way to handle that. The mod_fcgid module implements that for an Apache server.
This module isn’t included in the Apache binary by default, so we’ll need to download it. We want Windows files, so we’ll go back to the Apache Lounge download page. Scroll down to find the file for mod_fcgid, which for me is mod_fcgid-2.3.10-win64-VS17.zip
(the version might be different for you). Download it and extract it.
Before we go further, let’s look at the ReadMe file that came with the download. The ReadMe file includes instructions on how to install and include this module. It also includes an example configuration, which we will reference in a minute. For now, let’s copy mod_fcgid.so into our Apache modules folder, which for me is C:\Development\Apache24\modules
.
Next, we need to load the module from our main Apache configuration file. Look for the section with the block of the LoadModule
directives. Add this directive (which you can find in the ReadMe file for mod_fcgid):
LoadModule fcgid_module modules/mod_fcgid.so
Restart your Apache server and make sure that it still launches without errors. If it did, you’re ready to proceed.
Getting Ready for PHP
There’s a bit more setup we need to do before we can run PHP.
First of all, let’s define the folder where we’ve stored our PHP versions, like we did with the folder where we stored Apache and our other web files. I’ll define a new variable called PHP root and save the path to the PHP folder into it. Add this to httpd.conf:
Define PHPROOT "c:/Development/PHP"
Next, we need to tell Apache to recognize index.php as a valid index file. Look for DirectoryIndex
in the httpd.conf file. It should look like this by default:
<IfModule dir_module>
DirectoryIndex index.html
</IfModule>
This directive says that if a module labeled dir_module
is available, then it will look for a file called index.html and use it as the index page.
We need Apache to recognize index.php as an index file as well, and we need it to take priority over index.html. (This means that if we have index.php and index.html in the same folder, index.php should be displayed.) Update your directive like this:
<IfModule dir_module>
DirectoryIndex index.php index.html
</IfModule>
Let’s test if this worked. Let’s create another file in the test-1
folder, called index.php:
We aren’t running PHP yet, so let’s just add some simple text to our index.php file:
Hello from index.php
Restart Apache and refresh http://test-1.local/. (You may need to do a hard refresh.) You should see whatever text you added to index.php, which shows that even with both index.html and index.php available, Apache is using index.php as the index file.
Finally, let’s add some real PHP to our test-1
and test-2
folders. Add an index.php file to each folder with following code:
<?php
phpinfo();
?>
This function will display which version of PHP is running, so this will let us tell whether we’re actually running different versions of PHP on each site. You can also delete the index.html file from each folder.
With that done, we just need to run PHP to display our code.
Running PHP
Let’s go back to the ReadMe file for mod_fcgid. The exact details of every setting aren’t important right now, but we can get the general gist of this and we can see that most of these settings can be true for anything that is using the FastCGI module.
In the main configuration file, we’re going to set any settings that can apply to any site, regardless of what version of PHP it’s going to run. We only want these settings if the FastCGI module is available, so we’ll nest them inside an IfModule
directive. Add this to the end of httpd.conf:
# FastCGI setup
<IfModule fcgid_module>
FcgidInitialEnv SystemRoot "C:/Windows"
FcgidInitialEnv SystemDrive "C:"
FcgidInitialEnv TEMP "C:/WINDOWS/Temp"
FcgidInitialEnv TMP "C:/WINDOWS/Temp"
FcgidInitialEnv windir "C:/WINDOWS"
FcgidIOTimeout 64
FcgidConnectTimeout 16
FcgidMaxRequestsPerProcess 1000
FcgidMaxProcesses 50
FcgidMaxRequestLen 8131072
FcgidInitialEnv PHP_FCGI_MAX_REQUESTS 1000
</IfModule>
If you compare this to the ReadMe file, this is most of the configuration settings, except for the following:
FcgidInitialEnv PATH
: Indicates the path to the PHP directoryFcgidInitialEnv PHPRC
: Indicates where php.ini can be found<Files ~ "\.php$>"
: Runs any nested code only if the files meet certain criteria (more on this later)
We didn’t set these files in httpd.conf because they need to be different for each site. For the rest of the settings, open httpd-vhosts.conf. Update your code to this:
<VirtualHost *:80>
ServerName localhost
</VirtualHost>
<VirtualHost *:80>
ServerName test-1.local
DocumentRoot "${DOCROOT}/test-1"
<Directory "${DOCROOT}/test-1/">
Require all granted
</Directory>
<IfModule fcgid_module>
FcgidInitialEnv PATH "${PHPROOT}/php-8.3.9"
FcgidInitialEnv PHPRC "${PHPROOT}/php-8.3.9"
<Files ~ "\.php$>"
Options ExecCGI
AddHandler fcgid-script .php
FcgidWrapper "${PHPROOT}/php-8.3.9/php-cgi.exe" .php
</Files>
</IfModule>
</VirtualHost>
<VirtualHost *:80>
ServerName test-2.local
DocumentRoot "${DOCROOT}/test-2"
<Directory "${DOCROOT}/test-2/">
Require all granted
</Directory>
<IfModule fcgid_module>
FcgidInitialEnv PATH "${PHPROOT}/php-7.4.9"
FcgidInitialEnv PHPRC "${PHPROOT}/php-7.4.9"
<Files ~ "\.php$>"
Options ExecCGI
AddHandler fcgid-script .php
FcgidWrapper "${PHPROOT}/php-7.4.9/php-cgi.exe" .php
</Files>
</IfModule>
</VirtualHost>
Let’s look at what we’re doing with these changes:
- We only want this code to run if the FastCGI module is present, so we nest the rest of our directives in the
IfModule
directive FcgidInitialEnv PATH
tells Apache where to find each version of PHP (note that test-1 directs to PHP 8.3.9 and test-2 directs to 7.4.9)FcgidInitialEnv PHPRC
tells Apache where each php.ini file is- The
Files
directive tells Apache to only run the following directives if a file ends in .php - The
Options ExecCGI
directive explicitly allows CGI scripts to run (this isn’t in the ReadMe file but helps prevent conflicts if CGI scripts aren’t allowed globally) AddHandler
tells Apache to process any files that end in .php with the FastCGI protocolFcgidWrapper
tells Apache where to find the script that it needs to run on these files
Save your files, restart your server, and visit each page. Remember that you may need to do a hard refresh. You should see the “It works” fallback page when you visit localhost, PHP info that shows you’re running PHP 8 on test-1.local, and PHP info that shows you’re running version 7 on test-2.local.
Conclusion
That’s it for this section. It was a long one, but an important piece of the puzzle. In the next section, we’ll be adding a database to each of our virtual hosts.
Further Reading
- Tutorial about CGI by Adam Stanislav (archived on the Wayback Machine)
- “What does a CGI (Common Gateway Interface) do?” on Reddit / Explain Like I’m Five
- Apache Module mod_fcgid official documentation
Posted In: Tutorials