共享主机环境中的sys_get_temp_dir

时间:2012-11-01 21:50:31

标签: php apache2 cgi shared-hosting

注意:这也适合超级用户。

我在apache2 mpm itk和open_basedir的共享主机上设置PHP 5.3.10,每个用户可能看不到或更改其他用户的文件。在apache2 vhost设置中,我添加了相应的条目来限制用户:

    AssignUserId     userA userA
    php_admin_value  open_basedir      /home/userA/www/
    php_admin_value  upload_tmp_dir    /home/userA/www/tmp/
    php_admin_value  session.save_path /home/userA/www/tmp/
    SetEnv           TMPDIR            /home/userA/www/tmp/

现在,第一行将linux用户设置为用于apache2,接下来的三行将basedir,upload目录和session savepath定义在用户目录中。我会在一秒钟内回到最后一行。

现在出现问题:sys_get_temp_dir()应该回放php的临时目录,这是/ tmp在linux系统上的默认目录。出于安全原因,此目录应驻留在userA的open_basedir中。根据5.3.10的php-source,sys_get_temp_dir() - 函数使用环境变量TMPDIR来获取这个目录:

     // php-src/main/php_open_temporary_file.c:217-219
     /* On Unix use the (usual) TMPDIR environment variable. */
     {
             char* s = getenv("TMPDIR");

这就是上面配置中的第五行应该做的事情。但是,sys_get_temp_dir()只返回全局系统目录,忽略环境变量(在$ _SERVER中完美设置,也可通过phpinfo()查看)。

由于该目录不在sys_get_temp_dir()设置,因此会导致一些令人讨厌的错误,其中各种软件都依赖于open_basedir。我试图将变量直接设置为$ _ENV和$ _SERVER而不改变行为。我试过了putenv('TMPDIR=/home/userA/www/tmp')而没有改变。

但是,我可以通过将变量定义到/ etc / apache2 / envvars来更改输出 - 这对我来说没用,因为我希望每个VHOST都有自己的临时文件夹。

到目前为止,我找到的唯一解决方案是通过runkit这样的扩展程序覆盖内部sys_get_temp_dir(),并通过auto_prepend_file强制将其包含在内。但是这个解决方案太脏了,我简直无法相信,周围没有更好的解决方案。

所以,我的问题:有没有办法在apache2 vhost设置中更改sys_get_temp_dir()的结果,而不用runkit重新实现该功能?

编辑: apache版本是2.2.22,我目前使用的是mod_php。由于我必须手动添加所有用户,因此也可以使用fcgi或类似设置。

7 个答案:

答案 0 :(得分:22)

在内部运行putenv('TMPDIR=/foo/bar') PHP似乎能够影响sys_get_temp_dir()的结果。你可以安排一个auto_prepend_file指令来运行一段PHP来设置TMPDIR并避免弄乱sys_get_temp_dir()的重新定义。

编辑此外,您可以轻松使用putenv('TMPDIR='.ini_get('open_basedir').'/tmp')将临时目录设置为您在问题中列出的目录结构。

有趣的是,这也是有用的(假设您在Apache配置中保留SetEnv TMPDIR /foo/bar):

putenv('TMPDIR='.getenv('TMPDIR'));

看起来像是无操作,但实际上确实sys_get_temp_dir()有效。我开始怀疑这必须是PHP中的一些环境处理错误。

答案 1 :(得分:6)

您已标记了问题,但是您正在使用

 php_admin_value  open_basedir      /home/userA/www/
 ^^^^^^^^^^^^^^^

这是PHP的apache模块版本的设置, Mod_PHP 。在这种情况下,一旦Web服务器启动就会加载PHP。

然后你使用SetEnv

 SetEnv           TMPDIR            /home/userA/www/tmp/

这是设置内部环境变量。它被传递给其他apache模块,但我认为你需要它与请求,而不是虚拟服务器。我不是特别了解它,但我会根据你的描述假设这个环境变量在调用PHP脚本之前被重置。

更多的评论而不是真正的答案,但希望它可以帮助你澄清一些事情。

我通常将FCGI用于多用户环境,以便我可以更好地分离用户。我从未遇到过为每个用户设置环境变量的问题。但这只是另一个评论,我不想说你也必须使用它。只是为了强调你需要在apache中找到正确的位置来设置环境变量,以便在脚本执行时(仍然)设置它。


您也可能没有设置正确的环境变量。根据{{​​3}}:

  

虽然这些变量称为环境变量,但它们与底层操作系统控制的环境变量不同。相反,这些变量在内部Apache结构中存储和操作。它们仅在提供给CGI脚本和服务器端包含脚本时才成为实际的操作系统环境变量。如果您希望操作服务器本身运行的操作系统环境,则必须使用操作系统shell提供的标准环境操作机制。

您想为PHP设置操作系统环境变量。但是您只设置内部环境变量。

Mod_PHP 可能会将它们导入脚本,因此如果您使用getenv('TMPDIR'),则使用PHP SAPI特定实现 - 这允许您查看这些内部环境变量 - 但php_get_temporary_directory {{} 1}}函数没有使用它 - 看起来像。

