PHP实现大文件分片上传与断点续传实战
发布时间:2026/10/26 2:48:09 锦皓数字建站

1. 视频分片上传的核心价值与挑战在当今视频内容爆炸式增长的时代传统文件上传方式已经无法满足大文件传输的需求。我经历过一个真实案例某教育平台需要上传平均2GB的高清课程视频使用传统表单上传时90%的请求都会因超时或网络波动失败。这就是为什么我们需要分片上传技术——它将大文件切割成多个小块像接力赛一样分批传输即使某次传输失败也只需重传单个分片。PHP作为服务端主力语言与前端配合实现分片上传需要解决几个关键问题分片策略如何确定最优分片大小我们测试发现5MB在兼容性和效率上达到最佳平衡分片标识采用文件MD5分片序号的命名规则避免冲突断点续传服务端需要记录已接收分片信息我常用Redis的Hash结构存储进度分片合并所有分片上传完成后使用PHP的fopen/fwrite进行二进制合并重要提示分片上传必须配合秒传验证。我们曾因忽略这一步导致存储大量重复文件——先计算文件MD5并查询服务端是否已存在完整文件。2. 客户端分片处理方案2.1 前端分片切割实现现代浏览器提供了File API支持文件切割以下是核心代码示例// 获取文件对象 const file document.getElementById(videoFile).files[0]; const chunkSize 5 * 1024 * 1024; // 5MB分片 const totalChunks Math.ceil(file.size / chunkSize); // 创建分片上传任务 for (let i 0; i totalChunks; i) { const start i * chunkSize; const end Math.min(start chunkSize, file.size); const chunk file.slice(start, end); // 构造FormData const formData new FormData(); formData.append(file, chunk); formData.append(chunkNumber, i); formData.append(totalChunks, totalChunks); formData.append(fileId, md5(file.name file.size)); // 上传分片 await fetch(/upload.php, { method: POST, body: formData }); }2.2 上传优化策略在实际项目中我们发现几个性能瓶颈点顺序上传导致速度受限 → 改用Promise.all实现并行上传网络波动导致重复上传 → 增加分片MD5校验大文件内存占用高 → 使用FileReader的readAsArrayBuffer分段读取我们优化后的上传速度对比优化措施1GB文件上传时间网络消耗原始方案8分32秒1.2GB并行上传2分15秒1.05GB压缩分片1分48秒860MB3. 服务端PHP处理架构3.1 基础接收逻辑ThinkPHP框架下的分片处理示例public function uploadChunk() { $file request()-file(file); $chunkNumber input(chunkNumber); $totalChunks input(totalChunks); $fileId input(fileId); // 创建临时目录 $tempDir uploads/temp/{$fileId}; if (!is_dir($tempDir)) { mkdir($tempDir, 0777, true); } // 保存分片 $chunkName {$tempDir}/{$chunkNumber}.part; $file-move($tempDir, $chunkName); // 检查是否全部完成 $uploadedChunks count(glob({$tempDir}/*.part)); if ($uploadedChunks $totalChunks) { $this-mergeChunks($fileId, $tempDir); } return json([status success]); }3.2 分片合并的陷阱合并分片时我们踩过几个坑直接使用file_put_contents追加写入会导致内存溢出 → 改用fopenfwrite流式处理Windows系统对同时打开的文件数有限制 → 合并时限制同时打开的文件句柄数文件名排序问题导致合并顺序错乱 → 使用natsort自然排序改进后的合并函数核心逻辑private function mergeChunks($fileId, $tempDir) { $finalFile uploads/videos/{$fileId}.mp4; $handle fopen($finalFile, wb); // 获取并排序分片文件 $chunks glob({$tempDir}/*.part); natsort($chunks); // 分批合并 $bufferSize 4096; // 4KB缓冲区 foreach ($chunks as $chunk) { $chunkHandle fopen($chunk, rb); while (!feof($chunkHandle)) { fwrite($handle, fread($chunkHandle, $bufferSize)); } fclose($chunkHandle); unlink($chunk); // 删除已合并分片 } fclose($handle); rmdir($tempDir); }4. 生产环境进阶方案4.1 秒传与断点续传实现完整的文件上传状态管理需要三个关键接口预检接口/api/upload/checkpublic function check() { $fileId input(fileId); $fileSize input(fileSize); // 检查是否已存在完整文件 if (file_exists(uploads/videos/{$fileId}.mp4)) { return json([status exist]); } // 获取已上传分片 $tempDir uploads/temp/{$fileId}; $uploaded is_dir($tempDir) ? count(glob({$tempDir}/*.part)) : 0; return json([ status continue, uploaded $uploaded ]); }4.2 分布式环境适配当服务需要水平扩展时我们采用以下架构使用Redis存储分片元数据分片文件存储到对象存储如MinIO合并操作通过消息队列异步处理Redis存储结构示例$redis-hSet(upload:{$fileId}, total, $totalChunks); $redis-hSet(upload:{$fileId}, chunk_{$chunkNumber}, 1); $uploaded $redis-hLen(upload:{$fileId}) - 1; // 减去total字段5. 安全防护方案5.1 关键安全措施我们曾因安全漏洞导致视频被注入恶意内容现采用五层防护分片校验每个分片上传时验证MD5类型检测使用finfo_file检查真实文件类型权限控制上传目录禁止执行PHP病毒扫描调用ClamAV扫描接口流量限制Nginx层限制上传速率安全配置示例Nginxlocation ~ /upload\.php$ { client_max_body_size 10M; limit_rate 500k; include fastcgi_params; fastcgi_param PHP_VALUE upload_max_filesize10M \n post_max_size12M; }5.2 性能监控指标我们建立了完整的监控体系跟踪上传质量分片成功率98.7%低于95%触发告警平均合并时间1.2秒/GB错误类型分布网络超时43%分片校验失败31%存储空间不足17%其他9%通过ELK收集的日志分析我们发现周二上午10点是上传失败高峰期针对性增加了此时段的服务器资源。这套方案在我们多个项目中稳定运行最高支持过单日37TB的视频上传量。关键点在于分片策略要匹配网络状况合并操作要保证原子性监控体系要能快速定位问题。对于更复杂的场景可以考虑集成七牛云、阿里云等专业SDK但核心原理都是相通的。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。