因为$_files仅在完整http请求结束时填充,而分片上传是多个独立请求,需用file_id和chunk_index跨请求标识分片,自行管理状态、存储、合并及超时等细节。

为什么直接用 $_FILES 无法处理大文件分片
因为 $_FILES 是 PHP 接收完整 HTTP 请求后才填充的,而分片上传本质是多个独立请求(每片一个 POST),每片只含部分数据。服务端必须能识别“这是第几片”“属于哪个文件”“是否最后一片”,否则无法拼接。PHP 默认不维护跨请求状态,得自己设计标识和存储逻辑。
如何用唯一标识关联同一文件的所有分片
客户端必须在每次请求中携带两个关键字段:file_id(如 UUID)和 chunk_index(从 0 开始)。服务端用 file_id 作为临时目录名,把每片存为 $chunk_index.bin;同时记录总片数(可由客户端传 total_chunks,或首次上传时写入 meta.json)。别依赖文件名——重名或特殊字符会出问题。
-
file_id建议由前端生成(如crypto.randomUUID()),避免服务端生成后需额外返回 - 临时目录路径应带时间戳或哈希前缀,防止遍历攻击,例如
/tmp/upload_{$file_id} - 不要把
file_id存进 session——分片请求可能跨域、无 cookie,session 不可靠
怎么安全地合并分片并校验完整性
合并动作必须在收到最后一片后触发,且仅执行一次。先按 chunk_index 升序读取所有 .bin 文件,用 fopen(..., 'wb') 创建目标文件,再用 fwrite() 追加写入(注意二进制模式)。合并前建议校验:检查实际分片数量是否等于 total_chunks,缺失则返回 400;合并后可选计算 sha256_file() 与客户端传来的 file_hash 对比。
file_put_contents($target, file_get_contents($chunk_path), FILE_APPEND | LOCK_EX);
- 务必用
LOCK_EX防止并发合并导致文件损坏 - 不要用
cat或 shell 命令拼接——不可控、不安全、难调试 - 合并失败时,保留分片目录,供重试;成功后及时
unlink所有分片和meta.json
PHP 配置和 Nginx/Apache 的关键调整
默认配置会拦截大分片:PHP 的 post_max_size 和 upload_max_filesize 要设为单片大小上限(比如 10M),而非整个文件;Nginx 的 client_max_body_size 也需同步调大。更关键的是超时——分片上传可能持续数分钟,要调高 fastcgi_read_timeout(Nginx)或 max_execution_time(PHP),否则连接被中间件断开。
- Apache 下还需确认
LimitRequestBody未设为 0 或过小 - 如果用云对象存储(如 OSS),分片上传完成后可直接回调通知,无需本地合并
- 生产环境务必限制
file_id的生命周期,比如 24 小时后自动清理未完成的临时目录
foreach 拼文件重要得多。php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











