Guzzle and HTTPS

damien marchand picture damien marchand · Feb 18, 2015 · Viewed 16.6k times · Source

I want to use Guzzle and Silex to send request to https pages.

With http url I have a response :

app->get('/',function() use ($app, $client){

    $response = $client->get("http://www.google.fr");

    var_dump($response);

});    

My response:

object(GuzzleHttp\Message\Response)[102]
  private 'reasonPhrase' => string 'OK' (length=2)
  private 'statusCode' => int 200
  private 'effectiveUrl' => string 'http://www.google.fr' (length=20)
  private 'headers' (GuzzleHttp\Message\AbstractMessage) => 
    array (size=13)
      'date' => 
        array (size=1)
          0 => string 'Wed, 18 Feb 2015 10:57:37 GMT' (length=29)
      'expires' => 

But with https :

$app->get('/',function() use ($app, $client){
$url = "https://api.zoapp.com/v1/stc/cans/directory/pub/Employees";

$response = $client->get("https://www.facebook.com/");

var_dump($response);

});

I have to errors :

RequestException in RequestException.php line 51:

and

RingException in CurlFactory.php line 126:

Details : pastbin link

Answer

Hirnhamster picture Hirnhamster · Apr 12, 2015

Following your link to the details, the exception message says:

cURL error 60: See http://curl.haxx.se/libcurl/c/libcurl-errors.html

Looking up http://curl.haxx.se/libcurl/c/libcurl-errors.html I found

CURLE_SSL_CACERT (60)

Peer certificate cannot be authenticated with known CA certificates.

So it's most likely a problem with the SSL verification/CA bundle. By setting the verify request option to false, guzzle (resp. curl) will not try to verify the host against a certificate, hence the error disappears (-- in reply to https://stackoverflow.com/a/28582692/413531)

However, you do not want to do that ;) Instead, you should try to solve the issue by providing a valid CA bundle.

IIRC, in v4 guzzle provided a default certificate (see https://github.com/guzzle/guzzle/blob/4.2.3/src/cacert.pem ), but removed that in version 5 and now tries to discover your default system CA bundle. From the docs, those locations are checked:

Check if openssl.cafile is set in your php.ini file.
Check if curl.cainfo is set in your php.ini file.
Check if /etc/pki/tls/certs/ca-bundle.crt exists (Red Hat, CentOS, Fedora; provided by the ca-certificates package)
Check if /etc/ssl/certs/ca-certificates.crt exists (Ubuntu, Debian; provided by the ca-certificates package)
Check if /usr/local/share/certs/ca-root-nss.crt exists (FreeBSD; provided by the ca_root_nss package)
Check if /usr/local/etc/openssl/cert.pem (OS X; provided by homebrew)
Check if C:\windows\system32\curl-ca-bundle.crt exists (Windows)
Check if C:\windows\curl-ca-bundle.crt exists (Windows)

However, I found it easier to set the certificate explicitly when creating a new Client. That means:

Example (assuming you have the certificate named cacert.pem located in the same directory as the script):

$default = ["verify" => __DIR__ . "/cacert.pem"];
$config = ["defaults" => $default];
$client = new Client($config);
$response = $client->get("https://www.facebook.com");