实现大文件上传需分片处理与状态持久化:一、MD5秒传判定;二、前端分片切分与并发控制;三、服务端分片接收与临时存储;四、合并逻辑与原子性保障;五、断点续传状态同步。

如果您在搭建PHP网站时需要支持大文件上传,但遇到超时、内存溢出或网络中断导致失败的问题,则可能是由于未采用分片处理与状态持久化机制。以下是实现大文件分片上传、断点续传与服务端秒传功能的具体步骤:
一、基于MD5哈希的秒传判定
服务端通过计算客户端上传文件的完整MD5值,与已存储的文件指纹库比对,若匹配则跳过实际写入,直接返回已有文件路径,实现“秒传”。该机制依赖于客户端预计算并提交文件唯一标识。
1、客户端使用JavaScript FileReader API读取整个文件并计算MD5(或调用Web Worker避免阻塞UI)。
2、将计算出的32位小写MD5字符串作为参数,以GET方式请求服务端接口 /check-upload.php?md5=xxx。
立即学习“PHP免费学习笔记(深入)”;
3、服务端查询数据库或Redis中是否存在该md5字段对应的record,若存在则返回status=200及file_path值。
4、客户端接收到200响应后,直接触发上传完成回调,不发起后续分片请求。
二、前端分片切分与并发上传控制
浏览器端将大文件按固定大小(如5MB)切分为多个Blob块,并为每块生成唯一标识(如md5+index),确保服务端可识别顺序与完整性。并发数限制防止连接耗尽。
1、使用File.slice()方法按偏移量提取当前分片,例如file.slice(start, start + chunkSize)。
2、为每个分片构造FormData对象,添加chunkIndex、totalChunks、fileMd5、fileName等字段。
3、使用XMLHttpRequest或fetch发送POST请求至/upload-chunk.php,设置headers中包含X-Upload-Index和X-Total-Chunks用于服务端路由识别。
4、维护一个并发队列,最多同时执行3个上传请求,其余等待前序完成后再调度。
三、服务端分片接收与临时存储
PHP脚本接收单个分片后,校验其索引合法性、MD5一致性及文件归属,成功则写入临时目录并记录元数据,失败则返回明确错误码供前端重试。
1、从$_POST中获取fileMd5、chunkIndex、totalChunks,并验证是否为数字且在合理范围内。
2、检查$_FILES['file']['error']是否为UPLOAD_ERR_OK,否则返回HTTP 400及错误描述。
3、计算当前分片内容的MD5值,与传入的fileMd5拼接索引后比对,例如md5_file($_FILES['file']['tmp_name']) === md5($fileMd5 . $chunkIndex)。
4、将分片保存至./uploads/tmp/{$fileMd5}/chunk_{$chunkIndex},并写入JSON格式的进度文件./uploads/tmp/{$fileMd5}/progress.json,包含已接收索引数组。
四、服务端合并逻辑与原子性保障
当所有分片接收完毕,触发合并操作:按序读取各分片内容追加写入目标文件,并在完成后删除临时目录。使用rename()替代copy()确保最终文件写入的原子性。
1、读取./uploads/tmp/{$fileMd5}/progress.json,判断count(已接收索引)是否等于totalChunks。
2、创建目标路径./uploads/final/{$fileMd5}_{$fileName},使用fopen($target, 'wb')打开写入句柄。
3、循环读取./uploads/tmp/{$fileMd5}/chunk_*文件,使用fread()逐块写入目标句柄,每次写入后调用fflush()。
4、全部写入完成后,关闭句柄,执行rename('./uploads/final/xxx', './uploads/finished/' . $finalName)完成发布,随后递归删除./uploads/tmp/{$fileMd5}目录。
五、断点续传的状态同步与恢复
客户端在上传中断后再次进入页面时,需向服务端查询已上传分片列表,据此跳过已完成部分,从第一个缺失索引继续上传,避免重复传输。
1、客户端初始化时向/get-progress.php?md5=xxx发起GET请求,获取已成功接收的chunkIndex数组。
2、服务端读取./uploads/tmp/{$fileMd5}/progress.json,返回HTTP 200及JSON格式的{"uploaded":[0,1,3,4]}。
3、前端根据返回数组构建待上传索引集合,例如total=10时,缺失索引为[2,5,6,7,8,9],从中选取下一个进行上传。
4、每次成功上传一个分片后,更新本地记录并重新请求/get-progress.php,确保状态强一致,防止因缓存导致误判。



















