改 upload_max_filesize 仍上传失败,因 swoole 不读 php.ini,需设 package_max_length 控制请求体上限,并配合清理临时文件或改用分块上传。

为什么改了 upload_max_filesize 还上传失败?
因为 Swoole 的 HTTP 服务器不读取 php.ini 里的上传限制,它自己有一套独立的包大小控制逻辑。即使你把 upload_max_filesize 和 post_max_size 调到 10G,Swoole 默认仍只允许接收最大 2MB 的完整请求体 —— 超出部分直接被截断或报错 400 Bad Request。
package_max_length 必须设,但不能乱设
这是 Swoole HTTP 服务端解析请求时的「单次接收缓冲区上限」,直接影响 multipart 数据能否完整送达 $request->files。它不是“文件大小上限”,而是“整条 HTTP 请求体(含 headers + body)的最大字节数”。
- 默认值通常是
2 * 1024 * 1024(2MB),必须显式增大才能传大文件 - 设为
1024 * 1024 * 1024(1GB)看似稳妥,但高并发下极易耗尽内存 —— 每个连接都可能占用接近该值的缓冲空间 - 推荐按业务峰值预估:比如单次上传最大 500MB,同时最多 20 个上传连接,则内存预留至少
500MB × 20 = 10GB,需确认物理内存是否支撑 - Hyperf 用户在
app/config/autoload/service.php的settings中加:'package_max_length' => 500 * 1024 * 1024 - 原生 Swoole 启动时设置:
$server->set(['package_max_length' => 500 * 1024 * 1024]);
仅调 package_max_length 不够,还要防临时文件堆积
Swoole 解析 multipart 后会把文件写入系统临时目录(如 /tmp),路径存于 $request->files['xxx']['tmp_name']。但这个临时文件不会自动删除 —— 即使请求结束、协程退出,文件仍留在磁盘上。
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
- 没做
unlink()或move_uploaded_file(),上传 100 个 1GB 文件就占满 100GB 磁盘 - 协程异常退出(如超时、
throw)时,finally块未必执行,unlink容易遗漏 - 建议在处理逻辑开头记录
$tmpName,并在所有出口(包括catch和return前)确保清理,或用register_shutdown_function()做兜底 - 更稳的做法是:上传即刻用
swoole_coroutine_file_write()分块异步写入目标路径,跳过系统临时文件环节
大文件别依赖 $request->files 全量加载
当文件超过几百 MB,Swoole 虽能解析出 $request->files,但底层仍需把整个 body 缓存在内存或临时磁盘中。这不是真正流式,只是“解析完再交给你”,仍有 OOM 风险。
- 真正可靠的大文件方案是客户端分块上传(如 tus 协议),服务端只收 chunk,拼接写入,不进
$request->files - 若必须走表单上传,且文件稳定在 100–500MB 区间,可接受
package_max_length开大 + 强制move_uploaded_file()+ 定时清理/tmp的组合策略 - 切忌在协程里用
file_get_contents($tmp_name)—— 这会把整个文件又读进 PHP 内存,协程优势归零
实际部署时,package_max_length 的值和磁盘清理机制必须同步上线,缺一不可。很多人调通了上传,却在压测后发现磁盘爆满、服务假死,问题就出在这里。










