主因是全程加载文件致内存溢出和损坏;须全程流式操作,且前端分片须补零命名以确保正确排序。

直接读取整个分片再合并,是内存溢出和文件损坏的主因。关键不在调大 memory_limit,而在于全程避免把文件内容加载进 PHP 内存——从接收、存储到拼接,全部走流式操作。
前端必须补零命名分片
分片顺序错乱会直接破坏 MP4/AVI 等容器格式的头部结构(如 moov atom 位置),导致播放失败或 FFmpeg 报错。字符串排序 "1.part"
- 前端生成文件名时统一用 6 位补零:例如
file_abc123_000001.part、file_abc123_000002.part - 后端按
chunkIndex数值排序,或直接用scandir()+natsort()处理补零文件名,杜绝 0,1,10,2 这类错序 - 验证方式:用
xxd -l 64 merged.mp4对比原始文件前 64 字节,检查ftyp和moov签名是否一致
后端禁止整块读取,只做流式落盘与追加
任何 file_get_contents()、fread($fp, filesize()) 或 $_FILES['file']['tmp_name'] 后直接读取的操作,都会把分片(比如 5MB)塞进内存——多个并发上传极易突破 128M 限制,引发静默截断。
- 接收分片后立即用
move_uploaded_file()落盘到临时目录,不经过 PHP 内存中转 - 合并时用
fopen($final, 'wb')创建目标文件句柄,再逐片fopen($chunk, 'rb')+stream_copy_to_stream($src, $dst)流式写入 - 绝对不用
file_put_contents($final, $content, FILE_APPEND)拼字符串,避免编码干扰和缓冲区污染二进制流
必须加入完整性校验与原子操作
大小一致 ≠ 内容正确。网络丢包、磁盘写入异常、并发覆盖都可能导致损坏,仅靠文件长度无法发现。
- 前端上传每个分片时附带该片 MD5;合并前先校验所有分片哈希,缺失或不匹配则拒绝合并
- 合并完成后,调用
hash_file('sha256', $final_path)计算总哈希,并与前端传来的完整文件哈希比对 - 校验失败立即
unlink($final_path),不留下半成品;成功后再用rename()原子替换目标路径,避免中间状态被访问
配套基础设施不可忽略
分片上传不是纯 PHP 逻辑,Nginx、PHP-FPM 和临时目录权限共同决定成败。
- Nginx 必须设置
client_max_body_size 50M(匹配单片大小),否则请求根本进不了 PHP - PHP-FPM 的
request_terminate_timeout和pm.max_requests需调优,防止 worker 进程被长连接拖垮 - 临时分片目录需有写权限,且建议挂载在 SSD 或 tmpfs 上;合并完成立刻
rrmdir()清理,可用register_shutdown_function()做兜底
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











