file_get_contents(): SSL operation failed with code 1. And more

匿名 (未验证) 提交于 2019-12-03 02:09:01

问题:

I’ve been trying to access this particular REST service from a PHP page I’ve created on our server. I narrowed the problem down to these two lines. So my PHP page looks like this:

<?php $response = file_get_contents("https://maps.co.weber.ut.us/arcgis/rest/services/SDE_composite_locator/GeocodeServer/findAddressCandidates?Street=&SingleLine=3042+N+1050+W&outFields=*&outSR=102100&searchExtent=&f=json");  echo $response; ?> 

The page dies on line 2 with the following errors:

  • Warning: file_get_contents(): SSL operation failed with code 1. OpenSSL Error messages: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed in ...php on line 2
    • Warning: file_get_contents(): Failed to enable crypto in ...php on line 2
    • Warning: file_get_contents(https://maps.co.weber.ut.us/arcgis/rest/services/SDE_composite_locator/GeocodeServer/findAddressCandidates?Street=&SingleLine=3042+N+1050+W&outFields=*&outSR=102100&searchExtent=&f=json): failed to open stream: operation failed in ...php on line 2

We’re using a Gentoo server. We recently upgraded to PHP version 5.6. It was after the upgrade when this problem appeared.

I found when I replace the REST service with an address like https://www.google.com; my page works just fine.

In an earlier attempt I set “verify_peer”=>false, and passed that in as an argument to file_get_contents, as described here: file_get_contents ignoring verify_peer=>false? But like the writer noted; it made no difference.

I’ve asked one of our server administrators if these lines in our php.ini file exist:

  • extension=php_openssl.dll
  • allow_url_fopen = On

He told me that since we’re on Gentoo, openssl is compiled when we build; and it’s not set in the php.ini file.

I also confirmed that allow_url_fopen is working. Due to the specialized nature of this problem; I’m not finding a lot of information for help. Have any of you come across something like this? Thanks.

回答1:

This was an enormously helpful link to find:

http://php.net/manual/en/migration56.openssl.php

An official document describing the changes made to open ssl in PHP 5.6 From here I learned of one more parameter I should have set to false: "verify_peer_name"=>false

So my working code looks like this:

<?php $arrContextOptions=array(     "ssl"=>array(         "verify_peer"=>false,         "verify_peer_name"=>false,     ), );    $response = file_get_contents("https://maps.co.weber.ut.us/arcgis/rest/services/SDE_composite_locator/GeocodeServer/findAddressCandidates?Street=&SingleLine=3042+N+1050+W&outFields=*&outSR=102100&searchExtent=&f=json", false, stream_context_create($arrContextOptions));  echo $response; ?> 


回答2:

You shouldn't just turn off verification. Rather you should download a certificate bundle, perhaps the curl bundle will do?

Then you just need to put it on your web server, giving the user that runs php permission to read the file. Then this code should work for you:

$arrContextOptions=array(     "ssl"=>array(         "cafile" => "/path/to/bundle/cacert.pem",         "verify_peer"=> true,         "verify_peer_name"=> true,     ), );  $response = file_get_contents("https://maps.co.weber.ut.us/arcgis/rest/services/SDE_composite_locator/GeocodeServer/findAddressCandidates?Street=&SingleLine=3042+N+1050+W&outFields=*&outSR=102100&searchExtent=&f=json", false, stream_context_create($arrContextOptions)); 

Hopefully, the root certificate of the site you are trying to access is in the curl bundle. If it isn't, this still won't work until you get the root certificate of the site and put it into your certificate file.



回答3:

I fixed this by making sure that that OpenSSL was installed on my machine and then adding this to my php.ini:

openssl.cafile=/usr/local/etc/openssl/cert.pem 


回答4:

If your PHP version is 5, try installing cURL by typing the following command in the terminal:

sudo apt-get install php5-curl 


回答5:

You can get around this problem by writing a custom function that uses curl, as in:

function file_get_contents_curl( $url ) {    $ch = curl_init();    curl_setopt( $ch, CURLOPT_AUTOREFERER, TRUE );   curl_setopt( $ch, CURLOPT_HEADER, 0 );   curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );   curl_setopt( $ch, CURLOPT_URL, $url );   curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, TRUE );    $data = curl_exec( $ch );   curl_close( $ch );    return $data;  } 

Then just use file_get_contents_curl instead of file_get_contents whenever you're calling a url that begins with https.



回答6:

You basically have to set the environment variable SSL_CERT_FILE to the path of the PEM file of the ssl-certificate downloaded from the following link : http://curl.haxx.se/ca/cacert.pem.

It took me a lot of time to figure this out.



回答7:

Just wanted to add to this since I ran into the same problem and nothing I could find anywhere would work (e.g downloading the cacert.pem file, setting cafile in php.ini etc.)

If you are using NGINX and your SSL certificate comes with an "intermediate certificate", you need to combine the intermediate cert file with your main "mydomain.com.crt" file and it should work. Apache has a setting specific for intermediate certs, but NGINX does not so it must be within same file as your regular cert.



回答8:

Reason for this error is that PHP does not have a list of trusted certificate authorities.

PHP 5.6 and later try to load the CAs trusted by the system automatically. Issues with that can be fixed. See http://php.net/manual/en/migration56.openssl.php for more information.

