file_get_contents():代码1的SSL操作失败

我一直在尝试从我们在服务器上创build的PHP页面访问这个特定的REST服务。 我把这个问题缩小到了这两条线。 所以我的PHP页面如下所示:

<?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; ?> 

该页面在第2行中死亡,出现以下错误:

  • 警告:file_get_contents():SSL操作失败,代码为1. OpenSSL错误消息:错误:14090086:SSL例程:SSL3_GET_SERVER_CERTIFICATE:证书validation失败
    • 警告:file_get_contents():无法在第2行的… php中启用encryption
    • 警告: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 ):未能打开stream:操作失败,在第2行的PHP

我们正在使用一个Gentoo服务器。 我们最近升级到PHP版本5.6。 这个问题出现后就是升级之后。

我发现当我用https://www.google.com这样的地址replaceREST服务时, 我的网页工作得很好。

在之前的尝试中,我设置了“verify_peer”=>false ,并将其作为parameter passing给file_get_contents,如下所述: file_get_contents忽略verify_peer => false? 但是就像作者指出的那样; 它没有任何区别。

我问过我们的一个服务器pipe理员,如果我们的php.ini文件中有这些行:

  • 延长= php_openssl.dll
  • allow_url_fopen = On

他告诉我,既然我们使用Gentoo,openssl是在编译时编译的。 并没有在php.ini文件中设置。

我也确认allow_url_fopen正在工作。 由于这个问题的特殊性, 我没有find大量的帮助信息。 有没有人遇到过这样的事情? 谢谢。

这是一个非常有用的链接,find:

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

描述在PHP 5.6中打开ssl所做的更改的官方文档从这里我学到了另外一个我应该设置为false的参数:“verify_peer_name”=> false

所以我的工作代码如下所示:

 <?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; ?> 

你不应该关掉validation。 相反,你应该下载一个证书包,也许curl包会做?

然后你只需要把它放在你的web服务器上,给运行php权限的用户读取文件。 那么这个代码应该为你工作:

 $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)); 

希望您尝试访问的网站的根证书位于curl包中。 如果不是,直到获得站点的根证书并将其放入您的证书文件,这仍然不起作用。

我解决了这个问题,确保在我的机器上安装了OpenSSL,然后将其添加到我的php.ini中:

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

如果你的PHP版本是5.那么试试这个修复。通过在terminal中input下面的命令来安装curl。
sudo apt-get install php5-curl

你可以通过编写一个使用curl的自定义函数来解决这个问题,如下所示:

 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; } 

然后,只要调用以https开头的url,只需使用file_get_contents_curl而不是file_get_contents

您基本上必须将环境variablesSSL_CERT_FILE设置为从以下链接下载的ssl证书的PEM文件的path: http : //curl.haxx.se/ca/cacert.pem 。

我花了很多时间才弄明白这一点。

只是想添加到这个,因为我遇到了同样的问题,没有什么我可以find任何地方工作(例如下载cacert.pem文件,在php.ini中设置cafile等)

如果您使用的是NGINX,并且您的SSL证书带有“中间证书”,那么您需要将中间证书文件与您的主“mydomain.com.crt”文件结合起来使用。 Apache有一个特定于中级证书的设置,但是NGINX并不是这样,它必须与常规证书在同一个文件中。

在我的开发人员机器上使用自签名证书试图打开“ https:// localhost / …”文件时,出现了相同的ssl问题(php 7,windows上的xampp)。 显然,根证书程序集(cacert.pem)不起作用。 我只是手动复制下载的cacert.pem中的apache server.crt-File中的代码,并在php.ini中执行了openssl.cafile = path / to / cacert.pem条目

此错误的原因是PHP没有可信任的证书颁发机构的列表。

PHP 5.6和更高版本尝试自动加载系统信任的CA. 问题可以修复。 有关更多信息,请参阅http://php.net/manual/en/migration56.openssl.php

PHP 5.5和更早的版本确实很难正确设置,因为您必须手动在每个请求上下文中指定CA bundle,这是您不想在代码中出现的东西。 所以我决定为PHP版本<5.6的代码,SSLvalidation只是被禁用:

 $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); } 

关于类似的错误

[11-May-2017 19:19:13 America / Chicago] PHP警告:file_get_contents():SSL操作失败,代码为1. OpenSSL错误消息:错误:14090086:SSL例程:ssl3_get_server_certificate:证书validation失败

你是否检查过openssl引用的cert和目录的权限?

你可以这样做

 var_dump(openssl_get_cert_locations()); 

为了得到类似的东西

 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) "" } 

这个问题让我感到沮丧,直到我意识到我的“certs”文件夹有700个权限,而且应该有755个权限。 请记住,这不是密钥文件夹,而是证书。 我build议阅读这个链接上的SSL权限。

一旦我做到了

 chmod 755 certs 

问题是固定的,至less对我来说无论如何。

在XAMPP和OSX上与PHP 7有相同的错误。

https://stackoverflow.com/上面提到的答案是好的,但它并没有完全解决我的问题。; 我必须提供完整的证书链才能使file_get_contents()再次工作。 我就这样做了:

获取根/中级证书

首先,我必须弄清楚什么是根证书中间证书。

最方便的方式可能是像ssl-shopper这样的在线证书工具

在那里,我发现了三个证书,一个服务器证书和两个链式证书(一个是根,另一个是中间的)。

我只需要在互联网上search他们两个。 就我而言,这是根源:

解冻DV SSL SHA256 CA

这导致他的urlthawte.com 。 所以我只是把这个证书放到一个文本文件中,并为中间文件做了相同的处理。 完成。

获取主机证书

接下来我必须要下载我的服务器证书。 在Linux或OS X上,可以使用openssl完成:

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

现在把它们放在一起

现在把所有的文件合并成一个文件。 (也许把它们放到一个文件夹中是好的,我只是将它们合并成一个文件)。 你可以这样做:

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

告诉PHP哪里可以find链

有这个方便的函数openssl_get_cert_locations()告诉你,PHP正在寻找证书文件。 还有这个参数,它会告诉file_get_contents()在哪里查找证书文件。 也许这两种方式将工作。 我更喜欢参数的方式。 (与上面提到的解决scheme相比)。

所以这现在是我的PHP代码

 $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)); 

就这样。 file_get_contents()再次工作。 没有CURL,希望没有安全漏洞。