PHP实现表单上传20GB大视频至服务器的最佳实践咨询
20GB级PHP视频上传实现方案(解决大文件上传损坏问题)
原Plupload方案100MB以上文件损坏的核心原因
- PHP配置未对齐:默认
post_max_size、upload_max_filesize、memory_limit、max_input_time、max_execution_time配置值小于实际上传分片大小,服务端接收中途截断文件,前端却收到假的完成响应 - 分片合并逻辑错误:后端合并分片时未按分片序号排序、遗漏分片、读写文件未使用二进制安全模式,直接导致最终文件结构损坏
- Web服务器层限制:Nginx/Apache自带的请求体大小限制、超时时间配置过短,请求中途被服务端切断
- 临时目录空间不足:PHP默认临时上传目录所在分区剩余空间小于上传文件大小,写入中途失败生成残次文件
推荐落地实现方案(稳定支持20GB单文件上传)
核心架构必须采用分片上传,不要使用整文件直传逻辑:前端将大文件切为固定大小的分片逐个上传,全部分片传输完成后由PHP后端合并为完整文件,全程加完整性校验,同时支持断点续传降低网络波动带来的失败率。
前端实现要点
- 不要依赖Plupload默认的分片配置,直接用原生
File API实现切片逻辑:通过File.slice()方法切割文件,单分片大小推荐设为10MB~50MB(根据服务器带宽调整,不建议超过100MB),每个分片携带三个核心参数:文件唯一标识(建议用文件MD5+文件大小+文件名生成)、分片序号、总分片数 - 单个分片上传失败自动重试3次,避免单个分片传输失败导致整个文件重传
- 上传前先计算全文件MD5值,传给后端做最终完整性校验
- 可选支持断点续传:正式上传前先向后端查询当前文件已上传成功的分片列表,直接跳过已完成分片,适配大文件上传中途断网的场景
PHP后端配置&实现要点
- 调整PHP核心配置(
php.ini/.user.ini/代码动态修改均可):分片上传场景下不需要把大小限制调到20GB,只要大于单分片大小留足冗余即可
# 假设单分片设为50MB,这里设为64MB留冗余 upload_max_filesize = 64M post_max_size = 64M # 不需要分配过大内存,分片逐块读写即可,避免内存溢出 memory_limit = 256M # 单分片传输超时时间设为5分钟,适配慢网络场景 max_input_time = 300 max_execution_time = 300 # 临时目录改到剩余空间大于单文件总大小的分区,避免写盘失败 upload_tmp_dir = /data/php_upload_tmp
- 对齐Web服务器配置:
- Nginx修改
client_max_body_size 64M;、client_body_timeout 300s; - Apache修改
LimitRequestBody 67108864(对应64MB)、Timeout 300
- Nginx修改
- 分片接收逻辑:
- 每个分片上传完成校验通过后,立刻移动到和文件唯一标识绑定的专属分片目录,以分片序号命名存储,避免顺序混乱
- 每次接收分片后校验当前分片的MD5值,和前端传入的分片MD5对比,不一致直接返回错误让前端重传当前分片
- 读写分片必须用二进制安全模式,比如
fopen打开文件时使用wb参数,不要用字符串操作函数处理二进制文件内容
- 分片合并逻辑:
- 收到前端合并请求后,先校验分片目录下的文件数量是否和总分片数一致,缺片直接返回错误
- 严格按照分片序号从小到大的顺序,逐块读取分片内容追加写入最终目标视频文件,不要一次性把所有分片读入内存
- 合并完成后计算完整文件的MD5值,和前端传入的全文件MD5做对比,校验一致才返回上传成功;校验失败立刻删除残次文件和临时分片,通知前端重传
- 合并完成后及时删除临时分片目录释放磁盘空间
运维避坑项
- 配置定时清理脚本,定期删除超过24小时未完成上传的临时分片,避免无效文件占满磁盘
- 存储最终视频文件的分区要提前预留足够空间,建议预留值为单文件最大大小的2倍以上
- 不要尝试通过调整配置用整文件上传逻辑处理20GB文件,即使配置拉满,也会因为网络闪断、服务器重启导致全量上传失败,用户体验极差
问题参考截图

内容的提问来源于stack exchange,提问作者Noweh
相关产品推荐
相关产品推荐

