如何使用putenv()更新现有的环境变量?

17

编辑:据我所知,我的问题是由于PHP的缺陷引起的。我已将此问题复制到PHP错误跟踪器中:https://bugs.php.net/bug.php?id=74143,并计划尝试实现修复。


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

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

要重现此问题,请使用PHP FPM在Web服务器中设置一个环境变量,方法是使用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()更新现有环境变量?


您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - miken32
1
实际上,我刚刚使用Nginx和PHP-FPM进行了测试,而不是CLI,结果看到了相同的情况。 - miken32
你认为这是 PHP 的 bug 还是 PHP-FPM 的问题? - Greg
1
好的,我刚刚在带有mod_php的Apache中尝试了一下,并获得了相同的行为。 - miken32
使用 $_SERVER 的效果符合预期。 - miken32
2
php.net页面上说成功返回TRUE,失败返回FALSE。我无法让自己相信“失败”更改现有变量的值不是其他任何失败...这使得这成为了PHP的缺陷。 - user1180316
2个回答

8

这很有趣。在调查后,我发现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。也就是说,如果您在nginx / Apache配置中根本没有设置TESTVAR_ENV,则putenv/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 上的文档以反映此行为,尽管我仍然认为功能可以进一步改进。 - Greg
将“true”传递给getenv会在apache/error_log中产生此错误:PHP警告:getenv()期望恰好1个参数,但实际提供了2个 - Danny

0

您可以直接将新变量设置到$_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环境变量管理器(php dotenv)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接