unlink() 失败主因是父目录无写权限,而非文件自身权限;需确认 PHP 进程用户对父目录有 w 权限,并排查 open_basedir 限制及 Windows 只读属性或文件占用。
PHP 的 unlink() 失败,和文件自身权限(chmod)关系极小——真正起决定作用的是**父目录的写权限**。即使文件是 777,只要它所在的目录没有写权限(w 位),unlink() 就会报 Permission denied。这是 POSIX 文件系统的基本行为,不是 PHP Bug。
常见错误现象:
- 手动 chmod 777 file.txt 后,unlink('file.txt') 仍失败
- is_writable('file.txt') 返回 true,但 unlink() 报错
- 错误信息通常是:Warning: unlink(): Permission denied in ...
ls -ld /path/to/dir,确认当前 PHP 进程用户(如 www-data 或 nginx)对该目录有 w 权限chmod u+w /path/to/dir(若属主是 PHP 进程用户)chown www-data:www-data /path/to/dir + chmod 755(更安全)Web 服务器(Apache/Nginx)以特定用户身份运行 PHP,而你用 root 或个人账户执行 chmod,容易造成权限“看起来对、实际不对”。关键不是“谁改的权限”,而是“谁在删”。
实操建议:
- 查 PHP 进程用户:ps aux | grep -E '(apache|httpd|nginx|php-fpm)',看 USER 列
- 在 PHP 脚本中加一行:echo posix_getpwuid(posix_geteuid())['name'];,确认真实执行用户
- 若用户是 www-data,但文件属主是 root,且目录权限是 755,则 www-data 无法删除——因为其他用户无写目录权
sudo -u www-data ls -l /path/to/dir 模拟 PHP 用户视角root 直接 chown/chmod 网站目录;应统一归属到 Web 用户或组setgid 目录(chmod g+s /path/to/dir)即使权限全对,unlink() 也可能因 PHP 运行时限制被拦截。最常见的是 open_basedir——它限制 PHP 只能访问指定路径,超出即拒绝所有 I/O 操作,包括 unlink()。
排查方式:
- 查 phpinfo() 输出中 open_basedir 值,或运行 echo ini_get('open_basedir');
- 若返回非空字符串(如 /var/www/html:/tmp),确保你要删的文件路径在其中
- 错误信息可能仍是模糊的 Permission denied,但实际是策略拦截
ini_set('open_basedir', '');(仅开发环境)ini_set('open_basedir', '/var/www/html:/tmp:/your/delete/path');
safe_mode,但旧配置残留仍可能被解析为警告源Linux 看目录写权,Windows 还要看文件本身的 read-only 属性 + 是否被其他进程打开。PHP 在 Windows 上调用 unlink() 时,这两点任一触发都会失败。
典型表现:
- unlink() 返回 false,但无明确错误
- error_get_last() 可能返回 Access is denied
- 文件在资源管理器里显示“只读”小锁图标
chmod 644 $file 在 Windows 上无效,改用 exec("attrib -R " . escapeshellarg($file));
handle.exe(Sysinternals)或任务管理器“性能 → 打开资源监视器 → CPU → 关联的句柄”搜索文件名EnableSendfile on,可能缓存文件句柄;重启服务可释放权限问题本质是三层叠加:操作系统级(目录写权 + 用户匹配)、PHP 运

open_basedir)、文件系统级(Windows 属性/占用)。最容易忽略的是第一层——盯着文件改权限,却忘了删动作发生在目录上。