根本原因是umask掩码机制:PHP mkdir()创建目录时实际权限为0777 &^ umask(如默认0022),结果为0755;chmod()可绕过umask直接设权,故推荐先mkdir再chmod。

PHP 的 mkdir() 函数设了 0777 却没生成真正 777 权限的目录,根本原因不是 PHP 写错了,而是它尊重操作系统底层的权限控制机制——umask。这个值会“屏蔽”掉你指定的部分权限位,导致最终结果比预期更严格(比如变成 755)。
umask 是什么,它怎么影响 mkdir
umask 是 Linux/Unix 系统为所有进程设定的默认权限掩码,作用是“从最大权限中减去哪些位”。目录最大权限本是 0777,但系统默认 umask 通常是 0022,计算方式是按位与取反:0777 & ~0022 = 0755
所以无论你传 0777、0766 还是 0744,实际创建的权限都不会超过 0755(除非 umask 更小)。
为什么 chmod 能绕过 umask 限制
chmod() 是在目录创建之后单独设置权限,它不经过 umask 过滤,属于“强制重写”。这也是最推荐的做法:
- 先用
mkdir($path, 0777, true)创建多级目录(true启用递归) - 再立即调用
chmod($path, 0777)覆盖权限 - 注意:权限数字必须写成
0777(八进制),不能加引号,如'0777'会被当字符串处理,导致失败
递归创建多层目录时的权限处理
如果要创建像 cache/a/b/c 这样的嵌套路径,mkdir(..., true) 只能保证最末层目录被创建,但中间层级可能权限不一致(尤其在脚本多次运行、部分目录已存在时)。稳妥做法是:
- 对每一级新创建的目录都单独
chmod - 或使用自定义递归 chmod 函数(遍历目录树,逐个调用
chmod) - 避免依赖系统 umask 修改(如
umask(0)),因线程/并发环境下可能干扰其他请求
其他常见误区提醒
以下操作看似合理,实则容易出错:
- 把权限写成
777(缺前导0)→ PHP 当作十进制 777,等效于八进制1411,结果不可控 - 在 Windows 上测试
0777→ 权限参数被完全忽略,无意义 - 直接改系统全局 umask(如编辑
/etc/bashrc)→ 影响所有用户和服务,不安全也不必要 - 用 shell 命令
mkdir -m0777对比 PHP 行为 → 系统命令确实可绕过 umask,但 PHP 的mkdir()函数设计上就是遵循 POSIX 规范,必须受其约束
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











