修复PHP文件删除未校验漏洞的核心是堵住路径遍历、权限越界和静默失败三个缺口:需用realpath()解析用户输入路径,严格比对是否位于合法根目录内,删前校验存在性与可写性,删后检查返回值,禁用@操作符,并对目录删除、Windows兼容、框架场景等实施分步加固与系统层兜底。

修复PHP文件删除未校验漏洞,核心是把“直接删”变成“确认再删”,重点堵住路径遍历、权限越界和静默失败三个缺口。
路径必须先解析再比对
用户输入的路径(如$_GET['file'])不能直接拼接后删除。攻击者可能传入../../etc/passwd或%2e%2e%2fconfig.php绕过简单过滤。
- 用
realpath($input)强制解析为绝对路径,消除./、../和编码干扰 - 设定一个合法根目录(如
UPLOAD_PATH = '/var/www/html/uploads/') - 检查解析后的路径是否以该根目录开头:
strpos($realPath, UPLOAD_PATH) === 0,否则拒绝 - 避免用
str_replace()或preg_replace()“过滤..”,它容易被双编码、大小写、空格等绕过
删前必查存在性与可写性
不检查就调unlink(),会因文件不存在触发Warning,或在Windows下因被占用而静默失败——你以为删了,其实还在。
- 先调
file_exists($path)确认文件真实存在 - 再调
is_writable($path):对文件指能否修改内容,对目录指能否创建/删除子项 - 删完必须检查返回值:
if (unlink($path) === false) { log_error(...); },别用@unlink()掩盖问题 - 若需兼容Windows(文件可能被占用),可先尝试重命名再删:
rename($path, $temp) && unlink($temp)
批量删和目录删要分步隔离
直接rmdir()非空目录会失败;边scandir()边unlink()会导致漏删或警告。
立即学习“PHP免费学习笔记(深入)”;
- 删目录前,先用
glob($dir . '/*')或array_diff(scandir($dir), ['.', '..'])拿到完整列表 - 逐个判断类型:
is_file()就unlink(),is_dir()就递归清空后再rmdir() - 关键目录(如缓存、上传)加防护文件,如
.keep,脚本遇到就跳过该目录 - 自动清理任务必须加开关(如
'enable_cleanup' => false)和日志,记录谁、何时、删了什么
ThinkPHP场景额外加固
TP框架自带缓存、上传、日志等模块,很多内部删操作也依赖unlink(),需统一约束。
- 模型删除走软删除:
use think\model\concern\SoftDelete;+delete_time字段,物理文件另做清理 - 自定义删除逻辑中,所有
unlink()前补三重校验(路径、存在、可写) - 上传目录禁止PHP执行:Nginx加
location ~* \.php$ { deny all; },Apache用.htaccess禁用解析 - 配置
open_basedir限制PHP只能操作指定路径,从系统层兜底



















