unlink()返回true不代表文件已删除,因它仅检查删除权限而不验证文件是否存在或是否被进程占用;windows下文件被记事本等占用时即现此现象,可靠确认需unlink后调用file_exists()并配合clearstatcache()。

PHP 删除文件最常用的是 unlink(),但它不报错不代表删成功了——权限、路径、符号链接、Windows 句柄占用都会让它静默失败。
为什么 unlink() 返回 true 却没删掉文件?
这是最常被忽略的坑:unlink() 只检查「是否有权限执行删除操作」,不验证文件是否真实存在或是否被其他进程锁住。尤其在 Windows 上,如果文件正被记事本、IDE 或日志写入进程打开,unlink() 会返回 true,但文件实际仍留在磁盘上(直到句柄关闭)。
- 用
file_exists()在unlink()后再检查一次,才是可靠确认方式 - 删除前加
clearstatcache(true, $filepath),避免因 PHP 缓存导致file_exists()返回旧结果 - Windows 下可先尝试
fopen($filepath, 'c')+flock()判断是否可写/可删,但成本高,一般只用于关键流程
删除前必须校验的三件事
跳过校验直接 unlink() 是线上事故高发原因。
-
路径是否绝对:相对路径依赖
getcwd(),CLI 和 Web SAPI 下 cwd 不同。务必用__DIR__ . '/path/to/file.txt'或realpath()转成绝对路径 -
是否越权访问:不要拼接用户输入到路径中。如
$_GET['file']必须白名单过滤或用basename()截取文件名,再拼进可信目录 -
是否是目录:
unlink()只删文件,对目录会警告并失败。要删空目录用rmdir();删非空目录得先递归清空——别手写,用RecursiveDirectoryIterator+RecursiveIteratorIterator
unlink() 的替代方案:什么时候该换?
不是所有场景都适合裸用 unlink()。
- 需要原子性(比如删配置文件后立刻写新文件):用
rename($old, $new_temp)先改名,再unlink($new_temp),避免中间状态暴露 - 跨文件系统移动+删除(如归档旧日志):
rename()在同设备上是原子的,比copy()+unlink()更安全 - 批量删且关心失败明细:用
array_map('unlink', $files)会中断于第一个失败;改用foreach+try/catch(注意unlink()不抛异常,得靠返回值 +error_get_last()捕获 warning)
真正难的不是写那行 unlink($path),而是删之前想清楚:这文件此刻能不能删、删完有没有残留、删错了能不能回滚。尤其是日志、上传临时文件、缓存这些高频操作点,静默失败比报错更危险。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











