我一直试图从我在服务器上创建的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正在工作。由于这个问题的专门性;我找不到很多有用的信息。你们有人遇到过这样的东西吗?谢谢。
对我来说,我在一台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");
另一件要尝试的事情是重新安装ca-certificate,详见此处。
# yum reinstall ca-certificates
...
# update-ca-trust force-enable
# update-ca-trust extract
另一件要尝试的事情是显式地允许此处所述的一个站点的证书(特别是如果该站点是您自己的服务器,并且您已经可以访问.pem)。
# cp /your/site.pem /etc/pki/ca-trust/source/anchors/
# update-ca-trust extract
我在CentOS 6上升级到PHP 5.6后遇到了这个确切的SO错误,试图访问服务器本身,它有一个cheapsslsecurity证书,可能需要更新,但我安装了一个letsencrypt证书,上面的这两个步骤做到了这一点。我不知道为什么第二步是必要的。
有用的命令
查看openssl版本:
# openssl version
OpenSSL 1.0.1e-fips 11 Feb 2013
查看PHP cli ssl当前设置:
# php -i | grep ssl
openssl
Openssl default config => /etc/pki/tls/openssl.cnf
openssl.cafile => no value => no value
openssl.capath => no value => no value
对我来说,我在一台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");
这是一个非常有用的链接:
http://php.net/manual/en/migration56.openssl.php
一份官方文档,描述了在PHP 5.6中对open ssl所做的更改
从这里我了解到我应该将另一个参数设置为false:“verify_peer_name”=>false
注意:这具有非常重要的安全影响。禁用验证可能会允许MITM攻击者使用无效的证书来窃听请求。虽然在本地开发中这样做可能有用,但在生产中应该使用其他方法。
所以我的工作代码是这样的:
<?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; ?>
你不应该只是关闭验证。你应该下载一个证书包,也许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包中。如果不是,在获得站点的根证书并将其放入证书文件之前,这仍然不能工作。