php file_get_contents():SSL 操作失败,代码为 1,无法启用加密

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26148701/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 18:11:41  来源:igfitidea点击:

file_get_contents(): SSL operation failed with code 1, Failed to enable crypto

phprestsslfile-get-contents

提问by Joe

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 页面访问这个特定的 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; ?>

The page dies on line 2 with the following errors:

该页面在第 2 行终止,并出现以下错误:

  • 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
  • 警告:file_get_contents():SSL 操作失败,代码为 1。OpenSSL 错误消息:错误:14090086:SSL 例程:SSL3_GET_SERVER_CERTIFICATE:第 2 行...php 中的证书验证失败
    • 警告:file_get_contents():无法在第 2 行的 ...php 中启用加密
    • 警告: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 中的操作失败

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

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

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

我发现当我用类似的地址替换 REST 服务时https://www.google.com;我的页面工作得很好。

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.

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

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

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

  • extension=php_openssl.dll
  • allow_url_fopen = On
  • 扩展=php_openssl.dll
  • allow_url_fopen = 开

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.

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

I also confirmed that allow_url_fopenis 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.

我也确认这allow_url_fopen是有效的。由于这个问题的特殊性;我没有找到很多信息来寻求帮助。你们中有人遇到过这样的事情吗?谢谢。

回答by Joe

This was an enormously helpful link to find:

这是一个非常有用的链接,可以找到:

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

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

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

Note:This has verysignificant security implications. Disabling verification potentially permits a MITM attackerto use an invalid certificate to eavesdrop on the requests. While it may be useful to do this in local development, other approaches should be used in production.

注意:这具有非常重要的安全隐患。禁用验证可能会允许MITM 攻击者使用无效证书来窃听请求。虽然在本地开发中这样做可能很有用,但在生产中应该使用其他方法。

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

回答by elitechief21

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

您不应该只是关闭验证。相反,您应该下载证书包,也许curl包可以吗?

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:

然后你只需要把它放在你的 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));

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.

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

回答by andlin

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

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

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

回答by Ben Shoval

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

您可以通过编写使用 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;

}

Then just use file_get_contents_curlinstead of file_get_contentswhenever you're calling a url that begins with https.

然后只需使用file_get_contents_curl而不是file_get_contents在您调用以 https 开头的 url 时使用。

回答by ARUNBALAN NV

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

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

sudo apt-get install php5-curl

回答by Dipti

Working for me, I am using PHP 5.6. openssl extension should be enabled and while calling google map api verify_peer make false Below code is working for me.

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

<?php
$arrContextOptions=array(
    "ssl"=>array(
         "verify_peer"=>false,
         "verify_peer_name"=>false,
    ),
);  
$url = "https://maps.googleapis.com/maps/api/geocode/json?latlng="
      . $latitude
      . ","
      . $longitude
      . "&sensor=false&key="
      . Yii::$app->params['GOOGLE_API_KEY'];

$data = file_get_contents($url, false, stream_context_create($arrContextOptions));

echo $data;
?>

回答by Kshitij Mittal

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.

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

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

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

回答by shakee93

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.cainfoand paste the absolute pathwhere you have download the Certificate. curl.cainfo ="C:\wamp\htdocs\cert\cacert.pem"
  4. Restart WAMP/XAMPP (apache server).
  5. It works!
  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. 有用!

hope that helps !!

希望有帮助!!

回答by SlickTheNick

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.)

只是想补充一下,因为我遇到了同样的问题,而且我在任何地方都找不到工作(例如下载 cacert.pem 文件,在 php.ini 中设置 cafile 等)

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.

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

回答by cweiske

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

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

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.phpfor more information.

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

PHP 5.5 and earlier are reallyhard 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:

PHP 5.5 及更早版本真的很难正确设置,因为您必须在每个请求上下文中手动指定 CA 包,这是您不想在代码中散布的事情。所以我决定对于 PHP 版本 < 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);
}