Webman 中用 c->formFile('file') 接收单文件,需确保表单为 POST 且 enctype="multipart/form-data",返回 UploadFile 实例或 null,须判空;推荐 formFile() 是因其在协程下更稳定、自动校验、支持中文名,而 $_FILES 在 Swoole 环境中易丢失或乱码。

Webman 默认不内置文件上传中间件,但通过原生 $_FILES 或框架封装的 c->formFile() 可直接处理上传;大文件分片必须自行实现服务端合并逻辑,Webman 本身不提供断点续传或分片状态管理。
Webman 中怎么用 c->formFile() 接收单文件
Webman 的 Context 对象提供了 formFile() 方法替代直接读 $_FILES,更安全且自动校验是否为合法上传文件。
- 调用前确保前端表单是
method="POST"且enctype="multipart/form-data" -
formFile("file")的参数名必须与<input type="file" name="file">一致 - 返回值是
UploadFile实例,含getRealPath()(临时路径)、getClientFilename()(原始名)、getSize()等方法 - 若上传失败(如超限、无文件),
formFile()返回null,需主动判空,不能直接调用方法
示例:
use Webman\Http\Context;
function upload(Context $c) {
$file = $c->formFile('file');
if (!$file) {
return $c->json(['code' => 400, 'msg' => '未检测到上传文件']);
}
$tmpPath = $file->getRealPath();
$originalName = $file->getClientFilename();
$targetPath = 'uploads/' . uniqid() . '_' . basename($originalName);
if (move_uploaded_file($tmpPath, $targetPath)) {
return $c->json(['code' => 0, 'path' => $targetPath]);
}
return $c->json(['code' => 500, 'msg' => '保存失败']);
}
为什么不能直接用 $_FILES 而推荐 formFile()
Webman 运行在 Swoole 协程环境下,$_FILES 在某些版本或配置下可能被清空、延迟填充,或受协程上下文干扰;formFile() 是框架在请求解析阶段就完成的可靠封装,绕过 PHP 原生 CGI 模式依赖。
立即学习“PHP免费学习笔记(深入)”;
-
$_FILES在 CLI/Swoole 模式下行为不稳定,尤其配合upload_max_filesize较大时易丢失数据 -
formFile()内部已校验error === UPLOAD_ERR_OK,避免手动漏判 - 它能正确处理中文文件名(UTF-8 编码),而
$_FILES['file']['name']在 Windows 客户端可能为 GBK 编码乱码 - 若使用
formFile()后再访问$_FILES,可能因底层已消费流而导致$_FILES为空数组
大文件分片上传要自己实现哪些关键环节
Webman 没有内置分片上传支持,必须手动设计「分片接收 → 存临时块 → 合并 → 清理」全流程。核心难点不在接收,而在状态保持和并发安全。
- 前端需按固定大小切片(如 1MB/片),每片带唯一
identifier(如文件 hash)、filename、chunkIndex、totalChunks - 服务端接收后存为
uploads/chunks/{identifier}/{chunkIndex},**不能直接写入最终目录** - 合并逻辑需检查所有分片是否齐备(
chunkIndex从 0 到totalChunks-1),用fopen(..., 'wb')+ 多次fwrite()拼接,**不可用file_put_contents(..., FILE_APPEND)**(顺序不可靠) - 合并成功后立即删除整个
chunks/{identifier}/目录,否则磁盘会被碎片占满 - 必须加锁:同一
identifier的多次请求不能并发合并,可用file_put_contents('lock_'.$identifier, '', LOCK_EX)简单实现
注意:upload_max_filesize 和 post_max_size 仍需调大(如 200M),否则单个分片请求就会被 PHP 层拦截,根本进不到 Webman 路由。
上传目录权限与 MinIO 集成的取舍点
本地存储简单,但扩容、高可用、CDN 加速弱;对接 MinIO 可解耦存储,但需额外维护对象存储服务,并修改上传逻辑为 SDK 调用。
- 若用本地目录,确保
uploads/和uploads/chunks/对 Swoole worker 进程用户(如www-data)可读写,且uploads/**禁止执行脚本**(Nginx/Apache 需配location ~ \.php$ { deny all; }) - 若集成 MinIO,不要在 Webman 中直接用
move_uploaded_file(),改用MinioClient::putObject()流式上传,避免内存爆掉 - MinIO 的
putObject()支持stream参数,可传$file->getRealPath()对应的fopen()资源,比先存本地再读取更省内存 - MinIO 不支持「分片上传后自动合并」,你仍需在服务端做分片接收 + 合并 +
putObject()三步,只是最终落盘位置变了
真正容易被忽略的是:分片上传的「合并触发时机」——不能靠前端发一个「合并请求」就立刻执行,得等所有分片确认到达且校验通过(比如每个分片附带 MD5),否则静默丢片会导致文件损坏,且无法追溯。



















