PHP mkdir()失败主因是Web进程用户(如www-data)对父目录无写权限,需用ls -ld确认父目录属主及权限,再chown修正所有权,而非盲目chmod 777。

Web 服务器用户必须拥有父目录写权限
PHP 脚本创建目录(比如 mkdir()、上传临时文件、session 写入)失败,90% 是因为 Web 进程用户(如 www-data)对目标路径的父目录没有写权限。不是“目录本身没权限”,而是“上一级目录不让进”。
- 用
ls -ld /var/www/sitea查看父目录权限和所有者,确认输出中包含www-data或你为该站点创建的专属用户(如sitea-user) - 若显示
drwxr-xr-x 5 root root,说明www-data无法在其中新建子目录——必须改所有者:sudo chown sitea-user:sitea-user /var/www/sitea - 不要盲目
chmod 777:这等于把门敞开,攻击者可直接写入恶意脚本
网站根目录和文件的标准权限组合
权限数字不是越小越安全,也不是越大越方便;关键是“最小必要”+“上下文隔离”。共用 www-data 用户时,这套组合能防住大部分横向渗透。
-
/var/www/sitea/(根目录):设为755—— 所有者可读写执行,组和其他用户只读+执行(允许 Web 服务器进入,但不能改文件) -
/var/www/sitea/*.php(脚本文件):统一644—— 所有者可读写,其他用户只读(防止被下载源码) -
/var/www/sitea/config/(含数据库配置等):必须700或750,且归属sitea-user:sitea-user,禁止其他用户访问 -
/var/www/sitea/tmp/(缓存、上传临时目录):需700,且确保sitea-user对其有完整控制权,chmod 700 /var/www/sitea/tmp
独立 PHP-FPM 池下权限容易漏掉的三处
用了 user = sitea-user 却仍报 Permission denied?问题往往不在 PHP 配置本身,而在配套的系统级约束。
-
listen.owner和listen.group必须与 Nginx 的user(通常是www-data)同组,或设为www-data—— 否则 Nginx 进程连不上 socket -
/run/php/目录本身需允许www-data写入:sudo chown root:www-data /run/php+sudo chmod 775 /run/php - 如果开了
opcache.file_cache,缓存目录(如/var/www/sitea/opcache)也得归sitea-user所有,并设700,否则 FPM 启动时静默失败
open_basedir 和实际目录权限的关系
open_basedir 是白名单机制,不替代文件系统权限。它只管“PHP 脚本能 fopen 哪些路径”,不管“能不能写进去”。两者必须配合使用。
立即学习“PHP免费学习笔记(深入)”;
- 即使
open_basedir = "/var/www/sitea:/tmp",若/tmp目录本身是drwxr-xr-x root root,PHP 仍无法在其中fopen('/tmp/test.txt', 'w') - 正确做法:把
/tmp下划出专用子目录,如/tmp/sitea,再chown sitea-user:sitea-user /tmp/sitea+chmod 700 /tmp/sitea,然后在 pool 配置里加php_admin_value[open_basedir] = "/var/www/sitea:/tmp/sitea" - 注意:Nginx 的
fastcgi_param PHP_VALUE传open_basedir时,值里不能含空格或未转义的分号,否则整个参数被截断
sitea-user 能否写 /var/www/sitea/tmp,取决于它是否拥有该目录的所有权;而 Nginx 能否把请求转发过去,取决于它能否访问 /run/php/php8.3-fpm.sitea.sock——这两件事,一个都不能少。



















