PHP with WinCache on IIS

Reading Time: 18 Minutes

Install WinCache with PHP on IIS. In this article you’ll learn how to install PHP with Windows Cache Extension (WinCache) on Windows Server IIS. WinCache enabled PHP gives a great PHP performance boost for your WordPress, Drupal or Joomla website, and decreases CPU usage. This post will show you it’s not hard to set up high performance PHP on Windows Server (IIS). And as a bonus, we’ll dive into Windows TCP/IP tuning too. Learn how this very blog optimized it’s PHP hosting on Windows!

Install PHP and WinCache on IIS #

What is the Windows Cache Extension (WinCache)? WinCache is a great addition for your PHP configuration on Windows Server. High performance PHP application hosting on IIS ;-) However, over the years, problems were reported with either the installation and configuration of the Windows Cache (WinCache), or even with buggy versions. Just search forums.iis.net for examples.

Advertisement:

This is why I created this how to install and configure WinCache for PHP on IIS guide. Setting up PHP and WinCache is absolutely not that difficult.

The Windows Cache Extension for PHP is a PHP accelerator that is used to significantly increase the speed of PHP applications running on the Windows operating system. Any PHP application can take advantage of the functionality provided by the Windows Cache Extension for PHP without any code modifications. All that is required is that the extension is enabled and loaded by the PHP engine.

from iis.net

Remember that the IIS FastCGI extension provides thread safety, therefore we use non thread safe (NTS) versions of our software.

Pro Tip: Never try to set up a new configuration in a live environment! Always use a development-, testing- and staging PHP environment before deploying your PHP configuration to your live PHP hosting environment. This may go very bad when you haven’t tested your set-up.

Download and configure PHP and WinCache #

Download PHP and WinCache in a few steps:

  1. download PHP 5.4 VC9 x86 Non Thread Safe from http://windows.php.net/download/. Non Thread Safe because we’re using IIS/FastCGI
  2. unzip the files to a location on the server, for instance c:\php5 and edit the php.ini accordingly
  3. download WinCache 1.3 for PHP 5.4 from http://www.iis.net/downloads/microsoft/wincache-extension
  4. run the executable wincache-1.3.4-5.4-nts-vc9-x86.exe to unpack the files in, for instance c:\temp
  5. copy the file php_wincache.dll to the c:\php5\ext location

WinCache versions
If you to try to set up a buggy version of WinCache, just try a different version, or perhaps a development version to overcome errors. Test various newer or older version in your development environment, you can download these WinCache versions from http://sourceforge.net/projects/wincache/files/development/.

Configure PHP and WinCache settings #

