支持断点续传与秒传:通过分片哈希校验、Redis记录已传分片、全文件哈希预检、临时存储合并及并发加锁,实现大文件可靠上传与去重。

当用户在PHP项目中上传大文件时,若网络中断或上传失败,需支持从断点处继续上传;同时对已上传过的相同文件,应实现秒传以避免重复传输。以下是实现该功能的后端逻辑步骤:
一、文件分片与唯一标识生成
客户端将大文件按固定大小切分为多个片段,并为每个片段计算哈希值;服务端通过合并所有分片哈希或计算整个文件的MD5/SHA1值,生成全局唯一标识,用于判断文件是否已存在。
1、接收前端传递的文件分片信息,包括分片序号、总分片数、文件唯一标识(如file_id)、分片哈希(chunk_hash)及当前分片数据。
2、校验请求中是否包含file_id和chunk_index字段,缺失则返回400错误。
立即学习“PHP免费学习笔记(深入)”;
3、使用sha1_file()或md5_file()对已完整写入的临时分片文件进行哈希比对,确保分片内容完整性。
二、断点续传状态检查与恢复
服务端需维护每个file_id对应的已上传分片索引列表,上传前查询数据库或缓存,返回已成功接收的分片序号,使前端跳过重传。
1、根据file_id查询Redis中存储的已上传分片集合,键名为upload:status:{file_id}。
2、若集合存在且非空,遍历返回已上传的分片序号数组,格式为JSON:{"uploaded_chunks":[0,1,3,4]}。
3、若Redis中无对应记录,则初始化该file_id的状态,设置过期时间为24小时,防止无效状态长期占用内存。
三、分片接收与临时存储
每个分片独立接收并保存为临时文件,路径按file_id组织,避免命名冲突;分片文件不直接写入最终目标位置,待全部接收完成后再合并。
1、构造临时分片路径:/tmp/uploads/{file_id}/chunk_{chunk_index},确保目录存在并具有写权限。
2、使用move_uploaded_file()将PHP临时文件移至目标路径,失败时返回500错误并记录日志。
3、写入成功后,向Redis中upload:status:{file_id}集合添加当前chunk_index值。
四、秒传判定与快速完成
当客户端上传首个分片前,先发送全量文件哈希请求;服务端比对历史文件指纹库,若命中则跳过所有分片上传,直接创建文件记录。
1、接收POST /api/upload/check请求,参数包含file_hash(如全文件MD5)和file_name。
2、查询MySQL表uploaded_files,WHERE条件为file_md5 = ?,若存在记录则返回{"code":200,"message":"秒传成功","file_url":"/storage/xxx"}。
3、若未命中,返回{"code":204,"message":"需分片上传"},前端开始分片流程。
五、分片合并与文件落盘
当所有分片接收完毕,服务端按序号拼接临时文件,生成最终文件,并更新元数据;合并过程需加锁防止并发冲突。
1、获取Redis中upload:status:{file_id}集合成员数,与请求头中total_chunks比对,相等才执行合并。
2、使用fopen()以追加模式打开目标文件路径,循环读取/tmp/uploads/{file_id}/chunk_*并写入。
3、合并完成后,删除临时分片目录,并向uploaded_files表插入新记录,包含file_id、file_md5、file_size、storage_path等字段。



















