IISUnderground - A help website for setting up Microsoft IIS

Securing PHP with the php.ini

This article will guide you through protecting your server from malicious PHP scripts and also allows you to run multiple sites with different configurations which is imperative in a multiple domain environment for security reasons.

Time to complete: ~15 minutes

Requirements: Working installation of IIS with PHP installed and at least 2 websites


1. Setting up a php.ini file

PHP arrives by default with 2 PHP.ini files. These are overly complex for a new user and ultimately not everything within it is needed. Here, we will use a stripped down version of a php.ini file which I have developed over several years for the “average” setup.

A default php.ini file:

; PHP.ini by Andrew Whyman from www.iisunderground.com
; 08/03/2013

; Time Zone
date.timezone = GMT

; Fast CGI fixes for IIS

; Base directories for htdocs, uploads and sessions
open_basedir = c:\sites\your_website\
;doc_root = c:\sites\your_website\
upload_tmp_dir = c:\sites\your_website\
; Double backslash the session save path. Remember to create the session folder.
; Option only applies when WinCache is not being used
session.save_path = c:\\sites\\sessions\\

; Extension Dir
extension_dir = "./ext/"

; These need disabling for php5.4 as they're deprecated
; You should never need to enable these if your scripts are secure
safe_mode = Off
register_long_arrays = Off
allow_call_time_pass_reference = Off
register_globals = Off

; Logging
log_errors = On
error_log = syslog

; Error Reporting
error_reporting  =  E_ALL & ~E_NOTICE
display_errors = On
display_startup_errors = Off

; Disable functions that could cause a security risk, comma separated
disable_functions = system,shell_exec,exec,escapeshellarg,escapeshellcmd,passthru,proc_ close,proc_ get_ status,proc_ open,proc_terminate

; Memory limits
max_execution_time = 60     ; Maximum execution time of each script, in seconds
max_input_time = 60	; Maximum amount of time each script may spend parsing request data
;max_input_nesting_level = 64 ; Maximum input variable nesting level
memory_limit = 64M      ; Maximum amount of memory a script may consume (128MB)
post_max_size = 8M

; Sendmail / mail()
SMTP = localhost
smtp_port = 25
;sendmail_from = user@domain.com

; File Uploads
file_uploads = On
upload_max_filesize = 100M

; fopen wrappers
allow_url_fopen = On
allow_url_include = On
default_socket_timeout = 10

; Extensions

; WinCache

; More info http://us2.php.net/manual/en/wincache.configuration.php

; To use these make sure the WinCache DLL is enabled

; Enable WinCache?
; If you disable WinCache be sure to set the session.save_handler to "files"
wincache.fcenabled = 0

; Defines a comma-separated list of IIS web site identifiers where file cache should be enabled or disabled.
wincache.fcenabledfilter = 

; Defines the maximum memory size (in megabytes, default 24) that is allocated for the file cache.
; If the total size of all the cached files exceeds the value specified in this setting,
; then most stale files will be removed from the file cache.
wincache.fcachesize = 24

; Enables or disables the file change notification detection functionality.
wincache.fcndetect = 1

; Defines the maximum allowed size (in kilobytes, default 256) for a single file to be cached.
; If a file size exceeds the specified value, the file will not be cached.
; This setting applies to the file cache only.
wincache.maxfilesize = 256

; Enables or disables the opcode cache functionality
wincache.ocenabled = 1

; Defines a comma-separated list of IIS web site identifiers where opcode cache should be enabled or disabled. 
wincache.ocenabledfilter = 

; Defines the maximum memory size (in megabytes, default 96) that is allocated for the opcode cache.
; If the cached opcode size exceeds the specified value, then most stale opcode will be removed from the cache.
; Note that the opcode cache size must be at least 3 times bigger than file cache size.
; If that is not the case the opcode cache size will be automatically increased.
wincache.ocachesize = 96

; Defines how many files (default 4096) are expected to be cached by the extension, so that appropriate memory size is allocated at the startup time. 
wincache.filecount = 4096

; Defines how often (in seconds, default 30) the extension checks for file changes in order to refresh the cache.
; Setting it to 0 will disable the refreshing of the cache.
wincache.chkinterval = 600

; Defines the maximum time to live (in seconds, default 1200) for a cached entry without being used.
; Setting it to 0 will disable the cache scavenger, so the cached entries will never be removed
; from the cache during the lifetime of the IIS worker process.
wincache.ttlmax = 1200

; Defines if caching is enabled when PHP is running in command line (CLI) mode.
wincache.enablecli = 0

; Defines a list of files that should not be cached by the extension.
; The files list is specified by using file names only, separated by the pipe symbol - "|".
; E.g. wincache.ignorelist = "index.php|misc.php|admin.php"
wincache.ignorelist = 

