How to install PHP ISAPI on Windows 2008 IIS7 x64

With the release of Windows Server 2008 and IIS 7, Microsoft has included PHP5 FASTCGI support. ISAPI is still faster in my opinion, and if used correctly, very stable. PHP uses a 32-bit DLL so it will not work with an x64 system. There are several ports of PHP to x64, but all have proved to be unstable. Below I will outline the steps to install PHP 32-bit on Windows 2008 x64 (and have it stable).

  1. Install the PHP4 or PHP5 package (32-bit) in C:\PHP or wherever you like. Only use the Windows installer from php.net if you do not need any extensions. I would recommend downloading the PHP zip package. 
  2. Open the Internet Information Services (IIS) Manager. 
  3. Double-click “Handler Mappings” from the main IIS screen.
  4. Click on “Add Script Map.”
  5. Set up the handler mapping for c:\PHP\php5isapi.dll with extension *.php and check to allow the ISAPI extension and execution of scripts.
  6. Double-click “ISAPI & CGI Restrictions” on the main IIS screen. Right-click on PHP and select “Edit Feature Settings” and check “Allow unspecified ISAPI modules.”  
  7. Right-click on the Default Application Pool (or the one you want to use if more than one) and select “Advanced Settings.” 
  8. Change the “Enable 32-bit Applications” to True. Click OK. This spawns the App Pool in 32-bit mode, so if you have other modules that need to be run in 64-bit mode, best to separate the website into two App Pools: one 32-bit and one 64-bit.
  9. Restart the server.

Wordpress & PHP on Windows Server IIS 6

This is a quick tip to those who are having trouble installing or using Wordpress on Windows Server with PHP.

Make sure in the PHP.ini file that the following is set:

; Magic quotes for runtime-generated data, e.g. data from SQL, from exec(), etc.
magic_quotes_runtime = Off   

If this is ON, Wordpress will not allow you to login. It will spit out the following error:

“You do not have sufficient permissions to access this page.”

You CAN have magic_quotes ON though, which is a different setting. The above setting is for data being pulled from a MySQL database for example.

Also make sure the following is set:

; cgi.fix_pathinfo provides *real* PATH_INFO/PATH_TRANSLATED support for CGI.  PHP’s
; previous behaviour was to set PATH_TRANSLATED to SCRIPT_FILENAME, and to not grok
; what PATH_INFO is.  For more information on PATH_INFO, see the cgi specs.  Setting
; this to 1 will cause PHP CGI to fix it’s paths to conform to the spec.  A setting
; of zero causes PHP to behave as before.  Default is zero.  You should fix your scripts
; to use SCRIPT_FILENAME rather than PATH_TRANSLATED.
cgi.fix_pathinfo=1

PHP 5.2.x ISAPI stability on Windows IIS 6.0

Having dealt with multiple IIS servers with all kinds of PHP configurations, I’ll let you in on a little secret. PHP 4.4.4 or 4.4.x ISAPI is by far the most stable in any situation. PHP 5.2.x has terrible memory management. If you have a piece of bad code that eats up memory, PHP will not put a stop to it like it should. Here’s an error I received:

The description for Event ID ( 2 ) in Source ( PHP-5.2.2 ) cannot be found. The local computer may not have the necessary registry information or message DLL files to display messages from a remote computer. You may be able to use the /AUXSOURCE= flag to retrieve this description; see Help and Support for details. The following information is part of the event: php[3556], PHP Fatal error:  Allowed memory size of 134217728 bytes exhausted (tried to allocate 2061628868 bytes) in Unknown on line 0.

And of course no matter how much memory I allocate, it eats it all up. It’s just a matter of time. Then comes this error:

Faulting application w3wp.exe, version 6.0.3790.3959, faulting module php5ts.dll, version 5.2.2.2, fault address 0x#.

The obvious solution is to write better code that doesn’t leak memory. However, this isn’t always possible, especially if you are hosting websites run by other people. Many shared hosting accounts on IIS 6.0 experience total PHP shutdown due to one site’s bad code. I have thoroughly tested every 5.2.x line of PHP and they all suffer from this problem. If you want to or need to use PHP 5.2.x, use CGI or Fast-CGI (there’s a beta from IIS.net) as you will not experience any of these memory issues. However Fast-CGI still isn’t as quick as ISAPI, and in terms of the IIS.net beta, suffers from max uploads of ~1 MB.

