thinkphp 5.1 实现网盘分片上传与断点续传需严格落地“状态可查、分片可控、合并可靠”:前端用 file api 切片并携带 filehash、chunkindex、totalchunks;后端校验参数、落盘至独立目录、合并时校验完整性并异步清理;元数据须持久化至 mysql 或 redis 保障服务重启后续传。

ThinkPHP 5.1 实现企业级网盘的分片上传与断点续传,关键不在框架有多强,而在于前后端对“状态可查、分片可控、合并可靠”这三点的严格落地。它不依赖插件自动完成,需要你手动设计标识逻辑、存储结构和校验环节。
前端切片与上传控制(Vue/原生JS均可)
用 File API 的 slice() 按固定大小(推荐 4–8MB)切片,每片必须携带三个核心字段:
- fileHash:全文件 MD5(非仅文件名),用于唯一标识同一文件,支持跨设备续传
- chunkIndex:从 0 开始的整数序号,不能跳号或重复
-
totalChunks:总片数,由
Math.ceil(file.size / chunkSize)精确计算得出
上传前先发 GET 请求到 /api/upload/status?hash={fileHash},后端返回已存在分片索引数组(如 [0,1,3,4]),前端据此跳过重传。失败分片需带重试机制(最多 3 次),超时设为 60s 以上。
ThinkPHP 5.1 后端接收与分片落盘
控制器中禁用自动验证和模型绑定,直接处理原始请求:
- 检查
$_POST['fileHash']、$_POST['chunkIndex']、$_POST['totalChunks']是否齐全且类型合法 - 分片目录结构为
runtime/upload/chunks/{fileHash}/,确保每个文件有独立空间 - 使用
move_uploaded_file($_FILES['chunk']['tmp_name'], $targetPath)落盘,不用Request::file()->move(),避免框架重命名干扰序号 - 写入成功后立即返回
['uploaded' => true, 'index' => $index],不渲染模板、不触发日志中间件(减少延迟)
合并逻辑与完整性保障
当收到 chunkIndex == totalChunks - 1 的请求时,触发合并检查:
- 遍历
0到totalChunks - 1,确认每个分片物理存在且大小非零 - 缺片则返回 HTTP 409 +
{ "error": "missing_chunk", "missing": [2,5] },前端按提示补传 - 全量就位后,用
fopen($finalFile, 'wb')创建目标文件,再用fwrite()逐片追加(顺序读取part_0→part_{n-1}) - 合并完成后,计算最终文件 MD5 并与原始
fileHash对比;不一致则删除目标文件并报错 - 建议合并成功后异步触发清理分片目录(可用命令行
php think clean:chunks {fileHash})
断点续传的持久化支撑
仅靠临时目录无法应对服务重启或负载均衡场景,必须引入轻量元数据记录:
- 每次分片上传成功后,向 MySQL 写入一条记录:
INSERT INTO upload_chunks (hash, index, uploaded_at) VALUES (?, ?, NOW()) ON DUPLICATE KEY UPDATE uploaded_at = NOW() - 查询接口
/api/upload/status不查文件系统,而是查该表,返回SELECT index FROM upload_chunks WHERE hash = ? ORDER BY index - 表结构含联合唯一键
(hash, index),避免重复写入;加索引提升查询速度 - 若使用 Redis,可用
SET upload:status:{hash} "{0,1,3,4}"存字符串,但注意过期时间设为 7 天以上
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











