将 Curl 客户端 ssl 移动到 Guzzle

Posted

技术标签:

【中文标题】将 Curl 客户端 ssl 移动到 Guzzle【英文标题】:Moving Curl client ssl to Guzzle 【发布时间】:2014-11-13 11:19:18 【问题描述】:

我将 Guzzle v3.9.2 与 php 5.3 和 php 5.5 一起使用。

我有以下使用 ssl 客户端证书的工作 curl 代码:

$url = "https://example.com/";
$cert_file = '/path/to/certificate.pem';

$ch = curl_init();
$options = array(
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_FOLLOWLOCATION => true,
  CURLOPT_URL => $url ,
  CURLOPT_SSLCERT => $cert_file ,
);

curl_setopt_array($ch , $options);
$output = curl_exec($ch);

if (!$output) 
  echo "Curl Error : " . curl_error($ch);

else 
  echo htmlentities($output);

我已尝试将其移至 Guzzle:

require '/var/www/vendor/autoload.php';
use Guzzle\Http\Client;
$client = new Client();
$request = $client->get($url, array('cert' => $cert_file));
$response = $client->send($request);
echo $response . PHP_EOL;
print 'HI' . PHP_EOL;

当我使用 curl 运行它时,我得到 200 响应。当我使用 Guzzle 时,我得到了 403。

【问题讨论】:

cert 选项仅适用于客户端证书。如果您使用的是私有证书,那么 curl 会给您无法设置私有密钥文件的错误。请参考下面我的回答 【参考方案1】:

试试这样:

 $client = new Client();
 $response = $client->get($url, array(), array('cert' => $cert_file));

为了检查添加这一行:

 $this->assertEquals($cert_file, $request->getCurlOptions()->get(CURLOPT_SSLCERT));

或者使用这个:

 $client = new Client();
 $request = $client->createRequest('GET', $url);
 $request->getCurlOptions()->set(CURLOPT_SSLCERT, $cert_file);
 $response = $client->send($request);

如果您使用自签名证书,请设置此选项:

$request->getCurlOptions()->set(CURLOPT_SSL_VERIFYHOST, false);
$request->getCurlOptions()->set(CURLOPT_SSL_VERIFYPEER, false);

在发送请求之前设置这一行:

$request = $client->get( .... )
.
.
.
$request->setResponse(new Response(200), true);
$request->send();

检查您的网址并像这样输入它:

$url = 'https://example.com/index.php';

您可以添加默认选项,例如您的 curl 代码:

$request->getCurlOptions()->set(CURLOPT_RETURNTRANSFER , true);
$request->getCurlOptions()->set(CURLOPT_FOLLOWLOCATION , true);

【讨论】:

嗯,好消息和坏消息。 assertEquals 的东西确实显示了完全相同的值。但是……不知怎的,它仍然不起作用。有关如何调试的更多想法? 在发送请求之前使用 var_dump($request->getCurlOptions());并查看创建的 curloptions 这让我得到了答案,我相信通常是最准确的答案,所以我接受了它并授予了赏金。我的最终问题是,我收到了关于目录列表被拒绝这一事实的 403(关于 index.php 的建议让我想到了这一点)。我必须从 Guzzle 捕获 403 异常并打印请求的正文,以知道它是“目录列表被拒绝”错误而不是证书错误。谢谢!【参考方案2】:

首先,因为这会导致一些混乱,所以 Gihub 上有两个版本的 Guzzle:

Guzzle3(旧版,你用的) Guzzle(重写后的新版本)

这里有两个(经过测试的)示例,每个版本的 Guzzle 都有一个:

对于Guzzle 的最新版本(不是所谓的旧版本 Guzzle3),它应该是:

use GuzzleHttp\Client;

$client = new Client();
$response = $client->get($url, array('cert' => $cert_file));

var_dump($response);

确保客户端证书以PEM 格式存储。如果证书受密码保护,您需要像这样指定它:

