同样的cURL脚本可以在开发中使用,但我不知道为什么不能在生产中使用


Same cURL script works in dev. Can't figure out why not in production

这是脚本,在我的开发机器上运行:

$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不能。我是从另一个问题的高分答案中得到这个想法的。