为什么putenv()函数需要对已定义的环境变量? [英] Why is putenv() needed on an already defined environment variable?
问题描述
在 PHP
被用作阿帕奇
模块,环境变量从Apache SETENV
指令是提供给PHP的的getenv()
,但它似乎并没有提供给 C
通过STDLIB的 getenv的扩展()
。至少它与情况的pgsql
模块。
如果变量被重新实例与PHP code:
传给putenv(VARNAME =GETENV(VARNAME)。);
那么它就变成可供扩展的code。
问题:为什么是必要的,重新实例?如何为核心的PHP环境从标准( STDLIB
)的环境不同?
这发生: PHP版本5.3.10-1ubuntu3.17
在Ubuntu 12.04,作为Apache模块。当从命令行运行,上述解决办法是没有必要的。
从这另一个问题:来自Apache使用.pgpass libphp5.so 的看来,这种解决方法也是必要的PHP-5.4在FreeBSD下使它不只是Ubuntu的或php-5.3。
它不依赖于的variables_order
有电子
在里面。我都试过 EGPCS
和 GPCS
和 $ _ ENV
不填充时电子
是不存在的,符合市场预期,但是这并不能改变 GETENV的结果()
,因为记录或STDLIB的显然结果的getenv()
从内扩展。
问题与的pgsql
模块的演示。它是建立在写在 C中的
,要求的libpq
共享库的顶部的getenv()
上可选的 PG一把*
环境变量。
在Apache配置文件,下<虚拟主机>
,我设置这使连接尝试失败:
SETENV PGHOST doesnotexist
和不指定在 pg_connect
呼叫主机,所以 PGHOST
必须采取时present。
第一次尝试
$ V = GETENV(PGHOST);
回声PGHOST = $ V \\ N的;$ CNX = pg_connect(用户=丹尼尔);
如果($ CNX){
回声连接成功。
}
结果:
PGHOST = doesnotexist
连接成功。
所以 PGHOST
是越来越被忽略,尽管在环境之中。
第二个尝试,现在又开始把 PGHOST
进入,即使它已经存在的环境:
$ V = GETENV(PGHOST);
回声PGHOST = $ V \\ N的;
传给putenv(PGHOST =GETENV(PGHOST)。);
$ CNX = pg_connect(用户=丹尼尔);
如果($ CNX){
回声连接成功。
}
结果(未能连接到指定的主机,如预期):
PGHOST = doesnotexist
警告:pg_connect():无法连接到PostgreSQL服务器:
不能将主机名doesnotexist应对:
名称或服务/var/www/test/pgtest2.php不知道在第8行
原因是这样的:
环境值从的getenv()得到[PHP]
(PHP函数),比你用 getenv的查询环境的不同() [C]
(的C LIB功能)。什么的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]
没有。
现在,黑客是一个简单的还有: putenv()函数[PHP]
,在运行过程中的环境中存储给定的键/值,这就是为什么它可以通过 GETENV(后来上找到)[C]
。
When php
is used as an apache
module, an environment variable coming from an apache SetEnv
directive is available to php's getenv()
, but it does not appear to be available to C
extensions through stdlib's getenv()
. At least it happens with the pgsql
module.
If the variable is reinstantiated with the php code:
putenv("varname=".getenv("varname"));
then it becomes available to the extension's code.
The question: why is that reinstantiation necessary? How is the core php environment distinct from the "standard" (stdlib
) environment?
This occurs with: PHP Version 5.3.10-1ubuntu3.17
in Ubuntu 12.04, as an apache module. When run from the command line, the above workaround is not necessary.
From this other question: Using .pgpass from Apache libphp5.so it appears that this workaround is also necessary for php-5.4 under FreeBSD so it's not just Ubuntu or php-5.3.
It doesn't depend on variables_order
having E
in it. I've tried both EGPCS
and GPCS
, and $_ENV
is not populated when E
is not there, as expected, but that doesn't change the result of getenv()
, as documented, or apparently the result of stdlib's getenv()
from inside extensions.
Demo of the problem with the pgsql
module. It's built on top of the libpq
shared library written in C
, which calls getenv()
on a handful of optional PG*
environment variables.
In apache configuration file, under a <VirtualHost>
, I'm setting this to make connection attempts fail:
SetEnv PGHOST doesnotexist
and not specifying a host in the pg_connect
call, so PGHOST
must be taken when present.
First try:
$v=getenv("PGHOST");
echo "PGHOST=$v\n";
$cnx=pg_connect("user=daniel");
if ($cnx) {
echo "Connection is successful.";
}
Result:
PGHOST=doesnotexist Connection is successful.
So PGHOST
is getting ignored, despite being in the environment.
Second try, now putting again PGHOST
into the environment even though it's already there:
$v=getenv("PGHOST");
echo "PGHOST=$v\n";
putenv("PGHOST=".getenv("PGHOST"));
$cnx=pg_connect("user=daniel");
if ($cnx) {
echo "Connection is successful.";
}
Result (failure to connect to the specified host, as expected):
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
The reason is this:
The environment values you get from getenv()[PHP]
(the php function) are different than the environment you query with getenv()[C]
(the C lib function). What getenv()[PHP]
does, is checking with the registered sapi for a match (http://lxr.php.net/xref/PHP_5_6/ext/standard/basic_functions.c#3999).
The apache2 sapi does this through its own environment context (http://lxr.php.net/xref/PHP_5_6/sapi/apache2handler/sapi_apache2.c#253), not the standard OS environment from the apache process itself.
ONLY when there is no match found, it will check at the environment of the actual process. So this is why getenv()[PHP]
returns a value, but getenv()[C]
does not.
Now, the "hack" is a simple one as well: putenv()[PHP]
, stores the given key/value in the environment of the running process, which is why it can be found later on by getenv()[c]
.
这篇关于为什么putenv()函数需要对已定义的环境变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!