You can configure PHP and WinCache in a few short steps (WinCache configuration below the list items):

  1. copy php.ini to php.wincache.ini and open php.wincache.ini in your favorite editor
  2. add extension=php_wincache.dll to the Dynamic Extensions list
  3. manually create a [WinCache] configuration section and turn on the WinCache extension (see all configuration options: http://www.php.net/manual/en/wincache.configuration.php). Other WinCache-settings may be left at their default settings.
[WinCache]
; Enables or disables the file cache functionality. Defaults to 1
wincache.fcenabled = 1
; Enables or disables the opcode cache functionality. Defaults to 1
wincache.ocenabled = 1
; Enables or disables the user cache functionality. Defaults to 1
wincache.ucenabled = 1
  1. It is important look at the following php.ini settings, and change them to your needs
output_buffering = Off
display_errors = Off
log_errors = Off
cgi.force_redirect = 0
cgi.fix_pathinfo = 1
fastcgi.impersonate = 1
fastcgi.logging = 0

While you’re at it, tune PHP realpath_cache_size and OPcache too. WinCache’s opcode cache is deprecated in favor of PHP OPcache. PHP OPcache on Windows Server gives a great performance boost too.

Pro tip: Don’t turn off CURLOPT_SSL_VERIFYPEER to fix issues with SSL, fix your PHP configuration.

PHP is now configured to use WinCache, if we set the handler for it in IIS. We created a different PHP configuration file called php.wincache.ini, remember. That one needs to be activated as a PHP handler in IIS.

Disable WinCache
Suppose you want to disable WinCache completely. Open up your php.wincache.ini file and remove the php_wincache.dll extension by commenting it out: ; extension=php_wincache.dll. Or you may just change back to your default IIS PHP handler and WinCache is disabled too.

How to set up a PHP handler using IIS Manager #

Open up the FastCGI Settings feature of the webserver in IIS Manager.

In the Actions pane, click Add Application…

Set up PHP as a FastCGI application

  • Full Path: c:\php5\php-cgi.exe
  • Arguments: -c c:\php5\php.wincache.ini

You can tweak other settings, such as Instance MaxRequests and Max Instances, after a while, when the server is running smoothly. Don’t start over-optimizing your IIS web server configuration too soon.

Open up the EnvironmentVariables Collection and add two environment variables, which tells FastCGI where the .ini-file is located and sets the native PHP process-recycling.

Hint: by setting instanceMaxRequests to a value that is smaller than or equal to PHP_FCGI_MAX_REQUESTS, you can make sure that the native PHP process-recycling logic will never start. See “Configuring FastCGI to Host PHP Applications (IIS 7)“.

Now, open up the Handler Mappings feature in IIS Manager.

Scroll down to *.php and click Edit... in the Actions pane (or just double click). Fill out the requested information. The pipe (|) is important, the full Executable will become c:\php5\php-cgi.exe|-c c:\php5\php.wincache.ini

and click the Request Restrictions… button.

Set the handler Request Restrictions to invoke the handler only if request is mapped to File. If you forget this step, you may leave your webserver open to a nasty ASP.NET source code disclosure vulnerability and you may receive "No input file specified." errors instead of a 404 Not Found page.

Click OK twice (in the Request Restrictions screen and Edit Module Mapping) to exit. In the next screen, you may click NO to not set up a FastCGI application, because we already manually did.

AppCmd command line to set up FastCgi and PHP configuration #

In addition, command-line gurus may use AppCmd to configure FastCGI applications and PHP handlers. I’m not going to post all AppCmd commands here, they’re already in older posts like here and here.

Some example AppCmd commands you might need when setting up PHP and FastCgi:

Appcmd set config /section:system.webServer/fastCGI
 /+"[fullPath='c:\php5\php-cgi.exe', arguments='-c c:\php5\php.wincache.ini', 
 maxInstances='0', idleTimeout='300', activityTimeout='70', 
 requestTimeout='90', instanceMaxRequests='9999', 
 protocol='NamedPipe', flushNamedPipe='False']" /commit:apphost
AppCmd set config -section:system.webServer/fastCgi
 /+"[fullPath='c:\php5\php-cgi.exe', arguments='-c c:\php5\php.wincache.ini'].environmentVariables.
 [name='PHP_FCGI_MAX_REQUESTS',value='10000']" /commit:apphost
AppCmd set config -section:system.webServer/fastCgi
 /+"[fullPath='c:\php5\php-cgi.exe', arguments='-c c:\php5\php.wincache.ini'].environmentVariables.
 [name='PHPRC',value='c:\php5\php.wincache.ini']" /commit:apphost
AppCmd set config /section:system.webServer/handlers 
  "-+[name='PHP',
    path='*.php',
        verb='*',
        modules='FastCgiModule',
        scriptProcessor='c:\php5\php-cgi.exe|-c c:\php5\php.wincache.ini',
        resourceType='File',
        allowPathInfo='true',
        requireAccess='Script',
        responseBufferLimit='256']"

In PowerShell, escape the single quote ' with a backtick `. And put in your website web.config file:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.webServer>
    <handlers>
      <remove name="PHP"/>
      <add name="PHP" path="*.php" verb="*" modules="FastCgiModule"
        scriptProcessor="c:\php5\php-cgi.exe|-c c:\php5\php.wincache.ini"
        resourceType="File"
        allowPathInfo="true"
        requireAccess="Script"
        responseBufferLimit="256" />
    </handlers>
  </system.webServer>
</configuration>

Troubleshooting PHP configuration on IIS #

Tip: use the command line

Sometimes things go wrong. It just does, for example when you make a typo. That is not a problem. You can very easily troubleshoot PHP configuration errors on the command line. Just run php-cgi.exe with some parameters and a pop-up will show an error (no error means everything is OK).

load php.wincache.ini and run a .php-file (one line)

c:\php5\php-cgi.exe
  -c c:\php5\php.wincache.ini
  c:\inetpub\wwwroot\site1.com\index.php

