Webman 是基于 Workerman 的 PHP 高性能常驻进程框架,非 Python 框架;PHP 大文件切片上传需绕过 $_FILES,用流式分片接收与合并,并校验完整性、记录断点状态。

Webman 是 Python 框架,不是 PHP 框架 —— 你用 PHP 写 Webman 代码,永远跑不起来。
PHP 生态里没有叫 “Webman” 的主流框架。你查到的所谓 “Webman + PHP” 内容,基本是混淆了名字:
- 真实存在的
webman是基于 Workerman 的 PHP 高性能常驻进程框架(由 PHP 编写,非 Python); - 而网上部分错误资料把 Python 的
webman(压根不存在)、FastAPI、Flask拼凑成 PHP 教程,导致配置路径错、函数名错、依赖报错。
如果你正在写 PHP 项目并想支持大文件切片上传,别被“Webman”误导 —— 你真正需要的是 Workerman 或其上层封装框架(如 Webman-PHP),但核心逻辑和 PHP 原生处理方式一致。
为什么 move_uploaded_file 在大文件场景下必然失败
PHP 默认上传流程走 $_FILES 全局变量,意味着整个文件必须先完整写入临时目录(upload_tmp_dir),再由脚本搬运。这带来三重硬限制:
立即学习“PHP免费学习笔记(深入)”;
-
upload_max_filesize和post_max_size会直接拦截超限请求(返回 413 或空白页) - 内存中加载
$_FILES['file']['tmp_name']后调用move_uploaded_file,对 2GB 文件等于强制吃掉 2GB 内存(memory_limit立刻炸) - 合并分片时若用
file_get_contents+file_put_contents,同样触发内存溢出
php://input 是分片接收的唯一可行入口
前端分片必须绕过传统表单提交,改用 fetch 发送 application/octet-stream 或自定义二进制载荷,后端才能跳过 $_FILES 直接读原始流:
- 必须关闭
enable_post_data_reading = Off(仅限 CLI/Swoole 环境,FPM 下不可用)—— 所以实际项目几乎都用 Swoole/Workerman - 更通用做法:前端仍用
FormData,但每个分片只传blob+ 元数据(chunk_index,total_chunks,identifier),后端用$_POST解析索引,用$_FILES['file']['tmp_name']接收当前分片(此时单片仅几 MB,安全) - 关键点:
php.ini中的upload_max_filesize应设为略大于单片大小(如6M),而非总文件大小
分片合并必须用流式写入,禁用全量加载
合并阶段最常踩的坑是写法错误,例如:
// ❌ 错误:把所有分片读进内存再拼
$allData = '';
foreach ($chunks as $path) {
$allData .= file_get_contents($path); // 10GB 文件 → 10GB 内存
}
file_put_contents($final, $allData);
<p>// ✅ 正确:逐片打开、追加写入
$fp = fopen($final, 'ab');
foreach ($chunks as $path) {
$chunk = fopen($path, 'rb');
stream_copy_to_stream($chunk, $fp);
fclose($chunk);
}
fclose($fp);
- 用
fopen($final, 'ab')确保原子追加,避免并发写乱序 - 不要用
file_put_contents($final, ..., FILE_APPEND),它在大文件下性能差且可能丢数据 - 合并前务必按
chunk_index排序,否则视频/zip 等二进制文件直接损坏
断点续传依赖服务端状态记录,不能只靠前端 localStorage
用户刷新页面后,前端只能知道“本地已传第几片”,但无法确认服务器是否真实收到并落盘。必须由服务端持久化记录:
- 建一张表
upload_chunks,字段至少含:identifier(文件唯一标识,建议用sha256(file_content))、chunk_index、status(success / failed)、created_at - 每次分片上传成功后,插入或更新该记录;合并前查
COUNT(*) == total_chunks且全部status = 'success' - 前端初始化上传时,先发个
GET /api/upload/status?identifier=xxx,服务端返回已传分片列表,前端跳过重传 - 忽略这点,用户网络抖动一次,就可能重复上传几百 MB
分片上传不是“前端切、后端合”八个字能概括的事。最容易被忽略的是:服务端没有校验分片完整性(比如每片单独算 MD5),就直接合并,结果传完发现视频播放卡顿、PDF 打不开 —— 因为某一片在网络传输中被悄悄截断了 3 字节,而你没发现。



















