使用PHP CURL通过AWS S3预签名URL下载文件到远程服务器失败如何解决
问题根因
你遇到的「授权机制不支持,请使用签名版本4」报错,以及CURL下载为空的问题,通常由以下几个配置错误导致:
- CURL自动携带了多余的
Authorization请求头:如果运行环境配置了AWS相关环境变量、或者PHP侧有扩展自动注入了AWS身份请求头,S3会优先校验请求头里的授权信息,而非URL携带的签名参数,如果请求头里的授权信息不符合V4签名要求,就会触发对应报错。 - 预签名URL被二次编码:如果
$download_url变量在赋值过程中被做了urlencode处理,原本正确的签名参数(比如路径转义符%2F)被再次转义,会导致签名校验失败。 - 缺少重定向跟随配置:如果预签名URL触发了S3的临时重定向,CURL默认不会自动跟随跳转,导致拿到的是重定向响应而非文件内容。
- SSL证书校验失败:部分服务器的CURL默认没有配置根证书,请求HTTPS的S3地址时校验失败终止请求。
修复后的代码
// Download zip file // 注意$download_url为预签名URL原始值,不要对URL做二次编码处理 $ch = curl_init(); $fp = fopen($theme_zip_path, "w+"); curl_setopt_array($ch, array( CURLOPT_URL => $download_url, CURLOPT_TIMEOUT => 600, CURLOPT_FILE => $fp, // 开启自动跟随重定向 CURLOPT_FOLLOWLOCATION => true, // 清空默认携带的Authorization头,避免覆盖URL中的签名参数 CURLOPT_HTTPHEADER => array('Authorization:'), // 生产环境建议开启SSL校验,调试阶段可临时设置为false排查问题 CURLOPT_SSL_VERIFYPEER => true, CURLOPT_SSL_VERIFYHOST => 2 )); curl_exec($ch); // 调试时可打开下方代码输出错误信息定位问题 // if(curl_errno($ch)) { // echo 'CURL错误:' . curl_error($ch); // } curl_close($ch); fclose($fp);
排查验证方法
- 先打印
$download_url的原始值,复制到服务器命令行直接用curl "原始URL"请求,看是否能正常下载文件,如果命令行也报错,说明预签名URL本身已过期或者生成逻辑有误。 - 如果命令行可正常下载,说明是PHP CURL的配置问题,通过curl_error输出的信息即可定位具体错误点。
内容的提问来源于stack exchange,提问作者Hans Desjarlais
相关产品推荐
相关产品推荐

