首页 文章

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

提问于
浏览
132

我一直在尝试从我在服务器上创建的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():无法启用加密 . 第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版 . 升级后出现此问题 .

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

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

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

  • extension = php_openssl.dll

  • allow_url_fopen =开

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

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

15 回答

  • 9

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

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

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

  • 7

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

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

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

  • 121

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

    sudo apt-get install php5-curl
    
  • 3

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

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

  • 0

    以下步骤将解决此问题,

    • 从以下链接下载CA证书:https://curl.haxx.se/ca/cacert.pem

    • 查找并打开php.ini

    • 查找 curl.cainfo 并将 absolute path 粘贴到您下载证书的位置 . curl.cainfo ="C:\wamp\htdocs\cert\cacert.pem"

    • 重启WAMP / XAMPP(apache服务器) .

    • 它有效!

    希望有所帮助!!

  • 6

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

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

  • 224

    此错误的原因是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);
    }
    
  • 1

    在我的开发人员机器(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条目

  • 2

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

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

    Get root / intermediate certificate

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

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

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

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

    thawte DV SSL SHA256 CA

    它导致他的网址thawte.com . 所以我只是把这个证书放到一个文本文件中,并为中间文件做了同样的事情 . 完成 .

    Get the host certificate

    接下来我必须下载我的服务器证书 . 在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
    

    Now bring them all together

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

    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

    有一个方便的函数openssl_get_cert_locations(),它会告诉你PHP在哪里寻找cert文件 . 并且有这个参数,它将告诉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,希望没有安全漏洞 .

  • 9

    在将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>
    
  • 24

    关于类似的错误

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

    这个问题让我感到沮丧,直到我意识到我的"certs"文件夹有700个权限,当它应该拥有755个权限时 . 请记住,这不是密钥的文件夹,而是证书 . 我建议读这个this link on ssl permissions.

    我曾经做过

    chmod 755 certs
    

    问题是固定的,至少对我来说是这样 .

  • 4

    使用 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
    

    现在都在工作 .

  • 3

    为我工作,我使用的是PHP 5.6 . openssl扩展应该启用,并在调用google map api verify_peer make 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; ?>
    

相关问题