通过PHP cURL调用REST API上传图片至S3时文件损坏无法打开
问题原因
上传后文件损坏的核心是请求格式与S3代理的预期不匹配:
- 给
CURLOPT_POSTFIELDS传数组或CURLFile对象时,PHP cURL会自动将请求编码为multipart/form-data格式,请求体中会自动插入multipart分隔符、表单字段元数据等冗余内容 - 你配置的API Gateway S3代理会将收到的请求体原样写入S3,不会自动解析multipart格式提取图片内容,最终存储的文件混入非图片二进制数据,自然无法正常预览
- 你终端测试可用的
curl命令通过--data-binary参数直接发送图片原始二进制流,无额外格式包装,这才是该S3代理能正确处理的请求格式
修复后的PHP cURL实现代码
无需引入AWS SDK,直接按原始二进制流上传即可,参考代码如下:
<?php if (isset($_FILES['image']['tmp_name'])) { // 先校验上传是否出错 if ($_FILES['image']['error'] !== UPLOAD_ERR_OK) { exit("文件上传失败,错误码:" . $_FILES['image']['error']); } // 初始化cURL会话 $curl = curl_init(); // 读取临时目录中上传图片的原始二进制内容 $imageRawContent = file_get_contents($_FILES['image']['tmp_name']); // 拼接S3代理接口的目标地址 $targetUrl = 'https://xxxxxx.execute-api.us-east-1.amazonaws.com/v1/test57827/' . $_FILES['image']['name']; // 批量设置cURL选项 curl_setopt_array($curl, [ CURLOPT_URL => $targetUrl, CURLOPT_POST => true, // 直接传入原始二进制字符串,不要传数组、不要传CURLFile对象 CURLOPT_POSTFIELDS => $imageRawContent, // 手动设置请求头,和终端测试的可用逻辑保持一致 CURLOPT_HTTPHEADER => [ 'Content-Type: */*', // 也可替换为$_FILES['image']['type']传入图片真实MIME类型 'Content-Length: ' . strlen($imageRawContent), 'Expect:' // 移除默认的Expect:100-continue头,避免网关兼容性问题 ], CURLOPT_RETURNTRANSFER => true, // 生产环境保持SSL校验开启,本地调试证书问题可临时开启以下两行 // CURLOPT_SSL_VERIFYPEER => false, // CURLOPT_SSL_VERIFYHOST => 0, ]); // 执行请求 $response = curl_exec($curl); $curlError = curl_error($curl); curl_close($curl); if ($curlError) { exit("上传请求失败:" . $curlError); } echo "上传成功,接口返回:" . $response; } ?>
关键注意点
- 禁止给
CURLOPT_POSTFIELDS传数组或CURLFile实例,这两种传参方式都会触发cURL自动封装multipart格式,导致上传的文件内容被污染 - 必须手动设置Content-Type请求头,否则cURL发送字符串类型POST内容时会默认使用
application/x-www-form-urlencoded类型,可能触发网关格式校验错误 - 文件名建议做合法性校验,避免用户传入带路径的特殊文件名导致S3存储路径异常
内容的提问来源于stack exchange,提问作者Anudocs
相关产品推荐
相关产品推荐

