Symfony 5.3使用Doctrine访问数据库被拒绝 命令行正常Web请求失败
问题根因
这是php-fpm默认清理环境变量的典型问题,和Symfony的环境变量加载逻辑叠加导致:
- CLI和FPM模式的环境变量隔离
你执行php bin/console系列命令走的是PHP CLI模式,该模式不会限制系统环境变量读取,既可以直接读取项目根目录的.env文件,也能拿到docker-compose通过env_file注入的环境变量,所以控制台操作一切正常。 - php-fpm默认开启环境变量清理
默认php-fpm的www.conf配置中clear_env = On处于开启状态,该参数会清除所有从系统层面传递给fpm进程的环境变量,仅保留fpm配置中显式声明的env[xxx]变量。所以即使docker-compose已经通过env_file把DATABASE_URL注入到容器系统环境中,php-fpm进程处理的web请求也拿不到这个变量。 - Symfony的Dotenv加载逻辑限制
Symfony 5.3默认仅在dev/test环境下会自动加载项目根目录的.env系列文件,如果你运行在prod环境下,Dotenv组件默认不会加载.env文件,而是优先读取系统环境变量。当读不到DATABASE_URL时,就会 fallback 到Doctrine bundle的默认配置,也就是你打印出来的默认连接参数。 - 直接配置environment生效的原因
大概率是你的镜像构建过程中,已经在php-fpm配置里显式声明了env[DATABASE_URL] = $DATABASE_URL,显式设置的环境变量优先级更高,所以可以被正常读取。
解决方案
以下方案按优先级推荐:
- 方案1(推荐生产环境使用):修改php-fpm配置,放行需要的环境变量
在你的php-fpm配置文件www.conf(通常路径为/usr/local/etc/php-fpm.d/www.conf)中添加以下配置,显式声明要传递给web请求的环境变量:
env[APP_ENV] = $APP_ENV env[DATABASE_URL] = $DATABASE_URL # 其他需要用到的Symfony环境变量都可按该格式添加
修改后重启php-fpm即可,env_file注入的变量后续就可以正常被web请求读取。
- 方案2(适合开发环境使用):强制Symfony加载.env文件
如果你不想修改php-fpm配置,可以修改项目入口文件public/index.php,取消Dotenv加载的环境限制,强制所有环境都加载.env文件:
找到对应代码段:
if (isset($_SERVER['APP_DEBUG']) && $_SERVER['APP_DEBUG']) { umask(0000); Dotenv::loadEnv(dirname(__DIR__)); }
修改为:
umask(0000); Dotenv::loadEnv(dirname(__DIR__));
注意该方案每次请求都会读取.env文件,性能略低,不建议生产环境使用。
- 方案3(生产环境可选):生成.env缓存文件
执行命令composer dump-env <你的运行环境,如prod/dev>,Symfony会生成编译后的环境变量缓存文件.env.local.php,该文件不需要依赖系统环境变量,CLI和FPM都可以直接读取,性能很高。
内容的提问来源于stack exchange,提问作者Benjamin
相关产品推荐
相关产品推荐

