我有一个symfony 2.8应用程序,在用户点击“下载”按钮时,我使用s3上的几个大(图像,视频)文件的密钥,使用ZipStream将其作为zip文件传输到浏览器({{3 }})。
文件流和下载为zip(存储,未压缩)在浏览器中是成功的。 zip下载。但是,尝试使用Archive Utility(OSX上的本机存档软件)在Mac OSX El Capitan中打开zip时,会出错。错误:
无法将“test.zip”扩展为“下载”。 (错误2 - 没有这样的文件或目录。)
我在SO上看过较旧的,相同的问题,并尝试了这些修补程序,特别是这篇文章:https://github.com/maennchen/ZipStream-PHP并对问题& ZipStream中的PR与Guzzle等中的上游修复有关。
问题是,上述修复工作已于2011年重新开始,并且事情正在进行中。因此,应用相同的修复程序,我无法获得有效的结果。
我尝试过的具体修复方法是: 1.按照建议将“要提取的版本”设置为0x000A。同样在另一篇文章中推荐为“20”。我为“版本制作”设置了相同的内容。 2.我试图强制压缩方法“放气”而不是“存储”以查看我是否得到了工作结果。存储的结果是我所需要的并且适用于用作图像和容器的容器文件的zip。视频。
我可以使用名为The Unarchiver的第三方存档应用程序解压缩zip。但是,用户不会知道&不能指望安装替代存档应用程序以适应我的网络应用程序。这不是一个有效的解决方案。
有没有人有解决这个问题的知识或经验,可以帮我解决这个问题吗?
注意:浏览器的流式压缩是必需的解决方案。将资产从s3下载到服务器以创建zip然后将生成的zip流式传输到浏览器并不是一个解决方案,因为这种方法需要花费大量的时间和开销。
根据需要添加信息:
代码&设置: - 文件存储在s3上。 - Web应用程序是PHP7.0上的symfony 2.8,在使用Ubuntu的ec2上运行。 - 使用aws-sdk-php,创建一个有效凭据的s3client,并在s3client上注册StreamWrapper(s3client-> registerStreamWrapper())。这是通过fopen从s3获取文件以流式传输到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输出结果:
通过Archive Utility在mac上提取失败,错误2
使用unarchiver工作,在Mac上进行提取。
使用7-zip工作在窗户上进行提取。
使用WinRar在Windows上进行提取失败 - 说zip已损坏。
响应标题:
https://stackoverflow.com/a/5574305/136151
修改 我愿意使用另一种将文件流式传输到浏览器的方法作为zip,可以在Mac,Windows,Linux上本地打开而不使用ZipStream(如果建议的话)。只是不创建一个zip文件服务器端以便随后流式传输。
答案 0 :(得分:2)
下载zip的问题是它包含来自调用ZipStream-> addFileFromStream()的Symfony控制器中的响应的html。基本上,当ZipStream在客户端浏览器中传输数据以创建zip下载时,还会发送控制器操作响应,最好的猜测是,这两者在客户端的浏览器上混淆了。在十六进制编辑器中打开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。