直接比对md5无法实现真正秒传,根本原因是浏览器formdata上传会添加boundary和换行符污染原始二进制流;客户端须用filereader+arraybuffer计算原生md5,服务端需读php://input校验后跳过保存。

为什么直接比对MD5无法实现真正的秒传
客户端上传前计算的 MD5 值,和服务端用 file_get_contents() 或 fopen() 读取后计算的 MD5 理论上一致,但实际常不匹配——根本原因是:**浏览器 FormData 上传时会自动添加 boundary 和换行符,原始文件二进制流已被污染**。你拿到的不是原始文件,而是 multipart 编码后的数据体。所以服务端若直接对临时文件($_FILES['file']['tmp_name'])算 MD5,大概率和客户端不符。
客户端必须用 FileReader + ArrayBuffer 计算原始 MD5
只有绕过表单提交、用 fetch 或 XMLHttpRequest 发送原始二进制,才能保证一致性。常见错误是用 jQuery.ajax 传 FormData,这注定失败。
- 用
FileReader读取file得到ArrayBuffer - 用
spark-md5(或类似库)对ArrayBuffer计算原生 MD5,**不要转成 base64 或 hex 中间态再算** - 将得到的 32 位小写 hex 字符串(如
"d41d8cd98f00b204e9800998ecf8427e")作为md5字段随文件元数据一起发送 - 请求头设为
Content-Type: application/octet-stream,避免被当 multipart 处理
PHP 接口需跳过 $_FILES,直接读取原始输入流
如果前端发的是纯二进制流,$_FILES 根本不会被填充,强行依赖它会导致空数组、找不到临时文件等错误。必须用 php://input 获取原始字节,并在入库前校验 MD5。
- 用
file_get_contents('php://input')读取全部上传内容(注意内存限制,大文件需分块读) - 用
md5($rawData)计算服务端 MD5,与客户端传来的md5字段严格比对(区分大小写) - 若一致,**跳过保存文件**,直接返回已有文件路径或 ID;若不一致,才写入磁盘并记录
md5 → filepath映射(建议存 MySQL 或 Redis) - 务必校验
Content-Length头是否与读取长度一致,防止截断或注入
生产环境必须加文件分片与断点续传兜底
纯 MD5 秒传只适用于小文件(
- 客户端按固定块大小(如 4MB)切片,每片单独计算 MD5 并预检
- 服务端返回已存在的分片列表,客户端只上传缺失分片
- 所有分片上传完成后,服务端拼接并再次校验整体 MD5 —— 这才是防错的关键一环
- PHP 中拼接不能简单
file_put_contents($final, $chunk, FILE_APPEND),需用fopen(..., 'a')+fwrite避免并发写乱序
MD5 本身不抗碰撞,敏感系统应升级为 sha256,且永远不要把 MD5 当唯一索引——两个不同文件哈希冲突概率虽低,但一旦发生,秒传就变成“错传”。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











