ChatGPT解决这个技术问题 Extra ChatGPT

file_get_contents():SSL 操作失败,代码为 1,无法启用加密

我一直在尝试从我在我们的服务器上创建的 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 正在工作。由于这个问题的特殊性;我没有找到很多帮助信息。你们有没有遇到过这样的事情?谢谢。

如果您使用 Kaspersky,请检查:stackoverflow.com/a/54791481/3549317
我发现只有在从同一个网站(不是本地)中抓取时才会出现此错误,即:将不同的网站抓取到运行脚本的位置非常有效。
对于那些在 2021 年得到这个的人,请参阅这个问题:stackoverflow.com/questions/69413223/…

c
ceejayoz

这是一个非常有用的链接,可以找到:

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

这会破坏 SSL 认证并且是一个安全漏洞
W
William Desportes

您不应该只是关闭验证。相反,您应该下载一个证书包,也许 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 编码)。我相信输出中列出的最后一个证书是根证书,并且该证书必须在您正在使用的证书文件中,才能使其正常工作。请注意,主机或客户端可能存在其他问题导致其失败(即主机证书过期、客户端时间不正确等)
我发现这非常有帮助。比接受的更好的答案。我们的服务器有一个来自 RapidSSL 的证书,在我们尝试连接到服务器的任何机器上,它都不存在于 php 中。因此,我们必须将 rapidssl2017.pem 松鼠并让 php 知道(感谢这个答案)。所以能够告诉 file_get_contents() 在哪里寻找它...比使用 curl 抓取要好得多。
可悲的是,在我在 10 月 10 日之前的评论中完成了所有工作之后……今天我从假期回来,一切都停止了。没有多少链接或抓取 pem 文件是有效的。不得不暂时禁用验证 :( 将在这里发布一个关于我们与这些糟糕的 RapidSSL 证书的具体问题的全新问题。
从安全角度来看:除了使用 cafile 流上下文选项之外,在 ciphers 流上下文选项中定义允许的密码并禁止那些被称为易受攻击的 SSL 版本可能非常重要。还建议将流上下文选项 disable_compression 设置为 true 以减轻 CRIME 攻击向量。
r
rodskagg

我通过确保在我的机器上安装了 OpenSSL 然后将其添加到我的 php.ini 来解决此问题:

openssl.cafile=/usr/local/etc/openssl/cert.pem

我在 IIS 上使用 PHP 7 使用了相同的方法,下载了 cert.pem 文件并像这样设置 php.ini,它起作用了:openssl.cafile=D:\Tools\GnuWin32\bin\cacert.pem
我从 curl.haxx.se/docs/caextract.html 下载了 PEM 文件 - 在 Windows 上使用特定的 gstatic.com URL 为我解决了问题。
在 Centos 7 上从 curl.haxx.se/docs/caextract.html 下载 PEM 文件对我不起作用。我通过连接主证书和 pkcs7 创建了一个捆绑证书,并将其放在服务器上,然后指定 openssl.cafile 路径。 +1 正确答案和方向。
创建捆绑包时不要忘记将 pkcs 转换为 pem 文件,然后再将其连接到主要认证
B
Ben Shoval

您可以通过编写使用 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


顶级解决方案只是禁用了不安全的 SSL - 这效果更好。
这是一个简单的解决方案,尽管它不像elitechief 提供的那样直接。接受的会导致安全漏洞。
导致我这边出现类似错误:User Notice: SSL certificate problem: unable to get local issuer certificate
这在功能上与 file_get_contents 有何不同?它对解决 SSL 问题没有任何帮助。
@MarshallC我的答案在功能上与file_get_contents没有什么不同。它只是在大多数情况下解决了问题,而不会造成安全噩梦。
D
David Newcomb

为我工作,我使用的是 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;
?>

A
Andy Gee

在将 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>

谢谢你唯一对我有用的东西
K
Kshitij Mittal

您基本上必须将环境变量 SSL_CERT_FILE 设置为从以下链接下载的 ssl 证书的 PEM 文件的路径:http://curl.haxx.se/ca/cacert.pem

我花了很多时间才弄清楚这一点。


P
Pang

如果您的 PHP 版本是 5,请尝试通过在终端中键入以下命令来安装 cURL:

sudo apt-get install php5-curl

这与 cURL 完全无关。
安装php curl应该是正确的答案!对于我的 Mac 系统,我使用的是端口,命令是:sudo port install php70-curl
s
shakee93

按照以下步骤将解决此问题,

从此链接下载 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 有效。
M
Martin Ille

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

S
SlickTheNick

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

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


c
cweiske

此错误的原因是 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);
}

这帮助我找到了我的问题。尽管我使用的是 PHP 5.6,但我使用的是过时的 api 客户端库,该库使用 cafile 上下文选项手动指定旧 CA 文件,如您上面的链接所示。从 api 客户端库中删除它为我修复了它。大概 PHP 开始使用 OpenSSLs 受信任的捆绑包
n
n.r.

在 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吗?
它不是chain.crt,而是实际证书。这是中间证书的列表,也就是证书链。你不一定需要它。使用 SSL 证书检查器来确定您是否需要它。如果是这样,您可以搜索您的证书颁发者的名称 + 术语“链”或“中间”以找到正确的文件。
h
hangerer

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


s
site

要尝试的另一件事是重新安装 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

B
Bang Nguyen
    <?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,它运行良好


G
GabLeRoux

关于类似的错误

[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

这个问题已经解决了,至少对我来说是这样。


耶! CHMOD 也是我的问题 ;-) 谢谢
A
Aubs

使用 wgetfile_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

现在都在工作。


M
Mark Bench

对我来说,我在 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");

P
Paris Z

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


C
Christopher S.

修复了 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

关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