lundi 20 avril 2015

Why is putenv() needed on an already defined environment variable?

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

Aucun commentaire:

Enregistrer un commentaire