Question:

Hi all,

I have trouble to configure PHP 5 (CGI mode) in IIS 7 on Vista 5308...

What I did:
- Download and unpack PHP
- set user permission to PHP folder AND script folder (IIS_IUSRS and Internet Guest Account)
- in IIS Manager: Added pages in Default documents
- Added in "ISAPI and GCI Restrictions": Allowed PHP  group ID PHP path c:\php\php-cgi.exe
- Added in "Global Modules" PHP as integratedmode path c:\php\php-cgi.exe
- Added in "Handler" PHP to map *.php,*.php3 type:File path c:\php\php-cgi.exe all verb handler:cgimodule
- Added in "module": PHP code:c:\php\php-cgi.exe module:native entry:local

Answer:

Unfortunately, at this point in the beta cycle, IIS7 configuration failures are still cryptic, so you basically need to really know what you are configuring. However, most things are conceptually the same as prior IIS versions - just maybe named/organized or configured differently.

For many reasons, I do not use the UI nor give instructions for the UI (except if explicitly talking about a UI-behavior), so all my instructions directly manipulate the necessary .config files with the right values to generate the desired behavior.

  • The UI is still under development and can change from build to build, including introduce bugs. A UI bug should not prevent you from using server features.
  • The server behavior (and hence configuration) rarely changes. The UI surrounding it may change in response to concepts/feedback, so UI-based instructions can be out-of-date, especially during beta.
  • I want to illustrate how to configure and use IIS, not how to use the UI to generate the necessary configuration.

In your case, you basically chose to configure all possible locations, but that is not all correct and thus IIS7 will mysteriously fail. In particular, configuring PHP as a "Global Module" or "Module" is incorrect.

Instructions

This is all you should do (and why):

  1. Install PHP into %SYSTEMDRIVE%\Inetpub\PHP (I want to easily inherit any IIS7-related ACLs)
  2. Download and unpack PHP into %SYSTEMDRIVE%\Inetpub\PHP (For this example, I chose the latest currently available build, PHP 5.1.2 ZIP package, from http://www.php.net/downloads.php )
  3. Use the recommended PHP.INI-Recommended INI file inside the PHP directory (or whatever PHP configuration you need)
  4. Configure a Handler for *.php using %SYSTEMDRIVE%\Inetpub\PHP\PHP5ISAPI.DLL or %SYSTEMDRIVE%\Inetpub\PHP\PHP-CGI.EXE (I prefer the ISAPI version on IIS) and order the Handler AHEAD of the StaticFile Handler
  5. Configure an ISAPI and CGI Restrictions entry to enable the added Handler for PHP

This is all you need to do. Conceptually, it is not any different than prior IIS versions, like IIS6, and the necessary data is pretty much the same. The only difference is that you are configuring a Handler instead of an Application Mapping. This is because we have reconciled the IIS Application Mapping with the ASP.Net httpHandlers (as well as many other things, such as ISAPI Filters and httpModules) to form the new IIS7 Integrated Pipeline. The new unified section is called "handlers".

The Details

The astute Reader should note that it is important to place the PHP Handler ahead of the StaticFile Handler. Why?

Unlike the IIS Application Mapping list, which is unordered, the Handlers list is ordered. This means:

  • For Application Mappings prior to IIS7, we chose to have arbitrary behavior of wildcard application mappings always run first to handle a request, and if unhandled, then the first Application mapping with a matching extension is executed).
  • For Handlers in IIS7, we chose to have first-match (of extension/verb) wins. This gives user complete control over Handler resolution order; no arbitrary ordering imposed by IIS core.

In other words, you can configure IIS7 Handlers to act like pre-IIS7 Application Mappings by doing the following (conceptual). Note that IIS6 hardcodes the ordering of WildcardApplicationMappings and StaticFileModule to be first and last, respectively... while IIS7 allows you to order the Handlers however you want:

<handlers>
    <add modules="WildcardApplicationMapping1" verb="*" path="*" />
    <add modules="WildcardApplicationMapping2" verb="*" path="*" />
    <add modules="IsapiModule" verb="GET,HEAD,POST" path="*.asp" />
    <add modules="StaticFileModule" verb="*" path="*" />
</handlers>

Of course, with power comes responsibility. With such a flexible system, it means that the StaticFile Handler, which maps to all extensions and all verbs, must be configured last so that it is the Handler of last resort after all other Handlers fail to match. This means that any added  handlers must be ahead of the "wildcard" handlers since otherwise the wildcard handler will get picked first.

Instructions (Automation)

Ok, suppose the Instructions weren't clear enough. Here is the commandline version of the above instructions. :-)

MKDIR %SYSTEMDRIVE%\Inetpub\PHP
ECHO Extract PHP files from ZIP archive into %SYSTEMDRIVE%\Inetpub\PHP
COPY /Y %SYSTEMDRIVE%\Inetpub\PHP\PHP.INI-Recommended %SYSTEMDRIVE%\Inetpub\PHP\PHP.INI
PUSHD %SYSTEMROOT%\System32\inetsrv
APPCMD SET CONFIG -section:handlers -+[name='PHP',path='*.php',verb='GET,HEAD,POST',modules='IsapiModule',scriptProcessor='%SYSTEMDRIVE%\Inetpub\PHP\php5isapi.dll',resourceType='File']
APPCMD SET CONFIG -section:isapiCgiRestriction -+[path='%SYSTEMDRIVE%\Inetpub\PHP\php5isapi.dll',allowed='true',groupId='PHP',description='PHP5']
POPD

Yes, I am using the new APPCMD commandline tool for manipulating IIS7 configuration to make scriptable changes. You can view it as the IIS7 uber-replacement for adsutil.vbs and all of the IIS6 commandline tools. Bear with the cryptic syntax for the moment - it is really quite handy once you get past the syntax (especially the syntax for collection manipulation - I can spend a blog entry just talking about it alone ;-) ).

Conclusion

The above instructions are all the IIS-specific steps necessary to get PHP to work on IIS7. I was able to run a PHP page containing <?php phpinfo();?> after making just those changes on top of a default IIS7 installation. If you still have problems, it is most likely coming from PHP itself.

For example, php-cgi.exe does not seem to work because its CGI output is missing the Status: field as required by CGI 1.1 specification.

[Modified 4-4-2006] php-cgi.exe does work on IIS7. You need to modify PHP.INI to have the line:

cgi.force_redirect = 0

If you do not do this modification, PHP-CGI.EXE outputs a security warning response without proper response headers, which causes IIS to return a 502 Bad Gateway. Strangely, running PHP-CGI.EXE from the commandline does not generate this error - I guess using NPH CGI is the only way to debug PHP, because running it from the commandline is not 100% indicative of web-server Runtime behavior.

[Modified 6-14-2006] Removed the following lines of batch script to work-around of APPCMD manipulation of StaticFile module since the bug got fixed.

APPCMD SET CONFIG -section:handlers --[name='StaticFile',path='*',verb='*']
APPCMD SET CONFIG -section:handlers -+[name='StaticFile',path='*',verb='*',modules='StaticFileModule,DefaultDocumentModule,DirectoryListingModule',resourceType='Either',requireAccess='Read']

[Modified 6-24-2006] Linked to newer instructions here.

//David