Paul Kiddie

Configuration methods in PHP to enable large uploads on a per-site basis

June 07, 2010

As dry as the subject of PHP configuration is, I thought a blog entry was necessary as I’ve just spent a fair bit of time digging around to find a way to configure PHP directives on a per-site basis. The mechanisms available vary based on the runtime environment and the method PHP runs.

My problem was to set PHP directives on a per site basis in order to enable large file uploads on a single web application running on the web server. I also wanted to modify the temporary upload folder PHP uses for file uploads, and enable file upload progress monitoring through the APC extension (preferrably only on the file uploader web app). The directives corresponding to these are in a number of different “modes”, so I was looking for a way that provided complete freedom over specifying the directives.

Depending on your PHP install and operating system there are several ways to customise your site’s PHP configuration. PHP itself can run in CGI mode, or as an Apache module. I’ll leave it to http://docs.joomla.org/Should_PHP_run_as_a_CGI_script_or_as_an_Apache_module%3F#What_is_the_difference_between_CGI_and_apache_Module_Mode.3F as it does a great job at explaining security and performance differences between PHP running in CGI or Apache module mode.

Determining your PHP runtime environment.

To determine the best way for configuring PHP on a per-site basis you’ll need to determine your PHP runtime environment (i.e. your operating system and whether PHP runs as a CGI or an Apache module). So, create a script that outputs your PHP runtime environment information:

<?php
phpinfo();
?>

You should then look at the “Server API” field, which will say something like “CGI/FastCGI” for PHP running as a CGI:

cgi

or “Apache Handler” for PHP running as an Apache module:

apache handler

Now we’ve identified the mode of operation, I’ll explain some general methods for customising PHP directives on a per-site basis:

General per-site configuration methods

This should work on PHP running in any environment (Linux/Windows/Mac/etc) as either an Apache module or CGI.

Use ini_set() (limited number of options available)

You can customise a limited number of PHP directives on a per-script basis, by adding ini_set() to the top of your scripts. You can adjust PHP_INI_USER directives within scripts. See http://uk.php.net/ini_set for more information on this.

Allow user defined INI files (greater number of options available)

Edit your php.ini to permit user defined .ini files, by looking for a field user_ini.filename (which might be currently commented out). Uncomment it and state the filename you want to use for the user defined .ini files (which by default is .user.ini).

Then, within your web application (e.g. C:\phpwebs\helloworld), create a new file called .user.ini and add in the directives to suit:

upload_max_filesize = 1024M post_max_size = 1500M

You can adjust PHP_INI_PERDIR and PHP_INI_USER directives in user defined INI files, which may or may not be enough. In my case, it was not, as I wanted to also update upload_tmp_dir, a PHP_INI_SYSTEM directive.

Define folder and directives in php.ini (most, if not all options available)

In this approach, you edit php.ini wherever it is located (see output from phpinfo() above), and at the end add your site-specific configuration, by specifying the folder that the web application resides in. Lets say our web app is located in C:\phpwebs\helloworld\. To configure the PHP runtime on this web app, add

\[PATH=C:/phpwebs/helloworld/\]
upload\_max\_filesize = 1024M
post\_max\_size = 1500M

At the end of php.ini.

Note virtually any directive can be customised on a per-site basis using this method, and this was the approach I went for when hosting a PHP web app on IIS to in order to adjust upload_tmp_dir for the uploader app. What I didn’t seem to be able to do was to enable some extension based directives on a per site basis. The progress meter failed when apc.rfc1867=on was specified under the per-site declaration, so I made this part of the global php.ini.

Per-site configuration options with PHP as a CGI in Windows IIS

Any of the general per-site configuration options mentioned above should work. You can also edit the registry to manage a subset of PHP directives, illustrated at http://www.php.net/manual/en/configuration.changes.php, in the section entitled ‘Changing PHP configuration via the Windows registry’. The process is as follows:

  • Open up regedit
  • Navigate to HKLM\SOFTWARE\PHP\Per Directory Values
  • Create keys corresponding to the directory hierarchy of your web app and at the child node specify the customised directives via New > String Value. Using our C:\phpwebs\helloworld\ example see the screenshot below for how you modify PHP directives:

registry

Note that you can customise only PHP_INI_USER directives in this manner.

Per-site configuration options with PHP as an Apache module

All-in-one *AMP stacks (such as XAMPP) mostly have PHP running as an Apache module. Any of the general per-site configuration options mentioned above should also work for PHP configured as an Apache module.

If your PHP install in running this way, you can also edit httpd.conf file to specify PHP directives for virtual hosts and additionally directories and subdirectories exposed by the virtual host.

To do this:

1. Ensure AllowOverride All in httpd.conf. This should reside in the conf folder in the Apache folder.

2. In XAMPP, virtual host declarations are containerised and are specified in <apache_dir>/conf/extra/http-vhosts.conf. In this file you would type the following:

DocumentRoot "C:/phpwebs/helloworld"
ServerName www.helloworld.com
php\_admin\_value upload\_tmp\_dir "C:\\tmp"
php\_value post\_max\_size 1500M
php\_value upload\_max\_filesize 1024M
php\_admin\_value apc.rfc1867 on

With this method you have complete freedom over which PHP directives you want to set. Valid apache directive syntax can be found at http://www.php.net/manual/en/configuration.changes.php.


👋 I'm Paul Kiddie, a software engineer working in London. I'm currently working as a Principal Engineer at trainline.