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)
Related
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);
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);
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);
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).
I'm trying to write a PHP script using cURL that can authorize a user through a page that uses an SSL certificate, in addition to username and password, and I can't seem to get past the SSL cert stage.
In this case, curl_setopt($handle, CURLOPT_VERIFYPEER, 0) unfortunately isn't an option. The certificate is a required part of authentication, otherwise I get the error mentioned in this other similar SO post.
I've tried a few command-line runs with cURL:
> curl --url https://website
This returns the (60) SLL certificate problem error. If I adjust the command to include the --cacert option:
> curl --url https://website --cacert /path/to/servercert.cer
It works just fine; the auth website is returned.
However, I've tried the following PHP code:
$handle = curl_init();
$options = array(
CURLOPT_RETURNTRANSFER => false,
CURLOPT_HEADER => true,
CURLOPT_FOLLOWLOCATION => false,
CURLOPT_SSL_VERIFYHOST => '0',
CURLOPT_SSL_VERIFYPEER => '1',
CURLOPT_CAINFO => '/path/to/servercert.cer',
CURLOPT_USERAGENT => 'Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)',
CURLOPT_VERBOSE => true,
CURLOPT_URL => 'https://website'
);
curl_setopt_array($handle, $options);
curl_exec($handle);
if (curl_errno($handle)) {
echo 'Error: ' . curl_error($handle);
}
curl_close($handle);
I would have thought the code was essentially analogous to the shell commands, but instead I'm greeted with the following error message:
Error: error setting certificate verify locations: CAfile: /path/to/servercert.cer CApath: none
I've read all the literature I can find (particularly on php.net and curl.haxx) and can't seem to find anything that fixes this problem. Any suggestions?
I have tried chmod 777 servercert.cer with no success. However, in executing the PHP script with the above code from the command line instead of the browser via php test.php, it works perfectly. Any explanation for why it doesn't work in the browser?
Because things work via the command line but not via php using curl then I would pursue curl being the problem.
According to this URL, http://curl.haxx.se/docs/sslcerts.html, which was reference in an SO post you cited above ( reading SSL page with CURL (php) )...
"Until 7.18.0, curl bundled a severely outdated ca bundle file that was
installed by default. These days, the curl archives include no ca certs at
all. You need to get them elsewhere. See below for example.
If the remote server uses a self-signed certificate, if you don't install a CA
cert bundle, if the server uses a certificate signed by a CA that isn't
included in the bundle you use or if the remote host is an impostor
impersonating your favorite site, and you want to transfer files from this
server, do one of the following:"
It then goes on to list a number of steps that you can try.
Since your 7.16.3 version of curl is prior to 7.18.0, if you haven't already, I would recommend updating your curl and openssl components and then working through the list referenced above.
To elaborate and sum this up:
if you have a PHP file using PHP curl and place the ca certificate for your systems in the same directory, the below code will give you a jumpstart
$url = "https://myserver.mydomain.local/get_somedata.php";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
//These next lines are for the magic "good cert confirmation"
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_VERBOSE, true);
//for local domains:
//you need to get the pem cert file for the root ca or intermediate CA that you signed all the domain certificates with so that PHP curl can use it...sorry batteries not included
//place the pem or crt ca certificate file in the same directory as the php file for this code to work
curl_setopt($ch, CURLOPT_CAINFO, __DIR__.'/cafile.pem');
curl_setopt($ch, CURLOPT_CAPATH, __DIR__.'/cafile.pem');
//DEBUG: remove slashes on the next line to prove "SSL verify" is the cause
//curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
//Error handling and return result
$data = curl_exec($ch);
if ($data === false) {
$result = curl_error($ch);
} else {
$result = $data;
}
// Close handle
curl_close($ch);
return $result;
After 6 years of the question, I meet the same problem on a shared-host, and apparently there is no satisfactory answer. I found for myself a solution, hope it useful for everybody.
You can try this config:
curl_setopt($config,CURLOPT_SSL_VERIFYHOST,0);
curl_setopt($config,CURLOPT_SSL_VERIFYPEER,1);
curl_setopt($config,CURLOPT_CAINFO,'ca-bundle.crt');
curl_setopt($config,CURLOPT_CAPATH,'ca-bundle.crt');
I met same error with #Magsol: Error: error setting certificate verify locations: CAfile: /path/to/servercert.cer CApath: none; so I added the 4th line to set CAPath.
It's work with me. But note, the CA file must be place in accessable dir (with chmod 755 or 777) and it will better if CA file is in the same dir with PHP file.
Now that this question is vey old, but maybe could be useful for some users looking for an answer currently.
I have a similar problem about an API with SSL, having problems with CURL (not with the browsers) my problem was that I just put the certificate but not the ceritifcates chain/bundle. Then I put that and things started working. So that's important in order to avoid problems.
Hope this can be useful for someone.
You can try this if it works for you:
curl_setopt($ch, CURLOPT_URL, "https://test.example.com/v1/authenticate.json?api_key=123456");
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,0);
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_FAILONERROR, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch,CURLOPT_CAINFO,'cert.embedapp.20191004.pem');
curl_setopt($ch,CURLOPT_CAPATH,'./cert.embedapp.20191004.pem');
Comment these lines and add this:
//curl_setopt($ch,CURLOPT_CAINFO,'cert.embedapp.20191004.pem');
//curl_setopt($ch,CURLOPT_CAPATH,'./cert.embedapp.20191004.pem');
curl_setopt($ch, CURLOPT_SSLCERT,'cert.embedapp.20191004.pem');