我一直试图从我在服务器上创建的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更新到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>

其他回答

在我的开发机器(php 7, windows上的xampp)上有相同的ssl问题,使用自签名证书试图打开“https://localhost/…”-文件。显然根证书程序集(cacert.pem)不起作用。 我只是从apache服务器手动复制了代码。crt-File下载的cacert。openssl.cafile=path/to/cacert. Pem,然后执行openssl.cafile=path/to/cacert. Pem。php.ini中的Pem条目

对我来说,我在一台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,导致了另一个证书包。这个包需要用来验证“localhost”url。为了提醒自己这个bundle在哪里,我打开httpd-ssl.conf,找到这样一行:

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

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

为了使本地主机和外部url同时工作,我复制了本地主机“服务器”的内容。将“curl-ca-bundle.crt”文件导入到Mozilla的bundle“curl-ca-bundle.crt”中。

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

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

在这一点上,我可以使用file_get_contents()与本地主机url和外部url,而无需额外配置。

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

$csm = stream_context_create(['ssl' => ['capture_session_meta' => TRUE]]); $ sourceccountry =file_get_contents('https://api.wipmania.com/'.$ip.'?website.com', FALSE, $csm);

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

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

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