Как использовать putenv() для обновления существующей переменной среды?

Редактировать: насколько я могу судить, мой вопрос связан с дефектом в PHP. Я скопировал этот вопрос в средство отслеживания ошибок PHP здесь: https://bugs.php.net/bug.php?id=74143 и запланируйте внедрение исправления.


Функция putenv устанавливает значение переменной среды. Согласно руководству, putenv возвращает true в случае успеха и false в случае неудачи.

Однако я обнаружил, что функция putenv иногда возвращает значение true без обновления переменной среды для текущего сеанса.

Чтобы воспроизвести эту проблему, установите переменную среды на веб-сервере с помощью PHP FPM с помощью директивы fastcgi_param. Это невероятно полезно, так как позволяет устанавливать переменные среды изолированно от других хостов на том же сервере.

Пример nginx.conf:

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

Пример test.php:

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

Вывод test.php:

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

Как вы видете:

  1. существующее значение успешно читается getenv,
  2. функция putenv возвращает true, указывая на успех,
  3. новое значение на самом деле не установлено, что невероятно сбивает с толку.

Я неправильно понимаю, какова цель функции putenv? На странице руководства setenv отсутствует какая-либо документация? Как использовать putenv() для обновления существующей переменной среды?


person Greg    schedule 21.02.2017    source источник
comment
Сам я такого поведения не видел. Вы пробовали сначала удалить старое значение? putenv("TESTVAR_ENV") следует очистить значение или, может быть, вместо этого попробовать использовать $_SERVER?   -  person miken32    schedule 22.02.2017
comment
На самом деле, только что проверил это с Nginx и PHP-FPM вместо CLI, и я вижу то же самое.   -  person miken32    schedule 22.02.2017
comment
Как вы думаете, это ошибка PHP или PHP-FPM?   -  person Greg    schedule 22.02.2017
comment
Что ж, я только что попробовал это в Apache с mod_php и получил такое же поведение.   -  person miken32    schedule 22.02.2017
comment
Использование $_SERVER работает, как и ожидалось.   -  person miken32    schedule 22.02.2017
comment
На странице php.net написано Returns TRUE on success or FALSE on failure. Я не могу убедить себя, что не изменить значение существующей переменной - это что-то иное, чем сбой... что делает это дефектом php.   -  person user1180316    schedule 22.02.2017


Ответы (1)


Это интересно. После изучения я обнаружил, что есть недокументированный параметр для getenv().

Вызов putenv("TESTVAR_ENV=new-value") с последующим getenv("TESTVAR_ENV", true) возвращает new-value, как и ожидалось. Однако getenv("TESTVAR_ENV", true) возвращает false при вызове без предварительной явной установки значения.

Чтение из источника кажется, что если для local_only задано значение false (по умолчанию), значение извлекается с использованием sapi_getenv, тогда как если для local_only установлено значение true, используется собственный getenv.

Кроме того, если sapi_getenv не возвращает значение, то getenv вызывается как запасной вариант. Это означает, что если вы вообще не установите TESTVAR_ENV в конфигурации nginx/Apache, putenv/getenv будет работать как положено.

Итак, резюмируя:

  • getenv(name) выполняет поиск в таблице внутренней среды SAPI (php-fpm) и откатывается к среде ОС, если переменная не установлена.
  • getenv(name, true) ищет только из среды ОС, которая не обязательно (в зависимости от SAPI) содержит переменные, зарегистрированные в конфигурации веб-сервера.
  • putenv() всегда обновляет только среду ОС.

Я использовал следующее, чтобы проверить это:

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";
}
person Joe    schedule 22.02.2017
comment
Спасибо за ваш вклад в это. Я обновил документацию на php.net, чтобы отразить это поведение, хотя я все еще думаю, что функциональность может быть несколько улучшена. - person Greg; 25.02.2017
comment
передача «true» в getenv дает эту ошибку в apache/error_log: PHP Warning: getenv() expects exactly 1 parameter, 2 given - person Danny; 13.08.2018