Lately, I’ve noticed more and more shared web hosts making the switch to running PHP under suExec. The benefits of this are:

  • PHP scripts run as the owning user
  • No more file system permission juggling
  • Scripts are generally sandboxed to the owner’s home directory

Unfortunately, this poses a problem for any custom PHP configuration changes as the usual .htaccess php_flag and php_value properties are no longer supported. The recommended method of setting a custom configuration is to place a php.ini file under each directory where required.

This method works fine for any properties set in the custom php.ini file however there appears to be one devastating omission. Server configuration properties do not cascade into the custom file. What this means is that for any property not set in your custom file, PHP will revert to the PHP default.

For example, say your host has enabled PDO (as any decent host should). The instant you introduce a custom php.ini file, PDO will be lost. Sure, you could just include the relevant extension_dir and extension properties but consider this example (from my host)

extension_dir = "/usr/local/lib/php/extensions/no-debug-non-zts-20060613"

That property is awfully specific and your custom entry wouldn’t fare too well in the event of an upgrade.

In a perfect world, the host would have compiled PHP with the --with-config-file-scan-dir=/some/dir option that allows an environmentally settable directory to be scanned for additional config files. Unfortunately, this is rarely the case.

My solution is a little hacky and hardly perfect but it certainly gets the job done for me.

1. Create your custom.ini file with the options you want. Mine is /home/user/etc/php.d/custom.ini and looks like this

register_globals = Off
magic_quotes_gpc = Off

Do not name this file php.ini.

2. Locate your host’s php.ini file. This information is available from phpinfo(). In the below examples it is /usr/local/lib/php.ini

3. Add a cron job to create a full php.ini file in a location of your choosing (/home/user/etc/php.d) that is the concatenation of the server php.ini file and your custom.ini file. The below example is set to run hourly with any errors displayed on stdout which should be mailed to the crontab owner.

0 * * * * /usr/bin/test -f /usr/local/lib/php.ini && /bin/cat /usr/local/lib/php.ini /home/user/etc/php.d/custom.ini > /home/user/etc/php.d/php.ini || echo '/usr/local/lib/php.ini NOT FOUND'

The reason for the cron job is to keep your full, custom php.ini file in sync with any server changes. The job will also inform you in the unlikely event that the host php.ini file is moved.

If you’ve got shell access, you can create this file immediately by running

cat /usr/local/lib/php.ini /home/user/etc/php.d/custom.ini > /home/user/etc/php.d/php.ini

otherwise, wait for the hour to come around in which case your cron job should have done the work for you.

4. Add the following to your web application’s .htaccess file

SetEnv PHPRC /home/user/etc/php.d

The PHPRC environment variable informs any PHP scripts of the location of the preferred php.ini file.