环境变量是配置PHP应用程序的一个很好的方法,因为它们把应用程序的设置放在代码之外。通过这样做,可以更容易地防止安全凭证的暴露,维护应用程序,以及在多个环境中使用应用程序。
在本教程中,你将了解到在PHP应用程序中设置和检索环境变量的许多方法中的一些。这样,你的应用程序就可以访问它需要的所有信息,如API密钥、上传的文件、查询字符串和表单数据。
如何在PHP中访问环境变量
使用PHP的Superglobals
在PHP中访问环境变量的最常见的方式之一是通过使用Superglobals。这些是内置的、预定义的变量,在所有作用域中都可用。由PHP运行时初始化,它们以一种(大部分)逻辑和有效的方式组织PHP的环境信息,因此只需要查阅一个数组就可以检索到所需的信息。
例如,$_SERVER 包含请求头、路径和脚本位置,$_SESSION 包含会话变量,$_POST 包含用 HTTP POST 方法调用时传递给当前脚本的变量。
也就是说,有一些事情是需要注意的:
- 首先,根据
variables_order指令的设置方式,一个或多个超全局数组可能为空。如果你的应用程序依赖于某个特定的Superglobal被填充,那么检查这一点就很重要。 - 其次,
$_SERVER和$_ENV(包含从 PHP 解析器运行环境中导入的变量)中包含的变量可能会相互重叠,这取决于脚本的上下文。如果你希望这些键在所有的Superglobals中都是唯一的,这可能会令人困惑。
SAPI/CGI和CLI环境之间的差异
除了variables_order 指令外,环境也对Superglobals中的信息设置起到了一定作用。具体来说,如果你的应用程序是使用CGI、FastCGI或SAPI运行的,那么$_SERVER ,除了正常的变量外,还将被填充环境变量。或者,如果你使用的是PHP CLI,那么只有$_SERVER 会被设置。
使用 getenv()
除了使用PHP的Superglobals之外,还可以使用getenv()来检索环境变量。如果调用该函数时没有参数,那么它会返回所有可用的环境变量。然而,如果传递了一个参数,就会返回具有该名称的环境变量的值。
你可以在下面看到它的使用例子:
echo getenv('SHELL');
foreach (getenv() as $key => $value) {
echo $key . ' - ' . $value;
}
与PHP的Superglobals一样,使用这个函数也有一个问题。引述该函数的文档:
如果 PHP 在一个 SAPI 中运行,如 Fast CGI,这个函数将总是返回 SAPI 设置的环境变量的值,即使putenv()被用来设置同名的本地环境变量。使用
local_only参数来返回本地设置的环境变量的值。
请注意,getenv() 不是线程安全的。
使用apache_getenv()
如果你使用Apache作为你的网络服务器,那么你有一个额外的函数可以使用:apache_getenv()。这个函数可以检索在Apache进程中设置的环境变量。你可以在下面看到一个使用它的例子:
echo apache_getenv('NAME');
不要隐含地相信环境变量!
需要强调的是--无论数据来自哪里,无论是来自PHP的某个超级球体、Web服务器配置,还是操作环境--都不要隐含地相信它环境变量应该被过滤和验证,就像任何其他应用的外部数据一样。
如何设置环境变量
除了阅读环境变量,知道如何设置它们也很有帮助,这样,你就知道如何在必要时改变它们。在下面的例子中,我们要把环境变量NAME ,设置为 "Robert Smith",英国摇滚乐队The Cure的主唱。
在环境中设置它们
在启动Web服务器或执行PHP脚本之前,可以在当前环境中设置环境变量。
如果你想更深入地了解设置环境变量,Dominik Kundel已经写了一篇详细的博文。
UNIX、Linux和macOS
如果你使用的是这三个操作系统中的一个,或者像BSD这样的变种,那么有三个范围,你可以设置环境变量:
- 对当前环境(会话)和所有子会话可用。
- 只对当前会话可用。
- 只对一个特定的进程可用。
你可以在下面的代码中看到这三种情况的例子:
# Available to the current environment (session) and all child sessions.
export NAME="Robert Smith"
# Available only to the current session.
NAME="Robert Smith"
# Available only to a specific process.
NAME="Robert Smith" php script.php
微软视窗
设置环境变量在Microsoft Windows中有些不同。你可以在控制面板上设置它们,也可以在命令提示符或PowerShell控制台中设置它们。下面有后两者的例子:
# Set NAME in the Windows Command Prompt
set NAME="Robert Smith"
# Set NAME in the Windows PowerShell console
$Env:NAME = "Robert Smith"
使用Docker
如果你使用Docker,你可以使用ENV 命令在Docker文件中设置环境变量,如下面的例子:
ENV NAME "Robert Smith"
如果你使用Docker Compose构建一个多容器配置,你可以在docker-compose.yml中使用环境键设置环境变量,如下面的例子:
environment:
- NAME="Robert Smith"
在使用Docker时,还有其他一些设置环境变量的方法,你可以在Docker文档和Docker Compose文档中阅读。
使用putenv()
使用这个函数,你可以在当前请求中设置一个环境变量的值--以及取消设置它。在下一个请求中,如果该变量在当前请求之外设置,将返回其原始值。
以这种方式设置的变量对该脚本调用的进程也是可用的,并且只有通过调用getenv() 。
你可以在下面的代码中看到这两个函数的一个例子:
// Set the environment variable, NAME.
putenv('NAME="Robert Smith"');
// Retrieve the environment variable, NAME.
echo getenv('NAME');
// Unset the environment variable, NAME.
putenv('NAME');
请注意,putenv() 不是线程安全的。
使用apache_setenv() 与`putenv()`相似的是`apache_setenv()`。这个函数设置一个Apache进程特定的环境变量。当然,这个函数和它的补码只有在使用Apache时才可用。你可以在下面看到一个使用它的例子:
apache_setenv('NAME', 'Robert Smith');
echo apache_getenv('NAME');
在NGINX配置中设置环境变量
如果你使用NGINX作为你的网络服务器,你可以使用 fastcgi_param 指令来设置一个环境变量。该指令需要一个区分大小写的名称和值,如果包含空格,必须加引号:
fastcgi_param NAME "Robert Smith";
这些变量可以通过getenv() ,以及$_ENV 和$_SERVER 超级全局数组中获得。
在Apache配置中设置环境变量
如果你使用Apache作为你的网络服务器,那么你可以使用SetEnv 指令来设置环境变量。该指令可以在Apache的主服务器配置、虚拟主机配置、目录配置或*.htaccess*文件中使用。
该指令需要一个区分大小写的名称和值,如果它包含空格,则必须加引号。如果没有提供值,该变量将被初始化为一个空字符串:
SetEnv NAME "Robert Smith"
与在NGINX中使用fastcgi_param 不同,在Apache中使用SetEnv (或相关函数之一)设置的环境变量只在$_SERVER 超级全局中可用。
使用.env文件
虽然上述每种方式都有其优点,但也有一些缺点需要记住:
- 根据项目的复杂性,它们在长期的维护过程中可能具有挑战性。
- 没有必要的环境变量的中央清单,也没有关于特定变量作用的细节,更没有它们允许的数据类型。
另一种方法是使用dotenv文件,以事实上的文件名命名:.env,这种方法近年来在PHP中获得了很大的发展。这些文件是纯文本文件,以键/值对列表的形式定义了应用程序工作所需的环境变量。
你可以看到下面的一个例子:
NAME="Robert Smith"
假设上面的例子是我们项目的*.env文件,我们可以使用vlucas/phpdotenv这样的包,它默认读取.env*文件,并将其中定义的变量添加到$_ENV 和$_SERVER 超级球体中。
要做到这一点,我们首先要通过运行下面的命令将该包安装为应用程序的依赖项:
composer require vlucas/phpdotenv
然后,我们将使用该包来加载环境变量,如下面的例子:
<?php
declare(strict_types=1);
require_once('vendor/autoload.php');
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->load();
echo $_ENV['NAME'] . "\n";
echo $_SERVER['NAME'] . "\n";
- 使用
safeLoad(),而不是load(),以避免在没有找到.env时抛出一个异常。 - 将一个文件路径作为第二个参数传给
createImmutable(),以使用.env以外的文件。
关于.env文件安全的说明
重要的是要意识到*.env*文件中的敏感数据不能存储在版本控制之下!如果发生这种情况,所有的安全性都会受到影响。
如果发生这种情况,使用dotenv文件的所有安全优势都会丧失。这就是为什么通常要把它们排除在版本控制之外,例如在使用Git时,把*.env*和文件名的变化添加到项目的.gitignore文件中。
这就是如何在PHP中使用环境变量的方法
我希望这篇文章能帮助你理解如何在你的PHP项目中使用环境变量。你还有其他使用环境变量的方法吗?我很想知道!