load a Zend extension like ioncube_loader and run a .php-file (one line)

c:\php5\php-cgi.exe
  -z c:\php5\ioncube_loader_win_5.4.dll
  c:\inetpub\wwwroot\site1.com\index.php

combine both ioncube_loader and php.wincache.ini (one line)

c:\php5\php-cgi.exe 
  -c c:\php5\php.wincache.ini 
  -z c:\php5\ioncube_loader_win_5.4.dll
  c:\inetpub\wwwroot\site1.com\index.php

WinCache opcode cache with PHP 5.5, 5.6 & PHP 7 #

With the release of WinCache version 1.3.5 for PHP 5.5, the WinCache opcode cache (ocenabled) is now deprecated and will be removed in a future release of the WinCache extension. WinCache opcode cache is deprecated in favor of PHP’s native OPcache, the Zend OPcache extension is in the PHP core available.

Here is how to optimize PHP OPcache configuration.

Tune IIS and TCP/IP stack for high performance websites and high volume of web requests

This may deserve a dedicated post sometime. For the time being, it’s here.

TCP state diagram
TCP state diagram

Now that you have your PHP 5.4 / 5.5 / 5.6 / 7.0 and WinCache set up for high performance websites, it is important to tune IIS and the TCP/IP stack too. Increase the network performance, or you just might run out of available ports/sockets (TCP/IP port exhaustion).

IIS limits for a website #

The <limits> element of the <site> element configures settings that limit the amount of bandwidth, the number of connections, or the connection time-out for client requests to a site.

Note: If the <limits> element is configured in both the <siteDefaults> section and in the <site> section for a specific site, the configuration in the <site> section is used for that site.

IIS Connection Timeout #

IIS’ default Connection Timeout for HTTP requests is 120 seconds. This means that a connection will remain open for two minutes, even when the client has disconnected (e.g, clicked a link and left to a different website). We can safely reduce this to 60 or 30 seconds, depending on your needs, with AppCmd:

appcmd.exe set config
 -section:system.applicationHost/sites
 "/[name='example.com'].limits.connectionTimeout:00:01:00"
 /commit:apphost

Or globally for all sites:

appcmd.exe set config
 -section:system.applicationHost/sites
 /siteDefaults.limits.connectionTimeout:"00:01:00"
 /commit:apphost

appcmd.exe set config
 -section:system.applicationHost/webLimits
 /connectionTimeout:"00:01:00"
 /commit:apphost

Notice limit and webLimits. This releases sockets that are waiting in a TIME_WAIT state, faster.

IIS maxConnections #

Use the following AppCmd command to increase the number of maximum number of connections for a site. Use this setting to limit the number of simultaneous client connections.

appcmd.exe set config
 -section:system.applicationHost/sites
 "/[name='example.com'].limits.maxConnections:1500"
 /commit:apphost

Ephemeral ports #

MaxUserPorts
The number of available short-lived (or ephemeral) ports differs per Windows Server version. In the early Windows 2003 days, ephemeral ports are allocated between the values of 1024 and 5000 inclusive. You could increase this in the Windows Registry, by adding the MaxUserPorts key in

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters

For example:

reg.exe
 add HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
 /v MaxUserPort
 /t REG_DWORD
 /d 0x000067c0

However, this is no longer relevant for Windows Server 2012 (R2).

TCPTimedWaitDelay
For WIndows Server 2012, the registry setting TCPTimedWaitDelay determines how long a closed port waits until the closed port can be reused. This defaults to 240 seconds and can be decreased to 30 seconds. This DWORD (32-bit) Value name is also found under

HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters

Set it’s Value data to 3c hexadecimal for a 60 second TIME_WAIT window. Again an example:

reg.exe
 add HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
 /v TCPTimedWaitDelay
 /t REG_DWORD
 /d 0x0000003c

Dynamic Port range #

On Windows 2008 and 2012 we use the Network Shell (netsh) to determine a dynamic port range. Its default setting is:

C:\Users\userName>netsh int ipv4 show dynamicportrange tcp

Protocol tcp Dynamic Port Range
---------------------------------
Start Port      : 49152
Number of Ports : 16384

We increase this, in the next example with roughly 9151 extra ephemeral ports:

