为什么在已经定义的环境变量中需要putenv()? [英] Why is putenv() needed on an already defined environment variable?

查看:145
本文介绍了为什么在已经定义的环境变量中需要putenv()?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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

  putenv(varname =。getenv(varname)); 

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



问题:为什么重新进行必要?核心php环境与标准( stdlib )环境不同?作为一个apache模块,在Ubuntu 12.04中发生这种情况: PHP版本5.3.10-1ubuntu3.17 。从命令行运行时,上述解决方法不是必需的。
从另一个问题:使用.pgpass从Apache libphp5.so 看来,这种解决方法也是必要的php- 5.4在FreeBSD下,所以它不只是Ubuntu或php-5.3。



它不依赖于 variables_order code> E 中。我尝试过 EGPCS GPCS $ _ ENV E 不在预期中,但不会更改 getenv()的结果,如记录的,或者显然是stdlib的




问题演示

strong>与 pgsql 模块。它是建立在以 C 编写的 libpq 共享库之上,调用 getenv() 在一些可选的 PG * 环境变量。



在apache配置文件中,在< VirtualHost> 下,我设置此选项使连接尝试失败:

 code> SetEnv PGHOST不会删除

并且不指定 pg_connect 呼叫,所以 PGHOST 必须在存在时被采取。



尝试

  $ v = getenv(PGHOST); 
echoPGHOST = $ v\\\
;

$ cnx = pg_connect(user = daniel);
if($ cnx){
echo连接成功。
}

结果:

 
PGHOST = doesnotexist
连接成功。

所以 PGHOST 被忽略,尽管处于环境中。 >

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

  $ v = getenv(PGHOST); 
echoPGHOST = $ v\\\
;
putenv(PGHOST =。getenv(PGHOST));
$ cnx = pg_connect(user = daniel);
if($ cnx){
echo连接成功。
}

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

 PGHOST = doesnotexist 
警告:pg_connect():无法连接到PostgreSQL服务器:
无法将主机名doesnotexist转换为地址:
第8行/var/www/test/pgtest2.php中未知的名称或服务


解决方案

原因是这样的:



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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