You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP原生CURL PUT上传MinIO图片失败,请求无数据发送求助

PHP原生CURL PUT上传MinIO失败,shell curl可正常工作

问题场景

通过shell的curl命令能成功向MinIO存储桶PUT上传图片:

$url = "http://192.168.1.1:9000/bucket/$fname";
$date = date ('r');

exec ("curl -s -X PUT -T '$fname.jpg' -H 'Host: 192.168.1.1' -H 'Date: $date' -H 'Content-Type: image/jpeg' $url");

替换为PHP原生CURL调用后却无法正常运行:

$curl = curl_init($url);

curl_setopt($curl, CURLOPT_CONNECTTIMEOUT,2);
curl_setopt($curl, CURLOPT_TIMEOUT, 10);

curl_setopt($curl, CURLOPT_URL, $url);
#curl_setopt($curl, CURLOPT_CUMSTOMREQUEST, "PUT"); # Was here, does nothing
curl_setopt($curl, CURLOPT_PUT, true);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, false);

$headers = array(
    "Host: 192.168.1.1",
    "Date: ". date ('r'),
    "Content-Type: image/jpeg",
);

curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);

# First way to send data
#$data = file_get_contents ("$fname.jpg");
#curl_setopt($curl, CURLOPT_POSTFIELDS, $data);

# Second way to send data
curl_setopt($curl, CURLOPT_INFILE, "$fname.jpg");
curl_setopt($curl, CURLOPT_INFILESIZE, filesize ("$fname.jpg"));

$resp = curl_exec($curl);

抓包对比发现,两者请求头几乎一致,服务器均返回HTTP/1.1 100 Continue,但PHP原生CURL后续不再发送数据,最终超时失败。尝试添加Expect:请求头也无改善,怀疑PHP CURL存在特殊等待逻辑,求排查提示或确认是否为BUG。


问题根源与修复方案

核心错误点

PHP的CURLOPT_INFILE要求传入文件资源句柄,而非字符串格式的文件名——这是代码失效的关键。shell curl的-T参数会自动处理文件的打开与读取,但PHP CURL需要显式打开文件并传入资源。另外,CURLOPT_PUT属于旧版API,用CURLOPT_UPLOAD替代更可靠。

修复方案1:修正CURLOPT_INFILE使用(推荐)

$url = "http://192.168.1.1:9000/bucket/$fname";
$date = date('r');
$filePath = "$fname.jpg";

$curl = curl_init($url);

curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 2);
curl_setopt($curl, CURLOPT_TIMEOUT, 10);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
// 用CURLOPT_UPLOAD替代CURLOPT_PUT,适配现代CURL API
curl_setopt($curl, CURLOPT_UPLOAD, true);
// 打开文件资源句柄
$fileHandle = fopen($filePath, 'rb');
curl_setopt($curl, CURLOPT_INFILE, $fileHandle);
curl_setopt($curl, CURLOPT_INFILESIZE, filesize($filePath));

$headers = [
    "Host: 192.168.1.1",
    "Date: $date",
    "Content-Type: image/jpeg",
    // 显式添加Expect头,和shell curl行为对齐
    "Expect: 100-continue"
];
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);

$resp = curl_exec($curl);
$error = curl_error($curl);

// 关闭资源
fclose($fileHandle);
curl_close($curl);

if ($error) {
    echo "CURL错误:$error";
} else {
    echo "上传成功:$resp";
}

修复方案2:用CURLOPT_POSTFIELDS配合CURLOPT_CUSTOMREQUEST

如果不想处理文件句柄,可直接读取文件内容发送:

$url = "http://192.168.1.1:9000/bucket/$fname";
$date = date('r');
$filePath = "$fname.jpg";
$data = file_get_contents($filePath);

$curl = curl_init($url);

curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 2);
curl_setopt($curl, CURLOPT_TIMEOUT, 10);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "PUT");
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);

$headers = [
    "Host: 192.168.1.1",
    "Date: $date",
    "Content-Type: image/jpeg",
    // 显式设置Content-Length,避免CURL自动处理异常
    "Content-Length: " . filesize($filePath)
];
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);

$resp = curl_exec($curl);
$error = curl_error($curl);
curl_close($curl);

if ($error) {
    echo "CURL错误:$error";
} else {
    echo "上传成功:$resp";
}

额外排查点

  • 权限检查:确保PHP进程对目标图片文件有读取权限(与shell执行用户权限一致)
  • CURL版本:过低版本的PHP CURL扩展可能存在100 Continue处理BUG,建议升级到7.60+
  • 错误日志:开启CURL错误输出(curl_error()),可直接获取具体失败原因,比抓包更高效
  • MinIO SDK:生产环境建议使用MinIO官方PHP SDK(minio/minio),避免手动处理请求头的繁琐与潜在问题

内容的提问来源于stack exchange,提问作者kab00m

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 13:54:37