Nginx fastcgi_param 是透传环境变量到 PHP 的最可靠方式,需在 location ~ .php$ 块中显式设置并置于 include fastcgi.conf 之后;变量默认进 $_SERVER,ThinkPHP 的 Env::get() 需手动同步至 $_ENV 才能读取。

为什么 $_SERVER 里找不到自定义环境变量
ThinkPHP 在 FastCGI(如 Nginx + php-fpm)下运行时,你通过 putenv() 或系统级配置(如 /etc/environment)设的环境变量,大概率不会自动出现在 $_SERVER 或 getenv() 中——因为 php-fpm 默认隔离了父进程环境,且 Nginx 不会主动把变量透传给 PHP 子进程。
这不是 ThinkPHP 的 bug,是 FastCGI 架构本身的限制。关键点在于:变量必须显式从 Web 服务器层「注入」到 PHP 进程空间,否则 Env::get()、$_ENV、getenv() 都拿不到。
- Nginx 的
fastcgi_param是最常用、最可控的注入入口 - php-fpm 的
env[]配置项只对 pool 级生效,且不覆盖已存在的同名变量 -
putenv()在请求生命周期内有效,但不能跨请求,也不影响$_SERVER
Nginx 配置中如何正确透传环境变量
必须在 location ~ \.php$ 块里用 fastcgi_param 显式设置,且要放在 include fastcgi.conf 之后(否则会被覆盖)。
例如想让 PHP 脚本能读到 APP_ENV=production:
立即学习“PHP免费学习笔记(深入)”;
location ~ \.php$ {
include fastcgi.conf;
fastcgi_param APP_ENV "production";
fastcgi_param DB_HOST "10.0.1.5";
}
注意:fastcgi_param 设置的变量会进入 $_SERVER,不是 $_ENV;ThinkPHP 的 Env::get('APP_ENV') 默认优先查 $_ENV,所以需额外确保变量也写入 $_ENV —— 可在 public/index.php 开头加一行:
foreach ($_SERVER as $k => $v) {
if (strpos($k, 'HTTP_') !== 0 && !isset($_ENV[$k])) {
$_ENV[$k] = $v;
}
}
php-fpm 的 env[] 和 clear_env 怎么配合用
php-fpm pool 配置(如 /etc/php/*/fpm/pool.d/www.conf)中:
-
clear_env = no是前提,否则所有父进程环境都会被清空(默认值是yes) -
env[APP_ENV] = production会写入$_ENV和getenv(),但不会进$_SERVER - 如果同时用了 Nginx
fastcgi_param和 php-fpmenv[],且键名相同,fastcgi_param会覆盖env[](因它更晚生效)
推荐只选一种方式,避免混淆。线上环境建议用 Nginx 注入,便于按站点/路径差异化配置;开发环境可用 php-fpm env[] 快速调试。
ThinkPHP 里读取变量的兼容写法与陷阱
直接调 getenv('APP_ENV') 或 $_ENV['APP_ENV'] 很容易返回 false,原因包括:
- 变量没被注入(最常见)
- php.ini 中
variables_order没包含E(即不解析环境变量) - 启用了
opcache.enable_cli=1且未重载配置(CLI 模式下变量行为不同)
安全读取建议统一走 ThinkPHP 的 Env::get(),但它内部依赖 getenv() → $_ENV → $_SERVER 三级 fallback。所以务必确认至少有一路通:
// public/index.php 开头补全 ENV
if (!isset($_ENV['APP_ENV'])) {
$_ENV['APP_ENV'] = $_SERVER['APP_ENV'] ?? 'dev';
}
另外,.env 文件加载不受 FastCGI 影响,但仅限于本地开发;上线后应禁用 .env,靠服务器注入保证一致性。
真正麻烦的是多级代理或容器场景:Nginx → Traefik → php-fpm,中间任意一层没透传,变量就断了。这种时候别猜,直接在 phpinfo() 页面搜变量名看它到底出现在哪一级数组里。



















