先用 is_writable() 和 posix_getpwuid() 确认真实写权限与运行用户;再逐级检查目录 x 权限;最后排查 selinux 或 open_basedir 限制。

PHP写文件报“Permission denied”怎么快速定位
别急着改权限,先让代码自己说话。在 file_put_contents() 或 fopen() 前加两行诊断:
if (!is_writable('/target/dir')) { error_log('NOT WRITABLE: ' . '/target/dir'); die(); }error_log('PHP user: ' . posix_getpwuid(posix_geteuid())['name']);
is_writable() 在 Linux 下实际检测的是当前 PHP 进程(不是你登录的用户)是否有写权限,比手动 ls -l 更准;posix_getpwuid() 能确认真实运行用户——常见是 www-data(Debian/Ubuntu)、apache(CentOS/RHEL)或 nginx(某些 Nginx + PHP-FPM 配置)。
目录权限到底缺哪一环
Linux 目录写入需要两个条件同时满足:目录本身有 w(写)位,且上层路径每级都有 x(执行)位。很多人只改了目标目录权限,却漏掉父级目录的 x。
- 用
ls -ld /var/www/html/uploads看目标目录:末位必须有x(如drwxr-xr-x),否则 PHP 连“进入”都做不到 - 再往上查:
ls -ld /var/www/html、ls -ld /var/www、ls -ld /var—— 任意一级缺x,都会导致 Permission denied - 修复命令:
sudo chmod 755 /var/www/html/uploads(保证 rwxr-xr-x),再逐级补x:sudo chmod a+x /var/www /var/www/html
SELinux 或 open_basedir 拦路怎么办
即使 ls -ld 显示权限全开、is_writable() 返回 true,仍可能被 SELinux 或 PHP 安全限制拦截。
- 查 SELinux:运行
sestatus,若输出enabled,再执行ausearch -m avc -ts recent | grep httpd看是否报avc: denied。CentOS/RHEL 上常见,需执行:sudo setsebool -P httpd_write_content 1 - 查 open_basedir:运行
php -i | grep open_basedir,若返回非no value,说明被限制。修改php.ini或站点配置,把目标路径加进白名单,例如:open_basedir = "/var/www/html:/tmp",然后重启 Web 服务 - 注意:Nginx + PHP-FPM 场景下,
open_basedir通常在php-fpm.conf或 pool 配置里设置,不是全局php.ini
用 sudo 执行系统命令时卡在 “no tty present”
PHP 的 exec()、shell_exec() 调用 sudo 会失败,因为默认要求交互式终端(tty)。硬改 /etc/sudoers 开放所有命令风险太大。
- 不要写
sudo /path/to/cmd,而是用visudo添加最小化授权: - 注释掉
#Defaults requiretty - 添加一行:
www-data ALL=(ALL) NOPASSWD: /usr/local/bin/yourcmd(把www-data换成你的 PHP 用户,路径写绝对路径) - PHP 中调用:
exec('sudo /usr/local/bin/yourcmd arg', $out)—— 不带密码、不依赖 tty,且只放行指定命令
真正麻烦的不是权限数字本身,而是路径中某一级目录默默缺了 x,或者 SELinux 策略在后台静默拒绝——这两处最容易被跳过。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











