Hosting PHP on IIS7

Running PHP sites on Internet Information Services (IIS) is easy! And with a few extra steps, you can achieve a versatile and extensible setup to avoid management headaches down the line. Follow this guide to add PHP functionality to your IIS server and avoid common mistakes.

Install the PHP Binaries

Head over to http://windows.php.net/download/ and download the Zip of your desired PHP version. For IIS, get the "Non Thread Safe" version. If your desired version has an Installer download, ignore it and get the Zip instead. For this guide we'll get the latest version, 5.4.8.

Extract the Zip to a central location with a descriptive folder name, such as C:\Program Files (x86)\PHP\PHP_5_4_8_NTS_x86\. The folder name will distinguish these binaries from other versions you install later. For reasons discussed later, you should minimize spaces in the folder path.

Configure PHP in IIS

Verify that the CGI feature is enabled in IIS. In Administrative Tools > Server Manager enable Roles > Web Server > Application Development > CGI.

To help bridge the gap between development and server configuration, I recommend enabling Feature Delegation. In the IIS server properties, open Feature Delegation and change all of the properties to Read/Write. Or to enable Feature Delegation for a single site, choose "Custom Site Delegation" from the Actions menu. With read/write Feature Delegation, most changes made through the IIS Manager will be saved in the <system.webServer> section of the site's web.config, and changes made to the web.config will be enacted by IIS. This lets you track configuration changes in your source control and deploy them just like code updates.

Before continuing, let's discuss IIS's FastCGI settings. Every FastCGI module used in IIS — the executable and parameters — must be added to a whitelist. If you run a module not in the whitelist, you'll get an error like:

Error Summary

HTTP Error 500.0 - Internal Server Error <handler> scriptProcessor could not be found in <fastCGI> application configuration

Detailed Error Information

Module: FastCgiModule
Notification: ExecuteRequestHandler
Handler: PHP 5.4.8 NTS x86 via FastCGI
Error Code: 0x80070585

This whitelist improves security but complicates Feature Delegation. If you modify a handler in your web.config (like changing the PHP version), you must also update the IIS whitelist before the new handler will work. Every FastCGI module in the whitelist has its own configuration, including a distinct set of environment variables. To allow every site to have its own configuration, we'll create a separate entry for each one. This is more tedious than having one entry per PHP version, but is necessary to keep independent settings.

In the properties of the IIS site/application/folder/virtual directory for which you want to enable PHP scripts, open Handler Mappings. In the Actions menu, choose "Add Module Mapping". Enter the following settings:

  • Request path: *.php
  • Module: FastCgiModule
  • Executable: (Path to php-cgi.exe)|my.app=(Name for application)
  • Name: (Descriptive name of PHP version)

The executable is the most complex part, so let's break it down.

  1. First specify the absolute path to php-cgi.exe that you extracted earlier from the Zip. If the path contains spaces, enclose it in quotes. But these quotes are lost when writing to the web.config and must be constantly replaced. To avoid headaches later, I recommend using the 8.3 filename for any folders with spaces.
  2. Next add a vertical bar (|) to separate the executable from its arguments.
  3. Finally supply a custom parameter that will distinguish this handler in the list of FastCGI modules. The name you assign is for your reference only.
  4. Altogether, the executable looks like C:\PROGRA~2\PHP\PHP_5_4_8_NTS_x86\php-cgi.exe|my.app=Blog.

Open "Request Restrictions" and set the following options:

  1. Invoke handler only if request is mapped to: File or folder
  2. Specify the verbs to be handled: GET,POST
  3. Specify the access required by the handler: Script

Choose Yes when prompted to add the module to the FastCGI whitelist.

Customize your PHP INI

Your site's PHP configuration needs updating to work on IIS. If you're starting a new application, you'll find sample php.ini files in the Zip you downloaded earlier. Copy the sample INI to your application files and rename it to php.ini. Verify the following settings:

  • cgi.fix_pathinfo = 1
  • cgi.force_redirect = 0
  • extension_dir = "ext"
  • fastcgi.impersonate = 0 - This is contrary to the Microsoft guides — I'll explain in the Permissions section.

Configure FastCGI Module

Next we need to configure the newly-created FastCGI module. There are two ways to change these settings in the IIS Manager, both in the server properties. The first method is FastCGI Settings, but this doesn't let you edit the executable path if you upgrade PHP. So I recommend using the Configuration Editor. Choose a section of system.webServer/fastCgi and edit the collection. Use the my.app argument to find the new FastCGI entry.

Next we need to configure the newly-created FastCGI module. There are two ways to change these settings in the IIS Manager, both in the server properties. The first method is FastCGI Settings, but this doesn't let you edit the executable path if you upgrade PHP. So I recommend using the Configuration Editor. Choose a section of system.webServer/fastCgi and edit the collection. Use the my.app argument to find the new FastCGI entry.

  1. Set instanceMaxRequests to 10000 (Per Microsoft).
  2. Add a PHP_FCGI_MAX_REQUESTS environment variable with a value of 10000 (Also per Microsoft).
  3. Add a PHPRC environment variable with the absolute path of the directory containing php.ini. Ex. C:\inetpub\wwwroot\Blog\public
  4. Any other site-specific variables should be added here, such as the APPLICATION_ENV environment variable used by the Zend Framework.

