2012-11-01 180 views
21

注意:这也适用于超级用户。共享主机环境中的sys_get_temp_dir

我使用apache2 mpm itk和open_basedir以某种方式在共享主机上设置PHP 5.3.10,即每个用户可能不会看到或更改其他用户的文件。在apache2的虚拟主机设置,我添加相应的条目,以限制用户:

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,上传目录和会话savepath在用户目录中。我会在一秒内回到最后一行。

现在的问题:sys_get_temp_dir()应该返回临时目录为PHP,这是/ tmp默认在Linux系统上。出于安全原因,这个目录应该驻留在userA的open_basedir中。据5.3.10的PHP代码中,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()查看)。

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

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

我发现迄今是通过扩展覆盖内部sys_get_temp_dir()runkit和经由auto_prepend_file执行其包含唯一的解决办法。但是这个解决方案太脏了,我简直不敢相信,没有更好的解决方案。

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

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

+0

您正在使用哪个Apache版本? 2.0? 2.2? 2.4? – hakre

+1

只是被告知''open_basedir''可能会非常昂贵。我已经看到在open_basedir保护下,复杂CMS后端(TYPO3)的页面加载时间从3秒增加到> 50秒的情况。 – Jpsy

回答

21

运行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')将临时目录设置为您在问题中列出的目录结构。

够滑稽的,事实证明这也工作(因为你保持SetEnv TMPDIR /foo/bar在你的Apache配置):

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

似乎是一个空操作,但实际上确实sys_get_temp_dir()效果。我开始怀疑这必须是PHP中的一些环境处理错误。

+0

它不适合我(正如我在问题中写的,只是重新检查)。如果它适合你,你能否指定你正在使用的php和apache版本? – Lars

+0

我已经运行了Apache 2.2.17和PHP 5.3.16。测试代码:'<?php putenv('TMPDIR =/foo/bar'); print(sys_get_temp_dir());',在浏览器中输出'/ foo/bar'。 – lanzz

+0

自从我的5.3.10以来,这个函数没有任何改变 - 你在测试什么操作系统? – Lars

6

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

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

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

然后,你做的SetEnv使用:

SetEnv   TMPDIR   /home/userA/www/tmp/ 

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

所以更多的评论比真实的答案,但希望它可以帮助你澄清一些事情。

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


此外,您可能没有设置正确的环境变量。根据Apache Documentation about environment variables

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

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

mod_php的可能将其导入到脚本,因此,如果您使用getenv('TMPDIR')的PHP SAPI具体实现,则使用 - 这确实让你看到那些内部环境变量 - 但是php_get_temporary_directory功能不使用它 - 它看起来像。

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

+1

这显然是一个'mod_php'场景,否则没有模块会处理'php_admin_value'指令,并且Apache会在其配置中抱怨无效指令。 – lanzz

+1

这就是我写的,是'mod_php'场景。有趣的问题是,如何使用Apache通过'mod_php'调用的PHP脚本来反映环境变量。 – hakre

+1

'mod_php'执行的PHP脚本中的环境变量_is_;虽然''getenv('TMPDIR')'返回正确的值,但是'sys_get_temp_dir()'在执行'putenv('TMPDIR ='。getenv()')后只能看到正确的值, 'TMPDIR'))' – lanzz

5

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

  • ,你可以尝试使用仅修复了这个问题库(&打开一个错误,对于那些谁没有)
  • 或追加/tmp(或任何你的操作系统使用)在您的open_basedir,为it can hold multiple directories(像include_path - 与;在Windows上它分离出来,否则:
+0

感谢您的回答 - 不幸的是,多目录选项并不适用于我。我忘了在问题中提到这个可能的解决方案。 – Lars

+0

@pozs现在它*最终*固定:) – user11153

1

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

<?php 
putenv('TMPDIR=/path/to/your/tmp'); 
      ...your code here ... 
?> 
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)。

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

3

望着PHP sourcesys_get_temp_dir()适用于以下优先级:

  1. 如果它的价值已经被之前计算,用于缓存的值。
  2. sys_temp_dir在ini配置中被选中。
  3. 在Windows中,GetTempPathW Win32 API的方法被使用,并且根据它的文档被使用(以该顺序)执行以下操作:
    1. TMP环境变量指定的路径。
    2. 环境变量TEMP指定的路径。
    3. 环境变量USERPROFILE指定的路径。
    4. Windows目录。
  4. 在* nix中,使用(以该顺序)执行以下操作:
    1. TMPDIR环境变量。
    2. P_tmpdir
    3. /tmp(根据来源,这是最后一次应该不会发生的努力)。

这应该给你的控制sys_get_temp_dir除非先前计算(如ini_set('sys_temp_dir', $tmpPath)putenv('TMPDIR=/foo/bar')如其他人所说),在这种情况下,你作为SOL据我所知的结果足够的选择并且将使用缓存的值(但我在PHP中没有任何知识,所以很想听听)。