HOWTO: Install and Run PHP on IIS7, Part 3
A short while ago, I came out with a small script to properly configure PHP for IIS7. Sure enough, I got asked to make a similar one for IIS6. So, I figure that while I am at it, I might as well cover IIS4, IIS5, and IIS5.1 as well since it is not very different, and put it all into one script so that you can see one classic way to maintain a single automation script which runs version-specific logic.
For the astute reader - no, this script is not minimal, optimal, nor foolproof... it is illustrative. I am deliberately showing several possibilities at the expense of conciseness... but I hope you agree that the information is worth more than the result here...
To correctly configure the PHP Application Mapping prior to IIS7, you MUST provide a tool that can modify the IIS LIST data type.
I have provided such a tool in this blog entry, so you need to copy that script tool into the same directory as you copy this script and name it "ChgList.vbs". If you want to put the tool in a different directory or with a different name, you must modify the FILE_CHGLIST variable in this script appropriately to give the complete pathname.
In addition, I made several little illustrative enhancements:
- Debug mode - if you want to merely SEE what is going to execute but NOT execute anything, set the _DEBUG environment variable to 1. Default executes.
- Functions vs. Labels - the label :VerifyScripts is treated as a FUNCTION in batch (with ERRORLEVEL as the return value), while the labels :Menu and :Start are treated like GOTO labels
- File Existence Validations - depending on the OS/IIS Version, validate the existence of necessary files and scripts
- OS BuildNumber detection
Yes, when you write scripts/tools meant to run on multiple platforms and versions, you get constrained into the most reliable least-common-denominator and never get to use the new-fangled stuff. But that's the difference between getting stuff done with compatible software vs experimenting with the bleeding edge... ;-)
In this case, I am using OS BuildNumber, parsed from 'ver', to determine IIS version. If I can constrain this script to IIS5.1 and above (or W2K with REG.EXE from the Resource Kit), I can use REG.EXE to read the installed IIS version from the Registry... but I am not making those assumptions and hence use the OS BuildNumber as a compatible mechanism.
And to be complete - all of these actions require you to run with administrative privileges since you cannot modify the IIS Configuration file(s) without them. Prior to Vista, this means the user must be in the local Administrators group. On Vista with UAC (default), it means that you either run as the built-in Administrator (disabled by default) or run the script with elevated permissions (by saving the script and right-click running as Administrator).
One final disclaimer:
*** Please realize that the script tool simply makes PHP work in one configuration (default). It is not meant to fix or make your arbitrary configuration work ***
In particular, if you run this script more than once, it may not work correctly or configure duplicate settings. For example, APPCMD will fail to configure duplicate handlers and WebServiceExtension entries, iisext.vbs will fail to configure duplicate WebServiceExtension entries, and ChgList.vbs will keep adding duplicate .php ScriptMappings. It is a slippery slope, so I draw the line early.
Also, the script does not go through your ScriptMaps to change the right ones; you can do that yourself. It also does not verify file ACLs, user identities and permissions, etc - it assumes everything is working perfectly and you just need to make the minimal IIS-related configuration to make PHP work.
Sorry... but please understand that I am not in the business of writing and supporting installation programs for other products nor troubleshooting why it does not work on IIS. I am just trying to show how things work, together.
@IF ?%_ECHO%?==?? ECHO OFF SETLOCAL IF ?%_DEBUG%? EQU ?1? (SET DEBUG=ECHO) ELSE (SET DEBUG=) SET FILE_CHGLIST=chglist.vbs SET FILE_IISEXT=%SYSTEMROOT%\System32\iisext.vbs SET CMD_CHGLIST=CSCRIPT //NoLogo %FILE_CHGLIST% SET CMD_IISEXT=CSCRIPT //NoLogo %FILE_IISEXT% SET CMD_APPCMD=%SYSTEMROOT%\System32\inetsrv\APPCMD.EXE SET DIR_PHP_FROM=%SYSTEMDRIVE%\Inetpub\PHP SET PHP_TYPE=ISAPI SET PHP_MODULE=IsapiModule SET PHP_BINARY=php5isapi.dll REM REM Determine OS BuildNumber REM 1381 NT4 IIS4 REM 2195 W2K IIS5 REM 2600 WXP IIS5.1 REM 3790 WS03 IIS6 REM Other Vista IIS7 REM FOR /f "tokens=3 delims=.]" %%i IN ('ver') DO SET OS_BUILDNUMBER=%%i IF "%OS_BUILDNUMBER%"=="" FOR /f "tokens=4" %%i IN ('ver') DO IF "%%i"=="4.0" SET OS_BUILDNUMBER=1381 :Menu ECHO. ECHO David.Wang's Sample PHP/IIS Configurator ECHO Version: June 2006 ECHO OS BuildNumber: %OS_BUILDNUMBER% ECHO. ECHO ------------------------------ Summary ------------------------------ ECHO PHP Binaries Dir : %DIR_PHP_FROM% ECHO PHP Binary Type : %PHP_TYPE% ECHO PHP Binary Name : %PHP_BINARY% ECHO --------------------------------------------------------------------- REM REM Do some basic validations REM ECHO. ECHO Validating inputs... IF /I ?%PHP_TYPE%? NEQ ?CGI? IF /I ?%PHP_TYPE%? NEQ ?ISAPI? ECHO.&ECHO ERROR: Binary Type MUST be either CGI or ISAPI FOR %%I IN ( %PHP_BINARY% ) DO ( IF /I ?%PHP_TYPE%? EQU ?CGI? IF /I ?%%~xI? NEQ ?.exe? ECHO.&ECHO WARNING: Binary Type %PHP_TYPE% requires a CGI EXE binary IF /I ?%PHP_TYPE%? EQU ?ISAPI? IF /I ?%%~xI? NEQ ?.dll? ECHO.&ECHO WARNING: Binary Type %PHP_TYPE% requires an ISAPI DLL binary ) IF /I ?%PHP_TYPE%? EQU ?CGI? SET PHP_MODULE=CgiModule IF /I ?%PHP_TYPE%? EQU ?CGI? ECHO.&ECHO ERROR: PHP CGI requires modifying cgi.force_redirect to 0 in "%DIR_PHP_FROM%\PHP.INI" IF /I ?%PHP_BINARY%? NEQ ?php5isapi.dll? IF /I ?%PHP_BINARY%? NEQ ?php-cgi.exe? ECHO.&ECHO WARNING: Unrecognized PHP binary %PHP_BINARY% Call :VerifyScripts ECHO. ECHO Remember to tweak PHP.INI for security and functionality per php.net ECHO Finished input validation. ECHO. SET GO= SET /P GO=Press 1 to EDIT choices, or ENTER to start IIS modifications: IF ?%GO%? EQU ?? GOTO :Start ECHO. ECHO Press ENTER to accept [%DIR_PHP_FROM%], or provide new value (folder path) SET /P DIR_PHP_FROM=PHP Binaries Dir: ECHO Press ENTER to accept [%PHP_TYPE%], or provide new value (CGI or ISAPI) SET /P PHP_TYPE=PHP Binary Type: ECHO Press ENTER to accept [%PHP_BINARY%], or provide new value (filename) SET /P PHP_BINARY=PHP Binary Name: GOTO :Menu :Start REM REM Start Configuration REM ECHO. ECHO Starting IIS Configuration... ECHO. ECHO Copying "%DIR_PHP_FROM%\PHP.INI-Recommended" to PHP.INI... %DEBUG% COPY /Y "%DIR_PHP_FROM%\PHP.INI-Recommended" "%DIR_PHP_FROM%\PHP.INI" CALL :VerifyScripts IF %ERRORLEVEL% EQU 2 GOTO :EOF REM REM Use OS Version to distinguish between IIS Versions REM REM 1381 NT4 IIS4 REM 2195 W2K IIS5 REM 2600 WXP IIS5.1 REM 3790 WS03 IIS6 REM Other Vista IIS7 REM IF %OS_BUILDNUMBER% GTR 3790 ( ECHO Setting PHP Handler... %DEBUG% %CMD_APPCMD% SET CONFIG -section:handlers "-+[name='PHP-%PHP_TYPE%',path='*.php',verb='GET,HEAD,POST',modules='%PHP_MODULE%',scriptProcessor='%DIR_PHP_FROM%\%PHP_BINARY%',resourceType='File']" ECHO Adding and Enabling PHP in ISAPI/CGI Restriction List... %DEBUG% %CMD_APPCMD% SET CONFIG -section:isapiCgiRestriction "-+[path='%DIR_PHP_FROM%\%PHP_BINARY%',allowed='true',groupId='PHP',description='PHP']" ) ELSE IF %OS_BUILDNUMBER% EQU 3790 ( ECHO Setting PHP Handler... %DEBUG% %CMD_CHGLIST% W3SVC/ScriptMaps "" ".php,%DIR_PHP_FROM%\%PHP_BINARY%,0" /INSERT /COMMIT ECHO Adding and Enabling PHP in ISAPI/CGI Restriction List... %DEBUG% %CMD_IISEXT% /AddFile "%DIR_PHP_FROM%\%PHP_BINARY%" 1 PHP 1 PHP ) ELSE IF %OS_BUILDNUMBER% LSS 3790 ( ECHO Setting PHP Handler... %DEBUG% %CMD_CHGLIST% W3SVC/ScriptMaps "" ".php,%DIR_PHP_FROM%\%PHP_BINARY%,0" /INSERT /COMMIT ) ECHO. ECHO Finished IIS Configuration. ECHO. ECHO Test installation using PHP file content of: ^<?php phpinfo();?^> ENDLOCAL GOTO :EOF REM REM Sub-routines and Functions REM :VerifyScripts SET ERRORLEVEL=0 IF NOT EXIST "%DIR_PHP_FROM%\%PHP_BINARY%" ( ECHO. ECHO ERROR: PHP Binary "%DIR_PHP_FROM%\%PHP_BINARY%" does not exist! ECHO Please first completely extract PHP to "%DIR_PHP_FROM%" SET ERRORLEVEL=2 ) IF NOT EXIST "%DIR_PHP_FROM%\PHP.INI" ( ECHO. ECHO ERROR: "%DIR_PHP_FROM%\PHP.INI" does not exist! SET ERRORLEVEL=2 ) IF %OS_BUILDNUMBER% GTR 3790 ( IF NOT EXIST "%CMD_APPCMD%" ( ECHO. ECHO ERROR: Script requires %CMD_APPCMD% for this OS. SET ERRORLEVEL=2 ) ) IF %OS_BUILDNUMBER% EQU 3790 ( IF NOT EXIST "%FILE_IISEXT%" ( ECHO. ECHO ERROR: Script requires %FILE_IISEXT% for this OS. SET ERRORLEVEL=2 ) ) IF %OS_BUILDNUMBER% LEQ 3790 ( IF NOT EXIST "%FILE_CHGLIST%" ( ECHO. ECHO ERROR: Script requires %FILE_CHGLIST% for this OS. ECHO http://blogs.msdn.com/david.wang/archive/2004/12/02/273681.aspx SET ERRORLEVEL=2 ) ) GOTO :EOF