; Defines a string that will be used when naming the extension specific objects that are stored in shared memory.
; This is used to avoid conflicts that may be caused if other applications within an IIS worker process tries
; to access shared memory. The length of the namesalt string cannot exceed 8 characters.
wincache.namesalt = 

; Enables or disables the user cache functionality.
wincache.ucenabled = 1

; Defines the maximum memory size in megabytes (default 8) that is allocated for the user cache.
wincache.ucachesize = 8

; Defines the maximum memory size in megabytes that is allocated for the session cache.
wincache.scachesize = 8

; Specifies an absolute or a relateve path to the reroute.ini file that contains the list of PHP functions whose
; implementation should be replaced with the WinCache function equivalents.
wincache.rerouteini = 

;; ####
;; Don't edit these unless you know what you're doing!
;; ####

; Sessions
; "files" - save to files
; "wincache" - use WinCache
session.save_handler = files
session.use_cookies = 1
session.name = PHPSESSID
session.cache_limiter = nocache
session.cache_expire = 180

; Default MIME-TYPE
default_mimetype = "text/html"

; Allow


There are several items that we will need to amend before it is ready for use on your server.

– Copy and paste the text in the box above into a new text file.

– Inside your PHP folder, create a folder called ‘ini’.

Save the text file inside the ini folder you just created.

Rename the file to the name of your website. For example ‘yourdomain.com.ini’.

– Open the file in your favourite text editor.


From here, we now need to change some settings in the php.ini to suit your setup.


date.timezone = GMT

Change this to your time zone. Here is a link to a list of valid time zones: Time Zones.

You will need to do this to make sure the time and date is correctly reported to PHP scripts.


; Base directories for htdocs, uploads and sessions
open_basedir = c:\sites\your_website\
;doc_root = d:\public_html\iisunderground\
upload_tmp_dir = c:\sites\your_website\
; Double backslash the session save path
; Option only applies when WinCache is not being used
session.save_path = c:\\sites\\sessions\\

Change the above paths to the location of your website root folder. The session.save_path must have double backslashes, so don’t forget. Also be sure to create the sessions folder. You should not store the sessions folder inside your web accessible folder for security reasons.

These directories are used to prevent scripts from accessing locations outside of their web accessible folders. The defined folder is the “lowest” they can go. They can go forward  directories but not backwards beyond this set folder.


; Sendmail / mail()
SMTP = localhost
smtp_port = 25
;sendmail_from = user@domain.com

Change SMTP to the host you wish to use for e-mail. Normally this will stay at the default ‘localhost’ if you are using a mail server on your system.

Change SMTP port to the port the mail server SMTP service uses. The default is 25 and normally won’t need to be changed.

Un-comment sendmail_from (removing the semi-colon) if you intend to use a global address to send mail from. Lots of sites will use noreply@domain.com.


; Extensions

There are lots of extensions to choose from here (which I won’t list). If you ever find that your scripts tell you an extension or function is not available, you can often un-comment the extension (remove the semi-colon) here, save the file and restart IIS to get it working. The defaults enabled already will get you going for most applications.


; Enable WinCache?

; If you disable WinCache be sure to set the session.save_handler to "files"
wincache.fcenabled = 0

WinCache is an extension for IIS that enables caching of PHP scripts. This allows them to run up to 5-10x faster than normal. There will be a tutorial in the future on how to install this.

To enable WinCache, follow the installation tutorial and then set this extension to ‘1’ (enabled) rather than ‘0’ (disabled).

The default settings will get you moving. If you ever come back to developing a site, you may need to disable WinCache to avoid the script being cached while you work on it. WinCache is designed for production systems only when using long cache time periods.


– Once you are done editing, save the file and note down it’s full location.


2. Configuring IIS to accept the new php.ini

The php.ini is now ready to be configured into IIS.

– Open the IIS Manager from Start > Control Panel / Administrative Tools / IIS Manager.

– On the left hand side, select your website from the sites list.

– From the icons, select Handler Mappings just as you would for installing PHP.

Find your php handler mapping in the list and double click it.

– Under the executable box, you will have your PHP executable location. We need to edit it to include your php.ini file:


Example: c:\php\php-cgi.exe|-c c:\php\ini\your_website.com.ini
The '-c' modifier tells PHP to load a custom php.ini file.

– Using the above example, modify it to your PHP location and your php.ini location. – Once you are done, click OK.

3. Test your configuration

Your modified php.ini is now installed. All that is left to do is test your website to make sure it is working as intended. To do this, create a php file and include the following code:

<?php phpinfo(); ?>

Save it to your web accessible folder and then navigate to it in your browser. Check that the Loaded Configuration File location matches the one you put into the php handler mapping. If it matches then your configuration was successful.

An example of a PHPInfo page


4. Repeat for each of your sites

For each site you have now or create in the future, follow this process to make sure it has it’s own php.ini file. This ensures it will be secure and if you are hosting others, it makes sure they can’t access other peoples files by locking them down into their own folders.