Summary for maximum stability/speed combo:

PHP 4.4.x -> use ISAPI

PHP 5.2.x -> CGI (in PHP package) or Fast-CGI (from IIS.net)

Don’t use any other line of PHP since they are no longer supported and have multiple security issues.

Unable to load dynamic library php_mysql.dll (MySQL 5.0.41)

You might have seen this error before in the Windows event viewer. However, even if you haven’t seen it, you still might (if you upgrade MySQL). Below is the full error you might find:

The description for Event ID ( 2 ) in Source ( PHP-5.x ) cannot be found. The local computer may not have the necessary registry information or message DLL files to display messages from a remote computer. You may be able to use the /AUXSOURCE= flag to retrieve this description; see Help and Support for details. The following information is part of the event: php[4560], PHP Warning:  PHP Startup: Unable to load dynamic library ‘c:\dir\php_mysql.dll’ - Access is denied.

The reason is that in MySQL 5.0.41 libmysql.dll cannot be dynamically loaded on windows. The symbol USE_TLS is no longer defined in the Windows build.  Windows is expected to allocate the storage for THR_KEY_mysys in mysys/my_thr_init.c using the pthread_key macro.

How to fix this? Downgrade to MySQL 5.0.40 or 5.0.37. You can find them by simply pasting the download URL of the current build and changing the numbers. They always leave old builds on the FTP server.

vBulletin / Photopost and MySQL 5

On a few sites I run I have vBulletin and / or Photopost installed. Upgrading from MySQL 4 to MySQL 5 is simple because these programs are 100% compatible with both (as they should be). Except for one issue. When installing MySQL 5 it defaults to asking to be installed in “Strict Mode” which is how a database should work. Strict Mode behaves in a way that when a malformed statement is entered into the database, it aborts the operation. This is great for helping to provide a structure and predictability to the data in the database. However, some scripts are not programmed in a way that would allow it to work well with strict mode. In vBulletin, this error will show up:

  MySQL is running in strict mode. While you may proceed, some areas of vBulletin may not function properly. It is strongly recommended that you set $config['Database']['force_sql_mode'] to true in your includes/config.php file!

 

I would disable strict mode if possible over forcing vBulletin to use it, as some add-ons don’t play well with it.

If you are using the MySQL Administrator, go to startup variables -> advanced -> sql mode and note the options in the field. If there are no options stated, you are NOT in strict mode. If you see any or all of the following, the database is operating in strict mode:

STRICT_TRANS_TABLES, NO_AUTO_CREATE_USER, NO_ENGINE_SUBSTITUTION

Just remove all 3 statements to disable strict mode. If your server has been operating in strict mode previously and scripts have been designed around it, be sure you can disable it without any adverse effects.

Here is an explanation from the MySQL manual on the above options:

STRICT_TRANS_TABLES

If a value could not be inserted as given into a transactional table, abort the statement. For a non-transactional table, abort the statement if the value occurs in a single-row statement or the first row of a multiple-row statement.

NO_AUTO_CREATE_USER

Prevents GRANT from automatically creating new users unless a non-empty password is specified.

NO_ENGINE_SUBSTITUTION

Control automatic substitution of the default storage engine when a statement such as CREATE TABLE or ALTER TABLE specifies a storage engine that is disabled or not compiled in.

With NO_ENGINE_SUBSTITUTION disabled, the default engine is used and a warning occurs if the desired engine is known but disabled or not compiled in. If the desired engine is invalid (not a known engine name), an error occurs and the table is not created or altered.

Setting Processor Affinity Permanently

The post below talks about processor affinity and setting IIS to use only one processor to increase stability of certain applications (PHP ISAPI anyone?).

You can set the affinity by opening Task Manager and selecting w3svc.exe or inetinfo.exe on the Processes tab. Right click and choose Set Affinity. Uncheck the processors which should not execute the application.

