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
相关产品推荐
相关产品推荐

