Today I realized, that handling temporary paths in PHP is not always very clear. I thought setting upload_tmp_dir and session.save_path in a virtual host would be enough to keep temporary files of vhosts separated and keep applications working.
Well at least in the past ~15 years of on and off work with PHP and with thousands of virtual hostings I never had any problems with the temporary paths in combination with open_basedir. Until today when someone wasn't able to write into the temp path because of an open_basedir restriction.
It turns out that the PHP script, wanting to create a temporary file, was using the function sys_get_temp_dir(). And this function always returned /tmp. I tested this with the following code:
$temp_file = sys_get_temp_dir();
The result always resulted in /tmp. Even when all the following settings were set for this virtual host:
upload_tmp_dir = /var/www/user/phptmp/
session.save_path = /var/www/user/phptmp/
As this didn't help, I even tried setting an Apache environment variable:
SetEnv TMPDIR /var/www/user/phptmp/
Although the env vars could be read by PHP (verified in phpinfo), none of that helped. The function sys_get_temp_dir() still read /tmp.
Unfortunately as this web server is still using PHP 5.3, this is not configurable. Only in PHP 5.5 a new option sys_temp_dir was added, as can be seen on http://php.net/manual/en/ini.list.php:
Name Default Changeable Changelog
sys_temp_dir "" PHP_INI_SYSTEM Available since PHP 5.5.0.
There are two workarounds to help in this scenario:
1) The PHP script/application shouldn't use sys_get_temp_dir() to define its own temporary path. It should rather read the value from upload_tmp_dir. If you programmed the script yourself, that shouldn't be much effort.
2) Adapt the open_basedir path to include /tmp.
As the affected web server still runs with PHP 5.3 and the script is part of a web application, I went for workaround 2 and added /tmp to the open_basedir value.