file_get_contents():SSL操作失败,代码为1.还有更多

时间:2014-10-01 19:04:50

标签: php rest ssl file-get-contents

我一直在尝试从我在服务器上创建的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:证书验证失败   ...第2行的PHP      
        
    • 警告:file_get_contents():无法在... php上启用加密   第2行
    •   
    • 警告:   的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):   无法打开流:在第2行的php中操作失败
    •   
  •   

我们正在使用Gentoo服务器。我们最近升级到PHP 5.6版。升级后出现此问题。

我在用https://www.google.com这样的地址替换REST服务时发现了我的页面工作正常。

在之前的尝试中,我设置了“verify_peer”=>false,并将其作为参数传递给file_get_contents,如下所述:file_get_contents ignoring verify_peer=>false?但是就像作者所说的那样;它没有任何区别。

我问过我们的服务器管理员是否存在php.ini文件中的这些行:

  • 延长= php_openssl.dll
  • allow_url_fopen =开启

他告诉我,因为我们在Gentoo上,所以我们在构建时会编译openssl;并且它没有在php.ini文件中设置。

我也确认allow_url_fopen正在运作。由于这个问题的专业性;我没有找到很多帮助信息。有没有人遇到过这样的事情?谢谢。

18 个答案:

答案 0 :(得分:264)

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

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

一份官方文档,描述了在PHP 5.6中打开ssl所做的更改 从这里我学到了另一个我应该设置为false的参数:&#34; verify_peer_name&#34; =&gt; 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; ?>

答案 1 :(得分:131)

您不应该只关闭验证。相反,您应该下载证书包,也许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包中。如果不是,则在获得站点的根证书并将其放入证书文件之前,这仍然无效。

答案 2 :(得分:29)

我通过确保在我的机器上安装了OpenSSL然后将其添加到我的php.ini来修复此问题:

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

答案 3 :(得分:13)

您可以通过编写使用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开头的网址,只需使用file_get_contents_curl代替file_get_contents

答案 4 :(得分:11)

如果您的PHP版本是5,请尝试通过在终端中键入以下命令来安装cURL:

sudo apt-get install php5-curl

答案 5 :(得分:7)

您基本上必须将环境变量SSL_CERT_FILE设置为从以下链接下载的ssl-certificate的PEM文件的路径:http://curl.haxx.se/ca/cacert.pem

我花了很多时间来解决这个问题。

答案 6 :(得分:6)

以下步骤将解决此问题,

  1. 从以下链接下载CA证书:https://curl.haxx.se/ca/cacert.pem
  2. 查找并打开php.ini
  3. 查找curl.cainfo并粘贴绝对路径,即可下载证书。 curl.cainfo ="C:\wamp\htdocs\cert\cacert.pem"
  4. 重启WAMP / XAMPP(apache服务器)。
  5. 有效!
  6. 希望有所帮助!!

答案 7 :(得分:5)

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

如果您使用的是NGINX并且您的SSL证书附带了“中间证书”,则需要将中间证书文件与主“mydomain.com.crt”文件合并,它应该可以正常工作。 Apache具有针对中间证书的特定设置,但NGINX不具有此设置,因此它必须与常规证书位于同一文件中。

答案 8 :(得分:5)

首先您需要在 PHP 中启用 curl 扩展。然后就可以使用这个函数了:

function file_get_contents_ssl($url) {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($ch, CURLOPT_HEADER, false);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_REFERER, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3000); // 3 sec.
    curl_setopt($ch, CURLOPT_TIMEOUT, 10000); // 10 sec.
    $result = curl_exec($ch);
    curl_close($ch);
    return $result;
}

它的工作原理类似于函数 file_get_contents(..)

示例:

echo file_get_contents_ssl("https://www.example.com/");

输出:

<!doctype html>
<html>
<head>
    <title>Example Domain</title>
...

答案 9 :(得分:3)

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

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

PHP 5.5及更早版本确实难以正确设置,因为您手动必须在每个请求上下文中指定CA捆绑包,这是您不希望在代码周围散布的内容。 所以我为我的代码决定了PHP版本&lt; 5.6,SSL验证只是被禁用:

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

答案 10 :(得分:3)

我的开发者机器(php 7,Windows上的xampp)上有一个自签名证书尝试打开“https://localhost/ ...”文件的同一个ssl问题。显然,root-certificate-assembly(cacert.pem)不起作用。 我只是手动复制了下载的cacert.pem中的apache server.crt-File中的代码,并在php.ini中执行了openssl.cafile = path / to / cacert.pem条目

答案 11 :(得分:3)

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

https://stackoverflow.com/中的上述答案很好,但它并没有完全解决我的问题。我必须提供完整的证书链才能使file_get_contents()再次运行。这就是我如何做到的:

获取root /中间证书

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

最方便的方法可能是像ssl-shopper

这样的在线证书工具

在那里我找到了三个证书,一个服务器证书和两个链证书(一个是根,另一个是中间人)。

我需要做的只是在互联网上搜索它们。就我而言,这是根:

