Workerman 中无法使用 $_FILES,需手动解析 multipart/form-data 请求体;应通过 $request->rawBody() 获取原始数据,借助 multipart-parser 库解析,并自行处理临时文件、编码、权限及清理。

Workerman 里没有 $_FILES,别直接搬 PHP-FPM 那套
Workerman 是常驻内存的异步服务,不走 CGI/FPM 生命周期,所以原生 PHP 的 $_FILES、move_uploaded_file() 全都不可用。你如果在 onMessage 里打印 $_FILES,它永远是空数组——这不是配置问题,是架构决定的。
真正要处理 multipart 表单上传,得自己解析 HTTP 请求体里的 boundary 分隔段。Workerman 不内置 multipart 解析器,但提供了原始请求数据入口:$connection->recv(TCP)或 $request->rawBody()(HTTP 协议栈)。
- 用
Worker::$protocol = 'Http'启动时,推荐从$request->rawBody()拿完整 body - 如果是自定义 TCP 协议,需确保客户端发的是标准 HTTP POST + multipart/form-data 头,再手动收包
- 别试图用
file_get_contents('php://input')—— Workerman 下这玩意不生效
用 multipart-parser 库解析 raw body 最省事
手写 boundary 解析容易漏掉换行、编码、文件名截断等问题。社区成熟的 multipart-parser(如 dflydev/multipart-parser 或轻量版 nikic/fast-route 生态中更小的 parser)能正确拆出字段和文件流。
安装后,在 onMessage 或 HTTP 路由回调里做:
use Dflydev\ApacheMimeTypes\PhpExtensionMimeTypeGuesser;
use Dflydev\Paperclip\MultipartParser;
<p>$parser = new MultipartParser($request->header('content-type'), $request->rawBody());
$parsed = $parser->parse();</p><p>// $parsed['fields'] 是普通表单字段
// $parsed['files'] 是文件数组,每个含 name、tmp_name、size、type 等模拟 $_FILES 键-
content-type头必须带boundary=...,否则解析失败,检查前端是否漏设enctype="multipart/form-data" - 大文件别全读进内存:
parse()默认把文件内容也载入内存,生产环境应配合tempnam()写临时文件,再传路径给后续处理 - 中文文件名要用
mb_convert_encoding()从ISO-8859-1转回UTF-8,否则乱码
Workerman 文件上传必须自己管临时目录和清理
PHP-FPM 自动管理 upload_tmp_dir 和请求结束自动删临时文件;Workerman 没这机制,所有上传文件的临时存储、重命名、权限、过期清理都得你写逻辑。
- 用
sys_get_temp_dir()+uniqid()构建临时路径,避免并发冲突 - 文件写完立刻
chmod(0644),否则 Web 服务器可能读不到(尤其 Nginx 反代时) - 务必设超时清理任务:比如用
Timer::add(300, function() { /* 删除 5 分钟前的 tmp 文件 */ }); - 别把上传文件直接存到
public/下——没中间校验环节,容易被传 webshell
WebSocket 场景下不能直接传 multipart
WebSocket 协议本身不支持 multipart/form-data。如果你看到“WebSocket 上传文件失败”,大概率是前端误用 FormData 直接塞进 ws.send()——这发出去的是二进制 blob,不是 HTTP body。
- 方案一:前端分片(Blob.slice)+ Base64 或 ArrayBuffer 发送,后端拼接再解码成文件
- 方案二:改用 HTTP 接口上传,WebSocket 只负责通知进度和结果(更推荐)
- 方案三:用 WebSocket 子协议协商,自己定义二进制帧格式(复杂度高,除非有强实时要求)
multipart 是 HTTP 协议层概念,硬套到 WebSocket 上等于自己造一套传输协议,边界、错误恢复、重试都得重写。










