The Secret to cURL in PHP on Windows…

cURL is a great library created by Daniel Stenberg, that allows you to connect and communicate to many different types of servers using many different types of protocols. In particular, it’s used heavily in PHP to communicate to Payment Gateways and fetch XML feeds from other sites whilst being ‘transparent’ to web page visitors.

The particular secret I would like to share involves establishing connections to secure sites (SSL-enabled ones in particular). When you browse to an SSL–enabled site in your web browser, a few things happen… One of the things that happen is that your browser checks to see if the site’s security certificate is trusted. It does this by checking the entity that signed the certificate against it’s built in book of trusted signatures and if it finds a match, onto the next step. However, if your browser can’t find a match the certificate will be invalid and it will complain that the site could potentially be a fake or insecure.

The ‘book of trusted signatures’ is known as a Certificate Authority bundle and usually comes built in with most web browsers. If you install cURL (the standalone version that can be run from the command–line), chances are it will come with the cURL Certificate Authority bundle and you won’t need to do a thing as the cURL functions within PHP will use this as it’s book of trusted signatures. However, on Windows the cURL functions within PHP are pre–built and included in the standard PHP setup, thus do not include this bundle. Chances are if you don’t know this you’ll probably spend a good amount of your time screaming at your webpage as it mocks you with error number 60! I know I spent quite a good few hours wondering why it worked on my Linux PC but not on the Windows server!

CURL Error 60: SSL certificate problem, verify that the CA cert is OK.
Details: error:14090086:SSL routines
SSL3_GET_SERVER_CERTIFICATE:certificate verify failed

Luckily the fix is quite easy…

  1. Download standalone cURL for Windows (make sure it is the SSL version).
    Download the .pem file from the cURL site and rename the extension to .crt
  2. Extract curl-ca-bundle.crt from the download and copy to your web server folder.
  3. Add the following line to your code: –
    curl_setopt($ch, CURLOPT_CAINFO, "c:/path/to/ca-bundle.crt");
  4. Remember to change $ch to the variable you’ve assigned your curl connection to and “c:/path/to/ca-bundle.crt” to the location of where you have copied the ca-bundle.crt.
  5. Check the server has permission to read this file.

If you are getting started with cURL, here is some sample code I’ve written that should get you started. It outputs the contents of the secure server to a string, which is echoed out to your page.

// Set up cURL connection
$url = 'https://www.verisign.com/';
$ca = 'c:/path/to/ca-bundle.crt';
$ch = curl_init();

// Apply various settings
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0); // Don’t return the header, just the html
curl_setopt($ch, CURLOPT_CAINFO, $ca); // Set the location of the CA-bundle
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // Return contents as a string

$result = curl_exec ($ch);
curl_close($ch);
echo $result;

That’s it! You should now be able to connect successfully to SSL-enabled websites using the cURL functions of PHP on your Windows server.

UPDATE 2010/08/20: Apparently the certificates aren’t shipped with the archived versions any more. To get the latest certificate bundle that’s been extracted from the Mozilla browser you can download the .pem file from the cURL site and rename the extension to .crt.