This is a temporary solution since it is reset once you restart Windows or IIS. Some people often disregard setting processor affinity as a fix since it never seems to work…but this is because they don’t set it permanently. Below is how to set the processor affinity permanently.

Grab the Imagecfg.exe tool from the \support\debug\i386 folder of a Windows NT 4.0, or the Imagecfg.exe tool from the Windows 2000/2003 Server Resource Kit.

Open a CMD prompt and type:

imagecfg -a 0xn drive:\Path\program.exe

where 0xn is the affinity mask and drive:\Path\program.exe is the program you wish to set. The mask indicates which processor is to run the desired application. On a dual-core system, you use CPUs 0 and 1 (not 1 and 2).

 CPU   MASK
  0         0×1
  1         0×2
  2         0×4
  3         0×8

WordPress 2.1.x - 2.2 Breaks PHP 4.4.4

While I was trying to find a content management system for a section of World’s Cutest Animals I decided to try WordPress 2 instead of programming my own (I’m lazy sometimes).

When I installed WordPress 2.1.x it was working fine until midday when requests for the page spiked as usual. It was the dreaded PHP Access Violation. Previous to this, there had never been a PHP related issue with the site in 11 months. I figured I’d try to get it to work instead of uninstalling it right away, so I tried the following:

1. Disabled XCompress HTTP compression, thinking it was an issue with ISAPI ordering like so many IIS related problems.

2. Disabled Isapi Rewrite (thinking it was a compatibility issue between the many rewrite systems and rules on my server in addition to ISAPI ordering)

3. Upgrading PHP to 4.4.7, then downgrading to 4.4.2 (hoping another build had a fix in there, seems every build of PHP breaks or fixes something)

4. Uninstalling WordPress (Tada! Worked! But this is not what I wanted. I’m lazy, I wanted wordpress working)

5. Installed WordPress 2.2 (Still didn’t work)

6. Played with WordPress Permalinks (Nothing)

7. Tried Fast-CGI wrapper from IIS.net for IIS 6.0/7.0 (Worked!)

The Fast-CGI from IIS.net is an effort between Zend and Microsoft to increase the stability of PHP on the upcoming Longhorn Server and IIS 7.0. It’s no secret that PHP is one of the worst offenders of IIS instability. They do have a technology preview out that works with IIS 5.0/6.0. I recommend this if you do have stability issues with PHP ISAPI. It is about 5 times faster than php.exe CGI that comes with PHP 4. The wrapper works for PHP 5 as well. It installs in about 2 minutes thanks to Microsoft’s script and instructions.

Turns out WordPress has some XML GetFeatureList that breaks PHP by forcing a multithreading situation in IIS (w3svc.exe). PHP ISAPI is terrible at any sort of attempt of multithreading as it is not supported.

On a related note, because of PHP ISAPI threading issues, if you have a dual-core server, best to set the processor affinity of w3svc.exe or inetinfo.exe (depending on whether or not you are in isolation mode) to one processor. If you have mulitple websites, assign them to two Application Pools and have each pool running on a different processor. This will assure a much more stable instance of PHP (4 and 5). In each Application Pool, be sure to keep Worker Processes set to 1 (in the properties box). Setting it to a higher number causes multiple threads to be started.

Click here for instructions on permanently setting Processor Affinity in Windows

file_get_contents on IIS 6

To all those (3 people) who need to use file_get_contents in PHP on IIS 6, you may notice it doesn’t work by default. To see if it works, place the following code into a file called test.php.

  1. <?php
  2. $content=file_get_contents(“http://www.google.com“,FALSE,NULL,0,20);
  3. echo $content;
  4. ?>

You should have the first 20 bytes of the google source code echoed back to you on the page when it is executed. If not, you may need to play with IIS 6.

Does fsockopen work?

IIS 6 by default does not allow sockets to be created on port 80 (file_get_contents works on this port, of course). This is a result of how IIS 6 accepts connections. To get file_get_contents to work, you need to enable IIS 5 Compatibility (Isolation Mode) on IIS 6. You then need to choose Low (IIS Process) under “Application Protection.” Isolation mode settings are found in the IIS Admin Interface –> Right-click on Web Sites folder and look under the Service Tab.