Swoole下upload_tmp_dir必须通过$server->set()显式配置,完全忽略php.ini;PHP-FPM则依赖php.ini设置,两者互不相通,且均需确保路径存在、权限正确、长度≤220字节。

upload_tmp_dir 在 Swoole 和 PHP-FPM 下完全不互通
PHP-FPM 模式下,upload_tmp_dir 由 php.ini 控制,且必须存在、可写、未被 open_basedir 限制;而 Swoole HTTP Server 模式下,该 ini 配置**被彻底忽略**,它只认自己 $server->set() 中显式指定的 upload_tmp_dir 值。
常见错误现象:$_FILES['file']['tmp_name'] 为空、move_uploaded_file() 静默失败、或报 Unable to move uploaded file——本质是 Swoole 根本没按你 php.ini 里写的路径存文件,而是用了默认 /tmp(或你 set 里配错的路径)。
- PHP-FPM:改
php.ini→ 重启php-fpm→ 生效 - Swoole:必须在
$server->set(['upload_tmp_dir' => '/path/to/uploads'])中声明 → 启动服务时加载 → 不受 php.ini 影响 - 两者目录权限要求一致:PHP 进程用户(如
www-data)需有读、写、执行权限 - 路径长度不能超过 220 字节,否则
$server->set()会静默截断或触发未知行为
为什么不能用 sys_get_temp_dir() 替代 upload_tmp_dir
sys_get_temp_dir() 返回的是 PHP 系统级临时目录(比如 /tmp 或 C:\Windows\Temp),但它和文件上传流程无关。上传逻辑只走 upload_tmp_dir —— FPM 下读 php.ini,Swoole 下读 $server->set()。
尤其在容器环境(如官方 php:alpine 镜像),upload_tmp_dir 默认为空,sys_get_temp_dir() 可能返回 /tmp,但 Swoole 实际写入时若没显式配置 upload_tmp_dir,就会 fallback 到系统 /tmp,而该目录在很多容器里默认不可写或被挂载为只读。
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
- 永远不要用
sys_get_temp_dir()构造上传临时路径,它不参与上传生命周期 - 检查当前生效值:FPM 下用
ini_get('upload_tmp_dir'),Swoole 下看$server->getSetting()['upload_tmp_dir'] - 若
ini_get('upload_tmp_dir')返回空字符串,说明用了系统默认,此时才需要确认/tmp是否真实可用
move_uploaded_file() 失败的真实原因几乎都在前置环节
move_uploaded_file() 本身不校验来源合法性,它只是个搬运工。失败从来不是函数问题,而是上游已经出错了。
- 先查
$_FILES['x']['error'] === UPLOAD_ERR_OK,否则tmp_name无效 - 再确认
file_exists($_FILES['x']['tmp_name'])—— 若返回false,说明 Swoole 没成功落盘,或路径配错/权限不足/目录不存在 - 目标目录必须提前
mkdir -p创建好,并确保 PHP 进程用户有写权限(chown www-data:www-data /target) - Swoole 模式下,若
upload_tmp_dir路径末尾缺斜杠(如'/data/upload'而非'/data/upload/'),某些版本会拼接异常导致路径错乱
Swoole 的 upload_tmp_dir 配置容易被忽略的细节
很多人以为只要 $server->set(['upload_tmp_dir' => '/data/uploads/']) 就万事大吉,但实际部署中几个硬性条件常被跳过:
- 目录必须存在:
mkdir -p /data/uploads,Swoole 不会自动创建 - 权限要精确:Swoole 子进程以 worker 用户运行(常为
www-data或root),不是 nginx 用户,别只改 nginx 目录权限 - SELinux 环境下需额外打标:
semanage fcontext -a -t httpd_tmp_t "/data/uploads(/.*)?" && restorecon -Rv /data/uploads - Docker 容器中,必须把宿主机目录挂载为可写:
-v /host/uploads:/data/uploads:rw,且注意挂载点用户 UID 匹配 - 如果用 Laravel Swoole 扩展,它的配置层可能覆盖原始
$server->set(),得查config/swoole_http.php里的upload_tmp_dir项
最麻烦的情况是:路径看着对、权限看着够、file_exists() 返回 true,但 move_uploaded_file() 仍失败——这时候大概率是 SELinux 或容器挂载权限没对齐,而不是代码问题。

















