mkdir() 默认不支持多级目录创建,需设 $recursive=true 并显式传入八进制权限(如 0755);注意 umask 影响实际权限、web 服务器用户写权限及路径编码一致性。

mkdir() 创建文件夹最常用,但默认不支持多级嵌套
直接调用 mkdir() 创建多层目录(比如 "uploads/images/2024/06")会失败,报错 Warning: mkdir(): No such file or directory。这是因为 PHP 默认只创建最后一级目录,前提是父目录必须已存在。
解决方法是传入第三个参数 $recursive = true,并确保第二个参数(权限)显式指定(尤其在 Linux 上,不传可能被 umask 限制):
mkdir('uploads/images/2024/06', 0755, true);
- 权限
0755是八进制写法,不能写成755(会被解释为十进制) - Windows 下权限参数基本被忽略,但建议仍保留以保持跨平台一致性
- 如果父路径中含中文或特殊字符,需确认当前脚本文件编码与系统 locale 一致,否则可能创建失败且无明确提示
创建前最好先检查路径是否存在,避免 warning
重复调用 mkdir() 会触发 warning(“File exists”),虽不影响执行,但污染错误日志。与其用 @mkdir() 抑制,不如主动判断:
$path = 'cache/templates';<br>if (!is_dir($path)) {<br> mkdir($path, 0755, true);<br>}
-
is_dir()比file_exists()更准确——后者对符号链接、文件都返回 true - 注意:
is_dir()对不存在的路径返回 false,但对权限不足的已存在路径也返回 false(容易误判),此时可补一个is_writable(dirname($path))判断父目录是否可写
权限设置不是万能的,Linux 下还要看 umask
即使写了 0755,实际创建的目录权限可能是 0744 或 0700,这是因 PHP 进程受系统 umask 掩码影响。例如 umask 为 0022,则 0755 & ~0022 = 0733 → 实际得 0733(即 rwx-wx-wx)。
立即学习“PHP免费学习笔记(深入)”;
若需严格控制权限,有两种选择:
- 临时修改 umask:
umask(0); mkdir($path, 0755, true); umask(0022);(注意并发时慎用) - 创建后用
chmod()补全:mkdir($path, 0755, true) && chmod($path, 0755); - Web 服务器用户(如 www-data)对父目录无写权限时,
mkdir()必然失败,和权限参数无关——先查ls -ld /var/www/html确认属主和权限
用 SPL 的 RecursiveDirectoryIterator 配合 mkdir 处理复杂路径逻辑
当需要按模板批量创建带日期、哈希等动态结构的目录(如 ./storage/{year}/{month}/{hash[0]}/{hash[1]}),手动拼接易出错。可用 dirname() 逐级向上构建:
$target = './storage/' . date('Y/m') . '/' . substr(md5('key'), 0, 2) . '/' . substr(md5('key'), 2, 2);<br>if (!is_dir($target)) {<br> mkdir($target, 0755, true);<br>}
- 避免直接
mkdir(dirname($target), ...)——dirname()对单层路径(如"logs")返回".",而"."是合法目录,is_dir(".") === true,但你未必想在当前目录下建东西 - 更健壮的做法是先
realpath()归一化路径,再用explode(DIRECTORY_SEPARATOR, ...)分段检查并逐级mkdir,但多数场景mkdir(..., true)已足够
mkdir() 的权限参数要写八进制、umask 会偷偷改结果、以及 Web 服务器用户根本没权写父目录——这三个点漏掉任何一个,都会让代码在本地跑通,上线就静默失败。










