根本原因是php-fpm默认clear_env=yes清空父进程环境变量;需在www.conf中设clear_env=no或用php_admin_value显式注入变量,并重启php-fpm生效。

PHP 无法读取环境变量,根本原因不是 PHP 本身的问题,而是 php-fpm 主动清空了进程环境 —— 默认情况下,clear_env = yes 会把所有父进程传下来的环境变量(包括 Docker、systemd、docker-compose 注入的)全部抹掉,只留下极少数安全白名单变量(如 PATH)。
为什么 php-fpm 默认清空环境变量
这是出于安全设计:防止敏感变量(比如 DB_PASSWORD、AWS_SECRET_ACCESS_KEY)意外泄露给任意 PHP 脚本。但副作用也很直接——你用 getenv('APP_ENV') 或 $_ENV['APP_ENV'] 拿不到值,返回空或 false。
常见错误现象:
-
var_dump($_ENV)输出空数组 -
getenv('DB_HOST')返回false或空字符串,哪怕echo $DB_HOST在 shell 中能正常显示 - Docker 容器里
env | grep APP_ENV显示变量存在,但 PHP 脚本里读不到
修改 php-fpm.conf 或 www.conf 的 clear_env 配置
必须在 php-fpm 的全局配置(php-fpm.conf)或进程池配置(如 www.conf)中显式设置 clear_env = no,否则改 .env 文件或 Docker environment: 都没用。
实操建议:
- 找到你的
www.conf(通常在/etc/php/{version}/fpm/pool.d/www.conf或容器内/usr/local/etc/php-fpm.d/www.conf) - 在
[www]段落内添加或修改这一行:clear_env = no - 重启
php-fpm:运行kill -USR2 $(cat /var/run/php-fpm.pid)或service php-fpm reload(取决于启动方式) - 验证是否生效:在 PHP 脚本中执行
var_dump(getenv('PATH'));,如果输出非空字符串,说明环境变量已可读
clear_env = no 的兼容性与风险权衡
设为 no 后,所有父进程环境变量都会透传到每个 worker 进程,包括你可能没意识到的变量(比如 HOSTNAME、KUBERNETES_SERVICE_HOST)。这不是 bug,是预期行为。
需要注意的点:
- 不要依赖
$_ENV数组自动填充 —— 它默认不启用,需在php.ini中设variables_order = "EGPCS"并确保含E;更推荐统一用getenv() - 敏感变量仍应通过
env_file+.gitignore管理,避免硬编码;clear_env = no只是“通道”,不解决变量来源是否安全 - 某些托管平台(如部分 PaaS)禁止修改
clear_env,此时只能改用php_admin_value[env[VAR_NAME]]在 pool 配置中显式注入单个变量
替代方案:不改 clear_env,也能让特定变量可用
如果你不能或不想关闭 clear_env(例如合规审计强制要求),可以用 php_admin_value 在 www.conf 中逐个注入:
php_admin_value[env[APP_ENV]] = production php_admin_value[env[DB_HOST]] = db.example.com
这种方式更精细、更可控,但维护成本高 —— 每新增一个变量都要改配置并 reload。Docker 场景下,还容易和 environment: 定义重复或冲突。
真正容易被忽略的是:即使 clear_env = no 生效,PHP 脚本也**不会自动重载环境变量**。变量只在 php-fpm worker 启动时读取一次。容器重启、fpm reload 后才更新 —— 这意味着改了 Docker 的 environment: 却没重启 fpm,变量依然旧的。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