解冻DV SSL SHA256 CA

它会导致他的网址thawte.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在哪里找到链

这个方便的函数openssl_get_cert_locations()告诉你,PHP在哪里寻找证书文件。并且有这个参数,它将告诉file_get_contents()在哪里查找cert文件。也许两种方式都可行。我更喜欢参数方式。 (与上述解决方案相比)。

所以现在这是我的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,希望没有安全漏洞。

答案 12 :(得分:3)

为我工作,我正在使用PHP 5.6。应该启用openssl扩展名,并在调用google map api时verify_peer设置为false 下面的代码对我有用。

<?php
    $arrContextOptions=array(
        "ssl"=>array(
        "verify_peer"=>false,
        "verify_peer_name"=>false,
    ),
 );  

 $response = file_get_contents("https://maps.googleapis.com/maps/api/geocode     /json?latlng=" . $latitude . "," . $longitude . "&sensor=false&key=" . Yii::$app->params['GOOGLE_API_KEY'], false, stream_context_create($arrContextOptions));

echo $response; ?>

答案 13 :(得分:2)

在将php更新到php5.6之后,在centOS上成为这个问题的受害者后,我找到了一个对我有用的解决方案。

默认情况下,使用此

获取正确的证书目录
php -r 'print_r(openssl_get_cert_locations());' | grep '\[default_cert_file\]' | awk '{print $3}'

然后使用它获取证书并将其放在上面代码中找到的默认位置

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

答案 14 :(得分:1)

关于与

类似的错误

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

您是否检查过openssl引用的证书和目录的权限?

你可以这样做

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

这个问题让我感到沮丧,直到我意识到我的&#34;证书&#34;文件夹有700个权限,当它应该有755权限。请记住,这不是密钥的文件夹,而是证书。我建议您阅读此this link on ssl permissions.

我做过

chmod 755 certs

问题已得到解决,至少对我来说是这样。

答案 15 :(得分:0)

另一种尝试是重新安装hereca-certificates

# yum reinstall ca-certificates
...
# update-ca-trust force-enable 
# update-ca-trust extract

另一件事是尝试按照here所述明确允许该站点的证书(特别是如果该站点是您自己的服务器并且您已经拥有.pem的话)。

# cp /your/site.pem /etc/pki/ca-trust/source/anchors/
# update-ca-trust extract

在CentOS 6上升级到PHP 5.6后,我尝试访问服务器本身时遇到了一个确切的SO错误,该服务器本身具有cheapsslsecurity证书,可能需要对其进行更新,但是我安装了letencrypt证书并通过以下两个步骤上面的技巧。我不知道为什么第二步是必要的。


有用的命令

查看openssl版本:

# openssl version
OpenSSL 1.0.1e-fips 11 Feb 2013

查看PHP cli ssl当前设置:

# php -i | grep ssl
openssl
Openssl default config => /etc/pki/tls/openssl.cnf
openssl.cafile => no value => no value
openssl.capath => no value => no value

答案 16 :(得分:0)

使用wgetfile_get_contents时,我在另一个安全页面上遇到了同样的问题。很多研究(包括对这个问题的一些回答)产生了一个简单的解决方案 - 安装Curl和PHP-Curl - 如果我已经正确理解,Curl有Comodo的根CA解决了这个问题

安装Curl和PHP-Curl插件,然后重启Apache

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

现在都在工作。

答案 17 :(得分:0)

对我来说,我在 Windows 10 机器(本地主机)上运行 XAMPP,最近升级到 PHP 8。我试图通过 file_get_contents() 打开本地主机 HTTPS 链接。

在我的 php.ini 文件中,有一行是这样写的:

openssl.cafile="C:\Users\[USER]\xampp\apache\bin\curl-ca-bundle.crt"

这是用于验证“外部”URL 的证书包,正如某些人所讨论的那样,它是来自 Mozilla 的包。我不知道 XAMPP 是那样来的,还是我过去设置的。

在某些时候,我在我的本地主机上设置了 HTTPS,从而产生了另一个证书包。此包需要用于验证“本地主机”URL。为了提醒自己那个包在哪里,我打开了 httpd-ssl.conf 并找到了如下一行:

SSLCertificateFile "conf/ssl.crt/server.crt" 

(完整路径为 C:\Users[USER]\xampp\apache\conf\ssl.crt\server.crt)

为了使 localhost 和外部 URL 同时工作,我将本地主机“server.crt”文件的内容复制到 Mozilla 的包“curl-ca-bundle.crt”中。

.
.
.
m7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg==
-----END CERTIFICATE-----

Localhost--I manually added this
================================
-----BEGIN CERTIFICATE-----
MIIDGDCCAgCgAwIBAgIQIH+mTLNOSKlD8KMZwr5P3TANBgkqhkiG9w0BAQsFADAU
...

那时我可以将 file_get_contents() 与 localhost URL 和外部 URL 一起使用,无需额外配置。

file_get_contents("https://localhost/...");
file_get_contents("https://google.com");