2

作为 eBay API 批量上传方法的一部分,我们收到来自 eBay(假设)的多部分响应,其中包含包含 XML 文件的 zip 文件的原始数据。我们在将其从原始二进制形式转换为 zip 文件时遇到问题。这是 ebay 响应的示例,其中 zip/xml 文档位于多部分消息的底部。

这是我们用来测试响应的一些快速(且肮脏)的 PHP:

$fpath = "http://developer.ebay.com/DevZone/file-transfer/CallRef/Samples/downloadFile_basic_out_xml.txt";
$responseXml = file_get_contents($fpath);
$endofxmlstring = "</downloadFileResponse>";
$pos = strpos($responseXml, $endofxmlstring) + 1; //plus one to catch the final return
$zipbuffer = substr($responseXml, $pos + strlen($endofxmlstring));
unset($responseXml);

$startofzipstring = "Content-ID:";
$pos = strpos($zipbuffer, $startofzipstring);
$zipbuffer = substr($zipbuffer, $pos);

$startofzipstring = "PK";
$pos = strpos($zipbuffer, $startofzipstring);
$zipbuffer = substr($zipbuffer, $pos);

$handler = fopen("response.zip", 'wb') or die("Failed. Cannot Open file to Write!");
fwrite($handler,$zipbuffer);
fclose($handler);

zip 文件已创建,但已损坏。传递给 zip 文件的内容$zipbuffer似乎是正确的代码(与响应内容底部的代码相同),所以我不确定发生了什么。

此处的 ebay 文档描述了此处返回的内容:

输出示例显示了下载文件响应的原始格式,以说明数据文件如何附加到多部分消息中。根部分(或正文)包含带有标准输出字段的调用响应,例如 ack、timestamp 和 version。最后一部分包含 base64binary 格式的压缩文件附件。文件附件流由正文的 Data 字段中的内容 ID(即 cid)引用。当 ack 值为“Success”时,必须将文件附件的二进制数据保存为 zip 文件。反过来,SoldReport XML 文件必须从 zip 文件中提取。

它提到返回的内容是“base64binary”,但实际上这是什么?它肯定不是我以前使用过的 base64 字符串。

4

1 回答 1

2

它提到返回的内容是“base64binary”,但实际上这是什么?它肯定不是我以前使用过的 base64 字符串。

它在 XML 内部提到了这一点。但请记住,XMLZIP 中,然后 ZIP 是多部分响应(HTTP 消息)的最后一部分。

好吧,这听起来有点像在胡说八道,这是一个提醒这一点的好方法:base64binary 最常用于 XML 上下文,因为 XML 不能包含完整的二进制数据(例如 NUL 字节不起作用,我们知道二进制数据可以包含它们,因为不支持其他一些字符)。因此,如果您发现base64binary和 XML 指日可待,那么假设两者属于一起并没有错。

对于给定的 HTTP 示例,您是完全正确的:那里没有 base64:

...
Content-Type: application/octet-stream
Content-Transfer-Encoding: binary
                           ######
Content-ID: <urn:uuid:D8D75F18A8343F8FC61226972901992>

PKÙÔG²x7œÿwšÌÐÛ?žû›ÚE0uRßÔçÒ©]SŒçÔU mSkèSkèS«·SÏ[M=o•Z¿N­_§þ:Kýu–úë,õÌ]
ê[ÈS'%¦¾Ù'uTcjGêÁÏÔ$IjKjKjKê¸ÎÔóV©ôÔzê?¯Ôdij²4uF\6݈ôÌ]jIjÂ<µ‹#õÕB©¯J=
ö˜:¨0».C-åiÙèl¢Ijå(õÜ_jÆ>5cŸ:(/µ—&amp;õØ]jÉ µd?ú^›Ô9?©‡þRý¥NJLí©Kí©Kí©K-¦–K‡cÃÒáØ0W¹

传输编码在这里显然是二进制的。

您应该在这里使用一个 HTTP 客户端,它能够对分块响应进行分块处理,并且还可以很好地处理多部分响应。

$startofzipstring = "PK";
$pos = strpos($zipbuffer, $startofzipstring);
$zipbuffer = substr($zipbuffer, $pos);

如果最后一部分被分块,可能会失败。


您通过 Ebay 提供的示例数据有些损坏,因此测试起来并不容易,但是如果您安装PHP 的 HTTP 扩展,则处理多部分文档会有些简单。这可能不是 100% 符合 RFC,但我认为这对于少量的代码来说是相当不错的,而且比我可以通过快速搜索在 Stackoverflow 上找到的其他示例更严格:

$url = 'http://developer.ebay.com/DevZone/file-transfer/CallRef/Samples/downloadFile_basic_out_xml.txt';
$raw = file_get_contents('downloadFile_basic_out_xml.txt');

$message = MultipartHttpMessage::fromString($raw);

echo 'Boundary: ', $message->getBoundary(), "\n";

foreach ($message->getParts() as $index => $part) {
    printf("Part #%d:\n", $index);
    foreach ($part->getHeaders() as $name => $value) {
        printf("  %s: %s (%s)\n", $name, $value[NULL], $value);
    }
}

输出:

Boundary: MIMEBoundaryurn_uuid_9ADF5C1A6F530C078712269728985463257
Part #0:
  Content-Type: application/xop+xml (application/xop+xml; charset=utf-8; type="text/xml")
  Content-Transfer-Encoding: binary (binary)
  Content-Id: <0.urn:uuid:9ADF5C1A6F530C078712269728985463258> (<0.urn:uuid:9ADF5C1A6F530C078712269728985463258>)
Part #1:
  Content-Type: application/octet-stream (application/octet-stream)
  Content-Transfer-Encoding: binary (binary)
  Content-Id: <urn:uuid:D8D75F18A8343F8FC61226972901992> (<urn:uuid:D8D75F18A8343F8FC61226972901992>)

代码:https ://gist.github.com/hakre/f13e1d633301bf5f221c

于 2013-11-02T21:04:28.180 回答