netsh int ipv4 set dynamicportrange protocol=tcp startport=40000 numberofports=25535 store=persistent

A reboot is required to take this in effect.

TCP Chimney Offload #

TCP Chimney Offload is a networking technology that helps transfer the workload from the CPU to a network adapter during network data transfer.

In Windows Server, TCP Chimney Offload enables the Windows networking subsystem to offload the processing of a TCP/IP connection to a network adapter that includes special support for TCP/IP offload processing. TCP Chimney Offload is available in all versions of Windows Server 2008 and 2012. Both TCP/IPv4 connections and TCP/IPv6 connections can be offloaded if the network adapter supports this feature.

Configure TCP Chimney Offload in the operating system #

netsh int tcp set global chimney=enabled

In some rare circumstances, enabling TCP Chimney Offload might degrade performance. Maybe due to bad network interface card (NIC) firmware or drivers. Then you can disable TCP Chimney Offload:

netsh int tcp set global chimney=disabled

Disable ECN Capability in Windows Server 2012 #

If you are on Windows Server 2012, don’t forget to disable explicit congestion notification (ECN, or ECN Capability). This really slows down outbound connections to some outdated, or faulty, network equipment.

Disabling ECN Capability can improve your outbound connection speed.

Running PHP with WinCache on IIS, in conclusion #

In this post I showed you how easy it is to install PHP with WinCache on IIS. This post also showed you how to tweak and optimize your Windows TCP/IP settings, for you to create a high performance web stack to host high volume web sites. However, caution is called for: Enabling WinCache for all hosted websites (as default) can easily run a server out of memory if a settings is not optimized.

This is because Windows IIS reserves the configured amount of memory per website.

Note: Script engines on OS partition: it’s beyond the scope of this post to explain the dangers of having websites and/or script engines on the same partition as the Operating System!

If you develop PHP and MySQL based web sites, you can even use WinCache to cache MySQL query results. This is a turbo boost for your website because the website doesn’t have to create a connection to the back-end database for every request.

The WinCache functions are easily ported to APC, and vice versa, and thus you are not stuck on one hosting platform.

This article was written back in the PHP 5.4 days, but applies to PHP 5.5, PHP 5.6, and PHP 7, with or without WinCache or OPcache too. Use WinCache and OPcache in PHP to create a high performance PHP application hosting on Windows Server IIS. Decrease page load time and decrease CPU usage. Fast page loads are more and more important nowadays for seach engine optimization (SEO) and user experience.


Advertisement:

4 Replies to “PHP with WinCache on IIS”

  1. Hi,

    This article is awesome! Is there any article about the dangers of having websites and/or script engines on the same partition as the Operating System?

    thanx again for this article

    1. Hi ramzibot,
      Thank you for your comment!

      By not placing websites on the same partition as the operating system is just one step against directory traversal attacks. You might want to read the Windows Server 2003 hardening guide (chapter 9: “The Web Server Role”) about this: http://www.nsa.gov/ia/_files/os/win2003/MSCG-001R-2003.pdf‎.
      The same goes for script engines, plus the fact you need to give read (and perhaps some write or modify) permissions for anonymous users. You don’t want that near your OS :)

      Regards,
      Jan

  2. Hello Jan, great post. Will you do a follow up post on using the PHP opCache?
    I manage a few high-traffic volume websites and at this stage do not use caching at all
    as I dont know how best to implement opCache. My environment is IIS, PHP 5.5.14 on FastCGI.

    Thanks.

    1. Hi Dimitri, thank you for your comment and great to hear you liked it!

      You do know OPcache is opcode cache only and provides no user cache like APC or WinCache? Saotn.org is not that high volume, but runs OPcache (for opcode cache) with its default settings, and WinCache for other types of caches (user cache, or even session cache if I wanted to). SitePoint has a great OPcode post available at http://www.sitepoint.com/understanding-opcache/

      The PHP OPcache is easily enabled in the php.ini:

      [opcache]
      ; Determines if Zend OPCache is enabled
      opcache.enable=1

      and other configuration settings may be left to their defaults.

      Update: Almost exactly one year after your comment Dimitri, I created a post not about how to set up OPcache in PHP, but to optimize its configuration. You can find the article here:
      https://www.saotn.org/optimize-php-opcache-configuration/

Hi! Join the discussion, leave a reply!