mkdir() 权限受 umask 影响,需用 chmod() 补设或临时 umask(0);递归创建需 third param true;判断目录要用 is_dir() && is_writable();删非空目录须遍历清空。

mkdir() 创建目录时权限不生效?检查 umask 和系统限制
PHP 的 mkdir() 默认不会按你传入的 $mode 参数严格设权,因为受系统 umask 影响。比如写 mkdir('logs', 0755),实际可能变成 0700(如果 umask 是 0055)。
解决方法:
- 调用前临时修改 umask:
umask(0),创建完再恢复(注意并发风险) - 更稳妥的做法是创建后补调
chmod():mkdir('logs', 0755, true); chmod('logs', 0755); - 确保运行 PHP 的用户对父目录有写权限,否则即使 mode 正确也会报
Permission denied
递归创建多层不存在的目录用第三个参数 true
直接 mkdir('a/b/c') 会失败,除非 a/b 已存在。必须显式启用递归模式:
mkdir('a/b/c', 0755, true) —— 第三个参数 true 表示递归创建所有缺失的父级目录。
立即学习“PHP免费学习笔记(深入)”;
注意:
- PHP 5.0.0+ 才支持第三个参数,老版本需自己循环调用或改用
recursive_mkdir()封装 - 若中间某层是文件而非目录(比如已有
a/b是个普通文件),mkdir()仍会失败并抛出警告 - 权限只应用到最深层目录,父级目录权限由系统默认 umask 决定
判断目录是否存在且为目录,别只用 file_exists()
file_exists('path') 对文件和目录都返回 true,容易误判。正确做法是组合使用:
is_dir('path') && is_writable('path') —— 这样既确认是目录,又验证可写,适合日志、上传等场景。
常见疏漏点:
-
is_writable()在某些 Linux 环境下对目录可能返回false(即使权限足够),这是因 PHP 检查的是“是否能创建文件”,建议搭配touch()测试更可靠 - Windows 下
is_executable()对目录无意义,但is_dir()行为一致 - 符号链接需用
is_link()单独判断,is_dir()对指向目录的软链也返回true
删除非空目录不能只用 rmdir(),得先清空
rmdir() 只能删空目录,否则报错 Directory not empty。要删整个目录树,得手动遍历清理:
推荐用 RecursiveDirectoryIterator + RecursiveIteratorIterator 配合 unlink() 和 rmdir():
function rrmdir($dir) {
$iter = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS),
RecursiveIteratorIterator::CHILD_FIRST
);
foreach ($iter as $file) {
if ($file->isDir()) rmdir($file->getPathname());
else unlink($file->getPathname());
}
return rmdir($dir);
}
关键细节:
- 必须用
CHILD_FIRST遍历顺序,否则先删父目录会导致子项无法访问 -
SKIP_DOTS跳过.和..,避免误操作 - 对只读文件(如 git 的 .git 目录下文件),
unlink()会失败,需提前chmod($file, 0777)