请将您的Apache和PHP版本添加到您的问题中。

答案 2 :(得分:5)

根据this - 4 year old - bugsys_get_temp_dir()不适用于虚拟主机;所以

  • 您可以尝试仅使用修复此问题的库(并为没有修复此问题的人打开错误)
  • 或将/tmp(或操作系统使用的任何内容)附加到open_basedirit can hold multiple directories(如include_path - 在Windows上将其与;分开, :否则)

答案 3 :(得分:4)

查看PHP sourcesys_get_temp_dir()使用以下优先级:

  1. 如果之前已计算过其值,则使用缓存值。
  2. 在ini配置中检查了
  3. sys_temp_dir
  4. 在Windows上,使用GetTempPathW Win32 API方法,并根据其文档使用以下内容(按此顺序):
    1. TMP环境变量指定的路径。
    2. TEMP环境变量指定的路径。
    3. USERPROFILE环境变量指定的路径。
    4. Windows目录。
  5. 在* nix中,使用以下内容(按此顺序):
    1. TMPDIR环境变量。
    2. P_tmpdir
    3. /tmp(根据消息来源,这是一个不应该发生的最后努力)。
  6. 这应该为您提供足够的选项来控制sys_get_temp_dir的结果(例如ini_set('sys_temp_dir', $tmpPath)putenv('TMPDIR=/foo/bar'),如其他人提到的那样)除非以前计算过,否则据我所知,在哪种情况下你会使用SOL,并且会使用缓存的值(但我对PHP没有任何知识,所以我很乐意听到其他情况)。

答案 4 :(得分:2)

这是php 5.2中的一个错误 - specify temp dir by php.ini
它固定在5.5
使用此作为临时解决方案:

<?php
putenv('TMPDIR=/path/to/your/tmp');
          ...your code here ...
?>

答案 5 :(得分:1)

万一人们到这里来了,问题没有用putenv解决......

...对我来说,使用php ini_set设置sys_temp_dir是这样的:

$tmpPath = realpath(__DIR__.'/../app/tmp');
ini_set('sys_temp_dir', $tmpPath);

我在windows8机器上运行PHP 5.5.9(cli)。

答案 6 :(得分:0)

看起来您可以更改sys_get_temp_dir()返回的值,我刚刚尝试过apache 2.4和php 5.6.27。

在虚拟主机中添加sys_temp_dir

php_admin_value sys_temp_dir "/var/www/alternc/f/fser/tmp"

重新启动apache,并使用sys_get_temp_dir()

在网页中打印该值
<?php 
echo sys_get_temp_dir () ;

产生预期的输出:/var/www/alternc/f/fser/tmp