PHP and IIS – A Deeper Dive
This article takes a deeper dive into the way PHP works with Windows and IIS7. There are some great articles on IIS.Net in the Learn section that cover getting PHP set up and working. This article is going to focus more on the things you need to know as a developer and user of PHP applications on Windows.
Which PHP to get?
At the time this article was written, the current 5.x version of PHP was 5.2.6. We have worked with a number of PHP applications running on IIS with this version, and we have had good results. It is likely that any current version in the 5.x tree will work with the notes below.
There are two builds for each PHP version. One is thread safe, and one isn’t, referred to as the Non Thread Safe (NTS) version. The thread safe version is designed for environments where the web server core can keep the PHP engine in memory, running multiple treads of execution for different web requests simultaneously. The architecture of IIS and the FastCGI extension provide an isolation model that keeps requests separate, removing the need for a thread safe version. The NTS doesn’t have any of the code that allows PHP to manage multiple threads. As a result, you will see a performance improvement on IIS when using the NTS version as compared to the tread safe version.
There are two main ways that people get PHP installed on their Windows systems. They either download the Windows Installer, or the Windows Zip file from http://www.php.net/downloads.php. Either of those methods will get PHP working, but both of them have some extra steps that are needed to make PHP work really well.
Windows Installer version
The Windows Installer version does a good job of getting a complete PHP environment up and running. However, the installation of Extensions can be a little confusing. The default is to not install any extensions, which will adversely affect the usefulness of your PHP install. Alternately, you could tell the installer to install all of the extensions, which will leave you with an unstable system as some of the extensions will conflict with others.
If you use the ZIP installation, follow the instructions in http://learn.iis.net/page.aspx/246/using-fastcgi-to-host-php-applications-on-iis-70/ . One of the most important steps missing from that article, is changing the “extension_dir” variable in the php.ini file. This version installs many of the extensions that are available for the Installer version. However, none of them are enabled until their entries in the php.ini file are set up. I’ll cover this later in the article where I talk about the php.ini file.
PHP is a very versatile language and environment, with a number of powerful features to meet the needs of many different types of applications. There are dozens of extensions, and hundreds of configuration options in the base PHP installation packages. This article focuses on the needs of common Open Source PHP applications. Although these applications are diverse, there are a certain set of extensions and settings common to all of them which make them run better on a Windows environment.
You need to take some time and figure out which extensions you need to have to get your application running, and limit the installed extensions to just those. For a typical open source application install, I make sure the following extensions are installed:
- Database Extensions – Most open source applications that use MySQL use either the php_mysql or the php_mysqli extensions. If you are doing new development work, either of those would be fine. Or, you may want to consider using the PDO versions of the MySQL driver, as the extra layer of abstraction gives you a richer set of Object Database functionality and controls. If you are using either SQL or SQL Express as your engine, I would grab the php_mssql extension for open source applications. If you are doing new development, for open source, or otherwise, I would strongly recommend using the PDO version of the SQL driver, available soon from the Microsoft SQL website.
- Image Handling – Many of the open source applications that allow you to work with images make use of the GD2 extension – php_gd2. This extension has a number of good basic image manipulation APIs. Some applications use the ImageMagick application and libraries, available from http://imagemagick.org/script/index.php. There is also the php_exif library for working with the extended information that modern digital cameras store within the images.
- Internationalization and Localization – The two most used extensions for i18n and l10n are php_mbstring (Multi-Byte String) and php_gettext (Native Language Support). Many of the open source applications use one or both of these. For new development, you should look at these and decide if you want to use their functionality.
- Web Services Extensions – There are a few web service options out there. You should choose the ones you want to use based on the services you want to create or interact with. In the PHP world, the SOAP extension is widely used. The XML-RPC extension is often used in conjunction with SOAP and other services.
The php.ini file
The php.ini file tells PHP how to configure itself, and how to work with the environment that it runs in. Here are a number of settings for the php.ini file that help PHP work better with Windows. Some of these are optional. There are many other directives that may be relevant to your environment. The best way to learn more about them is to read the php.ini file installed with PHP, and to look at the PHP documentation.
- extension_dir = <PATH TO EXTENSIONS> - The extension_dir needs to point to the directory where your PHP extensions are stored. The path can be fully qualified (i.e. “C:\PHP\ext”) or relative (i.e. “.\ext”). Extensions that you specify lower in the php.ini file need to be located in the extension_dir. If the extensions specified are not in the extension_dir, then PHP will throw a warning message at the start of script execution, and often the application you are running will throw errors because of the missing functionality.
- extension = xxxxxx.dll – For each extension you wish to enable, you need a corresponding “extension=” directive that tells PHP which extensions in the extension_dir to load at startup time.
- log_errors=On – Another place that PHP errors can go is through the PHP error logging facility. This can be used to send errors to a file, or to a service (i.e. syslog) and works with the error_log directive below. When running under IIS, you need to have log_errors enabled, with a valid error_log. If you don’t, FastCGI considers any startup messages (which may just be benign) as an error condition which generates an HTTP 500 return error code to the browser.
- error_log=<path_to_error_log_file” – The error_log needs to specify the fully qualified, or relative path to the file where you want to store the PHP error log. This file needs to be writable for the IIS service. The most common places for this file are in various TEMP directories. I usually use “C:\inetpub\temp\php-errors.log” for this. That puts the log in a place that IIS can use, and also keeps it close to where I’m running or developing my PHP applications.
- cgi.force_redirect = 0 – This directive is required for running under IIS. It is a directory security facility required by many other web servers. However, enabling it under IIS will cause the PHP engine to fail on Windows.
- cgi.fix_pathinfo = 1 – This lets PHP access real path info following the CGI Spec. The IIS FastCGI implementation needs this set.
- fastcgi.impersonate = 1 - FastCGI under IIS supports the ability to impersonate security tokens of the calling client. This allows IIS to define the security context that the request runs under.
- fastcgi.logging = 0 - FastCGI logging should be disabled on IIS. If it is left enabled, then any messages of any class are treated by FastCGI as error conditions which will cause IIS to generate an HTTP 500 exception.
- · max_execution_time=## - This directive tells PHP the maximum amount of time that it can spend executing any given script. This is one of many places where a time limit can be placed on request execution time. The default for this is 30 seconds. If you are running applications which may need more time to process batch operations (i.e. Gallery2 loading multiple images from a remote location), you can increase this as much as you need to. From a practical perspective, going higher than 300 is not advised, as there will often be other places in the connection that refuse to go longer.
- · memory_limit=###M – The amount of memory available for the PHP process, in Megabytes. The default is 128, which is fine for most PHP applications. Some of the more complex ones might need more. I usually run with 256M available on a 4GB of RAM system.
- · display_errors=Off - This directive tells PHP whether to include any error messages in the stream that it returns to the Web server. If this is set to “On”, then PHP will send whichever classes of errors that you define with the error_reporting directive back to IIS as part of the error stream. Many of the Open Source applications bypass error reporting by executing commands prefaced with ‘@’. This allows the applications to control error handling.
- · Mail functions – PHP is configured by default to send outbound mail through an SMTP server located on the web server’s box. Most Windows installations will usually have the Web and Mail servers on separate systems. There is a section in the php.ini (detailed below) which you need to update if you want PHP applications to be able to send e-mail.
Running PHP on Windows
There are a few aspects of running PHP applications on Windows that are different from running PHP on another platform. This section concentrates on those differences, and how you need to work with them.
Interacting with IIS 7 via FastCGI
The addition of FastCGI to IIS has brought about significant performance improvements to PHP apps running on Windows. Configuring it to work with PHP is relatively straightforward. The basics can be found in the article Using FastCGI to Host PHP Applications on IIS 7.0.
Another way of configuring FastCGI is using the IIS Administration Pack, available from http://www.iis.net/downloads/default.aspx?tabid=34&i=1683&g=6. With the Admin Pack, it is easier to tune your FastCGI environment. The setting that you are most likely to need changing is the ActivityTimeout, which defaults to 30 seconds. If you double click on the FastCGI Settings icon from the IIS Manager, and then double click on the application path for PHP displayed there, you will see the window below. Just click on the text you want to change, and type in the new value.
As with any web server, PHP requires IIS to be able to read the script and other files required for an application. For many PHP applications, PHP will require IIS to be able to write files into directories (i.e. a cache), or modify files (i.e. a configuration file). Make sure you evaluate what files and directories that your application will need to write to, and set up appropriate permissions.
In the early days of web application development, a bug in your application could cause a Web server to cycle indefinitely trying to process a request that would never complete. To address this, developers have added execution time caps into most levels of the Web request infrastructure. In a typical application environment, you will be able to adjust this timeout in a number of locations, each of which control the maximum execution time for the section of the request owned. The relevant locations and configure information for a typical PHP on IIS scenario are listed below
- Web server request time
- FastCGI ActivityTimeout – covered in the FastCGI section above
- PHP max execution time – covered in the php.ini section above
- MySQL request execution time
Here is an excerpt from a php.ini file that covers the settings discussed above. It’s not a complete php.ini file, so don’t just drop it in as one. However, if you put this at the end of a php.ini file, the values here will take precedence over the ones found previously.
max_execution_time = 60
memory_limit = 256M
display_errors = Off
log_errors = On
; For Win32 only.
SMTP = mail.example.com
smtp_port = 25
sendmail_from = email@example.com
extension_dir = “.\ext”