CURL & PHP Web Scraping - cainfo - php

I am trying to scrape some information from the steam community website.
I am getting an error related to a certificate when I try to access the URL through cURL.
I downloaded cacert.pem
modified the php.ini file to include
[curl]
; A default value for the CURLOPT_CAINFO option. This is required to be an
; absolute path.
curl.cainfo = "D:\xampp\php\caextract.pem.txt"]
PHP File
$url = 'https://steamcommunity.com/search/?text=' . $PlayerName . '&x=0&y=0';
$ch = curl_init(); // Initialising cURL
curl_setopt($ch, CURLOPT_URL, $url); // Setting cURL's URL option with the $url variable passed into the function
curl_setopt($ch, CURLOPT_RETURNTRANSFER, FALSE); // Setting cURL's option to return the webpage data
$html = curl_exec($ch); // Executing the cURL request and assigning the returned data to the $data variable
var_dump(curl_getinfo($ch ));
var_dump(curl_errno($ch) );
var_dump(curl_error($ch));
curl_close($ch); // Closing cURL
Setup:
XAMPP 3.2.2 (Default settings)
Windows 10
Chrome
Error:
error setting certificate verify locations: CAfile: D:\xampp\htdocs\steaminfo\cacert.pem CApath: none

I would not rely too much on such settings in php.ini as they may be overwritten by: 1) php.ini at other level; 2) .htaccess in any parent directory.
The only way to ensure your settings actually take effect is place/run phpinfo() in the same directory as your script.
However there is another, more simple, way: set respective CURL option by curl_setopt in your script:
...
curl_setopt($ch, CURLOPT_RETURNTRANSFER, FALSE);
curl_setopt($ch, CURLOPT_CAINFO, "D:\xampp\php\caextract.pem.txt");
...

Is it necessary to verify the SSL certificate? There is an option CURLOPT_SSL_VERIFYHOST you can set for cURL to not verify it.
Alternatively you can try sending the request to with http:// instead in the beginning of URL.

Since you only scrape, you don't actually need to verify the ssl certificate, because it will only slow you down. Plus you aren't logging anywhere, my advice would be to prevent CURL from checking the SSL.
All you have to do is add:
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

Related

Pulled down site with "BackupBuddy" to local machine, trying to use SendGrid to send email, getting "CURL Error 60: self signed certificate" [duplicate]

I try to send curl request with my correct APP_ID, APP_SECRET etc. to the
https://oauth.vk.com/access_token?client_id=APP_ID&client_secret=APP_SECRET&code=7a6fa4dff77a228eeda56603b8f53806c883f011c40b72630bb50df056f6479e52a&redirect_uri=REDIRECT_URI
I need to get access_token from it, but get a FALSE and curl_error() print next message otherwise:
60: SSL certificate problem: self signed certificate in certificate chain
My code is:
// create curl resource
$ch = curl_init();
// set url
curl_setopt($ch, CURLOPT_URL, $url);
//return the transfer as a string
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// $output contains the output string
$output = curl_exec($ch);
if ( ! $output) {
print curl_errno($ch) .': '. curl_error($ch);
}
// close curl resource to free up system resources
curl_close($ch);
return $output;
When I move manually to the link above, I get access_token well. Why it doesn't work with curl? Help, please.
Answers suggesting to disable CURLOPT_SSL_VERIFYPEER should not be accepted. The question is "Why doesn't it work with cURL", and as correctly pointed out by Martijn Hols, it is dangerous.
The error is probably caused by not having an up-to-date bundle of CA root certificates. This is typically a text file with a bunch of cryptographic signatures that curl uses to verify a host’s SSL certificate.
You need to make sure that your installation of PHP has one of these files, and that it’s up to date (otherwise download one here: http://curl.haxx.se/docs/caextract.html).
Then set in php.ini:
curl.cainfo = <absolute_path_to> cacert.pem
If you are setting it at runtime, use (where $ch = curl_init();):
curl_setopt ($ch, CURLOPT_CAINFO, dirname(__FILE__)."/cacert.pem");
This workaround is dangerous and not recommended:
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
It's not a good idea to disable SSL peer verification. Doing so might expose your requests to MITM attackers.
In fact, you just need an up-to-date CA root certificate bundle. Installing an updated one is as easy as:
Downloading up-to-date cacert.pem file from cURL website and
Setting a path to it in your php.ini file, e.g. on Windows:
curl.cainfo=c:\php\cacert.pem
That's it!
Stay safe and secure.
If the SSL certificates are not properly installed in your system, you may get this error:
cURL error 60: SSL certificate problem: unable to get local issuer
certificate.
You can solve this issue as follows:
Download a file with the updated list of certificates from https://curl.haxx.se/ca/cacert.pem
Move the downloaded cacert.pem file to some safe location in your system
Update your php.ini file and configure the path to that file:
Important: This issue drove me crazy for a couple days and I couldn't figure out what was going on with my curl & openssl installations. I finally figured out that it was my intermediate certificate (in my case, GoDaddy) which was out of date. I went back to my godaddy SSL admin panel, downloaded the new intermediate certificate, and the issue disappeared.
I'm sure this is the issue for some of you.
Apparently, GoDaddy had changed their intermediate certificate at some point, due to scurity issues, as they now display this warning:
"Please be sure to use the new SHA-2 intermediate certificates included in your downloaded bundle."
Hope this helps some of you, because I was going nuts and this cleaned up the issue on ALL my servers.
To add a more specific answer, I ran into this when using Guzzle v7, the PHP HTTP request package. Guzzle allows you to bypass this like so:
use GuzzleHttp\Client;
$this->client = new Client([
'verify' => false,
]);
Original source comment: https://github.com/guzzle/guzzle/issues/1490#issuecomment-375667460
Error: SSL certificate problem: self signed certificate in certificate
chain
Solution:
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_FAILONERROR, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);

