Использование ZipStream в Symfony: потоковая загрузка zip не будет распаковываться с помощью Archive Utility на Mac OSX

У меня есть приложение Symfony 2.8, и, нажимая кнопку "скачать", я использую ключи нескольких больших файлов (изображения, видео) на s3 для потоковой передачи в браузер в виде zip-файла с использованием ZipStream ( https://github.com/maennchen/ZipStream-PHP).

Потоковая передача файлов и загрузка в виде zip-файла (сохраненного, а не сжатого) успешно выполняется в браузере, и zip-файл попадает в раздел Downloads. Однако при попытке открыть zip-архив в Mac OSX El Capitan с помощью служебной программы архивирования (встроенного программного обеспечения для архивирования в OSX) происходит ошибка. Ошибка:

Невозможно развернуть "test.zip" в "Загрузки". (Ошибка 2 - Нет такого файла или каталога.)

Я видел более старые, идентичные проблемы с SO и пытался их исправить, в частности, этот пост: /questions/34210076/dinamicheski-sozdavaemyie-zip-fajlyi-zipstream-v-php-ne-otkryivayutsya-v-osx/34210102#34210102 и следил за связанными с ними проблемами и связями с ZipStream, а также последующими исправлениями в Guzzle и т.д.,

Проблема в том, что вышеперечисленные исправления были еще в 2011 году, и в это время дела пошли еще дальше. Поэтому, применяя те же исправления, я не получаю рабочего результата.

Конкретные исправления, которые я попробовал: 1. Установка "версии для извлечения" в 0x000A, как предложено. Также как "20", как рекомендуется в другом посте. Я установил то же самое для "версия сделана". 2. Я попытался заставить метод сжатия "сдуть", а не "сохранить", чтобы посмотреть, получился ли у меня рабочий результат. Сохраненный результат - все, что мне нужно и подходит для почтового индекса, используемого в качестве файла-контейнера для изображений и видео.

Я могу извлечь zip с помощью стороннего архивного приложения под названием The Unarchiver. Тем не менее, пользователи не будут знать и не смогут установить альтернативное архивное приложение, подходящее для моего веб-приложения. Это не эффективное решение.

Кто-нибудь имеет знания или опыт решения этой проблемы и может помочь мне с ее решением?

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

Добавлена ​​информация, если требуется:

Код и настройка: - Файлы хранятся на s3. - Веб-приложение Symfony 2.8 на PHP7.0 работает на ec2 с Ubuntu. - Используя aws-sdk-php, создайте s3client с действительными учетными данными, и я регистрирую StreamWrapper (s3client->registerStreamWrapper()) на s3client. Это для извлечения файлов из s3 через fopen для потоковой передачи в библиотеку ZipStream:

$this->s3Client = $s3Client;  
$this->s3Client->registerStreamWrapper();

// Initialize the ZipStream object and pass in the file name which
//  will be what is sent in the content-disposition header.
// This is the name of the file which will be sent to the client.
// Define suitable options for ZipStream Archive.
$opt = array(
        'comment' => 'test zip file.',
        'content_type' => 'application/octet-stream'
      );
$zip = new ZipStream\ZipStream($filename, $opt);

$keys = array(
      "zipsimpletestfolder/file1.txt"
  );

foreach ($keys 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);

    $bucket = 'mg-test';
    $s3path = "s3://" . $bucket . "/" . $key;

    if ($streamRead = fopen($s3path, 'r')) {
      $zip->addFileFromStream($fileName, $streamRead);        
    } else {
      die('Could not open stream for reading');
    }
}

$zip->finish();

Результаты вывода Zip:

  • Извлечение на Mac с помощью Archive Utility завершается с ошибкой 2

  • Извлечение на Mac с Unarchiver работает.

  • Добыча на окнах с 7-почтовыми работами.

  • Извлечение на Windows с WinRar не удается - говорит, что ZIP поврежден.

Заголовки ответа:

введите описание изображения здесь

Редактировать Я открыт для использования другого метода потоковой передачи файлов в браузер в виде почтового индекса, который можно открыть на Mac, Windows, Linux без необходимости использовать ZipStream, если это предлагается. Только чтобы не создавать сторону сервера zip-файлов для последующей потоковой передачи.

1 ответ

Решение

Проблема с загруженным zip-файлом заключается в том, что он содержал html из ответа контроллера Symfony, который вызывал ZipStream->addFileFromStream(). В основном, когда ZipStream осуществлял потоковую передачу данных для создания zip-загрузки в клиентском браузере, также отправлялся ответ на действие контроллера, и, скорее всего, оба были перепутаны в клиентском браузере. Открыв zip-файл в шестнадцатеричном редакторе и увидев там html, очевидно, это была проблема.

Чтобы это работало в Symfony 2.8 с ZipStream, я просто использовал Symfony StreamedResponse в действии контроллера и использовал ZipStream в функции streamedResponse. Для потоковой передачи файлов S3 я просто передал массив s3keys и s3client в эту функцию. Так:

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;
}

Решаемые. Может быть, это поможет кому-то еще использовать ZipStream в Symfony.

Другие вопросы по тегам