应通过实际写入临时文件并捕获erofs错误来判断磁盘分区是否只读,因为is_writable()仅检查权限而不反映挂载状态;需在目标路径创建、写入、删除临时文件,根据fopen/fwrite失败时的errno=30或错误消息含“read-only file system”判定。

PHP判断磁盘分区是否只读:为什么不能只靠 is_writable()
is_writable() 只检查当前用户对路径的写权限,不反映实际挂载状态。比如分区被 mount -o remount,ro 强制只读后,该函数仍可能返回 true(尤其在 root 用户下),因为文件系统权限没变,但内核已拒绝所有写操作。
真正可靠的判断方式是:在目标路径尝试创建并删除一个临时文件,捕获底层 I/O 错误。
用 fopen() + fwrite() 捕获真实写入失败
必须触发实际的系统调用,才能暴露挂载只读导致的 EROFS(Error Read-Only Filesystem)错误。仅检查权限或目录存在性不够。
- 选择目标路径的父目录(如
/var/log),确保你有执行权限(chdir()或realpath()后操作) - 生成唯一临时文件名,避免并发冲突:
$tmp = sys_get_temp_dir() . '/.ro_check_' . uniqid('', true); - 用
fopen($tmp, 'wb')尝试打开写入流,立即检查返回值是否为false - 若打开失败,用
error_get_last()['message']或errno判断是否含EROFS或Read-only file system - 成功打开后,务必
fwrite()一点数据再fclose(),否则某些 NFS 或 overlayfs 可能延迟报错
完整可复用的检测函数示例
function is_partition_readonly(string $path): bool
{
$dir = rtrim($path, '/\') ?: '/';
if (!is_dir($dir)) {
return false;
}
$tmpFile = $dir . '/.ro_check_' . bin2hex(random_bytes(4));
$fp = @fopen($tmpFile, 'wb');
if ($fp === false) {
$err = error_get_last();
return str_contains($err['message'] ?? '', 'Read-only file system')
|| (int)($err['errno'] ?? 0) === 30; // EROFS = 30 on Linux
}
if (fwrite($fp, 'x') === false) {
fclose($fp);
@unlink($tmpFile);
return true;
}
fclose($fp);
@unlink($tmpFile);
return false;
}
// 使用示例:
var_dump(is_partition_readonly('/var/log')); // true / false
常见陷阱和兼容性注意点
这个方法看似简单,但在生产环境容易踩坑:
- SELinux 或 AppArmor 可能拦截写入并返回
EACCES而非EROFS,需结合getenforce或日志判断 - NFS 挂载点可能返回
ETIMEDOUT或静默失败,建议加stream_set_timeout($fp, 2) - 容器环境(如 Docker)中,
/proc/mounts更可靠,但需exec('findmnt -n -o SOURCE,TARGET,FSTYPE')配合解析 - Windows 不支持
EROFS错误码,要用is_writable()+copy()到自身测试,逻辑需分支处理
最稳妥的做法是:先用临时文件写入试探,失败后再 fallback 到解析 /proc/mounts(Linux)或 Get-PSDrive(PowerShell)确认挂载选项。别省那一次系统调用。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











