Php 在Symfony中使用ZipStream:使用Mac OSX上的存档实用程序,流式zip下载不会解压缩
我有一个symfony 2.8应用程序,在用户单击“下载”按钮时,我使用s3上几个大文件(图像、视频)的键,使用ZipStream()将其作为zip文件传输到浏览器 在浏览器中,文件的流式传输和下载(存储,而不是压缩)是成功的&zip将在下载中着陆。但是,当尝试使用Archive Utility(OSX上的本机存档软件)在Mac OSX El Capitan中打开zip时,它会出错。错误: 无法将“test.zip”扩展为“Downloads”。(错误2-没有这样的文件或目录。) 我在SO上看到了一些更老、相同的问题,并尝试了这些修复,特别是这篇文章:并跟进了ZipStream中的相关问题&PRs和Guzzle中的上游修复等 问题是,上述修复工作早在2011年就开始了,而事情也在那个时候发生了变化。因此,应用相同的修复,我没有得到工作结果 我尝试过的具体修复方法是: 1.按建议将“提取版本”设置为0x000A。在另一篇文章中也被推荐为“20”。我已经为“版本制造者”设置了相同的设置。 2.我试图强制压缩方法“deflate”而不是“storage”,以查看是否得到了工作结果。一个存储的结果是我所需要的,适合作为图像和视频的容器文件使用的zip 我能够使用第三方归档应用程序Unarchiver来提取zip。但是,用户不会知道&也不能期望安装一个替代的存档应用程序来适应我的web应用程序。这不是一个有效的解决办法 是否有人拥有解决此问题的知识或经验,并能帮助我解决此问题 注意:流式zip到浏览器是必需的解决方案。考虑到这种方法的时间和开销,将资产从s3下载到服务器以创建zip,然后将生成的zip流式传输到浏览器不是一种解决方案 必要时添加信息: 代码和设置: -文件存储在s3上。 -Web应用程序是PHP7.0上的symfony 2.8,运行在带有Ubuntu的ec2上。 -使用aws sdk php,创建一个具有有效凭据的s3client,然后在s3client上注册StreamWrapper(s3client->registerStreamWrapper())。这是通过fopen从s3获取文件,并流到ZipStream库:Php 在Symfony中使用ZipStream:使用Mac OSX上的存档实用程序,流式zip下载不会解压缩,php,macos,symfony,amazon-s3,zipstream,Php,Macos,Symfony,Amazon S3,Zipstream,我有一个symfony 2.8应用程序,在用户单击“下载”按钮时,我使用s3上几个大文件(图像、视频)的键,使用ZipStream()将其作为zip文件传输到浏览器 在浏览器中,文件的流式传输和下载(存储,而不是压缩)是成功的&zip将在下载中着陆。但是,当尝试使用Archive Utility(OSX上的本机存档软件)在Mac OSX El Capitan中打开zip时,它会出错。错误: 无法将“test.zip”扩展为“Downloads”。(错误2-没有这样的文件或目录。) 我在SO上看到
$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-zip在windows上进行提取
- 使用WinRar在windows上提取失败-表示zip已损坏
我愿意使用另一种将文件流式传输到浏览器的方法作为zip,如果建议的话,可以在Mac、Windows和Linux上本机打开,而无需使用ZipStream。只是不要创建zip文件服务器端,以便随后进行流式处理。下载的zip文件的问题在于,它包含来自调用ZipStream->addFileFromStream()的Symfony控制器中的响应的html。基本上,当ZipStream在客户端浏览器中流式传输数据以创建zip下载时,也会发送控制器操作响应,最好的猜测是,这两个响应在客户端浏览器上混淆了。在hex编辑器中打开zip文件并看到其中的html,这显然是问题所在 为了在Symfony 2.8中使用ZipStream,我在控制器操作中使用了Symfony的StreamedResponse,在StreamedResponse的函数中使用了ZipStream。为了流式传输S3文件,我刚刚将S3KEY数组和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。下载的zip文件的问题是,它包含来自调用ZipStream->addFileFromStream()的Symfony控制器中的响应的html。基本上,当ZipStream在客户端浏览器中流式传输数据以创建zip下载时,也会发送控制器操作响应,最好的猜测是,这两个响应在客户端浏览器上混淆了。在hex编辑器中打开zip文件并看到其中的html,这显然是问题所在 为了在Symfony 2.8中使用ZipStream,我在控制器操作中使用了Symfony的StreamedResponse,在StreamedResponse的函数中使用了ZipStream。为了流式传输S3文件,我刚刚将S3KEY数组和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。您可能在该库中做了一些不符合顺序的事情。在测试复杂案例之前,您是否测试过简单案例?一个小文本文件?两个小文本文件?两个大的文本文件?打开生成的文件并用十六进制编辑器检查它?@Michael sqlbot我尝试了一个简单的案例,一个图像,两个图像,一个视频等等,最初也遇到了同样的问题。我现在正在用基本的txt文件再试一次。将很快恢复。我在inspect with hex editor中寻找什么?@Michael sqlbot在s3上尝试了一个txt文件,得到了下载,但在使用存档实用程序提取时,我得到了相同的错误:无法将“test.zip”提取到“Downloads”中。(错误2-没有这样的文件或目录。)既然你说你不是在压缩文件,就用zip作为容器,你应该能够用十六进制编辑器看到所有的文本。如果不是全部,这表明您已经确认了一个问题,无论是与库有关还是与您的使用有关。如果存在文本,则可以检查容器结构并与已知属性进行比较(如果存在)。代码中缺少的是
$zip->finish()
它可能在zip文件(流)的末尾写入内部目录结构。@Michael sqlbot$zip->finish();是在我的代码中,只是不在上面的示例中。我已经编辑了上面的内容。您可能在该库中做了一些不符合顺序的事情。