Создание и обслуживание архивированных файлов с помощью php
Вопрос
Я пытаюсь использовать следующий код для создания zip-файла из каталога и предоставления его пользователю через http-загрузку:
// write the file
file_put_contents($path . "/index.html", $output);
// zip up the contents
chdir($path);
exec("zip -r {$course->name} ./");
$filename = "{$course->name}.zip";
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' .urlencode($filename));
header('Content-Transfer-Encoding: binary');
readfile($filename);
Я могу создать zip-файл, но загрузка его по http не работает.Если я загружаю zip-файл, созданный с помощью ftp-клиента, то программа Stuffit Expander Mac отлично разархивирует файлы, но если я загружаю его по http, программа mac unzipper создает бесконечный цикл.Под этим я подразумеваю, что файл, который я загружаю, называется course.zip, затем при распаковке файла выдается файл course.zip.cpgz, а при распаковке этого файла снова появляется course.zip .. и так далее, и тому подобное.
У кого-нибудь есть какие-нибудь идеи?
Спасибо!
Решение
Повторно архивировать его каждый раз, когда он запрашивается, не очень хорошая идея.Попробуйте сделать это только в том случае, если ZIP-файл еще не существует.
Если вы хотите передать изменяемый файл или просто один небольшой файл в сжатом виде, попробуйте использовать
ob_start('ob_gzhandler')
вместо этого - проще, меньше, чище.Файл передается в сжатом виде, но клиентская сторона сохраняет его в исходном формате.Указание заголовка Content-Length необходимо для того, чтобы загрузчик мог знать конец файла, позволяя контролировать ход выполнения, обнаруживать повреждение файла и избегать зависания HTTP-сеанса (если соединение находится в режиме поддержания активности), возможно, отсутствие этого заголовка является корнем проблемы.
Другие советы
У меня была эта проблема, и оказалось, что загруженный zip-файл содержал новую строку, вставленную в самом начале.
Решается с помощью функций ob_clean и flush
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private",false);
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename=".basename($archive_file_name));
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".filesize($archive_file_name));
ob_clean();
flush();
echo readfile("$archive_file_name");
Как было предложено карим79, Я помещу свой комментарий в качестве ответа:что произойдет, если вы измените тип MIME с application / octet-stream на application / zip?
Кроме того, я вижу, что вы используете zip-программу командной строки, но вы не проверяете успешность zip-файла, а также не проверяете, существует ли файл, прежде чем пытаться отправить его в браузер конечного пользователя.Попробуйте жестко закодировать имя файла вручную с помощью zip, чтобы гарантировать правильную форму zip-файла, а затем посмотрите, правильно ли ваш код передаст его вашему браузеру.
Что вы видите, так это то, что архивная утилита не распознает zip-файл как zip-файл и попыталась заархивировать сам zip-архив.Вторая операция просто разархивирует первый созданный файл, так что на самом деле файл вообще никогда не открывается.Это происходит из-за повреждения zip-файла.
Возможно, браузер каким-то образом исказил zip-файл (кто-нибудь преобразовал новую строку?) в процессе загрузки.Как уже упоминалось, проверьте тип mime и используйте php header(), чтобы установить правильный тип MIME (application/zip).