How to use putenv () to update an existing environment variable?

Edit: as far as I can tell, my question is due to a defect in PHP. I copied this question to the PHP error tracker here: https://bugs.php.net/bug.php?id=74143 and plan to try and implement the fix.


The putenv function sets the value of an environment variable. According to the manual, putenv returns true on success, false on error.

However, I found that the putenv function sometimes returns true without updating the environment variable for the current session.

To reproduce this problem, set the environment variable on the web server using PHP FPM using the fastcgi_param directive. This is incredibly useful because it allows you to configure environment variables in isolation from other hosts on the same server.

Example nginx.conf:

location ~ \.php$ { fastcgi_pass unix:/var/run/php/php7.0-fpm.sock; fastcgi_param TESTVAR_ENV old-value; include fastcgi_params; } 

Example test.php:

 var_dump(getenv("TESTVAR_ENV")); var_dump(putenv("TESTVAR_ENV=new-value")); var_dump(getenv("TESTVAR_ENV")); 

The output of test.php:

 string(12) "old-value" bool(true) string(12) "old-value" 

As you can see:

  • an existing value is read by getenv successfully,
  • putenv function returns true, indicating success,
  • a new value is not actually set, which is incredibly confusing.

Do I really not understand what is the purpose of the putenv function? Is there any missing documentation on the setenv man page? How to use putenv () to update an existing environment variable?

+8
php environment-variables getenv
source share
1 answer

It is interesting. After investigating, I found that there is an undocumented parameter for getenv() .

A call to putenv("TESTVAR_ENV=new-value") , followed by getenv("TESTVAR_ENV", true) , returns new-value , as expected. However, getenv("TESTVAR_ENV", true) returns false when called without explicitly setting the value first.

Reading from the source it seems that if local_only is set to false (the default), the value is selected using sapi_getenv , while with local_only set to true, native getenv .

In addition, if sapi_getenv does not return a value, then getenv is called as a reserve. Value, if you do not set TESTVAR_ENV in the nginx / Apache configuration at all, putenv / getenv works as putenv .

So, to repeat:

  • getenv(name) searches from the table of the internal SAPI environment (php-fpm) and returns to the OS environment if the variable is not set.
  • getenv(name, true) searches only from the OS environment, which optionally (depending on SAPI) contains variables registered in the web server configuration.
  • putenv() always updates only the OS.

I used the following to verify this:

 header("Content-Type: text/plain"); dump_env(); echo 'getenv("TESTVAR_ENV") => ' . var_export(getenv("TESTVAR_ENV"), true) . "\n"; echo 'getenv("TESTVAR_ENV", true) => ' . var_export(getenv("TESTVAR_ENV", true), true) . "\n"; echo "-----------\n"; echo 'putenv("TESTVAR_ENV=new-value") => ' . var_export(putenv("TESTVAR_ENV=new-value"), true) . "\n"; dump_env(); echo 'getenv("TESTVAR_ENV") => ' . var_export(getenv("TESTVAR_ENV"), true) . "\n"; echo 'getenv("TESTVAR_ENV", true) => ' . var_export(getenv("TESTVAR_ENV", true), true) . "\n"; function dump_env() { echo "--- env ---\n" . `env` . "-----------\n"; } 
+2
source share

All Articles