Using cURL in PHP to access HTTPS (SSL/TLS) protected sites


From PHP, you can access the useful cURL Library (libcurl) to make requests to URLs using a variety of protocols such as HTTP, FTP, LDAP and even Gopher. (If you’ve spent time on the *nix command line, most environments also have the curl command available that uses the libcurl library)

In practice, however, the most commonly-used protocol tends to be HTTP, especially when using PHP for server-to-server communication. Typically this involves accessing another web server as part of a web service call, using some method such as XML-RPC or REST to query a resource. For example, Delicious offers a HTTP-based API to manipulate and read a user’s posts. However, when trying to access a HTTPS resource (such as the delicious API), there’s a little more configuration you have to do before you can get cURL working right in PHP.

The problem

If you simply try to access a HTTPS (SSL or TLS-protected resource) in PHP using cURL, you’re likely to run into some difficulty. Say you have the following code: (Error handling omitted for brevity)

// Initialize session and set URL.
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);

// Set so curl_exec returns the result instead of outputting it.
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// Get the response and close the channel.
$response = curl_exec($ch);

If $url points toward an HTTPS resource, you’re likely to encounter an error like the one below:

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

The problem is that cURL has not been configured to trust the server’s HTTPS certificate. The concepts of certificates and PKI revolves around the trust of Certificate Authorities (CAs), and by default, cURL is setup to not trust any CAs, thus it won’t trust any web server’s certificate. So why don’t you have problems visiting HTTPs sites through your web browser? As it happens, the browser developers were nice enough to include a list of default CAs to trust, covering most situations, so as long as the website operator purchased a certificate from one of these CAs.

The quick fix

There are two ways to solve this problem. Firstly, we can simply configure cURL to accept any server(peer) certificate. This isn’t optimal from a security point of view, but if you’re not passing sensitive information back and forth, this is probably alright. Simply add the following line before calling curl_exec():

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

This basically causes cURL to blindly accept any server certificate, without doing any verification as to which CA signed it, and whether or not that CA is trusted. If you’re at all concerned about the data you’re passing to or receiving from the server, you’ll want to enable this peer verification properly. Doing so is a bit more complicated.

The proper fix

The proper fix involves setting the CURLOPT_CAINFO parameter. This is used to point towards a CA certificate that cURL should trust. Thus, any server/peer certificates issued by this CA will also be trusted. In order to do this, we first need to get the CA certificate. In this example, I’ll be using the server as a reference.

First, you’ll need to visit the URL with your web browser in order to grab the CA certificate. Then, (in Firefox) open up the security details for the site by double-clicking on the padlock icon in the lower right corner:


Then click on “View Certificate”:


Bring up the “Details” tab of the cerficates page, and select the certificate at the top of the hierarchy. This is the CA certificate.


Then click “Export”, and save the CA certificate to your selected location, making sure to select the X.509 Certificate (PEM) as the save type/format.


Now we need to modify the cURL setup to use this CA certificate, with CURLOPT_CAINFO set to point to where we saved the CA certificate file to.

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_CAINFO, getcwd() . "/CAcerts/BuiltinObjectToken-EquifaxSecureCA.crt");

The other option I’ve included, CURLOPT_SSL_VERIFYHOST can be set to the following integer values:

  • 0: Don’t check the common name (CN) attribute
  • 1: Check that the common name attribute at least exists
  • 2: Check that the common name exists and that it matches the host name of the server

If you have CURLOPT_SSL_VERIFYPEER set to false, then from a security perspective, it doesn’t really matter what you’ve set CURLOPT_SSL_VERIFYHOST to, since without peer certificate verification, the server could use any certificate, including a self-signed one that was guaranteed to have a CN that matched the server’s host name. So this setting is really only relevant if you’ve enabled certificate verification.

This ensures that not just any server certificate will be trusted by your cURL session. For example, if an attacker were to somehow redirect traffic from to their own server, the cURL session here would not properly initialize, since the attacker would not have access to a server certificate (i.e. would not have the private key) trusted by the CA we added. These steps effectively export the trusted CA from the web browser to the cURL configuration.

More information

If you have the CA certificate, but it is not in the PEM format (i.e. it is in a binary or DER format that isn’t Base64-encoded), you’ll need to use something like OpenSSL to convert it to the PEM format. The exact command differs depending on whether you’re converting from PKCS12 or DER format.

