必须启用调试并强制输出PHP错误才能暴露真实权限问题,否则仅显示500或空白页;需检查runtime、web/assets等目录属主/组是否匹配Web用户,确认父目录有x权限,并排查SELinux、Docker用户及OPcache干扰。

Yii2 文件权限报错默认不显示具体路径和原因,只返回 500 或空白页——这不是代码问题,而是错误被静默吞掉了。必须让真实权限错误浮出来,才能定位是 runtime、web/assets 还是上传目录没写入权。
打开调试并强制输出 PHP 错误
YII_DEBUG=true 只是第一步,它依赖 PHP 自身的错误报告机制。很多服务器(尤其是生产镜像或 Docker 容器)默认关闭 display_errors,导致即使开启调试也看不到堆栈。
- 打开
web/index.php,在require __DIR__ . '/../vendor/autoload.php';前插入两行:error_reporting(E_ALL);ini_set('display_errors', '1'); - 确认
php.ini中没有display_errors = Off覆盖该设置(可用php -i | grep display_errors验证) - 访问任意页面,若出现类似
failed to open stream: Permission denied in /path/to/yii2/framework/log/Target.php的报错,就说明权限问题已暴露
查日志比看页面更可靠
有些权限错误(比如 mkdir() 失败)不会触发 PHP 致命错误,但会写进 Yii 日志。而日志本身又依赖 runtime 目录可写——这就成了死循环。所以得先绕过日志,直查底层。
- 临时在
web/index.php开头加:file_put_contents('/tmp/yii-perm-test.txt', print_r($_SERVER, true), FILE_APPEND);
看能否写入系统临时目录,验证 PHP 写权限是否全局受限 - 手动执行:
ls -ld runtime/ web/assets/ uploads/
重点看第三列(属主)、第四列(属组)是否匹配 Web 进程用户(如www-data、nginx、www) - 检查父目录权限:
ls -ld . ./web ./runtime
若某一级缺少x(执行位),Web 进程根本无法进入子目录,chmod 777 也无效
运行时权限错误的典型报错字符串
这些字符串一旦出现在错误页、PHP 错误日志或 runtime/logs/app.log 中,基本可锁定为权限问题,无需再猜:
-
Failed to write file to disk→ 上传目标目录不可写 -
mkdir(): Permission denied→runtime或assets目录无法创建子目录 -
The directory is not writable by the Web process→ Yii 框架内置检测直接抛出的提示 -
file_put_contents(runtime/cache/xxx): failed to open stream: No such file or directory→ 父目录无x权限,或runtime本身不存在且进程无权创建
权限修复后仍不生效?注意三个隐藏开关
改完 chown 和 chmod 还报错,大概率卡在这三处:
- SELinux 启用中(CentOS/RHEL):
执行sudo setenforce 0测试;若恢复正常,需用chcon -R -t httpd_sys_rw_content_t runtime/修复上下文 - Docker 容器未挂载正确用户:
启动时加--user www-data,或在Dockerfile中用USER www-data切换,不能只靠chown - OPcache 缓存了旧的文件状态:
重启 PHP-FPM(sudo systemctl restart php*-fpm)或清空 OPcache(opcache_reset())
权限问题从来不是 chmod 数字不对,而是用户、组、路径遍历权限、安全模块四者没对齐。看到报错先抓字符串,再查属主和 x 位,最后盯住 SELinux 和容器上下文——这四步走完,95% 的“不显示错误”就变成“清楚错在哪”了。


















