Создать почтовый индекс из встроенного двоичного вложения в сообщение из нескольких частей
Как часть методов массовой загрузки 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>)