我一直在尝试从我在服务器上创建的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():无法在... php上启用加密 第2行
- 警告: 的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文件中的这些行:
他告诉我,因为我们在Gentoo上,所以我们在构建时会编译openssl;并且它没有在php.ini文件中设置。
我也确认allow_url_fopen
正在运作。由于这个问题的专业性;我没有找到很多帮助信息。有没有人遇到过这样的事情?谢谢。
答案 0 :(得分:264)
这是一个非常有用的链接:
http://php.net/manual/en/migration56.openssl.php
一份官方文档,描述了在PHP 5.6中打开ssl所做的更改 从这里我学到了另一个我应该设置为false的参数:&#34; verify_peer_name&#34; =&gt; 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; ?>
答案 1 :(得分:131)
您不应该只关闭验证。相反,您应该下载证书包,也许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包中。如果不是,则在获得站点的根证书并将其放入证书文件之前,这仍然无效。
答案 2 :(得分:29)
我通过确保在我的机器上安装了OpenSSL然后将其添加到我的php.ini来修复此问题:
openssl.cafile=/usr/local/etc/openssl/cert.pem
答案 3 :(得分:13)
您可以通过编写使用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
。
答案 4 :(得分:11)
如果您的PHP版本是5,请尝试通过在终端中键入以下命令来安装cURL:
sudo apt-get install php5-curl
答案 5 :(得分:7)
您基本上必须将环境变量SSL_CERT_FILE设置为从以下链接下载的ssl-certificate的PEM文件的路径:http://curl.haxx.se/ca/cacert.pem。
我花了很多时间来解决这个问题。
答案 6 :(得分:6)
以下步骤将解决此问题,
curl.cainfo
并粘贴绝对路径,即可下载证书。 curl.cainfo ="C:\wamp\htdocs\cert\cacert.pem"
答案 7 :(得分:5)
只是想加入这个,因为我遇到了同样的问题,我找不到任何地方都可以工作(例如下载cacert.pem文件,在php.ini中设置cafile等。)
如果您使用的是NGINX并且您的SSL证书附带了“中间证书”,则需要将中间证书文件与主“mydomain.com.crt”文件合并,它应该可以正常工作。 Apache具有针对中间证书的特定设置,但NGINX不具有此设置,因此它必须与常规证书位于同一文件中。
答案 8 :(得分:5)
首先您需要在 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>
...
答案 9 :(得分:3)
此错误的原因是PHP没有受信任的证书颁发机构列表。
PHP 5.6及更高版本尝试自动加载系统信任的CA.问题可以解决。有关详细信息,请参阅http://php.net/manual/en/migration56.openssl.php。
PHP 5.5及更早版本确实难以正确设置,因为您手动必须在每个请求上下文中指定CA捆绑包,这是您不希望在代码周围散布的内容。 所以我为我的代码决定了PHP版本&lt; 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);
}
答案 10 :(得分:3)
我的开发者机器(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条目
答案 11 :(得分:3)
在XAMPP和OSX上与PHP 7有同样的错误。
https://stackoverflow.com/中的上述答案很好,但它并没有完全解决我的问题。我必须提供完整的证书链才能使file_get_contents()再次运行。这就是我如何做到的:
获取root /中间证书
首先,我必须弄清楚根和中间证书是什么。
最方便的方法可能是像ssl-shopper
这样的在线证书工具在那里我找到了三个证书,一个服务器证书和两个链证书(一个是根,另一个是中间人)。
我需要做的只是在互联网上搜索它们。就我而言,这是根:
解冻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
现在将它们全部集中在一起
现在只需将它们合并到一个文件中即可。 (将它们放入一个文件夹可能会很好,我只是将它们合并到一个文件中)。你可以这样做:
cat /tmp/thawteRoot.crt > /tmp/chain.crt
cat /tmp/thawteIntermediate.crt >> /tmp/chain.crt
cat /tmp/tmp/whatsyoururl.de.cert >> /tmp/chain.crt
告诉PHP在哪里找到链
这个方便的函数openssl_get_cert_locations()告诉你,PHP在哪里寻找证书文件。并且有这个参数,它将告诉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,希望没有安全漏洞。
答案 12 :(得分:3)
为我工作,我正在使用PHP 5.6。应该启用openssl扩展名,并在调用google map api时verify_peer设置为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; ?>
答案 13 :(得分:2)
在将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>
答案 14 :(得分:1)
关于与
类似的错误[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) ""
}
这个问题让我感到沮丧,直到我意识到我的&#34;证书&#34;文件夹有700个权限,当它应该有755权限。请记住,这不是密钥的文件夹,而是证书。我建议您阅读此this link on ssl permissions.
我做过
chmod 755 certs
问题已得到解决,至少对我来说是这样。
答案 15 :(得分:0)
另一种尝试是重新安装here的ca-certificates
。
# yum reinstall ca-certificates
...
# update-ca-trust force-enable
# update-ca-trust extract
另一件事是尝试按照here所述明确允许该站点的证书(特别是如果该站点是您自己的服务器并且您已经拥有.pem的话)。
# cp /your/site.pem /etc/pki/ca-trust/source/anchors/
# update-ca-trust extract
在CentOS 6上升级到PHP 5.6后,我尝试访问服务器本身时遇到了一个确切的SO错误,该服务器本身具有cheapsslsecurity证书,可能需要对其进行更新,但是我安装了letencrypt证书并通过以下两个步骤上面的技巧。我不知道为什么第二步是必要的。
有用的命令
查看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
答案 16 :(得分:0)
使用wget
或file_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
现在都在工作。
答案 17 :(得分:0)
对我来说,我在 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,从而产生了另一个证书包。此包需要用于验证“本地主机”URL。为了提醒自己那个包在哪里,我打开了 httpd-ssl.conf 并找到了如下一行:
SSLCertificateFile "conf/ssl.crt/server.crt"
(完整路径为 C:\Users[USER]\xampp\apache\conf\ssl.crt\server.crt)
为了使 localhost 和外部 URL 同时工作,我将本地主机“server.crt”文件的内容复制到 Mozilla 的包“curl-ca-bundle.crt”中。
.
.
.
m7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg==
-----END CERTIFICATE-----
Localhost--I manually added this
================================
-----BEGIN CERTIFICATE-----
MIIDGDCCAgCgAwIBAgIQIH+mTLNOSKlD8KMZwr5P3TANBgkqhkiG9w0BAQsFADAU
...
那时我可以将 file_get_contents() 与 localhost URL 和外部 URL 一起使用,无需额外配置。
file_get_contents("https://localhost/...");
file_get_contents("https://google.com");