$response = $client->get($url, 
    array('cert' => array($cert_file, 'password' => '****'));

!!请注意,上面提供密码的代码在手册中有描述,但在最近的版本中不起作用。

对于旧版本 Guzzle3(您正在使用)

use Guzzle\Http\Client;

// Create a client and provide a base URL
$client = new Client();

$request = $client->get($url, array(), array(
    'cert' => $cert_file
));

// You must send a request in order for the transfer to occur
$response = $request->send();

var_dump($response);

【讨论】:

感谢您提供有关 PEM 的提示。 curl 是否使用与 guzzle 不同的证书格式?请注意,我正在一个接一个地运行此代码,并且完全相同的 $cert_file 值适用于 curl 而不是 guzzle。 $url 和 $cert_file 没有任何变化。 另外,您对 ->get() 发送请求的评论与 guzzle 文档和我的经验不一致。你能指出一个参考吗? 以这个页面上的第一个例子:github.com/guzzle/guzzle/blob/master/docs/clients.rst .. 你试过我的代码了吗? (到目前为止,我懒得设置基于客户端证书的身份验证测试服务器)。 哦,原来是版本问题。您使用的 Guzzle 版本与我不同。 (我用的是最新的)...需要查看3.9.2.. @greggles 您使用的是旧版本(可能应该升级)。这导致我的网站有些混乱。我已经给出了两个版本的例子,新的和旧的。我基本上只是错过了,get() 的选项参数在旧版本的 Guzzle 中排在第三位。如您所见,方法get() 的含义在新版本中也发生了变化。希望它对你有用(注意新版本中的密码问题,可能会创建一个补丁..但明天;))【参考方案3】:
If you are using private key then you have to use ssl_key option it will not 
work with cert.You can use **cert** options only with client certificate.

由于三个原因而发生此错误。

    未提供正确的证书路径。因此无法阅读 & 将证书信息传递给服务器。 由于证书无效,服务器无法验证请求。 由于文件所有者/权限问题,php curl 无法读取证书文件。

Guzzle 如何设置 ssl 卷曲路径:

Guzzle 对文件使用 CURLOPT_CAINFO,对目录中的多个证书使用 CURLOPT_CAPATH 默认证书路径是vendor/Http/Resources/cacert.pem。 如果您不在 require_once 中使用 phar,那么您可以用您的新证书替换现有证书文件,因为它会在每次请求时初始化 SSL。这将在不更改代码的情况下工作。 Guzzle 使用ssl.certificate_authority 参数设置curl ssl 认证。它支持 false、true 或文件路径等值

您可以在类初始化时设置文件路径如下-

$cert_file = '/var/www/stack/25924147/cert/example.pem'; #Use absolute path as relative path will not work
$client = new Client();
$client->setDefaultOption('verify',true); #pass it for self-signed certificate
$client->setSslVerification($cert_file,true,2);  #Last Verify Option states default value is 2. When the verify value is 0, the connection succeeds regardless of the names in the certificate. Use that ability with caution!. When the verify value is 1, curl_easy_setopt will return an error
try
    $request = $client->get($url);
    $options = $request->getCurlOptions(); #used to check curl options is set properly.
    var_dump($options); 
    $response = $client->send($request);
    echo $response . PHP_EOL;
    print 'HI' . PHP_EOL;
catch( Guzzle\Http\Exception\CurlException $e)
    print_r($e->getResponse());
    echo "\n Curl Error \n";
catch(Guzzle\Http\Exception\ClientErrorResponseException $e)
   print_r($e->getResponse());
   echo "\n Response Error \n";
catch( Guzzle\Http\Exception\RequestException $e)
  print_r($e->getResponse());
  echo "\n REquest Error \n";

如果您想在每个请求上通过证书,请尝试以下代码

   $cert_file = '/var/www/stack/25924147/cert/example.pem'; #Use absolute path as relative path will not work
   $client = new Client();
   $request = $client->get('https://www.example.com', array(), array(

      'ssl_key' => array('/etc/pki/private_key.pem')

  )


With Passoword - 
 $request = $client->get('https://www.example.com', array(), array(

     'ssl_key' => array('/etc/pki/private_key.pem', 's3cr3tp455w0rd')

 )

对于 Guzzle Http 客户端文档检查 - The Guzzle HTTP client

【讨论】:

以上是关于将 Curl 客户端 ssl 移动到 Guzzle的主要内容,如果未能解决你的问题,请参考以下文章

将 paypal curl 获取访问令牌请求转换为 guzzle

guzzlehttp/guzzle

PHP - 为啥使用 Guzzle 而不是 cURL?

如何使用Curl将这个mailchimp API请求转换为使用PHP的Guzzle?

cURL error 60: SSL certificate problem: unable to get local issuer certifica

php Guzzle HTTP将ssl验证设置为false