从内联二进制附件创建zip到多部分消息

时间:2013-10-30 16:57:52

标签: php xml zip ebay ebay-lms

作为Ebay API批量上传方法的一部分,我们收到来自Ebay(据称)的多部分响应,其中包含包含XML文件的zip文件的原始数据。我们在将其从原始二进制形式转换为zip文件时遇到问题。使用多部分消息底部的zip / xml文档的ebay响应的This is an example

这是我们用来测试响应的一些快速(和脏)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文件,但它已损坏。传递给$zipbuffer中的zip文件的内容似乎是正确的代码(尽管它与响应内容底部的代码完全相同)所以我不确定最新情况。

ebay docs here描述了返回的内容:

  

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

它提到返回的内容是“base64binary”,但究竟是什么呢?它肯定不是我之前使用过的base64字符串。

1 个答案:

答案 0 :(得分:2)

  

它提到返回的内容是“base64binary”,但究竟是什么呢?它当然不是我之前使用过的base64字符串。

它提到了XML内部。但请记住,XML是里面 ZIP,然后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Ÿ:(/µ—&õØ]jÉ µd?ú^›Ô9?©‡þRý¥NJLí©Kí©Kí©K-¦–K‡cÃÒáØ0W¹

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

你应该在这里使用一个能够解除分块响应的HTTP客户端,并且还能很好地处理多部分响应。

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

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


您通过Ebay提供的示例数据有些破碎,因此测试起来并不容易,但如果安装HTTP extension of PHP,处理多部分文档会有些简单。这可能不是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