There is a CURLOPT_CAPATH option that allows you to specify a directory that holds multiple CA certificates to trust. But it’s not as simple as dumping every single CA certificate in this directory. Instead, they CA certificates must be named properly, and the OpenSSL c_rehash utility can be used to properly setup this directory for use by cURL.


  1. PHP is rather new to me, but I was comfortable with the interpretive style with my experiences in Classic ASP, and PHP’s C-like syntax. I figured I could whip something out in a few minutes (maybe an hour once I saw what we could do) that would retrieve my Delicious feed using their API.

  2. I had this problem with Amazon S3 and your post helped me solved it.


  3. thank you so much. i have searched for over 4 hours to solve this issue and you have described it wonderfully.

    Solved it.

  4. There were 2 PEM export options for me in Firefox (when working with

    X.509 Certificate (PEM)
    X.509 Certificate with chain (PEM)

    After using the first, I was still getting the error:

    SSL certificate problem, verify that the CA cert is OK. Details:
    error:14090086:SSL routines:func(144):reason(134)

    However, using the second (with chain) export option made it work fine.

  5. Thank you for this post. Other tutorials on how to use PHP, cURL, and Delicious’ API failed to mention the CURLOPT_SSL_VERIFYPEER setting. My code works now :)

  6. Thanks everyone for their input and comments!

  7. HI ,really nice article. Keep on writing… its helps me to solve a issue. thank you very much..

  8. hey ! thanks a LOT !!! I was writing a quick
    and dirty script so that first idea hit to spot!
    very timely and very well written

  9. Its a very good solution, i am able to read a https page.
    BUT when try to auto login( using post method) it fails, do not show any data. can you please help me out.


  10. Excellent post mate! Thanks a lot for your help :)

  11. Thank you. This solution solve my problem.

  12. Thanks, works for me

    but over proxy I can´t access any https hosts.

    function getPage($proxy, $url, $referer, $agent, $header, $timeout) {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_HEADER, $header);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_PROXY, $proxy);
    curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 0);
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
    curl_setopt($ch, CURLOPT_REFERER, $referer);
    curl_setopt($ch, CURLOPT_USERAGENT, $agent);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

    curl_setopt($ch, CURLOPT_FRESH_CONNECT, 1);
    $result[‘EXE’] = curl_exec($ch);
    $result[‘INF’] = curl_getinfo($ch);
    $result[‘ERR’] = curl_error($ch);


    return $result;

    $result = getPage($proxyip,’!’,’’,’Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv: Gecko/2009032609 Firefox/3.0.8′,1,5);

  13. […] by checking against the genuine CA certificate in PEM format. There are plenty of tutorials (e.g. here) on the internet to obtain the PEM certificate, so I won’t go into that here. All you need to […]

  14. Thank you so much for this. It was a huge help in solving an issue I was having.

  15. Thank you for this; worked perfectly and finally allowed me to stop banging my head on the desk!



  16. Great article! Thank you!

    Just a quick question – when the certificate on the server expires and the CA has to re-issue the certificate, would you have to go through the process of downloading the PEM file (as shown in the illustration above)?

    Thanks so much again!

  17. @RD

    I haven’t encountered this situation yet, but I’ve got the expiration dates marked in my calendar…

    Since the cert. will expire and the site will get a new one, then I’d expect the key it contains to be different – and hence your local copy will need updating if you’re using it to verify against with cURL / PHP.

  18. Thanks Tom! Much appreciated. Have an excellent 2010.

  19. @RD
    As Tom indicated, you will have to re-download the certificate if it’s re-issued. Even if the public/private key used in the certificate stays the same, the other details (serial number, issue/expiry dates) will all be different, so in effect it’s a completely different certificate.

  20. Thanks for this post, works like a charm :) Saved me hours. :)

  21. Dear Peter,

    I discover that my yahoomail could not open the message page, instead of taking me to my page after loging it will display done without diplay the page. what can i do? meanwhile other website were open correctly.




  22. […] to validate the certificate. In those cases you can find a useful tutorial on how to do so over at unit step. cURL, HTTPS, PHP, SSL Address: […]

  23. This really helped me out while trying to set up my first php-gtk app. With everything else to learn, my heart dropped when i couldn’t get a quick and dirty curl to work – your article saved me hours of hacking. ta very much.

  24. Thank you so much for this. This was much more simple than I’d expected regarding using https:// sites. Crisp information, neatly presented.

    Thank you!

  25. I find that all of the options in cURL can be quite confusing, but fortunately there are tutorials from good people like you all over the internet. Thanks so much!

  26. Hi, I keep getting the blank page when trying to curl_exec() a https.

    I’m testing PHP and cURL on a MAMP 1.9 setup and I’m having the hardest time getting cURL to open a https site. I have spent over 20 hours testing different configurations with MAMP and also different script and even the most simple script will keep returning the blank page. Can anyone help me?

  27. @Hugo

    It would be difficult to discuss in comments and there isn’t any more information about you with your post (your e-mail address isn’t published and you didn’t supply a URL for yourself).

    Follow the URL attached to my name and complete a contact form, then I might be able to held you figure out the problem over e-mail.

  28. Can anyone know how to access “https://” link in php. I want to read a file from this link in php. Plz reply me if u knows it.

  29. @Dev

    Did you bother to read the article? The article is about how to use cURL in PHP with HTTPS – exactly what you asked about…

  30. Very helpful article indeed. Thank you!

    Is there anyway to set this through php.ini? Or any other way to do it globally for the whole site? For example we use a framework which tends to do all curl requests itself, hidden somewhere deep in it’s class hierarchy. So it would be great if we could enable curl to work with ssl globally, without patching framework files :(

  31. @Dave

    For the ‘quick fix’ – not that I know of, but it’s a possible I guess (since it’s potentially a config thing somewhere).

    For the ‘proper fix’ – this involves downloading certificates, etc. – not the sort of thing php.ini does.

  32. Thanks Peter! Your post helped me a lot! love you man!

  33. I just want to say thanks for the help!

  34. […] couldn’t find anything so I changed my search terms to “cURL PHP SSL” and I found this page which explains how to use cURL in PHP to access HTTPS sites.  After reading about it I realized I had two […]

  35. Great post. Exactly what I was looking for. My question is if I am accessing my bank using curl, just for example, how safe would it be to do this using curl. There is not a practical reasoning for doing it, just a what if. What extra security measures should I take?

  36. […] Google Reader API Using cURL in PHP to access HTTPS (SSL/TLS) protected sites […]

  37. Thanks man,
    You’re a life-saver!!

  38. Thanks!

  39. Thanks! Very well-written guide!

  40. Had the same problem as above commenter in connecting to S3.

    Worked fine from PHP in terminal, due I guess to already downloading Amazon certificates, or maybe different curl settings in OS X and MAMP….

    Either way, this helped.


  41. Quite helpful.

    Is there a more permanent solution so that we won’t have to call setopt after every curl_init?

    Thanks in advance

  42. Hi there,

    I am trying to connect with curl auto login script for https site, but i am getting the following response i dont kown whats wrong with my code, can you please help me to solve this problem…

    HTTP/1.1 200 OK Expires: Thu, 01 Jan 1970 00:00:00 GMT Set-Cookie: JSESSIONID=ef8rjhhickf3;Path=/ Set-Cookie: EHTrackingCookie=673213713eHT-7eHT20101017023317eHT1eHT0;Path=/;;Expires=Sun, 16-Jan-11 10:33:17 GMT Set-Cookie: EHTrackingCookie=673213713eHT-7eHT20101017023317eHT1eHT0;Path=/;;Expires=Sun, 16-Jan-11 10:33:17 GMT Set-Cookie: EHTrackingCookie=673213713eHT-7eHT20101017023317eHT1eHT0;Path=/;;Expires=Sun, 16-Jan-11 10:33:17 GMT Set-Cookie: EHTrackingCookie=673213713eHT-7eHT20101017023317eHT1eHT0;Path=/;;Expires=Sun, 16-Jan-11 10:33:17 GMT Set-Cookie: EHTrackingCookie=673213713eHT-7eHT20101017023317eHT1eHT0;Path=/;;Expires=Sun, 16-Jan-11 10:33:17 GMT Content-Type: text/html; charset=utf-8 Transfer-Encoding: chunked Server: Jetty(6.1.20) Set-Cookie: BIGipServerSinglesFront-US1=755962284.22811.0000; path=/ Set-Cookie: lbid=5b2cb3d5-22f9-4669-75e3-8dee3525857e;expires=Mon, 16-May-2011 10:33:17 GMT;path=/;;”

  43. Your tutorial was absolutely great, i have been looking everywhere and for quite a while for a explanation like this. thank you very much :)

    Keep doing what your doing .

  44. I tried the exact same method you instruct to download and verify another HTTPS URL, but i keep getting this error.

    SSL certificate problem, verify that the CA cert is OK. Details: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failedIncorrect data type!

    any ideas on how to fix?

  45. Hi,

    I try to make my first Facebook application and I managed to make the basic functions.

    Now I need to use some Facebook functions to query my user informations and friends. Here comes the problem :

    When I put in PHP code this line :

    $friends = $facebook->api(‘/me/friends’);

    the application gives me this error message :

    Fatal error: Uncaught CurlException: 60: SSL certificate problem, verify that the CA cert is OK. Details: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed thrown in C:\xampp\htdocs\…\facebook\src\facebook.php on line 614

    I tried to follow this tutorial but I dont know where to put the curl code so this will work. Should I put it in the same file where I try to interogate Facebook ?

    Thank you

  46. Great article an very easy to follow.
    I’m working on a PHP API class so this will come in handy.

  47. It works for me.
    Thanks a lot!!!

  48. thank you very much for your article.

    i am making a custom module for the klarna invoice the api supplied by klarna is standard less. i want to implement it via curl and your article helped me a lot.

    thanks again.

  49. Thanks, you helped me out a *LOT*!

  50. Thanks, works perfect :) … you really made my day!

  51. Thank u man it’s w0rk LoL

  52. Thanks buddy, really useful.

  53. very helpful article!

  54. this works fine when the URL is known…
    But my application is generating URL every time so each time new page will be there. In this scenario its difficult to have certificate for each URL. Is it possible to have https url without CURLOPT_CAINFO ?

  55. @Darshita

    Yes, it is possible to blindly accept any server certificate, as stated in the article under the section entitled ‘The quick fix’:

    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

    However, as noted above, this removes the verifiability aspect of HTTPS – you no longer can no for sure that the server is who it states it is.

  56. Thanks a lot!

  57. hello,
    i am trying to retrive data from this url.
    data is in xml format..
    i am trying to retrive data using curl..but dont show any thing..
    can you please help me..

    thanks in advance

  58. […] see the following well-written guide on downloading the certificate and adjusting the cURL call: Here is also a new function using your downloaded certificate (renamed it by adding .crt to the […]

  59. CURLOPT_SSL_VERIFYPEER did it! Thanks a lot!

  60. […] […]

  61. When the remote site is accessed via IP (as opposed to domain) and it DOES have SSL support (meaning, I was able to extract and save its certificate), using:

    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);

    does not work (setting it to 0 or 1 does work).

    Based on:

    “2: Check that the common name exists and that it matches the host name of the server”

    I was expecting the verification to be based on the actual server (meaning that it would basically do a reverse dns lookup) and arrive at the conclusion that the remote server/host determined by the reverse lookup does match that of the certificate and thus, it should work (when using option 2). However it SEEMS like what it is actually doing is comparing the host on the URL provided against the certificate. Is this the correct behaviour?

  62. THANK YOU!!
    Your post solved all my issues.

  63. Hi ,
    I tried the same thing mentioned in this article for accessing the using curl command line tool .
    I am able to get the page accessible irrespective of whether I am using the certificate or not .
    Got the result for the below mentioned requests but it shouldn’t be for the second case :

    1 . curl –cacert “”

    2 . curl

    So do you have any idea how to solve this prob ??

  64. Excelente solución, sirve también para la API de google.

  65. I have used the proper fix method on my site for connecting to a third party API. I have also obtained a certificate following the steps explained above. Everything and every but of code works fine on my development server. However, on my production server, the same code gives cUrl error(35): SSL connect error.

    I am running Fedora on both the production and development server. Is there anything required to be included in the default CA bundle ? Or some permission is required? Please help. I am stuck in this problem for the last 2 months.

  66. hi,
    im trying to connect to HTTP over TLS but i get the following error,

    Curl error: error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure

    while i want to use tlsv1.

    kindly help

  67. Thank you so much, this was stumping me for the longest time.

  68. USER ‘ instead of ”
    single coma instead of double coma

    For strings! this is fastest

  69. […] Here is a snippet from saved “cert chain X.509 in PEM format” from Firefox (described here: […]

  70. It was necessary for me to use CURLOPT_CAPATH instead of CURLOPT_CAINFO. With CURLOPT_CAINFO, I’d always get the “SSL certificate problem, verify that the CA cert is OK” error.

  71. It is a way with curl to read the certificate and to put the key in a variable.
    I’d like to make a script giving me the possibility to check some website certificate quickly to know if they are actif and untill when for exemple .

  72. I have further delved into the problem and found the difference between the curl version and built on my production and stage server. While on stage we have version 7.16 built with OpenSSL, the same on production server is version 7.12 built with NSS. Could this be the reason ? Can compiling the curl/libcurl with OpenSSL solve this issue ?

  73. Thanks a lot…its very helpful..

  74. Many thanks for your excellent explanation, solved my problem with Google Plus API.

  75. thanks, was beginning to get frustrated….saved me some serious time(and hair)

  76. You just saved me from tearing my hair out. No one else has explained this error in plain english so it can be more easily understood and addressed.


  77. […] after searching online for a while, I found the solution here The complete fix is kind of long, so I just used the quick and stupid fix: $url = […]

  78. […] if you have administrator rights on your host, refer to this article for a more permanent […]

  79. After searching for a looong time found your thread… tnx worked like a charm on first server that I had to bound with.
    Now I have to get some data from another https server and all the time I get damn 14090086 SSL error.

    On this second server first I login with a script then try to grab some data from search result, but no luck.

    This is my code:

    function curlURL($url){
    $curl = curl_init();

    // Setup headers - I used the same headers from Firefox version
    // below was split up because said the line was too long. :/
    $header[0] = "Accept: text/xml,application/xml,application/xhtml+xml,";
    $header[0] .= "text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5";
    $header[] = "Cache-Control: max-age=0";
    $header[] = "Connection: keep-alive";
    $header[] = "Keep-Alive: 300";
    $header[] = "Accept-Charset: Windows-1250,utf-8;q=0.7,*;q=0.7";
    $header[] = "Accept-Language: en-us,en;q=0.5";
    $header[] = "Pragma: ";
    // browsers keep this blank.

    $referers = array("", "", "", "", "");
    $choice = array_rand($referers);
    $referer = "http://" . $referers[$choice] . "";

    $browsers = array("Mozilla/5.0 (X11; U; Linux i686; en-US; rv: Gecko/2008092510 Ubuntu/8.04 (hardy) Firefox/3.0.3", "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1) Gecko/20060918 Firefox/2.0", "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv: Gecko/2008092417 Firefox/3.0.3", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506)");
    $choice2 = array_rand($browsers);
    $browser = $browsers[$choice2];

    curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);
    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
    curl_setopt($curl, CURLOPT_CAINFO, getcwd() . "/ajpes-chain.crt");

    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_USERAGENT, $browser);
    curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
    curl_setopt($curl, CURLOPT_REFERER, $referer);
    curl_setopt($curl, CURLOPT_AUTOREFERER, true);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_TIMEOUT, 30);
    curl_setopt($curl, CURLOPT_MAXREDIRS, 7);
    curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);

    $data = curl_exec($curl);

    if ($data === false) {
    $data = curl_error($curl);

    // execute the curl command
    // close the connection

    return $data;
    // and finally, return $html

  80. @Jernej

    I had the same error, depending on which pem export I chose from Firefox:

    As the article says, the cert does need to be in pem format though – it doesn’t look like you’re doing this. Firefox can be used to export this from a site you’re visiting (steps in the original article).

  81. Tnx for quick reply. As in original article I exported certificate in firefox to both .crt (PEM) versions and all the same. one cert is ajpes.crt and the second one is ajpes-chain.crt and with both 2 same problem.

    Any other idea? TNX again.

  82. @Jernej

    What’s the URL you’re working with?

  83. login url is:
    data url is:“.$davcna.”&status=1&MAXREC=5

    Bolded is variable that is grabbed from SQL

  84. This post helped a bunch thanks!

  85. @Jernej

    I don’t know specifically what you’re trying to do with your different URLs. Just stripping it back to the bare minimum to test the cURL portion – does the HTTPS login URL by itself present the problem? (ignoring the other parts of your system – just want to check the cURL portion for interacting that host)

    And you are aware that the SSL certificate for is not valid? (has an “unknown authority” warning in my browser)

  86. Tnx for reply again. Yes I know about certificate and had to add it to acception in firefox. Tried also to grab from main url not just the part where search returns something but same error. Was searching net for more solutions but all returns same error. Now I’m a bit frustrated :(

  87. @Jernej

    Ok, I’ve replicated this locally. I think the problem is because of the cert – the reason it’s not valid is that “no issuer chain was provided” (according to Firefox); therefore, trying to validate the cert will always fail (it should, since the cert isn’t valid – it’s wrongly configured it seems).

    The way around this is to not try to verify the cert by setting CURLOPT_SSL_VERIFYPEER to false (then you can forget about needing a copy of the cert). This article is about verifying the cert with cURL; if the cert is always invalid, you shouldn’t be doing this, as it should always fail. So either fix the cert config on the site (if it’s your site), or disable cert checking with cURL.

    Adding the cert as an exception to Firefox has no effect on your PHP install.

  88. Tnx gonna try this 😉

  89. Thanks a million. My curl script wasn’t working when pointing to an https site. Used your quick fix and worked like a charm.

  90. Is the .crt in line with CURLOPT_CAINFO (in original blog entry) correct?

    The steps suggest to save the file in FF as ‘.pem’.

    Thanks for submitting the article. Looks great.

  91. Sweet! You save my day. Thanks! (:

  92. I had all this working against a specific_site before we renewed our SSL certificate on a specific_site. I thought I just needed either a single openssl command (which I thought I initially used) or the Firefox export method (described in this article) to grab the new certificate from the specific_site.

    The Firefox export method gave me a .pem file similar to the old one, but no joy.

    Just for grins, I changed CURLOPT_CAINFO to CURLOPT_CAPATH as mentioned by “70. Timbo” and now it works! Also, I only used either CURLOPT_CAINFO or CURLOPT_CAPATH, and never both. Documentation on CURLOPT_CAPATH says you need to use the c_rehash utility, but I point to the file, not the directory, and like I said, it works.

    Our PHP version and openssl and curl have not changed. As far as I know, only the new SSL certificate changed.


  93. i have problem in paypal describe below

    The PayPal API has returned an error!
    Error Number: 60
    Error Message: SSL certificate problem, verify that the CA cert is OK. Details: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed

  94. How do i authenticate a Google site through PHP?

    The following are the code snippet
    ‘Email’ => ‘’,
    ‘Passwd’ => ‘xxxxxxxx’,

    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data);

    $hasil = curl_exec($ch);
    echo $hasil;

    $authRaw = strstr($hasil, “Auth”);
    $authToken = substr($authRaw, 5);

    $headers = array(“Authorization: GoogleLogin auth=$authToken”);

    //echo $headers;
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HEADER, false);

    $ch = curl_init(“”);

    $hasil = curl_exec($ch);
    echo $hasil;

    Getting the Auth tockens:

    Basically i am trying to access this through PHP passing with the google’s emailId and password.

    Pleas help me to fix this, i am trying to fix this very looong time.

    Thanks in advance.

  95. Missing snippet code lines(from top):


  96. Missing Snippet code:

    $ch = curl_init();

    curl_setopt($ch, CURLOPT_URL, “”);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

    $data = array(‘accountType’ => ‘GOOGLE’,
    ‘Email’ => ‘’,
    ‘Passwd’ => ‘xxxxxxxx’,

  97. very good, thanks

  98. Does this article apply for shared hostings?

    If I create the PEM file I’ll be only able to save it in html/, not above that.

    Doesn’t that endangers the certificate?


  99. @sergio

    Shared hosting should be irrelevant (unless they’ve limited PHP so you can’t use what you need to).

    If you’ve only got a HTML option for saving, you’re not following the instructions in the original article. Use Firefox and follow the instructions carefully; there will be a PEM option.


  100. i want to scrap one java site.which is done java struts mvc.i want scrap details of 6 page using their parameters and want result of last page.i searched lot but not founf any solution.please if any one can logic or idea please give me solution guys.

    thanks in advance guys.

  101. Awesome. I was doing curl and couldn’t get any response from the server. No errors or anything. Turns out to be https issue! You have saved my day!

  102. Thanks for the tutorial it helped me.

  103. Thank you! This is not mentioned commonly when CURL is mentioned.

  104. Thanks man!
    That was realy helpful.

  105. Thank you very much for this solution, and thank you to the commenter who mentioned to save (with chain) in Firefox. It worked perfectly for me.

  106. This is one of the most explicit solutions I have ever seen. Thanks a bunch.

  107. You are a legend. I have spent 6 hours trying to get my code working with the Quickbase API. Your explanation is clear and informative. I also picked up some new ideas along the way. Keep it up. We need more guys like you.

  108. U can use


    instead of cURL.


  109. I struggled with more than 8 hours thank you very much!

  110. just perfect THANKS

  111. Thanks! In all my years, this is the first time I’ve needed to access a TSL-protected page and the quick, one-liner fix is adequate for my application but the proper fix was an interesting read for future reference. cURL’s capabilities never cease to amaze me!

  112. Thank you :)
    It was helpful (Y)

  113. I am trying to setup a facebook application for my site ( using Add Link To Facebook plugin. I got “cURL communication error 60 SSL certificate problem”.

    According to your post, adding this line:

    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

    would fix it. But where do I add that line?


  114. […] article Using cURL in PHP to access HTTPS (SSL/TLS) protected sites has some workarounds/fixes for this error when using cURL in PHP. Tagged: […]

  115. Hi,
    I am using this code for a cron job to monitor https service. How do I know that the service is up?

    I am verifying it as follows.

    $response = curl_exec($ch);

    if($response == ”)
    echo ‘Failed’;
    echo $response;

    It is working fine if SSL is not installed or for the pages which do not exist. But it is not working correctly for the url

    It is showing 301 error (Moved Permanantly). So for this case $response != “”. Thus the monitoring service produces erroneous result.

    Is there any way to catch the status since I am calling this via cronjob?



  116. @Arnab

    The 301 is not an error – it’s a redirect because the website is sending your request from the domain only version to the www. version of their domain (this is their technical choice).

    But, further to your task, just checking the response content is not empty is not sufficient.

    First, after calling curl_exec, you need to check for any cURL errors:

    if (curl_errno($ch)) {
    if error value is > 0 something went wrong – for error codes meanings, see:

    Then, if there were no cURL errors, you should get the HTTP response code for the request:

    $responsecode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

    I suggest you consult:

    Unless you want to check for specific bits of content in the returned page, I suggest you check HTTP status codes.

    If you’re getting a redirect header, and you want to follow it and see what the redirected to URL returns, you want to look at the CURLOPT_FOLLOWLOCATION option:

    In combination with the CURLOPT_FOLLOWLOCATION option, this call is useful if you want to get the URL where you ended up at after redirects:

    curl_getinfo($ch, CURLINFO_EFFECTIVE_URL)

    you call it after curl_exec.

    Finally, if you’re using a cron, if you add a line at the top of the crontab in the following format (swapping in your email address):


    then any output from a script will be sent to you as an email (assuming your server is properly configured for sending mail). This is handy for error situations; no error, output nothing. If an error is found, output – then you’ll get an email with the output in.


  117. @Arnab Bhattacharjee:

    A Quick Example:
    $url = ‘’;
    $response = get_headers($url);
    if($response[0] == ‘HTTP/1.1 200 OK’){
    echo “Everything is alright!”;

  118. this was of great use for me, solved my problem the right way.

  119. […] –fresh   # cURL testen curl   Piwik › Sign in . .Quelle: Using cURL in PHP to access HTTPS (SSL/TLS) protected sites cURL: Adding/Installing/Trusting New Self-Signed CertificateTags: CA, cURL, Debian, Piwik, […]

  120. I love this post. It made my life easy.
    Many Thanks,

    -Waseem Akhtar Tanoli
    Vertex Solutions Pvt Ltd

  121. Code worked flawlessly (once I used chained export) on the delicious example, but when one follows the same instructions for the result is empty.

  122. does not return anything, but does work (when using chained keys). One very important detail, always returns regardless of giving it any keys. Perform the example but leave out the line for
    curl_setopt($ch, CURLOPT_CAINFO, getcwd() . ‘/’);
    and it still returns the page.

  123. I don’t know what your code looks like but it’s probably a waste of effort. Did you look into this before trying to scrape?

  124. Your post is very useful. But option 2(The proper fix) does not work for

  125. Very very very useful post. Thank you!

  126. […] cert is OK. Details:" in their error logs. You may be able to find a solution for this after reading this article. If you try to "Perform Backup" and it returns a blank page, check the /cache/log.php […]

  127. Look at the long list of people benefit from this post!
    I want to express my thanks too.

  128. Thanks , I’ve recently been searching for info about this topic for ages and yours is the best I have came upon till now. However, what concerning the conclusion? Are you certain about the source?

  129. Thanks, this was a really useful post. I remember running into this issue before but I wasn’t able to solve it. Learning more about curl every day. :)

  130. Posted back in 2009 and still incredibly useful to this day. Thank you so much for a point in the right direction, you are a gentleman and a scholar.

  131. Lots of love from Brazil.

  132. Hi, please could you help me with the ‘error reading X.509 key or certificate file’ error?

  133. Good day! Do you use Twitter? I’d like to follow you if that would be ok. I’m undoubtedly enjoying your blog
    and look forward to new updates.

  134. Infrared is 1 of the most beloved colorways in the Air Max ninety sequence.
    Shade cameras are, effortlessly, significantly additional outstanding and
    present a clearer impression.


  135. Hi!
    Thank you so much for your tutorial. It helped me solve my problem. :)


  136. […] el certificado de servidores seguros,aunque si alguien lo puedes implementar de forma sencilla aquí esta […]

  137. hello there and thank you for your info – I have certainly picked up something new
    from right here. I did however expertise several technical points using this site, since
    I experienced to reload the web site lots of times previous to I could get it to load properly.
    I had been wondering if your web hosting is OK? Not that I am complaining, but slow loading
    instances times will very frequently affect your placement in google and can damage your high-quality score if advertising and marketing with Adwords.
    Well I am adding this RSS to my e-mail and can look
    out for much more of your respective intriguing content. Ensure that you
    update this again very soon.

  138. […] you’ve ever had issues with working with SSL and cURL in PHP, perhaps this will help you out. It certainly helped me out, as I had no clue it wasn’t going to work as […]


  140. […] Set up cURL to either accept all certificates or add the needed certificate authority to cURLs CA list (check out […]

  141. Hi. it work for me on Wamp. Thanks :)

  142. THANKSS!!

  143. […] https in php […]

  144. So all of these tutorials tell people to add the CAINFO line with the path to the certificate…but I have multiple different customers with this issue. What would I put as the path in my company’s plugin? Wouldn’t it be specific to each server? Is there some general path I can put that will apply to everyone? If not, where should I tell a specific customer to put the certificate file. This will have to go on his web server somewhere, correct?

  145. I thought I hit a roadblock when I had just started working with Google voice, thanks for the instructions. This worked amazing.

  146. I has been stuck for almost an hour reading all other non sense posts looking what you call it “proper” solution and only your post have it. I had to thank you for your simple straight forward and yet complete explanation which is very rare!

  147. […] The better solution is to manually add only the certificate(s) or CA(s) you want to accept. See this article on cURL and SSL for more […]

  148. Is there a way to download the certificate using php code?

  149. I think, the really really nessecary thing is the Post in comment number 4. You have to choose export option: X.509 Certificate with chain (PEM)

    On the other hand, this was not enough to do for me. Because after selecting this option I still had one certificate in the file.

    In the end, all certificates of all hierarchy levels have to be listed in the crt-file, I guess even in the right order. Or, the second possibility, you have to export every hierarchy level into an own crt-file. That worked too.

  150. I am using amazon connecting daynamodb with codeigniter and faced this problem as getting error.
    “Fatal error: Uncaught exception ‘cURL_Exception’ with message ‘cURL resource: Resource id #43; cURL error: SSL certificate problem: unable to get local issuer certificate (cURL error code 60). See for an explanation of error codes.’ in C:\wamp\www\qmapp_old\application\libraries\aws\lib\requestcore\requestcore.class.php on line 843″.

    As i had followed your steps but not solved can you please guid me in proper manner so that it can solve.

    Many thanks

  151. I’ve been struggling to use CURL to retrieve data from a particular site. Following the instructions in this article has resolved my issue. Many Thanks for taking the time to right this very clear guide.

  152. Thanks! work for me

  153. hi,
    i did upload videos from viemo. I did set privacy to all videos. i want to get direct link with token from all vimeo videos in particular users. i have tried php language, with out privacy videos get direct link from all, but i have set privacy link can’t get direct link.

  154. Thank you very much, this is the best explanation about it. I was looking for this answer over 10 hours.

  155. I fix this problem by update php from 5.3.3-22 to 5.3.3-27.

  156. […] Similar Article […]

  157. I’m having a problem on connecting to a https site, I followed your post but nothing happens still can’t retrieve response from an API. It says “Failed to connect to **************** port 443: Connection timed “

  158. Hi,

    the step involving setting CURLOPT_CAINFO does not work (at least on PHP 5.4.4, Debian 7): cURL is unable to validate the chain with the ca-certificates.crt (or ca.pem) file.

    It requires instead setting CURLOPT_CAPATH to /etc/ssl/certs/ and letting it picking the right certificate by itself.
    This solves the problem.

  159. We have a client that has an app pointing to an old 2003 web cluster where https is not forced and their PHP cUrl app is working fine. We point them to the new 2012 web cluster where all calls a forced to https and the call fails with the following:
    Notice: SSL certificate problem: unable to get the local issuer certificate in …….
    We implemented the quick fix performed an IIS reset and still see the same issue. Any ideas? I do not have any PHP resources to help me at this time.

  160. Thanks , was the solution to my problem.

  161. Thank you

  162. Listen to this guy. THANK YOU :)

    “I think, the really really nessecary thing is the Post in comment number 4. You have to choose export option: X.509 Certificate with chain (PEM)”

  163. Thankyou, this worked (with Alberto’s edit)

  164. Thank you very much. That really helped.

  165. Thaks for solve my problem, crack

  166. Thank you!

  167. I have a FreeBSD server
    FreeBSD 6.2-RELEASE-p6 FreeBSD 6.2-RELEASE-p6 #0: Sat Jul 21 13:42:25 EDT 2007

    On this server I have an application in php using curl which connects to through their api. Recently they updated their SSL certificates to support sha256 and hence the SSL certificate also changed. After this change the application is failing to connecting. If I do a
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE)
    it connects successfully but I want to go with a full verification of the server during SSL handshake.
    I have noted the same gets connected from a different Linux ubuntu server after updating ca certificate file by specifying using CURLOPT_CAINFO option.

    But on this FreeBSD, it does not get connected. I have also noted that the SSL certificate is issued on a wildcard character i.e. * Because of this, on the ubuntu server also, I had to disable CURLOPT_SSL_VERIFYHOST. But on this FreeBSD server, it is simply not working with this option even.
    The server is a bit old with php version
    PHP 4.4.7 (cgi-fcgi) (built: May 4 2007 13:35:10)

    Any help is appreciated.

  168. Error I am getting above is

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

  169. Thank you.

  170. PHP names these fields ‘button_name_x’ and ‘button_name_y’, while ASP uses a dot. Also, as noted above, be sure to include the ‘__VIEWSTATE’ input field in your post request.

  171. Hi, thank you for this article.

    I had some problems with the proper fix.
    The certificate at the top of the hierarchy didn’t work for me.

    So I chose the second one and everything worked!

  172. Thanks a lot for this article. Saved my time.

Post a Comment


(will not be published) (required)

XHTML tags allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Note: rel="nofollow" will be added to all links in comments.

Comments will be closed on Monday, October 3rd, 2016.