在 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 文件?

php oracle数据库clob和nclob字段

18.有一个网页地址, 比如PHP开发资源网主页: http://www.phpres.com/index.html,如何得到它的内容?

[问答题]有一个网页地址, 比如PHP开发资源网主页: http://www.phpres.com/index.html,如何得到它的内容?

在 Maven 中,如何在版本中命名战争文件与在快照构建中不同

存储在 plist 中的数据在模拟器中有效,但在设备中无效