我一直试图从我在服务器上创建的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行结束,出现以下错误:

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

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

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

在前面的尝试中,我设置“verify_peer”=>false,并将其作为参数传递给file_get_contents,如这里所述:file_get_contents忽略verify_peer=>false?但正如作者所指出的;这没什么区别。

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

扩展= php_openssl.dll allow_url_fopen = On

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

我还确认allow_url_fopen正在工作。由于这个问题的专门性;我找不到很多有用的信息。你们有人遇到过这样的东西吗?谢谢。


当前回答

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

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

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

其他回答

你可以通过编写一个使用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。

你不应该只是关闭验证。你应该下载一个证书包,也许curl包可以?

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

$arrContextOptions= [
    'ssl' => [
        '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包中。如果不是,在获得站点的根证书并将其放入证书文件之前,这仍然不能工作。

首先,您需要在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>
...

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

在默认情况下,使用此命令获取放置证书的正确目录

php -r "print_r(openssl_get_cert_locations()['default_cert_file']);"

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

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

以下步骤将修复此问题,

从此链接下载CA证书:https://curl.haxx.se/ca/cacert.pem 找到并打开php.ini 注意卷发。然后粘贴下载证书的绝对路径。旋度。cainfo = " C: \ wamp \根\ cert \ cacert.pem” 重启WAMP/XAMPP (apache服务器)。 它的工作原理!

希望有帮助!!