Создание и обслуживание заархивированных файлов с помощью 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-клиента, то Mac Stuffit Expander отлично распаковывает файлы, но если я загружаю его по http, распаковщик Mac создает бесконечный цикл. Под этим я подразумеваю, скажем, файл, который я загружаю, называется course.zip, затем при распаковке файла вы получаете course.zip.cpgz, а при распаковке этого файла снова получается course.zip… и так далее.

У кого-нибудь есть идеи?

Спасибо!


person Eric Conner    schedule 17.09.2009    source источник
comment
Ваш mime-тип application/octet-stream не является неправильным, но может быть удобнее использовать application/zip.   -  person Tony Miller    schedule 17.09.2009
comment
@ Тони Миллер - почему бы не поставить это в качестве ответа? Вполне может быть проблема здесь.   -  person karim79    schedule 17.09.2009
comment
Как выполнить архивацию и потоковую передачу на лету из php: stackoverflow.com/a/4357904/416630   -  person Lee    schedule 23.11.2012


Ответы (4)


  1. Повторно архивировать его каждый раз, когда он запрашивается, - не очень хорошая идея. Попробуйте сделать это, только если ZIP-файл еще не существует.

  2. Если это изменчивый файл или просто один небольшой файл, который вы хотите передать в сжатом виде, попробуйте вместо этого использовать ob_start('ob_gzhandler'), проще, меньше, чище. Файл передается в сжатом виде, но сохраняется в исходном формате на стороне клиента.

  3. Указание заголовка Content-Length необходимо, чтобы позволить загрузчику узнать конец файла, позволяя контролировать ход выполнения, обнаруживать повреждение файла и избегать зависания сеанса HTTP (если Connection находится в режиме Keep-Alive), возможно отсутствие этого заголовка является корнем проблемы.

person Havenard    schedule 17.09.2009
comment
Я также указываю заголовок Content-Length, и он все еще не работает. По сути, я просто пытаюсь предоставить пользователю около 15 небольших файлов одновременно, и решил, что архивирование было моим единственным вариантом. Есть ли другой способ сделать это? - person Eric Conner; 17.09.2009

У меня была эта проблема, и оказалось, что в загруженный 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");
person adam    schedule 23.11.2009

Как было предложено karim79, я добавлю свой комментарий в качестве ответа: что произойдет, если вы измените тип MIME из application/ поток октетов в приложение/zip?

Кроме того, я вижу, что вы используете программу zip из командной строки, но вы не проверяете успешность zip, а также не проверяете, существует ли файл, прежде чем пытаться отправить его в браузер конечных пользователей. Попробуйте жестко закодировать имя файла, вручную используя zip, чтобы гарантировать правильно сформированный zip-файл, а затем посмотрите, правильно ли ваш код передаст его в ваш браузер.

person Tony Miller    schedule 17.09.2009
comment
Хорошо, я попытался изменить тип MIME на application/zip, а также жестко закодировать в zip-файле, который, как я знал, был правильно сформирован (файл, который успешно распаковывался как на моем компьютере, так и на сервере после загрузки) и получил тот же результат . - person Eric Conner; 17.09.2009

Вы видите, что утилита архивирования не распознает zip-файл как zip-файл и пытается заархивировать сам zip-архив. Вторая операция просто распаковывает первый созданный файл, поэтому фактически никогда не открывает файл. Это связано с тем, что zip поврежден.

Возможно, браузер каким-то образом исказил zip-файл (кто-нибудь преобразовал новую строку?) в процессе загрузки. Как уже упоминалось, проверьте тип MIME и используйте php header(), чтобы установить правильный тип MIME (приложение/zip).

person futureelite7    schedule 17.09.2009
comment
Хорошо, я безуспешно пытался использовать application/zip. Диалоговое окно загрузки браузера указывает мне, что я пытаюсь загрузить Zip-архив ПК, и когда он загружается на мою машину, OS X показывает «Вид: ZIP-архив», но он делает то же самое, когда я пытаюсь распаковать его. (Это также с жестко закодированным файлом, который я не заархивировал на лету, который работал на моей машине перед загрузкой) - person Eric Conner; 17.09.2009