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

Joe*_*Joe 163 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; ?>
Run Code Online (Sandbox Code Playgroud)

该页面在第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操作失败

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

我发现,当我一个地址替换REST服务一样https://www.google.com; 我的页面工作正常.

在我之前的一次尝试中,我将“verify_peer”=>false其作为参数传递给file_get_contents,如下所述: file_get_contents忽略verify_peer => false? 但就像作者所指出的那样; 它没有任何区别.

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

  • 延长= php_openssl.dll
  • allow_url_fopen =开

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

我也证实这allow_url_fopen是有效的.由于这个问题的专业性; 我没有找到很多帮助信息.有没有人遇到过这样的事情?谢谢.

Joe*_*Joe 294

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

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; ?>
Run Code Online (Sandbox Code Playgroud)

  • 这打破了SSL认证,是一个安全漏洞 (117认同)
  • 因为当我尝试这样做时总是来这里,这里是容易复制和粘贴的代码:`file_get_contents($ url,false,stream_context_create(array('ssl'=> array('verify_peer'=> false,'verify_peer_name' => false))));` (10认同)
  • 正如@ hypery2k指出的,你不应该只是禁用验证.请参阅我的答案,了解不会破坏使用ssl目的的替代解决方案. (7认同)
  • 如果您从针对api的本地环境进行测试,这可能会令人沮丧.在这种情况下,我通常会核实验证. (4认同)
  • 这真的不应该这样做.你应该实际修复它,而不是侧面解决问题.从@ elitechief21查看更好的解决方案. (3认同)
  • 为我工作,但我知道这会破坏 SSL 认证并且是一个安全漏洞 (2认同)

eli*_*f21 145

你不应该只关闭验证.相反,你应该下载一个证书包,也许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));
Run Code Online (Sandbox Code Playgroud)

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

  • 还有一个有用的函数`stream_context_set_default`可以使用,所以你不必每次都把它传递给file_get_contents (4认同)
  • 从安全角度来看:除了使用 cafile 流上下文选项之外,在 ciphers 流上下文选项中定义允许的密码并禁止那些易受攻击的 SSL 版本可能非常重要。另外,建议将流上下文选项disable_compression设置为true以减轻犯罪攻击向量。 (2认同)

and*_*lin 34

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

openssl.cafile=/usr/local/etc/openssl/cert.pem
Run Code Online (Sandbox Code Playgroud)

  • 我在IIS上使用了与PHP 7相同的方法,下载了`cert.pem`文件并设置了这样的`php.ini`,它起作用了:`openssl.cafile = D:\ Tools\GnuWin32\bin\cacert. pem` (2认同)
  • 我从 https://curl.haxx.se/docs/caextract.html 下载了 PEM 文件 - 在具有特定 gstatic.com URL 的 Windows 上为我解决了问题。 (2认同)

Ben*_*val 15

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

}
Run Code Online (Sandbox Code Playgroud)

然后只需使用file_get_contents_curl而不是file_get_contents每当您调用以https开头的网址时.


ARU*_* NV 11

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

sudo apt-get install php5-curl
Run Code Online (Sandbox Code Playgroud)

  • 这与`cURL`完全无关. (7认同)
  • 安装php curl应该是正确的答案!对于我的Mac系统,我使用的是端口,命令是:`sudo port install php70-curl` (2认同)

Ban*_*dre 8

<?php
    $stream_context = stream_context_create([
        "ssl" => [
            "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);
    
    echo $response;
?>
Run Code Online (Sandbox Code Playgroud)

刚刚测试了 PHP 7.2,运行良好。

编辑:也在 PHP 7.1 上进行了测试和工作


Ksh*_*tal 7

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

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


n.r*_*.r. 6

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

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

获取根/中级证书

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

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

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

我所需要做的就是在互联网上搜索他们两个。就我而言,这是根源:

thawte 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
Run Code Online (Sandbox Code Playgroud)

现在把它们全部放在一起

现在只需将它们全部合并到一个文件中即可。(也许最好将它们放入一个文件夹中,我只是将它们合并到一个文件中)。你可以这样做:

cat /tmp/thawteRoot.crt > /tmp/chain.crt
cat /tmp/thawteIntermediate.crt >> /tmp/chain.crt
cat /tmp/tmp/whatsyoururl.de.cert >> /tmp/chain.crt
Run Code Online (Sandbox Code Playgroud)

告诉 PHP 在哪里找到链

有一个方便的函数 openssl_get_cert_locations() 可以告诉您 PHP 在哪里寻找证书文件。还有这个参数,它将告诉 file_get_contents() 在哪里查找证书文件。也许两种方法都会起作用。我更喜欢参数方式。(与上面提到的解决方案相比)。

这就是我的 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));
Run Code Online (Sandbox Code Playgroud)

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


sha*_*e93 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

为我工作,我正在使用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;
?>
Run Code Online (Sandbox Code Playgroud)


Mar*_*tin 6

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

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;
}
Run Code Online (Sandbox Code Playgroud)

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

例子:

echo file_get_contents_ssl("https://www.example.com/");
Run Code Online (Sandbox Code Playgroud)

输出:

<!doctype html>
<html>
<head>
    <title>Example Domain</title>
...
Run Code Online (Sandbox Code Playgroud)

  • 当然可以,但这就像如果你家门上的锁坏了,你只需拆下整个锁就可以修复它。 (2认同)

小智 5

由于我遇到了同样的问题,我只是想补充一下,在任何地方都找不到任何东西(例如,下载cacert.pem文件,在php.ini中设置cafile等)。

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


cwe*_*ske 5

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

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

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);
}
Run Code Online (Sandbox Code Playgroud)


Edw*_*amo 5

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

使用此获取默认情况下要放置的证书的正确目录

php -r 'print_r(openssl_get_cert_locations()["default_cert_file"]);'
Run Code Online (Sandbox Code Playgroud)

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

wget http://curl.haxx.se/ca/cacert.pem -O <default location>
Run Code Online (Sandbox Code Playgroud)