Создать почтовый индекс из встроенного двоичного вложения в сообщение из нескольких частей

Как часть методов массовой загрузки Ebay API, мы получаем ответ Ebay из нескольких частей (предположительно), содержащий необработанные данные zip-файла, содержащего XML-файл. У нас возникли проблемы с преобразованием этого файла из исходного файла в 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. Ссылка на поток вложенных файлов указывается с помощью идентификатора содержимого (т. Е. Cid) в поле данных тела. Если значение ack равно "Success", двоичные данные вложения файла должны быть сохранены в виде zip-файла. XML-файл SoldReport, в свою очередь, должен быть извлечен из zip-файла.

Он упоминает, что возвращаемое содержимое является "base64binary", но что на самом деле это? Это, конечно, не строка base64, с которой я работал раньше.

1 ответ

Он упоминает, что возвращаемое содержимое является "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-клиент, который может разделить фрагмент на части, а также хорошо работает с multipart-ответами.

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

Вероятно, потерпит неудачу, если последняя часть будет разделена на части.


Образцы данных, которые вы предоставляете через Ebay, несколько разбиты, поэтому их было не так легко протестировать, но если вы установите HTTP-расширение PHP, вам будет несколько проще работать с составными документами. Это может не соответствовать 100% RFC, но я думаю, что это довольно хорошо для такого небольшого количества кода и более строго, чем другие примеры, которые я мог бы найти в Stackru с помощью быстрого поиска:

$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

Другие вопросы по тегам