我一直在尝试从我在我们的服务器上创建的 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:certificate verify failed in ...php on line 2 警告:file_get_contents(): Failed to enable crypto in ..第 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 文件中是否存在这些行:
扩展=php_openssl.dll
allow_url_fopen = 打开
他告诉我,因为我们在 Gentoo 上,所以我们在构建时会编译 openssl;并且它没有在 php.ini 文件中设置。
我还确认 allow_url_fopen
正在工作。由于这个问题的特殊性;我没有找到很多帮助信息。你们有没有遇到过这样的事情?谢谢。
这是一个非常有用的链接,可以找到:
http://php.net/manual/en/migration56.openssl.php
描述在 PHP 5.6 中打开 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 包可以吗?
然后你只需要把它放在你的网络服务器上,给运行 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 捆绑包中。如果不是,则在您获得站点的根证书并将其放入证书文件之前,这仍然无效。
stream_context_set_default
可以使用,因此您不必每次都将它传递给 file_get_contents
"capture_peer_cert_chain" => true
添加到 $arrContextOptions
。然后对 file_get_contents 的调用还将包括您尝试连接到的主机的证书链(base64 编码)。我相信输出中列出的最后一个证书是根证书,并且该证书必须在您正在使用的证书文件中,才能使其正常工作。请注意,主机或客户端可能存在其他问题导致其失败(即主机证书过期、客户端时间不正确等)
我通过确保在我的机器上安装了 OpenSSL 然后将其添加到我的 php.ini 来解决此问题:
openssl.cafile=/usr/local/etc/openssl/cert.pem
cert.pem
文件并像这样设置 php.ini
,它起作用了:openssl.cafile=D:\Tools\GnuWin32\bin\cacert.pem
您可以通过编写使用 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
。
User Notice: SSL certificate problem: unable to get local issuer certificate
为我工作,我使用的是 PHP 5.6。应该启用 openssl 扩展,并且在调用 google map api verify_peer 时使 false 下面的代码对我有用。
<?php
$arrContextOptions=array(
"ssl"=>array(
"verify_peer"=>false,
"verify_peer_name"=>false,
),
);
$url = "https://maps.googleapis.com/maps/api/geocode/json?latlng="
. $latitude
. ","
. $longitude
. "&sensor=false&key="
. Yii::$app->params['GOOGLE_API_KEY'];
$data = file_get_contents($url, false, stream_context_create($arrContextOptions));
echo $data;
?>
在将 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>
您基本上必须将环境变量 SSL_CERT_FILE 设置为从以下链接下载的 ssl 证书的 PEM 文件的路径:http://curl.haxx.se/ca/cacert.pem。
我花了很多时间才弄清楚这一点。
如果您的 PHP 版本是 5,请尝试通过在终端中键入以下命令来安装 cURL:
sudo apt-get install php5-curl
cURL
完全无关。
sudo port install php70-curl
按照以下步骤将解决此问题,
从此链接下载 CA 证书:https://curl.haxx.se/ca/cacert.pem 查找并打开 php.ini 查找 curl.cainfo 并将绝对路径粘贴到您下载证书的位置。 curl.cainfo ="C:\wamp\htdocs\cert\cacert.pem" 重新启动 WAMP/XAMPP(apache 服务器)。有用!
希望有帮助!
curl.cainfo
对我不起作用,但设置 openssl.cafile=C:\xampp\certs\cacert.pem
有效。
首先,您需要在 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>
...
只是想补充一点,因为我遇到了同样的问题,我在任何地方都找不到任何东西(例如下载 cacert.pem 文件,在 php.ini 中设置 cafile 等)
如果您使用 NGINX 并且您的 SSL 证书带有“中间证书”,您需要将中间证书文件与您的主“mydomain.com.crt”文件结合起来,它应该可以工作。 Apache 具有特定于中间证书的设置,但 NGINX 没有,因此它必须与常规证书位于同一文件中。
此错误的原因是 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);
}
在 XAMPP 和 OSX 上与 PHP 7 有同样的错误。
https://stackoverflow.com/中的上述答案很好,但它并没有完全解决我的问题。我必须提供完整的证书链才能使 file_get_contents() 再次工作。我就是这样做的:
获取根/中间证书
首先,我必须弄清楚什么是根证书和中间证书。
最方便的方法可能是像 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() 在哪里寻找证书文件。也许这两种方式都会奏效。我更喜欢参数方式。 (与上面提到的解决方案相比)。
所以这现在是我的 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,希望没有安全漏洞。
chain.pem
是什么?这是chain.crt
吗?
在我的开发人员机器(php 7,windows 上的 xampp)上遇到了相同的 ssl 问题,使用自签名证书尝试打开“https://localhost/...”文件。显然,根证书程序集(cacert.pem)不起作用。我刚刚从下载的 cacert.pem 中的 apache server.crt-File 手动复制了代码,并在 php.ini 中执行了 openssl.cafile=path/to/cacert.pem 条目
要尝试的另一件事是重新安装 ca-certificates
,详细说明 here。
# 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 证书,但是我安装了一个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
<?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; ?>
只需测试版本 PHP 7.2,它运行良好
关于类似的错误
[11-May-2017 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
这个问题已经解决了,至少对我来说是这样。
使用 wget
或 file_get_contents
时,我在另一个安全页面上遇到了同样的问题。大量研究(包括对此问题的一些回复)产生了一个简单的解决方案 - 安装 Curl 和 PHP-Curl - 如果我理解正确,Curl 有 Comodo 的 Root CA 解决了这个问题
安装 Curl 和 PHP-Curl 插件,然后重启 Apache
sudo apt-get install curl
sudo apt-get install php-curl
sudo /etc/init.d/apache2 reload
现在都在工作。
对我来说,我在 Windows 10 机器 (localhost) 上运行 XAMPP,最近升级到 PHP 8。我试图通过 file_get_contents() 打开 localhost HTTPS 链接。
在我的 php.ini 文件中,有一行内容如下:
openssl.cafile="C:\Users\[USER]\xampp\apache\bin\curl-ca-bundle.crt"
这是用于验证“外部”URL 的证书包,并且正如一些人所讨论的那样,它是来自 Mozilla 的一个包。我不知道 XAMPP 是这样出现的,还是我过去设置的。
在某些时候,我已经在我的本地主机上设置了 HTTPS,从而产生了另一个证书包。此捆绑包需要用于验证“localhost”URL。为了提醒自己该捆绑包在哪里,我打开 httpd-ssl.conf 并找到以下行:
SSLCertificateFile "conf/ssl.crt/server.crt"
(完整路径为 C:\Users[USER]\xampp\apache\conf\ssl.crt\server.crt)
为了使本地主机和外部 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");
$csm = stream_context_create(['ssl' => ['capture_session_meta' => TRUE]]); $sourceCountry=file_get_contents('https://api.wipmania.com/'.$ip.'?website.com', FALSE, $csm);
修复了 macos 12.4 / Mamp 6.6 / Homebrew 3.5.2 / Openssl@3
终端
检查版本
openssl version -a
我的指向:
...
OPENSSLDIR: "/opt/homebrew/etc/openssl@3"
...
所以我查看了自制软件的目录 /opt/homebrew/etc/openssl@3
并找到了 cert.pem 并确保我的 Mamp 的当前版本的 php 的 php.ini 文件指向自制软件的正确 openssl 版本的 cert.pem
添加到 php.ini
openssl.cafile=/opt/homebrew/etc/openssl@3/cert.pem