Yii2不会直接报“磁盘空间不足”,但系统因“No space left on device”导致PHP写入失败时,会抛出yii\base\ErrorException等异常或出现500/空白页;需启用PHP错误显示并检查runtime/web/assets目录空间及inode使用情况。

Yii2 本身不会直接报“磁盘空间不足”,但当系统底层因 No space left on device 导致 PHP 写入失败(如日志、session、runtime 缓存、上传临时文件)时,Yii2 会抛出异常或静默崩溃——你看到的往往是空白页、500 错误或 Failed to write session data 这类模糊提示。要让真实原因浮出来,关键不是改 Yii2 配置,而是**让 PHP 原生错误不被吞掉**。
启用调试模式并强制显示所有 PHP 错误
生产环境默认关闭错误输出,YII_DEBUG = false 会让 ErrorHandler 拦截一切异常并转成白屏,根本看不到磁盘满的底层信号。
必须在 web/index.php 开头插入三行(顺序不能错):
error_reporting(E_ALL);
ini_set('display_errors', '1');
defined('YII_DEBUG') or define('YII_DEBUG', true);
注意:YII_ENV 也需为 'dev',否则部分组件(如日志写入)仍可能跳过错误路径。
常见错误现象:
- 页面完全空白,Network 面板显示 500 但无响应体
- 日志写入失败却没报错,
runtime/logs目录为空或只有一两个旧文件 -
UploadedFile::getInstance()返回 null,但$_FILES也不为空 —— 实际是临时文件写入失败
检查 runtime 和 web/assets 是否可写且有空间
Yii2 启动时会尝试往 runtime(缓存、日志、session)和 web/assets(资源包发布)写文件。如果这些目录所在分区已满,就会触发 mkdir(): No space left on device 或 file_put_contents(): failed to open stream: No space left on device。
快速验证方法:
- 执行
df -h看/或/var分区是否 100% 使用 - 手动测试写入:
php -r "file_put_contents('runtime/test.tmp', 'x'); echo 'ok';" - 检查
runtime所在路径的父目录 inode 是否耗尽:df -i,若IUse%为 100%,说明有海量小文件(如旧日志、session 文件)占满索引节点
捕获并识别磁盘满引发的具体异常类型
磁盘空间不足通常不会抛出 Yii2 特有异常,而是触发 PHP 的 Warning 或 Error,最终被 ErrorHandler 转为 yii\base\ErrorException 或直接终止脚本。你在 site/error 视图里能拿到的 $exception 可能是:
-
yii\base\ErrorException,$exception->getMessage()包含No space left on device -
yii\web\HeadersAlreadySentException—— 这往往是前置 Warning(如 session_start 失败)导致 headers 发送中断的连锁反应,根源仍是磁盘满 - 空
$exception,但Yii::$app->getResponse()->getStatusCode() === 500—— 此时必须回看 PHP 错误日志(php_error.log或nginx/error.log),里面才有真实线索
不要依赖 $this->addError() 或模型层验证——磁盘问题发生在框架最底层 I/O 阶段,还没走到业务逻辑。
绕过写入失败的临时调试技巧
当磁盘已满无法写日志或 session 时,常规调试手段失效。可用以下方式抢在崩溃前输出信息:
- 在
web/index.php最开头加:error_log("DEBUG: start, disk=".shell_exec('df -h | grep \"/$\"')."\n", 3, '/tmp/yii-debug.log'); - 在
config/web.php中临时禁用日志组件:'log' => ['class' => 'yii\log\Dispatcher', 'targets' => []] - 将 session 存到数据库或 Redis(需提前配置),避开文件写入:
'session' => ['class' => 'yii\web\DbSession']
真正卡住的地方往往不是代码,而是 runtime 目录所在的那个分区 —— 它可能被日志、Docker 卷或旧备份悄悄塞满,而你还在翻控制器找 bug。


















