ThinkPHP文件完整性校验包含上传合法性校验(size/ext/image等)和落地后哈希比对(如sha256),需单独调用$file->validate()、避免复用实例、保存后读取再校验,并结合存储层增强可信链。

ThinkPHP 中“文件完整性校验”不是指上传过程不丢包(那是 HTTP 层保障),而是指确认文件内容未被篡改、未损坏、符合预期形态。它包含两个层面:一是上传阶段的合法性校验(防恶意文件、超限、格式伪装),二是落地后的可信性验证(如 MD5/SHA256 比对)。两者缺一不可。
上传时做严格合法性校验
这是第一道防线,防止非法或异常文件进入系统。
- 必须对每个
think\File实例单独调用$file->validate(),规则至少包含size(字节数)、ext(原始后缀)、image(如需图片)等。注意:ext校验只看上传名后缀,不检测内容,evil.jpg.php会被放过,需配合 MIME 或后续内容扫描 - TP6.0.13+ 可直接用
$request->file('files')获取数组;低版本需循环调用$request->file('files', $index)或手动构造 - 校验失败后不要调
move(),否则报 “Uploaded file is not valid”。应先收集错误,统一返回对应文件的失败原因 - 避免复用同一 File 实例多次 move —— 它内部会移动并重命名临时文件,第二次调用源文件已不存在
保存后做内容级哈希校验
上传通过 ≠ 文件安全。落地后生成哈希值,与可信快照比对,才能确认内容完整性。
- 用
md5_file($path)或更安全的hash_file('sha256', $path)计算文件摘要。MD5 快但不推荐用于高安全场景 - 若需校验整个文件夹,不能直接 hash 目录,而要递归遍历所有文件,按相对路径排序,逐个计算
hash_file(),再拼接整体哈希(如:sha256(sha256(f1).sha256(f2)...) - 快照建议存为 JSON 文件,含时间戳、文件路径列表及各自哈希值,便于回溯和增量比对
- 生产环境校验前,先用
is_readable($path) && is_file($path)轻量探测,避免因权限、IO 错误导致脚本中断
配合存储层增强可信链
ThinkPHP 的 think-filesystem 扩展让校验更可控。
立即学习“PHP免费学习笔记(深入)”;
- 上传成功后,立即用
Storage::disk('public')->get($path)读取刚存入的内容,再算一次哈希,确保写入无损 - 若使用云存储(如 OSS/COS),可开启服务端 MD5 校验(部分 SDK 支持自动传
Content-MD5Header),由对象存储服务完成一致性校验 - 对关键文件(如配置包、安装包),可在上传接口返回中附带服务端计算的
sha256值,供客户端二次比对
规避常见陷阱
很多“校验失败”其实源于细节疏忽。
- 不要用普通
Validate类校验文件对象 —— 它不识别fileSize规则;TP6 必须用Validate+ 手动构造含tmp_name/size/extension的数组,或直接走File->validate() -
scandir()遇到损坏目录会触发 Warning,要用@scandir()或 try/catch 包裹,否则脚本中断 - Redis 缓存 nonce 或哈希快照时,记得设 TTL,避免陈旧数据干扰验证逻辑



















