2017-02-21 29 views
8

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


Функция 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() для обновления существующей переменной среды?

+0

Я не видел такого поведения себя. Вы пытались сначала удалить старое значение? 'putenv (" TESTVAR_ENV ")' должен очистить значение или попробовать вместо этого использовать '$ _SERVER'? – miken32

+1

На самом деле, просто протестировал это с помощью Nginx и PHP-FPM, вместо CLI, и я вижу то же самое. – miken32

+0

Считаете ли вы, что это ошибка с PHP или PHP-FPM? – Greg

ответ

2

Это интересно. После расследования я обнаружил, что есть undocumented parameter для getenv().

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

Чтение из source кажется, что если local_only установлен в ложном (по умолчанию), значение выбирается с помощью sapi_getenv, в то время как с local_only значение ИСТИНА родной 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"; 
} 
+0

Спасибо за ваш ввод. Я обновил документацию на php.net, чтобы отразить это поведение, хотя по-прежнему считаю, что функциональность может быть несколько улучшена. – Greg