【问题标题】:How do I use putenv() to update existing environment variable?如何使用 putenv() 更新现有环境变量?
【发布时间】:2017-07-11 19:31:45
【问题描述】:

编辑:据我所知,我的问题是因为 PHP 存在缺陷。我已将此问题复制到此处的 PHP 错误跟踪器:https://bugs.php.net/bug.php?id=74143 并计划尝试实施修复。


putenv 函数设置环境变量的值。根据手册,putenv 成功返回 true,失败返回 false。

但是,我发现 putenv 函数有时会返回 true 而不更新当前会话的环境变量。

要重现此问题,请使用 fastcgi_param 指令在使用 PHP FPM 的网络服务器中设置环境变量。这非常有用,因为它允许将环境变量设置为与同一服务器上的其他主机隔离。

示例 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() 更新现有的环境变量?

【问题讨论】:

  • 我自己还没有看到这种行为。您是否尝试过先删除旧值? putenv("TESTVAR_ENV") 应该清除该值,或者尝试改用$_SERVER
  • 实际上,刚刚用 Nginx 和 PHP-FPM 测试了这个,而不是 CLI,我看到了同样的东西。
  • 您认为这是 PHP 还是 PHP-FPM 的错误?
  • 嗯,我刚刚在 Apache 中使用 mod_php 进行了尝试,得到了相同的行为。
  • php.net 页面显示Returns TRUE on success or FALSE on failure. 我无法说服自己“未能”更改现有 var 的值不是失败......这就是一个 php 缺陷。

标签: php environment-variables getenv


【解决方案1】:

这很有趣。经过调查,我发现getenv() 有一个undocumented parameter

调用putenv("TESTVAR_ENV=new-value") 后跟getenv("TESTVAR_ENV", true) 按预期返回new-value。但是 getenv("TESTVAR_ENV", true) 在没有先明确设置值的情况下调用时返回 false。

source 读取,似乎如果 local_only 设置为 false(默认值),则使用 sapi_getenv 获取值,而 local_only 设置为 true 使用原生 getenv

此外,如果sapi_getenv 没有返回值,则getenv 被称为后备。这意味着如果您根本没有在 nginx/Apache 配置中设置 TESTVAR_ENVputenv/getenv 将按预期工作。

回顾一下:

  • getenv(name) 从 SAPI 的 (php-fpm) 内部环境表中搜索,如果未设置变量,则回退到操作系统的环境。
  • getenv(name, true) 仅从操作系统环境中搜索,不一定(取决于 SAPI)包含在 Web 服务器配置中注册的变量。
  • 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";
}

【讨论】:

  • 感谢您对此的意见。我已经更新了 php.net 上的文档以反映这种行为,尽管我仍然认为功能可以有所改进。
  • 将 'true' 传递给 getenv 在 apache/error_log 中出现此错误:PHP Warning: getenv() expects exactly 1 parameter, 2 given
【解决方案2】:

您可以直接将新变量设置为$_ENV$_SERVER

/**
 * Return specified environment variable set in `.env` file
 */
function env(string $varname = '')
{
    return $varname ? $_ENV[$varname] : $_ENV;
}

/**
 * Set environment variable
 */
function setenv(string $key, string $value)
{
    return $_ENV[$key] = $value;
}

setenv("APP_ROOT_DIR", "YOUR_APPLICATION_ROOT_DIR"); // Sets the variable into $_ENV

echo env("APP_ROOT_DIR"); // Returns specified variable

print_r(env()); // Return the whole $_ENV array

或者:
你甚至可以使用这个包:PHP Environment variables manager (php dotenv)

【讨论】:

    猜你喜欢
    • 2022-01-09
    • 1970-01-01
    • 2017-10-18
    • 1970-01-01
    • 2015-09-29
    • 2013-10-29
    • 2019-09-03
    • 1970-01-01
    • 2021-10-25
    相关资源
    最近更新 更多