先确认PHP进程实际运行用户是谁,再逐级检查目录权限和路径存在性,最后排除SELinux、open_basedir等隐性限制;执行ps aux | grep -E '(php-fpm|nginx|apache|httpd)'看USER列,或用echo posix_getpwuid(posix_geteuid())['name']输出真实用户,确保每级父目录具备x和w权限,且目标路径在open_basedir白名单内、SELinux上下文正确。

先确认PHP进程实际运行用户是谁,再逐级检查目录权限和路径存在性,最后排除SELinux、open_basedir等隐性限制。
查清PHP到底以谁的身份在跑
别猜,直接看系统里真实运行的用户:
- 终端执行 ps aux | grep -E '(php-fpm|nginx|apache|httpd)',重点看 USER 列(常见是 www-data、nginx 或 apache)
- 或在PHP脚本里加一行:echo posix_getpwuid(posix_geteuid())['name'];,浏览器访问就能输出真实执行者
- 注意:get_current_user() 返回的是文件属主,不是执行者,不能用它判断权限主体
检查目标路径每一层是否可写可进
mkdir() 失败,90%是因为某一级父目录没给“进入”(x)或“创建”(w)权限:
- 用 ls -ld /a/b/c 查目标目录权限,确认属主/属组匹配上一步查到的用户,且权限位含 wx(如 drwxr-xr-x 中属主位有 wx)
- 逐级向上检查:/a → /a/b → /a/b/c,只要其中一层不可进入(缺 x)或不可写(缺 w),mkdir 就会报 Permission denied
- 临时验证:用 sudo -u www-data mkdir -p /a/b/c/test 模拟PHP行为,看是否成功
确认目录是否存在且能递归创建
mkdir 默认不建父目录,路径中间缺任何一级都会失败:
- 代码中必须显式传 true 作为第三个参数:mkdir('/a/b/c', 0755, true)
- 权限数字必须是八进制写法:0755(开头带 0),写成 755 会被当十进制解析,结果错误
- 建议先用 is_dir() 判断,再调 mkdir;或用 is_writable(dirname($path)) 提前验证父目录可写性
绕开常见隐形拦截点
权限看着对,还是失败?可能是这些“看不见”的规则在起作用:
- SELinux:运行 sestatus 看是否启用;若开启,用 ls -Z /path 查上下文,需确保是 httpd_sys_rw_content_t 类型
- open_basedir:执行 php -i | grep open_basedir,若返回非空值,目标路径必须落在该白名单内
- umask 干扰:新建目录权限受系统 umask 影响(如 umask=0022 时,0755 实际建成 755 & ~0022 = 755),线上建议统一设为 0002,并在入口文件开头加 umask(0002)
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











