thinkphp大文件分片上传需绕过同步接收模型,构建前后端协同、状态可追溯、失败可恢复的流程;前端用file api切片并持久化进度,后端校验防冲突、加锁写入、合并时校验md5并加锁防并发。

ThinkPHP 文件分片上传要稳定传输,核心不是“用哪个 Upload 类”,而是绕过框架默认的同步接收模型,构建前后端协同、状态可追溯、失败可恢复的分片流程。TP5/TP6 原生 request()->file() 或 Upload 类只适合几 MB 的小文件,大文件(≥50MB)必须走分片逻辑,否则极易因超时、内存溢出、Nginx 413 错误或网络抖动导致失败。
前端切片与状态管理要可靠
前端不能依赖表单提交,必须用 File API + fetch/Axios 控制全流程:
- 按固定大小切片(如 2MB 或 5MB),chunkSize 必须与后端配置严格一致,否则合并校验会失败
- 每个分片生成唯一 chunkId(推荐
MD5(file.name + file.lastModified + index)),不可用随机数,否则断点无法识别 - 上传前先 GET 请求
/api/upload/check?chunkId=xxx&chunkIndex=0查询是否已存在,返回 200 就跳过,避免重复传 - 上传成功后立即存入
localStorage(不是 sessionStorage),记录{index: i, status: 'success'},页面刷新不丢进度
后端接收与临时存储要防冲突
TP6 推荐用 request()->file() 接收单个分片,但需加关键防护:
- 校验
chunkIndex是非负整数,防止路径穿越(如传../../../etc/passwd) - 所有分片统一存到
runtime/upload/chunks/{date}/{chunkid}/,按日期分目录,避免单目录文件爆炸 - 分片文件名格式为
{chunkid}-{chunkindex}.tmp,便于后续顺序合并 - 高并发场景下,对每个分片写入前加
flock($fp, LOCK_EX),防止多进程同时写同一文件出错
合并阶段必须校验完整性
最后一个分片上传完成后,触发合并,这一步最容易出问题:
- 先查数据库或目录,确认
total_chunks个分片全部存在且大小匹配,缺一不可 - 用
fopen(..., 'ab')追加方式打开目标文件,逐个fread + fwrite写入,**不能一次性读入内存**(防 OOM) - 合并完成后,计算最终文件的 MD5,与原始文件 MD5 对比;不一致则删除目标文件并报错
- 整个合并过程加数据库行锁或 Redis 分布式锁,避免多个请求同时触发合并造成文件损坏
服务端配置和环境要兜底
再好的代码也架不住服务器拦腰截断:
- Nginx 中设置:
client_max_body_size 100M、client_body_buffer_size 10M、proxy_read_timeout 600 - PHP 中调整:
post_max_size = 100M、upload_max_filesize = 100M、max_execution_time = 600 - TP6 的
filesystem.php配置中,临时目录(如runtime/upload)要确保 PHP 进程有读写权限 - 生产环境禁用
display_errors,但开启error_log,所有分片操作都记日志(含 chunkId、index、耗时、IP)
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











