这是脚本,在我的开发机器上运行:
$certPath = SITE_ROOT.'/certs/GoDaddyRootCertificateAuthority-G2.crt';
$options = [
CURLOPT_POST => 1,
CURLOPT_URL => 'https://uat.dwolla.com/oauth/rest/offsitegateway/checkouts',
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_POSTFIELDS => json_encode(['name'=>'value']),
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_CAINFO => $certPath,
];
$ch = curl_init();
curl_setopt_array($ch, $options);
if( ! $result = curl_exec($ch)) $err = curl_error($ch);
curl_close($ch);
if(!$result) echo $err;
else print_r(json_decode($result,true));
echo '<br/><br/>';
readfile($certPath); //output cert on screen
echo '<br/><br/>';
没有问题。将它移动到生产环境后,cURL连接失败,并出现以下错误:
SSL证书问题:无法获取本地颁发者证书
- 打印相同的
.crt
内容,所以我知道证书的路径不是问题。 - 两个环境都在
Apache 2.4
上使用PHP 5.6.23
- 开发机为
Win 7 x64
,生产机为Linux CentOS 7
我不知道从哪里开始寻找原因。为什么脚本不能在生产中工作?
更新:感谢@blackpen在评论中的伟大提示,我了解了用于生成连接日志的CURLOPT_VERBOSE
选项。下面是破碎生产环境下的输出:
- 主机名在DNS缓存中找不到
- 尝试104.20.47.245…
- 连接到uwat.dwolla.com(104.20.47.245)端口443 (#0)
- 成功设置证书验证位置:
- CAfile:/道路//GoDaddyRootCertificateAuthority-G2。crt CApath: none
- SSL证书问题:无法获得本地颁发者证书
- 关闭连接0
下面是来自同一脚本的日志,但是来自工作开发环境:
- DNS缓存中的主机名过期,被破坏
- 尝试104.20.48.245…
- 连接到uwat.dwolla.com(104.20.48.245)端口443 (#0)
- 密码选择:ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4: @STRENGTH
- 成功设置证书验证位置:
- CAfile:/路径//GoDaddyRootCertificateAuthority-G2.crt
CApath:没有- NPN,协商HTTP1.1
- SSL连接使用TLSv1.2/ECDHE-RSA-AES128-GCM-SHA256
- 服务器证书:
- …(cert细节)
- SSL证书验证ok。
- …(更多POST细节)
我能够通过替换仅在开发环境中工作的.crt
和从这里取的名为cacert.pem
的文件
我仍然不知道到底发生了什么,但我怀疑这可能与证书的格式有关。也许Windows上的PHP可以处理.crt
,但是Linux上的PHP不能。我是从另一个问题的高分答案中得到这个想法的。