PHP cURL: Fixing the “SSL certificate problem: unable to get local issuer certificate” error.

If you are using PHP’s cURL functions to connect to an HTTPS URL, then you might come across the following error:

SSL certificate problem: unable to get local issuer certificate.  (cURL error code 60)

This is a common error that occurs whenever you attempt to use cURL functions to connect to an HTTPS website.

In plain English, it means that you have not configured cURL to connect to SSL-enabled websites.

The quick fix.

If you do not care about security and are looking for a quick fix, then you can simply disable the following cURL options:

  • CURLOPT_SSL_VERIFYHOST: This option tells cURL that it must verify the host name in the server cert.
  • CURLOPT_SSL_VERIFYPEER: This option tells cURL to verify the authenticity of the SSL cert on the server.

Disabling these two options disables SSL verification.

To disable these two options, you can use the curl_setopt function like so:

//The URL we are connecting to.
$url = 'https://google.com';

//Initiate cURL.
$ch = curl_init($url);

//Disable CURLOPT_SSL_VERIFYHOST and CURLOPT_SSL_VERIFYPEER by
//setting them to false.
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

//Execute the request.
curl_exec($ch);

//Check for errors.
if(curl_errno($ch)){
    throw new Exception(curl_error($ch));
}

The PHP code above essentially tells cURL that we don’t care if the server has a valid SSL cert or not. We want to connect to it anyway.

The problem with this method is that it is insecure and it leaves you open to man-in-the-middle attacks. Simply put, this means that an attacker could potentially intercept the data that you are sending in your cURL requests.

Using a cert with PHP’s cURL functions.

To use a certificate with PHP’s cURL functions, you can download the cacert.pem certificate bundle from the official cURL website.

Once you have downloaded the cacert.pem file, you should move it to whatever directory makes the most sense for you and your setup.

For example, on Windows, I moved my bundle to C:\wamp\cacert.pem

Then, you can simply tell cURL where your certificate bundle is located by using the curl_setopt function:

//Tell cURL where our certificate bundle is located.
$certificate = "C:\wamp\cacert.pem";
curl_setopt($ch, CURLOPT_CAINFO, $certificate);
curl_setopt($ch, CURLOPT_CAPATH, $certificate);

This allows us to make a secure request to the server and prevent any man-in-the-middle attacks.

Adding the cert to your php.ini file.

If you don’t like the thought of having to specify the location of the certificate bundle in your PHP code, then you can add its path information to your php.ini file like so:

curl.cainfo="C:\wamp\cacert.pem" 
openssl.cafile="C:\wamp\cacert.pem"

Once you add the above lines to your php.ini file, make sure that you reload the web server / PHP process so that the changes take effect.

Enabling mod_ssl and php_openssl.dll.

If you are using Apache and PHP on Windows, then you might need to enable both mod_ssl and php_openssl.dll.

To enable mod_ssl, you can add the following to your Apache configuration file:

LoadModule ssl_module /usr/lib/httpd/modules/mod_ssl.so

The configuration line above presumes that a file called mod_ssl.so exists in a Linux directory called “/usr/lib/httpd/modules/”.

On Windows, this directory might be something like “C:\wamp\bin\apache\apache2.4.9\modules\“.

You will need to change this line to match your own Apache setup.

To enable php_openssl.dll, you will need to uncomment the following line in your php.ini file:

extension=php_openssl.dll

As always, you should test your configurations and then reload your server for any changes to take effect.