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 putenv() function sets the value of an environment variable by altering an existing variable or creating a new one. The varname parameter points to a string of the form var=x, where x is the new value for the environment variable var .
The difference to the setenv function is that the exact string given as the parameter string is put into the environment. If the user should change the string after the putenv call this will reflect automatically in the environment.
Using putenv() Using this function, you can set the value of an environment variable — and unset it — within the current request. In the next request, the variable, if set outside of the current request, will return to its original value.
Environment variables provide a good way to set application execution parameters that are used by processes that you do not have direct control over. However, environment variables should not be used for configuration values within your own dynamic applications. Environment variables are global variables.
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]
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With