PHP 5.5 and earlier are really hard to setup correctly since you manually have to specify the CA bundle in each request context, a thing you do not want to sprinkle around your code. So I decided for my code that for PHP versions < 5.6, SSL verification simply gets disabled:

$req = new HTTP_Request2($url); if (version_compare(PHP_VERSION, '5.6.0', '<')) {     //correct ssl validation on php 5.5 is a pain, so disable     $req->setConfig('ssl_verify_host', false);     $req->setConfig('ssl_verify_peer', false); } 


回答9:

Had the same ssl-problem on my developer machine (php 7, xampp on windows) with a self signed certificate trying to fopen a "https://localhost/..."-file. Obviously the root-certificate-assembly (cacert.pem) didn't work. I just copied manually the code from the apache server.crt-File in the downloaded cacert.pem and did the openssl.cafile=path/to/cacert.pem entry in php.ini



回答10:

Regarding errors similar to

[11-May-2017 19:19:13 America/Chicago] PHP Warning: file_get_contents(): SSL operation failed with code 1. OpenSSL Error messages: error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed

Have you checked the permissions of the cert and directories referenced by openssl?

You can do this

var_dump(openssl_get_cert_locations()); 

To get something similar to this

array(8) {   ["default_cert_file"]=>   string(21) "/usr/lib/ssl/cert.pem"   ["default_cert_file_env"]=>   string(13) "SSL_CERT_FILE"   ["default_cert_dir"]=>   string(18) "/usr/lib/ssl/certs"   ["default_cert_dir_env"]=>   string(12) "SSL_CERT_DIR"   ["default_private_dir"]=>   string(20) "/usr/lib/ssl/private"   ["default_default_cert_area"]=>   string(12) "/usr/lib/ssl"   ["ini_cafile"]=>   string(0) ""   ["ini_capath"]=>   string(0) "" } 

This issue frustrated me for a while, until I realized that my "certs" folder had 700 permissions, when it should have had 755 permissions. Remember, this is not the folder for keys but certificates. I recommend reading this this link on ssl permissions.

Once I did

chmod 755 certs 

The problem was fixed, at least for me anyway.



回答11:

Had the same error with PHP 7 on XAMPP and OSX.

The above mentioned answer in https://stackoverflow.com/ is good, but it did not completely solve the problem for me. I had to provide the complete certificate chain to make file_get_contents() work again. That's how I did it:

Get root / intermediate certificate

First of all I had to figure out what's the root and the intermediate certificate.

The most convenient way is maybe an online cert-tool like the ssl-shopper

There I found three certificates, one server-certificate and two chain-certificates (one is the root, the other one apparantly the intermediate).

All I need to do is just search the internet for both of them. In my case, this is the root:

thawte DV SSL SHA256 CA

And it leads to his url thawte.com. So I just put this cert into a textfile and did the same for the intermediate. Done.

Get the host certificate

Next thing I had to to is to download my server cert. On Linux or OS X it can be done with openssl:

openssl s_client -showcerts -connect whatsyoururl.de:443 </dev/null 2>/dev/null|openssl x509 -outform PEM > /tmp/whatsyoururl.de.cert 

Now bring them all together

Now just merge all of them into one file. (Maybe it's good to just put them into one folder, I just merged them into one file). You can do it like this:

cat /tmp/thawteRoot.crt > /tmp/chain.crt cat /tmp/thawteIntermediate.crt >> /tmp/chain.crt cat /tmp/tmp/whatsyoururl.de.cert >> /tmp/chain.crt 

tell PHP where to find the chain

There is this handy function openssl_get_cert_locations() that'll tell you, where PHP is looking for cert files. And there is this parameter, that will tell file_get_contents() where to look for cert files. Maybe both ways will work. I preferred the parameter way. (Compared to the solution mentioned above).

So this is now my PHP-Code

$arrContextOptions=array(     "ssl"=>array(         "cafile" => "/Applications/XAMPP/xamppfiles/share/openssl/certs/chain.pem",         "verify_peer"=> true,         "verify_peer_name"=> true,     ), );  $response = file_get_contents($myHttpsURL, 0, stream_context_create($arrContextOptions)); 

That's all. file_get_contents() is working again. Without CURL and hopefully without security flaws.



回答12:

I had the same issue for another secure page when using wget or file_get_contents. A lot of research (including some of the responses on this question) resulted in a simple solution - installing Curl and PHP-Curl - If I've understood correctly, Curl has the Root CA for Comodo which resolved the issue

Install Curl and PHP-Curl addon, then restart Apache

sudo apt-get install curl sudo apt-get install php-curl sudo /etc/init.d/apache2 reload 

All now working.



回答13:

After falling victim to this problem on centOS after updating php to php5.6 I found a solution that worked for me.

Get the correct directory for your certs to be placed by default with this

php -r 'print_r(openssl_get_cert_locations());' | grep '\[default_cert_file\]' | awk '{print $3}' 

Then use this to get the cert and put it in the default location found from the code above

wget http://curl.haxx.se/ca/cacert.pem -O <default location> 


回答14:

following below steps will fix this issue,

  1. Download the CA Certificate from this link: https://curl.haxx.se/ca/cacert.pem
  2. Find and open php.ini
  3. Look for curl.cainfo and paste the absolute path where you have download the Certificate. curl.cainfo ="C:\wamp\htdocs\cert\cacert.pem"
  4. Restart WAMP/XAMPP (apache server).
  5. It works!

hope that helps !!



易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!