22

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

我正在使用 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/

现在,第一行设置用于 apache2 的 linux 用户,接下来的三行定义 basedir、上传目录和会话保存路径在用户目录中。稍后我会回到最后一行。

现在解决问题:sys_get_temp_dir()应该还给 php 的临时目录,在 linux 系统上默认为 /tmp。出于安全原因,此目录应位于 userA 的 open_basedir 中。根据5.3.10的php-source,sys_get_temp_dir()-function使用环境变量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 都有自己的临时文件夹。

到目前为止,我发现的唯一解决方案是通过runkitsys_get_temp_dir()之类的扩展覆盖内部,并通过auto_prepend_file强制包含它。但是那个解决方案太脏了,我简直不敢相信,周围没有更好的解决方案。

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

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

4

7 回答 7

23

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 中的一些环境处理错误。

于 2012-11-06T15:34:54.660 回答
6

You have tagged your question , however you are making use of

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

which is a setting for the apache module version of PHP, Mod_PHP. In that case PHP is loaded once the webserver starts.

Then you make use of SetEnv:

 SetEnv           TMPDIR            /home/userA/www/tmp/

this is setting an internal environment variable. It is passed to other apache modules, however I think you need it with the request, not with the virtual server. I don't know it specifically, but I would assume according to your description that this environment variable is getting reset before the PHP script is invoked.

So more a comment than a real answer, but hopefully it helps you clarify some things.

I normally use FCGI for multi-user environments so that I can better separate the users. I never had problems with setting environment variables per each user. But that's just another comment, I don't want to say you have to use it, too. Just to highlight that you need to find out the right place within apache to set the environment variable so it is (still) set when the script is executed.


Also you might not be setting the right environment variable. According to Apache Documentation about environment variables:

Although these variables are referred to as environment variables, they are not the same as the environment variables controlled by the underlying operating system. Instead, these variables are stored and manipulated in an internal Apache structure. They only become actual operating system environment variables when they are provided to CGI scripts and Server Side Include scripts. If you wish to manipulate the operating system environment under which the server itself runs, you must use the standard environment manipulation mechanisms provided by your operating system shell.

You want to set the operating system environment variable for PHP. But you are setting the internal environment variable only.

Mod_PHP might import them to the script, so if you use getenv('TMPDIR') the PHP SAPI specific implementation is used - which does allow you to see those internal environment variables - however the php_get_temporary_directory function is not using it - it looks like.

Please add your Apache and PHP version to your question.

于 2012-11-07T09:10:28.870 回答
5

根据这个 - 4 岁 - 错误sys_get_temp_dir()不适用于虚拟主机;所以

  • 您可以尝试仅使用已修复此问题的库(并为未修复的库打开错误)
  • 或在您的 中附加/tmp(或您的操作系统使用的任何内容)open_basedir,因为它可以包含多个目录(例如include_path-;在 Windows 上将其分隔,:否则)
于 2012-11-09T23:27:39.813 回答
4

查看PHP 源代码sys_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 所以很乐意听到其他)。

于 2017-08-20T21:50:17.533 回答
2

这是 php 5.2 中的一个错误 -通过 php.ini 指定临时目录
它在 5.5 中已修复
使用此作为临时解决方案:

<?php
putenv('TMPDIR=/path/to/your/tmp');
          ...your code here ...
于 2014-03-28T23:55:59.593 回答
1

万一人们最终来到这里,谁的问题没有用 putenv 解决......

...对我来说,它可以像这样设置sys_temp_dir使用 php ini_set

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

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

于 2014-06-04T08:48:52.400 回答
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.

于 2016-10-28T16:03:39.473 回答