У меня есть сайт PHP с большим количеством мультимедийных файлов, и пользователи должны иметь возможность загружать сразу несколько файлов в формате .zip. Я пытаюсь использовать ZipStream для обслуживания zip «на лету» с компрессией «store», поэтому на самом деле мне не нужно создавать zip-сервер на сервере, так как некоторые из файлов огромны, и их очень сложно сжать.
Это отлично работает, и полученные файлы могут быть открыты каждой программой zip, которую я пробовал без ошибок, за исключением программы Unzipping OS X по умолчанию, утилиты архива. Вы дважды щелкните файл .zip, и утилита Archive Utility решит, что она не выглядит реальной почтой и вместо этого сжимается в файл .cpgz.
Использование unzip или ditto в терминале OS X или StuffIt Expander распаковывает файл без проблем, но мне нужна программа по умолчанию (утилита архива) для работы ради наших пользователей.
Какие вещи (флаги и т. Д.) В других приемлемых zip-файлах могут отключить утилиту Archive Utility, считая, что файл не является допустимым почтовым индексом?
Я прочитал этот вопрос , который, похоже, описывает аналогичную проблему, но у меня нет каких-либо битов битботы общего назначения, поэтому это не третья проблема с битами, и я уверен, что у меня есть действительные crc-32, потому что когда я нет, WinRAR бросает посадку.
Я рад опубликовать некоторый код или ссылку на «плохой» zip-файл, если это поможет, но я почти просто использую ZipStream, заставляя его «работать в больших файлах» и используя «store» в качестве метода сжатия.
Изменить. Я также попробовал алгоритм сжатия «спящий» и получил те же результаты, поэтому я не думаю, что это «магазин». Также стоит отметить, что я каждый раз сбрасываю файлы с сервера хранения и отправляю их по мере их поступления, поэтому решение, требующее загрузки всех файлов, прежде чем отправлять что-либо, не будет жизнеспособным (экстремальный пример – 5 ГБ + из 20 МБ файлов. Пользователь не может дождаться, пока все 5 ГБ перейдут на сервер zipping, прежде чем их загрузка начнется или они подумают, что он сломан)
Вот 140-байтовый, «store» сжатый, тестовый zip-файл, который демонстрирует это поведение: http://teknocowboys.com/test.zip
Проблема заключалась в поле «версия, необходимая для извлечения», которую я нашел, выполнив шестнадцатеричный diff в файле, созданном ZipStream, против файла, созданного Info-zip, и просмотрев различия, пытаясь их разрешить.
ZipStream по умолчанию устанавливает его в 0x0603. Info-zip устанавливает его в 0x000A. Почтовые файлы с прежним значением, похоже, не открываются в утилите архива. Возможно, он не поддерживает функции этой версии?
Принуждение «версии, необходимой для извлечения» в 0x000A, привело к тому, что сгенерированные файлы открылись также в утилите Archive Utility, как и везде.
Изменить: Другой причиной этой проблемы является то, что zip-файл был загружен с помощью Safari (версия агента пользователя> = 537), и вы недооценили размер файла при отправке заголовка Content-Length.
Решение, которое мы используем, заключается в обнаружении сервера Safari> = 537, и если это то, что вы используете, мы определяем разницу между размером Content-Length и фактическим размером (как вы это делаете, зависит от вашего конкретного приложения) и после вызова $ zipStream-> finish (), мы эхо chr (0), чтобы достичь правильной длины. Полученный файл технически искажен и любые комментарии, которые вы помещаете в zip, не будут отображаться, но все почтовые программы смогут открыть его и извлечь файлы.
IE требует того же взлома, если вы неправильно сообщаете свою Content-Length, но вместо того, чтобы загружать файл, который не работает, он просто не завершит загрузку и выбросит «загрузку прерывается».
использовать ob_clean (); и флеш ();
Пример :
$file = __UPLOAD_PATH . $projectname . '/' . $fileName; $zipname = "watherver.zip" $zip = new ZipArchive(); $zip_full_path_name = __UPLOAD_PATH . $projectname . '/' . $zipname; $zip->open($zip_full_path_name, ZIPARCHIVE::CREATE); $zip->addFile($file); // Adding one file for testing $zip->close(); if(file_exists($zip_full_path_name)){ header('Content-type: application/zip'); header('Content-Disposition: attachment; filename="'.$zipname.'"'); ob_clean(); flush(); readfile($zip_full_path_name); unlink($zip_full_path_name); }
У меня была эта точная проблема, но с другой причиной.
В моем случае созданный php zip будет открываться из командной строки, но не через finder в OSX.
Я допустил ошибку, разрешив некоторое содержимое HTML в выходной буфер до создания zip-файла и отправив его обратно в ответ.
<some html></....> <?php // Output a zip file...
Программа unzip командной строки, очевидно, была терпимой к этому, но функция разблокировки Mac не была.
Без понятия. Если внешний класс ZipString не работает, попробуйте другой вариант. Расширение PHP ZipArchive
вам не поможет, поскольку оно не поддерживает потоковую передачу, а только записывает файлы.
Но вы можете попробовать стандартную утилиту Info-zip. Его можно вызвать из PHP следующим образом:
#header("Content-Type: archive/zip"); passthru("zip -0 -q -r - *.*");
Это приведет к несжатому zip-файлу, который сразу отправит обратно клиенту.
Если это не поможет, тогда интерфейс MacOS zip, вероятно, не понравится несжатым. Затем -0
флаг -0
.
Инструмент командной строки InfoZip, который я использую, как в Windows, так и в Linux, использует версию 20 для поля «версия, необходимая для извлечения» zip. Это необходимо и для PHP, поскольку сжатие по умолчанию – это алгоритм Deflate. Таким образом, поле «version needed to extract» должно действительно быть 0x0014. Если вы измените код «(6 << 8) +3» в ссылочном классе ZipStream на «20», вы должны получить действительный файл Zip на разных платформах.
Автор в основном говорит вам, что zip-файл был создан в OS / 2 с использованием файловой системы HPFS, а для версии Zip требуется InfoZip 1.0. Не многие реализации знают, что делать с этим больше;)
Для тех, кто использует ZipStream в Symfony, вот ваше решение: https://stackoverflow.com/a/44706446/136151
use Symfony\Component\HttpFoundation\StreamedResponse; use Aws\S3\S3Client; use ZipStream; //... /** * @Route("/zipstream", name="zipstream") */ public function zipStreamAction() { //test file on s3 $s3keys = array( "ziptestfolder/file1.txt" ); $s3Client = $this->get('app.amazon.s3'); //s3client service $s3Client->registerStreamWrapper(); //required $response = new StreamedResponse(function() use($s3keys, $s3Client) { // Define suitable options for ZipStream Archive. $opt = array( 'comment' => 'test zip file.', 'content_type' => 'application/octet-stream' ); //initialise zipstream with output zip filename and options. $zip = new ZipStream\ZipStream('test.zip', $opt); //loop keys useful for multiple files foreach ($s3keys as $key) { // Get the file name in S3 key so we can save it to the zip //file using the same name. $fileName = basename($key); //concatenate s3path. $bucket = 'bucketname'; $s3path = "s3://" . $bucket . "/" . $key; //addFileFromStream if ($streamRead = fopen($s3path, 'r')) { $zip->addFileFromStream($fileName, $streamRead); } else { die('Could not open stream for reading'); } } $zip->finish(); }); return $response; }
Если ваш ответ действия контроллера не является StreamedResponse, вы, скорее всего, получите поврежденный zip, содержащий html, как я узнал.