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

php用作apache模块时,来自apache SetEnv指令的环境variables可用于php的getenv() ,但是它似乎不能通过stdlib的getenv()用于C扩展。 至less它发生在pgsql模块上。

如果variables重新用php代码实现:

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

那么它可以被扩展的代码使用。

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

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

它不依赖于具有E variables_order 。 我已经尝试了EGPCSGPCS ,并且当E不在那里时, $_ENV没有被填充,但是这不会像logging的那样改变getenv()的结果,或者显然是从stdlib的getenv()内部扩展。


演示pgsql模块的问题 。 它build立在用C编写的libpq共享库之上,它在几个可选的PG*环境variables上调用getenv()

在apacheconfiguration文件中,在<VirtualHost> ,我正在设置这个连接尝试失败:

 SetEnv PGHOST doesnotexist 

而不是在pg_connect调用中指定一个主机,所以当出现PGHOST必须采取。

先试试

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

结果:

 PGHOST = doesnotexist
连接成功。

所以尽pipe处于环境中, PGHOST也被忽略了。

第二次尝试 ,现在再次把PGHOST放到环境中,尽pipe它已经在那里了:

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

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

  PGHOST = doesnotexist
警告:pg_connect():无法连接到PostgreSQL服务器:
无法翻译主机名“doesnotexist”来解决:
在第8行的/var/www/test/pgtest2.php中未知的名称或服务

原因是这样的:

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

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

只有在没有找到匹配的情况下,才会检查实际进程的环境。 所以这就是为什么getenv()[PHP]返回一个值,但是getenv()[C]没有。

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