cURL 多文件上传必须为每个文件创建独立 CURLFile 实例并用 realpath() 确保路径有效,字段名需与后端嵌套结构严格一致,禁用 @ 前缀,显式设置 CURLOPT_SAFE_UPLOAD 和 SSL 选项,避免手动设置 Content-Type,并注意 PHP 服务端 upload_max_filesize 等限制。

curl_multi_exec 不能直接传数组文件句柄
PHP 的 curl_setopt 不支持把多个 fopen() 句柄塞进一个 CURLOPT_POSTFIELDS 数组里直接发——它会报 Array to string conversion 或静默失败。必须为每个文件单独构造 CURLFile 实例,并确保路径真实可读。
- 用
new CURLFile(realpath($path))包裹每个文件,别用相对路径或未realpath()的字符串 - 字段名要和后端约定一致,比如后端 expect
files[],你就得写'files[]' => $curlFile - 禁用
@前缀写法(已废弃),否则 PHP 7.4+ 会警告,8.0+ 直接报错
POST 多文件时必须显式设置 CURLOPT_SAFE_UPLOAD
PHP 5.6+ 默认开启 CURLOPT_SAFE_UPLOAD(值为 true),但这个选项只控制是否允许旧式 @/path 语法,**不影响 CURLFile**。不过很多老项目还开着 ini_set('curl.cainfo', ...) 或混用旧逻辑,漏设会导致 SSL 验证失败或上传被截断。
- 显式加
curl_setopt($ch, CURLOPT_SAFE_UPLOAD, true),哪怕它本就是默认值 - 务必配
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false)(仅调试)或正确配置 CA 证书路径 - 若用
curl_multi_init()并发多文件,每个 handle 都要单独设这些选项,不能复用
$_FILES 接收不到?检查 enctype 和字段命名嵌套
后端 PHP 脚本看到空 $_FILES,大概率不是 cURL 问题,而是表单编码类型或字段名不匹配。浏览器表单用 enctype="multipart/form-data" 是硬性要求,cURL 没有这个属性,但它靠 CURLOPT_POSTFIELDS 中含 CURLFile 自动触发 multipart 编码——前提是没手动设 Content-Type 头。
- 绝对不要手动加
Content-Type: multipart/form-data; boundary=xxx,curl 会自己生成并管理 boundary - 如果后端期望
data[files][]这种嵌套键名,cURL 必须传'data[files][]' => new CURLFile(...),不能只传'files[]' - 用
curl_getinfo($ch, CURLINFO_CONTENT_TYPE)看发出的请求头,确认是否含multipart/form-data及有效 boundary
大文件上传失败常卡在 upload_max_filesize 或超时
cURL 本身不限文件大小,但 PHP 的 upload_max_filesize、post_max_size、max_execution_time 三者都会中途掐断。尤其并发上传时,max_execution_time 是所有请求共享的,不是每个 curl handle 独立计时。
立即学习“PHP免费学习笔记(深入)”;
- 服务端需调大
upload_max_filesize = 128M、post_max_size = 130M(略大于前者) - cURL 端加
curl_setopt($ch, CURLOPT_TIMEOUT, 300)和curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30) - 上传前用
filesize($path) > 2 * 1024 * 1024做简单校验,避免传到一半才发现后端拒收
实际最易忽略的是字段名嵌套层级和 realpath() 缺失——这两个点错一个,$_FILES 就全空,且无明确报错。











