Подтвердить что ты не робот

Почему putenv() необходим для уже заданной переменной среды?

Когда php используется как модуль apache, переменная среды, исходящая из директивы apache SetEnv, доступна для php getenv(), но она не представляется доступной для C расширений через stdlib getenv(). По крайней мере, это происходит с модулем pgsql.

Если переменная повторно установлена ​​с помощью php-кода:

putenv("varname=".getenv("varname"));

тогда он становится доступным для кода расширения.

Вопрос: зачем нужна переустановка? Как основная среда php отличается от "стандартной" (stdlib) среды?

Это происходит с помощью PHP Version 5.3.10-1ubuntu3.17 в Ubuntu 12.04, в качестве модуля apache. При запуске из командной строки это обходное решение не требуется. Из этого другого вопроса: Использование .pgpass из Apache libphp5.so кажется, что это обходное решение также необходимо для php-5.4 под FreeBSD, поэтому это не просто Ubuntu или php-5.3.

Это не зависит от variables_order, имеющего E. Я пробовал как EGPCS, так и GPCS, а $_ENV не заполняется, если E не существует, как и ожидалось, но это не меняет результат getenv(), так как документально или, по-видимому, результат stdlib getenv() из внутренних расширений.


Демонстрация проблемы с помощью модуля pgsql. Он построен поверх общей библиотеки libpq, написанной в C, которая вызывает getenv() в нескольких необязательных переменных среды PG*.

В файле конфигурации apache, под <VirtualHost>, я устанавливаю это, чтобы попытки подключения не выполнялись:

SetEnv PGHOST doesnotexist

и не указывая хост в вызове pg_connect, поэтому PGHOST следует принимать, когда он присутствует.

Первая попытка:

$v=getenv("PGHOST");
echo "PGHOST=$v\n";

$cnx=pg_connect("user=daniel");
if ($cnx) {
   echo "Connection is successful.";
} 

Результат:

PGHOST=doesnotexist
Connection is successful.

Итак, PGHOST игнорируется, несмотря на то, что он находится в среде.

Вторая попытка, теперь снова помещая PGHOST в среду, даже если она уже существует:

$v=getenv("PGHOST");
echo "PGHOST=$v\n";
putenv("PGHOST=".getenv("PGHOST"));
$cnx=pg_connect("user=daniel");
if ($cnx) {
   echo "Connection is successful.";
} 

Результат (невозможность подключения к указанному хосту, как ожидалось):

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
4b9b3361

Ответ 1

Причина такова:

Значения среды, которые вы получаете от getenv()[PHP] (функция php), отличаются от среды, которую вы запрашиваете с помощью getenv()[C] (функция C lib). Что getenv()[PHP] делает, проверяет с зарегистрированным sapi для соответствия (http://lxr.php.net/xref/PHP_5_6/ext/standard/basic_functions.c#3999).

Apache2 sapi делает это через свой собственный контекст среды (http://lxr.php.net/xref/PHP_5_6/sapi/apache2handler/sapi_apache2.c#253), а не стандартную среду ОС из самого процесса apache.

ТОЛЬКО, когда найдено совпадение не найдено, оно будет проверяться в среде фактического процесса. Вот почему getenv()[PHP] возвращает значение, но getenv()[C] не делает.

Теперь "хак" также прост: putenv()[PHP] хранит заданный ключ/значение в среде запущенного процесса, поэтому его можно найти позже getenv()[C].