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

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

问题描述

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

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