Installing PEAR

PEAR is a library of PHP extensions. If you're not using it now... don't start! Explore better options like Composer or Pyrus (PEAR2), and skip to the next section. But if you're supporting some legacy code that relies on PEAR, we'll install it now.

Download http://pear.php.net/go-pear.phar to your PHP installation directory, ex. C:\Program Files (x86)\PHP\PHP_5_4_8_NTS_x86\go-pear.phar.

We intentionally haven't added or changed any environment variables on the server, namely the PATH variable. This would tie our server to a single version of PHP and we want the flexibility to run several. Instead we'll use Windows batch scripts: any changes to the environment variable only occur in the scope of the script. Create the following batch script in your PHP installation directory.

@ECHO OFF
SET PHPFramework=%CD%

REM Append our PHP version to the PATH variable.
SET PATH=%PATH%;%PHPFramework%

REM When using PEAR from outside of its home directory, we need to specify PHP_PEAR_PHP_BIN as an absolute path to php.exe.
REM Use the same PHP installation that is specified in the PATH variable.
SET PHP_PEAR_PHP_BIN=%PHPFramework%\php.exe

REM Output the versions that will be used by this script.
REM After each "CALL" command we need to reset ECHO. The other batch files may reenable it.
CALL php -v
@ECHO OFF
ECHO;
CALL pear version
@ECHO OFF
ECHO;

ECHO Some PEAR package installers will verify that the prerequisite components are enabled in the PHP INI file. Because the PHP INI files on this server are per-site, not per-PHP version, these checks will fail. Verify that the prerequisites are enabled in the PHP INI of the site that will use the component, and then force the installation with "pear install -f ..."
ECHO;

REM Launch a shell so the user can issue commands.
CMD /T:17 /Q

Launch this batch script and run php go-pear.phar. When prompted to install PEAR system-wide or locally, enter local and confirm. All of the installation paths should auto-detect correctly, so press Enter to continue. When the installation completes, you can use the pear command to install the libraries you need. In your application's PHP INI, update the include_path to add the absolute path to the PEAR directory, ex. C:\Program Files (x86)\PHP\PHP_5_4_8_NTS_x86\PEAR.

Permissions

Lastly, let's configure the file permissions for your application. Your application may have special requirements, but these settings should get you started.

For some reason, PHP and Microsoft prescribe fastcgi.impersonate. I've asked around (1|2) for the rationale but can't get any answers. This seems to be a recommendation for IIS6, but thanks to improved security in IIS7 I advise disabling impersonation.

Here are the settings that I recommend:

  1. Create a dedicated IIS application pool for your site. In the Advanced Settings, choose an Identity of Built-in account: ApplicationPoolIdentity. This option, introduced in IIS7, will create a new user account named IIS APPPOOL\[Application pool name].
  2. In the IIS Authentication settings for your site, choose an Anonymous user identity of IUSR.
  3. Update the NTFS permissions on your site's web directory to Grant read access and Deny write access to IUSR.
  4. Update the NTFS permissions on your application directory and anything in your include_path to Grant read & list access to IIS APPPOOL\[Application pool name].
  5. Update the NTFS permissions for any path where your application will write (such as upload_tmp_dir, session.save_path, and error_log) to Grant modify access to IIS APPPOOL\[Application pool name].

Conclusion

Congratulations, you've added PHP support to IIS! With this setup, you can host multiple PHP versions on the same server, customize environment variables and PHP settings per site, manage multiple copies of PEAR, and sandbox your sites with separate user accounts. Happy coding!

Drew

Drew

Hi! I'm Drew, the Wimpy Programmer. I'm a software developer and formerly a Windows server administrator. I use this blog to share my mistakes and ideas.

Comments on "Hosting PHP on IIS7"

Avatar for KeithKeith

I know this is an old post, but I've done the same research as you over the past couple of years regarding fastcgi.impersonate with PHP and IIS 7.5

I believe fastcgi.impersonate = 1 is a relic of the past.

With 7.5, and using a unique application pool per site (which is the default anyway), everything just works correctly, and as you would hopefully want with permissions.

The lack of discussion on such a key piece of the installation of a PHP/IIS 7.5+ setup leads me to believe that there are even fewer people running IIS/PHP installations than I had hoped.

Thanks for the wonderful writeup.

Avatar for VicVic

Any changes for IIS 10 / Windows 2016?

Thanks!

Avatar for VicVic

Yes, the lacks of info and discussing makes me also thinks that no 'advanced' uses really uses PHP/IIS....

Avatar for DrewDrew

Hi Vic,

Unfortunately I don't have any more up-to-date information since I no longer develop PHP on Windows.