为什么在已经定义的环境变量上需要 putenv()?

当用作模块时,来自apache指令的环境变量可用于php的,但它似乎不能通过stdlib的扩展使用。至少它发生在模块上。phpapacheSetEnvgetenv()Cgetenv()pgsql

如果使用 php 代码重新验证变量:

putenv("varname=".getenv("varname"));

然后它可用于扩展的代码。

问题是:为什么有必要重新证实?核心 php 环境与“标准”() 环境有何不同?stdlib

这发生在:在Ubuntu 12.04中,作为apache模块。从命令行运行时,不需要上述解决方法。从另一个问题:使用Apache的.pgpass libphp5.so 似乎这个解决方法对于FreeBSD下的php-5.4也是必要的,所以它不仅仅是Ubuntu或php-5.3。PHP Version 5.3.10-1ubuntu3.17

它不依赖于其中。我已经尝试了和,并且正如预期的那样,当不存在时不会填充,但这不会改变,如文档所述,或者显然是内部扩展的stdlib的结果。variables_orderEEGPCSGPCS$_ENVEgetenv()getenv()


模块问题的演示。它建立在 编写在 的共享库之上,该库调用了一些可选的环境变量。pgsqllibpqCgetenv()PG*

在apache配置文件中,在a下,我将其设置为使连接尝试失败:<VirtualHost>

SetEnv PGHOST doesnotexist

而不是在呼叫中指定主机,因此必须在存在时采取。pg_connectPGHOST

第一次尝试

$v=getenv("PGHOST");
echo "PGHOST=$v\n";

$cnx=pg_connect("user=daniel");
if ($cnx) {
   echo "Connection is successful.";
} 

结果:

PGHOST=doesnotexist
Connection is successful.

被忽视也是如此,尽管在环境中。PGHOST

第二次尝试,现在再次放入环境中,即使它已经存在:PGHOST

$v=getenv("PGHOST");
echo "PGHOST=$v\n";
putenv("PGHOST=".getenv("PGHOST"));
$cnx=pg_connect("user=daniel");
if ($cnx) {
   echo "Connection is successful.";
} 

结果(无法按预期连接到指定的主机):

PGHOST=doesnotexist
Warning: pg_connect(): Unable to connect to PostgreSQL server:
could not translate host name "doesnotexist" to address:
Name or service not known in /var/www/test/pgtest2.php on line 8

答案 1

原因是这样的:

您从中获取的环境值(php 函数)与您查询时使用的环境(C lib 函数)不同。做什么,是与注册的sapi检查匹配(http://lxr.php.net/xref/PHP_5_6/ext/standard/basic_functions.c#3999)。getenv()[PHP]getenv()[C]getenv()[PHP]

apache2 sapi通过其自己的环境上下文(http://lxr.php.net/xref/PHP_5_6/sapi/apache2handler/sapi_apache2.c#253)来实现这一点,而不是apache进程本身的标准操作系统环境。

仅当未找到匹配项时,才会在实际过程的环境中进行检查。因此,这就是返回值但不返回值的原因。getenv()[PHP]getenv()[C]

现在,“hack”也是一个简单的:,将给定的键/值存储在正在运行的进程的环境中,这就是为什么以后可以找到它的原因。putenv()[PHP]getenv()[c]


答案 2

推荐