在 stream_get_contents() 中传递公钥、私钥和 CA 调用 Multipart/Related
Posted
技术标签:
【中文标题】在 stream_get_contents() 中传递公钥、私钥和 CA 调用 Multipart/Related【英文标题】:Pass Public Key, Private Key and CA In stream_get_contents() Call for Multipart/Related 【发布时间】:2019-10-19 09:52:11 【问题描述】:我正在尝试连接到第 3 方 API,他们要求我通过他们给我的 3 个证书文件:公共证书、私有证书和 CA 证书。使用以下设置在 cURL 中运行良好:
if (empty($this->order['connector']))
curl_setopt($_curl, CURLOPT_SSLKEY, API_PRIVATE_CERT);
curl_setopt($_curl, CURLOPT_CAINFO, API_CA_CERT);
curl_setopt($_curl, CURLOPT_SSLCERT, API_PUBLIC_CERT);
传递的每个值都是服务器上物理文件的路径。这很好用。
但是,对于一个请求,我必须传递一个标头 'Content-Type: Multipart/Related; boundary="---BOUNDARY123456"' 带有包含 XML 文件和 Base64 编码 PDF 的 MIME 消息。这失败了,最后出现 500 错误。在对此进行研究时,我发现 cURL 无法正确处理 Content-Type: Multipart/Related posts。
https://***.com/a/25998544/3434084
所以我尝试使用 stream_get_contents() 发送它,但没有得到回复。所以我认为我的证书数据是错误的。如何通过 stream_get_contents() 传递我在 cURL 中使用的相同值?
代码如下:
$payload = '----=FB498299F0F50D2A190B3C
Content-Type: application/x-ofx
<?xml version="1.0" encoding="ISO-8859-1"?>
<?OFX OFXHEADER="200" VERSION="201" SECURITY="NONE" OLDFILEUID="NONE" NEWFILEUID="NONE"?>
<OFX>
<SIGNONMSGSRQV1>
<SONRQ>
<LANGUAGE>ENG</LANGUAGE>
<APPID>TWEEN</APPID>
</SONRQ>
</SIGNONMSGSRQV1>
...
</OFX>
----=FB498299F0F50D2A190B3C
Content-Type: application/pdf
Content-Transfer-Encoding: base64
Content-Location: full1_1559588546.pdf
JVBERi0xLjQKJcOkw7zDtsOfCjIgMCBvYmoKPDwvTGVuZ3RoIDM...PRgo=
----=FB498299F0F50D2A190B3C' . "\r\n\r\n";
$params = [
'http' => [
'method' => 'POST',
'header' => 'Content-Type: Multipart/Related; boundary="----=FB498299F0F50D2A190B3C"',
'content' => $payload
],
'ssl' => [
'verify_peer' => true,
'local_pk' => API_PRIVATE_CERT,
'cafile' => API_CA_CERT,
'local_cert' => API_PUBLIC_CERT
]
];
$_stream = stream_context_create($params);
$response = @file_get_contents('https://blah/api/, FILE_TEXT, $_stream);
TIA!
【问题讨论】:
您在示例中抑制错误,我猜这会阻止故障排除。要进一步排除故障,您可以尝试挂钩流通知(事件),也许将超时设置为低值也有助于排除故障。请参阅 php.net/manual/en/stream.errors.php 和 php.net/manual/en/function.stream-notification-callback.php - 最后但并非最不重要的一点,这个问答材料看起来也很有趣:***.com/q/40999726/367456 在 PHP 相关问答中找到另一个 multipart/related w/ curl,即使答案已被接受:***.com/a/9252130/367456 /e:它特别指出:“注意,最后一个边界有一个额外的--
在末尾。”您的有效负载中的行也没有 \r\n 终止,我不知道具体的 mime 类型,但详细信息应该在这里:tools.ietf.org/html/rfc2387(也许)
@hakre 感谢您的链接!我以为我已经看过每一页,并在这里尝试了关于多部分/相关的每个示例。会看看。
总是这样,信息溢出。从我目前看到的情况来看,并不是 curl 本身不能做到这一点,只是您需要对自己的有效负载进行编码,因为 curl 无法编码多部分/相关,但是发送它(和使用您的 SSL 选项)确实如您所说的那样工作。所以我想说这不应该成为使用 curl 的阻碍(但是关于 HTTP/SSL 流出了什么问题的另一个问题也很有趣)。但是由于您已经使用 curl 处理证书,因此我只关注作为多部分/相关的有效负载编码。
@hakre 现在在 PHP 5.6 上运行,但明年需要在 7.x 上运行。我也在尝试github.com/robtimus/php-multipart 看看它是否也能做到。
【参考方案1】:
试试
$params = [
"ssl"=>[
"verify_peer"=> true,
"verify_peer_name"=> true,
"cafile" => "pem.pem",
],
];
$response = file_get_contents($URL, 0, stream_context_create($params)
【讨论】:
感谢发帖,但我还需要传递公钥和私钥。这些值会转到 SSL 下的哪些键> @JoelF.:从我昨天看到的情况来看,你所做的对我来说已经很不错了。我至少从文档中检查了这一点。我手头没有类似于完全测试该配置的设置。我很确定,最后这是可能的 w/streams(我也认为 curl)。这是“只是”(tm)找到配置被破坏的地方。其实,让我们面对现实吧:如果有 500,那就意味着传输层做到了,对吧?这更多的是有效载荷的编码错误并且其他服务器出现故障(或HTTP版本等。)。 @hakre 感谢您的所有帮助。我同意有效载荷确实发送了,但他们不会在他们这边修复它,所以我一直在确定原因。【参考方案2】:原来我的问题在于我使用的原始 cURL 代码失败了。这是我在这种情况下需要使用的更新代码,用于通过 cURL 发送多部分/相关内容,使用提供给我的第 3 方 SSL 证书数据来验证访问权限。
$headers = [
'Content-Type: Multipart/Related; boundary="--' . $this->api_boundary . '";type=text/xml'
];
$_curl = curl_init();
curl_setopt($_curl, CURLOPT_URL, $this->api_url);
curl_setopt($_curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($_curl, CURLOPT_SSLCERTTYPE, FALSE);
curl_setopt($_curl, CURLOPT_POSTFIELDS, $this->api_xml);
curl_setopt($_curl, CURLOPT_POST, TRUE);
curl_setopt($_curl, CURLOPT_HTTPHEADER, $headers);
// TLS items
curl_setopt($_curl, CURLOPT_SSLKEY, API_PRIVATE_CERT); // path to private cert in .pem format
curl_setopt($_curl, CURLOPT_CAINFO, API_CA_CERT); // path to CA cert in .pem format
curl_setopt($_curl, CURLOPT_SSLCERT, API_PUBLIC_CERT); // path to public cert in .pem format
// process
$response = curl_exec($_curl);
// check for errors
if (curl_error($_curl))
// capture error here
$status = curl_getinfo($_curl);
curl_close($_curl);
【讨论】:
@Dharman 你说得对。我在我的开发机器上关闭了它,因为 SSL 不会验证。生产可以。答案已更新。 这些值仍然是错误的。只需删除这些行并保留默认值即可。以上是关于在 stream_get_contents() 中传递公钥、私钥和 CA 调用 Multipart/Related的主要内容,如果未能解决你的问题,请参考以下文章
PhpSpreadsheet 从内存而不是文件加载 Excel 文件?
18.有一个网页地址, 比如PHP开发资源网主页: http://www.phpres.com/index.html,如何得到它的内容?
[问答题]有一个网页地址, 比如PHP开发资源网主页: http://www.phpres.com/index.html,如何得到它的内容?