2017-06-22 81 views
1

我有一个symfony 2.8应用程序,并且在用户点击“下载”按钮时,我使用几个大型(图像,视频)文件的键s3使用ZipStream将其作为zip文件流式传输到浏览器(https://github.com/maennchen/ZipStream-PHP)。在Symfony中使用ZipStream:在Mac OSX上使用Archive Utility不能解压缩流式zip压缩包

在浏览器&下载中的zip压缩文件中,文件流并以zip(存储,未压缩)形式下载成功。但是,当试图使用存档实用程序(OSX上的本机存档软件)在Mac OSX El Capitan中打开zip文件时,它会出错。错误:

无法将“test.zip”展开为“下载”。 (错误2 - 没有这样的文件或目录。)

我看到较旧的,相同的问题上SO并试图那些修复,特别是此信息:在ZipStream https://stackoverflow.com/a/5574305/136151和跟进的问题&的PR,其涉及与上游修复在Guzzle等

问题是,上述修复程序在2011年回来,并在那个时候的事情继续前进。因此,应用相同的修复程序,我没有得到一个工作结果。

我试过的具体修复方法是: 1.按照建议将“version to extract”设置为0x000A。另外在另一篇文章中推荐为'20'。我为“版本制作”设置了相同的设置。 2.我试图强制压缩方法'放气'而不是'存储',看看我是否得到了一个工作结果。存储结果是我所需要的,并且适用于作为图像&视频的容器文件的压缩文件。

我能够使用称为The Unarchiver的第三方存档应用程序提取zip。但是,用户不会知道&不能指望安装替代存档应用程序以适应我的web应用程序。那不是一个有效的解决方案。

有没有人有解决这个问题的知识或经验,可以帮我解决这个问题?

注意:流式浏览器是所需的解决方案。考虑到这种方法的时间和开销,从s3下载资产到服务器以创建zip,然后将产生的zip流式传输到浏览器并不是解决方案。如果需要的话

新增信息:

代码&设置: - 文件存储在S3。 - Web应用程序是使用Ubuntu在ec2上运行的PHP7.0上的symfony 2.8。 - 使用aws-sdk-php,使用有效凭证创建一个s3client,并在s3client上注册StreamWrapper(s3client-> registerStreamWrapper())。这是从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上的失败,错误2

  • 使用unarchiver工程在Mac上进行提取。

  • 提取与7拉链作品的窗户。

  • 使用WinRar在Windows上解压失败 - 表示zip损坏。

响应头:

enter image description here

编辑 我愿意使用流文件浏览器,可以在Mac,Windows,Linux的打开拉链的另一种方法本身如果建议不使用ZipStream。只是不要创建一个zip文件服务器端,随后进行流式处理。

+0

您可能会在该库的顺序上做某些事情。你有没有在复杂的案例之前测试过简单的案例?一个小文本文件?两个小文本文件?两个大文本文件?打开生成的文件并用十六进制编辑器检查它? –

+0

@ Michael-sqlbot我最初尝试了一个简单的例子,其中包含1个图像,2个图像,1个视频等,并得到同样的问题。我实际上现在再次尝试使用基本的txt文件。很快会恢复。 我用十六进制编辑器查找什么? – Forer

+0

@ Michael-sqlbot尝试使用s3上的单个文本文件,但使用归档实用程序获取下载内容,但得到相同的错误: 无法将“test.zip”提取到“下载”中。 (错误2 - 没有这样的文件或目录。) – Forer

回答

1

下载的zip文件的问题在于它包含了调用ZipStream-> addFileFromStream()的Symfony控制器中响应的html。基本上,当ZipStream传输数据以在客户端浏览器中创建zip下载时,控制器的动作响应也被发送出去了,最好的猜测是,这两者在客户端的浏览器上混淆起来。在十六进制编辑器中打开压缩文件,并看到那里的html显然是问题。

为了使用ZipStream在Symfony 2.8中正常工作,我只在控制器操作中使用了Symfony的StreamedResponse,并在streamedResponse的函数中使用了ZipStream。为了传输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; 
} 

已解决。也许这可以帮助别人在Symfony中使用ZipStream。