Как создать потоковый zip-архив на PHP, подходящий для утилиты архивирования OS X?
Я пытаюсь интегрировать систему резервного копирования по требованию для относительно небольшого веб-приложения, которое позволяет пользователю загружать zip-файл всех файлов на сервере и дамп базы данных. Zip-файл передается пользователю, а не упаковывается целиком во временный каталог на сервере.
Для этого я использую сторонний класс PHP, называемый ZipStream. Класс размещен здесь, а конкретный файл класса можно посмотреть здесь. Я выбрал эту версию (есть другая, более старая), поскольку она поддерживает включение каталогов. Также настройка должна работать на серверах без доступа к командам оболочки через shell_exec()
или же passthru()
,
Моя простая настройка теста работает, и я могу извлечь полученный поточный почтовый индекс, используя unzip
Команда из консоли или с помощью The Unarchiver.app
, Утилита архивирования OS X (Mac OS X 10.6 и, скорее всего, более старые и более поздние версии) вызывает проблемы, так как не может извлечь архив со следующей ошибкой:
Unable to unarchive "test.zip" into "test". (Error 1 - Operation not permitted.)
Фактическая зарегистрированная ошибка:
ditto: Couldn't read pkzip signature.
Я нашел несколько возможных объяснений этой проблемы здесь и здесь, в Stackru, и я хотел бы исправить класс ZipStream, чтобы он соответствовал спецификации Zip, чтобы утилита архивирования расширяла архив, как ожидалось.
"Версия, необходимая для извлечения" (хранится в ATTR_VERSION_TO_EXTRACT
постоянная) в классе ZipStream: x0Ax00
, но я не уверен, что эта запись отличается от стандартной 0x000A
упоминается в вышеупомянутом вопросе.
Кажется, проблема связана с каталогами, добавленными в zip-файл. Zip-файл, содержащий только текстовый файл, не вызывает проблем при использовании Archive Utility.
По мере того, как это движется вдоль границ сферы PHP, я не уверен, как редактировать скрипт с правильными шестнадцатеричными строками или как приспособить решение Zend к этому конкретному скрипту.
Я загрузил сгенерированный почтовый индекс здесь: http://dl.dropbox.com/u/6887873/test.zip
Код для генерации является урезанной версией примера кода:
$extime = ini_get('max_execution_time');
ini_set('max_execution_time', 600);
include_once("ZipStream.php");
$fileTime = date("D, d M Y H:i:s T");
$chapter1 = "Chapter 1\n"
. "Lorem ipsum\n"
. "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec magna lorem, mattis sit amet porta vitae, consectetur ut eros. Nullam id mattis lacus. In eget neque magna, congue imperdiet nulla. Aenean erat lacus, imperdiet a adipiscing non, dignissim eget felis. Nulla facilisi. Vivamus sit amet lorem eget mauris dictum pharetra. In mauris nulla, placerat a accumsan ac, mollis sit amet ligula. Donec eget facilisis dui. Cras elit quam, imperdiet at malesuada vitae, luctus id orci. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Pellentesque eu libero in leo ultrices tristique. Etiam quis ornare massa. Donec in velit leo. Sed eu ante tortor.\n";
$zip = new ZipStream("test.zip");
$zip->addFile("Hello World!\r\n", "Hello.txt");
$zip->addDirectory("files/");
$zip->addDirectoryContent("../images", "files/testing/");
$zip->finalize();
РЕДАКТИРОВАТЬ:
Я думаю, что сузил проблему немного больше. Не похоже, что шестнадцатеричные строки действительно имеют значение. Сгенерированный zip-файл, содержащий только текстовый файл, расширяется без ошибок с помощью служебной программы архивирования, поэтому кажется, что повреждение происходит при добавлении каталогов, особенно при вызове addDirectoryContent()
который в свою очередь вызывает addLargeFile()
класса ZipStream. Каталоги добавляются правильно и не приводят к неверному файлу, как только addDirectoryContent()
Утилита Archive Utility не может извлечь файлы, выводя ошибки выше.