How to debug curl in PHP and Azure

Ok, I've got a Drupal site which I'm deploying on Azure. My App perform an API call to Marketo to trigger an action in Marketo's API.
On my local dev and on a Debian server (regular lamp stack) all works fine.
When I deploy the site to Azure, it doesn't work and all I get is NULL.
Here's my code:
public function postData(){
$url = $this->host . "/rest/v1/campaigns/" . $this->id . "/schedule.json?access_token=" . $this->getToken();
$ch = curl_init($url);
$requestBody = $this->bodyBuilder();
print_r($requestBody);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('accept: application/json','Content-Type: application/json'));
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_VERBOSE, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $requestBody);
curl_getinfo($ch);
$response = curl_exec($ch);
dvm($response, $name = NULL);
return $response;
}
private function getToken(){
$ch = curl_init($this->host . "/identity/oauth/token?grant_type=client_credentials&client_id=" . $this->clientId . "&client_secret=" . $this->clientSecret);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('accept: application/json',));
curl_setopt($ch, CURLOPT_VERBOSE, true);
$response = json_decode(curl_exec($ch));
curl_close($ch);
$token = $response->access_token;
dvm($response, $name = NULL);
return $token;
}
Please note:
There are 2 calls: one to get the access_token and another the actual trigger.
dvm($response, $name = NULL); in simplistic terms is a Drupal equivalent to print_r
This exact same code works on my local machine (OS X, Apache, PHP5.6) and on Debian (Apache, PHP 5.6).
I'm using SQLite which is not exactly relevant but I though I should add just in case.
When I execute this code locally or on the Debian server I get the $result variable printed which tells me whether it was successful or not. On Azure I get just NULL for the first FALSE to the second.
The variables ($this->id, $this->getToken(), etc) are correctly set and I can I print them fine. Like I said, all works locally.
What am I missing?
Default settings on Azure has CURLOPT_SSL_VERIFYPEER set equal to TRUE. If you dont have an SSL there could be an issue.
The following was taken from a post on MSDN (http://blogs.msdn.com/b/azureossds/archive/2015/06/12/verify-peer-certificate-from-php-curl-for-azure-apps.aspx)
Common error messages related to SSL_VERIFYPEER option could be:
SSL certificate problem, verify that the CA cert is OK
SSL certificate problem: unable to get local issuer certificate
The error is usually caused by missing or having invalid SSL certificate in cURL option. If you see these messages, consider to validate SSL certificate, and check the path to CA certificate file. CA certificate must be in PEM format, for more detail about CA extract, visit http://curl.haxx.se/docs/caextract.html
Do not turn off CURLOPT_SSL_VERIFYPEER unless your cURL connect to non certificate protected server.
There are two ways that you can specify certificate info for cURL in PHP environment.
Specify CURLOPT_CAINFO in cURL option: (sample code)
curl_setopt($ch, CURLOPT_CAINFO, getcwd() . "\cert\ca-bundle.crt");
Note: getcwd() . "\cert\ca-bundle.crt" returns absolute path of your ca-bundle.crt. Make sure ca-bundle is installed at correct path.
Set curl.cainfo in php.ini
In php.ini file, find [curl] section, add this directive (sample code):
curl.cainfo ="D:\home\site\wwwroot\cert\ca-bundle.crt"
Note: Restart you web app after the change.
“curl.cainfo” is system level directive which has to be set in php.ini, not in .user.ini. To use this approach, need to have customer php.ini.
Refer to the link to setup customer php.ini, https://github.com/projectkudu/kudu/wiki/Xdt-transform-samples#using-a-custom-phpini
CURLOPT_SSL_VERIFYHOST option is used along with verify peer, default value of this option is 2, to check the existence of a common name and also verify that it matches the hostname provided (more detail at http://php.net/manual/en/function.curl-setopt.php)

Curl error 60, SSL certificate issue: self signed certificate in certificate chain

I try to send curl request with my correct APP_ID, APP_SECRET etc. to the
https://oauth.vk.com/access_token?client_id=APP_ID&client_secret=APP_SECRET&code=7a6fa4dff77a228eeda56603b8f53806c883f011c40b72630bb50df056f6479e52a&redirect_uri=REDIRECT_URI
I need to get access_token from it, but get a FALSE and curl_error() print next message otherwise:
60: SSL certificate problem: self signed certificate in certificate chain
My code is:
// create curl resource
$ch = curl_init();
// set url
curl_setopt($ch, CURLOPT_URL, $url);
//return the transfer as a string
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// $output contains the output string
$output = curl_exec($ch);
if ( ! $output) {
print curl_errno($ch) .': '. curl_error($ch);
}
// close curl resource to free up system resources
curl_close($ch);
return $output;
When I move manually to the link above, I get access_token well. Why it doesn't work with curl? Help, please.
Answers suggesting to disable CURLOPT_SSL_VERIFYPEER should not be accepted. The question is "Why doesn't it work with cURL", and as correctly pointed out by Martijn Hols, it is dangerous.
The error is probably caused by not having an up-to-date bundle of CA root certificates. This is typically a text file with a bunch of cryptographic signatures that curl uses to verify a host’s SSL certificate.
You need to make sure that your installation of PHP has one of these files, and that it’s up to date (otherwise download one here: http://curl.haxx.se/docs/caextract.html).
Then set in php.ini:
curl.cainfo = <absolute_path_to> cacert.pem
If you are setting it at runtime, use (where $ch = curl_init();):
curl_setopt ($ch, CURLOPT_CAINFO, dirname(__FILE__)."/cacert.pem");
This workaround is dangerous and not recommended:
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
It's not a good idea to disable SSL peer verification. Doing so might expose your requests to MITM attackers.
In fact, you just need an up-to-date CA root certificate bundle. Installing an updated one is as easy as:
Downloading up-to-date cacert.pem file from cURL website and
Setting a path to it in your php.ini file, e.g. on Windows:
curl.cainfo=c:\php\cacert.pem
That's it!
Stay safe and secure.
If the SSL certificates are not properly installed in your system, you may get this error:
cURL error 60: SSL certificate problem: unable to get local issuer
certificate.
You can solve this issue as follows:
Download a file with the updated list of certificates from https://curl.haxx.se/ca/cacert.pem
Move the downloaded cacert.pem file to some safe location in your system
Update your php.ini file and configure the path to that file:
Important: This issue drove me crazy for a couple days and I couldn't figure out what was going on with my curl & openssl installations. I finally figured out that it was my intermediate certificate (in my case, GoDaddy) which was out of date. I went back to my godaddy SSL admin panel, downloaded the new intermediate certificate, and the issue disappeared.
I'm sure this is the issue for some of you.
Apparently, GoDaddy had changed their intermediate certificate at some point, due to scurity issues, as they now display this warning:
"Please be sure to use the new SHA-2 intermediate certificates included in your downloaded bundle."
Hope this helps some of you, because I was going nuts and this cleaned up the issue on ALL my servers.
To add a more specific answer, I ran into this when using Guzzle v7, the PHP HTTP request package. Guzzle allows you to bypass this like so:
use GuzzleHttp\Client;
$this->client = new Client([
'verify' => false,
]);
Original source comment: https://github.com/guzzle/guzzle/issues/1490#issuecomment-375667460
Error: SSL certificate problem: self signed certificate in certificate
chain
Solution:
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_FAILONERROR, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);

PHP CURL CURLOPT_SSL_VERIFYPEER ignored

For some reason I am unable to use CURL with HTTPS. Everything was working fine untill I ran upgrade of curl libraries. Now I am experiencing this response when trying to perform CURL requests: Problem with the SSL CA cert (path? access rights?)
Following suggestions posted here on related issues I have tried to do the following:
Disable verification for host and peer
curl_setopt($cHandler, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($cHandler, CURLOPT_SSL_VERIFYPEER, true);
Enable CURLOPT_SSL_VERIFYPEER and point to cacert.pem downloaded from http://curl.haxx.se/docs/caextract.html
curl_setopt($cHandler, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($cHandler, CURLOPT_CAINFO, getcwd() . "/positiveSSL.ca-bundle");
I also tried to do the same thing with positiveSSL.ca-bundle which was provided as bundle CA certificate for the server I am trying to connect to.
Edit php ini settings with curl.cainfo=cacert.pem (file in the same directory and accessible by apache)
Rename /etc/pki/nssdb to /etc/pki/nssdb.old
Unfortunatelly none of the above are able to solve my problem and I constantly get Problem with the SSL CA cert (path? access rights?) message.
And I don't need this verification in the first place (I am aware of security issues).
Does anybody have any other suggestions?
UPDATE
After updating to the latest libraries and restart of the whole box, not just apache which I was doing it all seems to be working now again!!!
According to documentation: to verify host or peer certificate you need to specify alternate certificates with the CURLOPT_CAINFO option or a certificate directory can be specified with the CURLOPT_CAPATH option.
Also look at CURLOPT_SSL_VERIFYHOST:
1 to check the existence of a common name in the SSL peer certificate.
2 to check the existence of a common name and also verify that it matches the hostname provided.
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
$ch = curl_init();
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // Return data inplace of echoing on screen
curl_setopt($ch, CURLOPT_URL, $strURL);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); // Skip SSL Verification
$rsData = curl_exec($ch);
curl_close($ch);
return $rsData;
We had the same problem on a CentOS7 machine. Disabling the VERIFYHOST VERIFYPEER did not solve the problem, we did not have the cURL error anymore but the response still was invalid. Doing a wget to the same link as the cURL was doing also resulted in a certificate error.
-> Our solution also was to reboot the VPS, this solved it and we were able to complete the request again.
For us this seemed to be a memory corruption problem. Rebooting the VPS reloaded the libary in the memory again and now it works. So if the above solution from #clover does not work try to reboot your machine.

PHP Client to verify https certificates

I need to create a php that will act as a client and use some web services under https.
My Problem is that I also want to verify the server certificate.I need to know that I have the right server and that there is no one the middle that acts as the server.
Can someone help me please?
Thanks!
If you have the curl extension, it can be configured to verify a certificate on connection.
http://php.net/manual/en/function.curl-setopt.php
// As of writing this, Twitter uses Verisign, Google uses Eqifax
$exampleUrl = 'https://twitter.com/'; // Success
$exampleUrl = 'https://google.com/'; // Fails
// create a new CURL resource
$ch = curl_init($exampleUrl);
// enable verification
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
// list of CAs to trust
// If the remote site has a specific CA, they usually have a .crt
// file on their site you can download. Or you can export key items from
// some browsers.
// In this example, using: Verisign [1]
curl_setopt($ch, CURLOPT_CAINFO, __DIR__ . '/ca_bundle.crt');
// - or -
curl_setopt($ch, CURLOPT_CAPATH, __DIR__ . '/ca_certs/');
// If the remote site uses basic auth:
curl_setopt($ch, CURLOPT_USERPWD, $username . ':' . $password);
// And a helpful option to enable while debugging
//curl_setopt($ch, CURLOPT_VERBOSE, true);
// defaults to stdout, don't want that for this case.
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$page = curl_exec($ch);
[1] http://www.verisign.com/support/verisign-intermediate-ca/extended-validation/apache/
It looks like as of Curl 7.10, this is all set to be checked by default now:
http://php.net/manual/en/function.curl-setopt.php
CURLOPT_SSL_VERIFYPEER
FALSE to stop cURL from verifying the peer's certificate. Alternate certificates to verify against can be specified with the CURLOPT_CAINFO option or a certificate directory can be specified with the CURLOPT_CAPATH option.
TRUE by default as of cURL 7.10. Default bundle installed as of cURL 7.10.
CURLOPT_SSL_VERIFYHOST
1 to check the existence of a common name in the SSL peer certificate. 2 to check the existence of a common name and also verify that it matches the hostname provided. In production environments the value of this option should be kept at 2 (default value).

Categories