Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/macos/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 在Symfony中使用ZipStream:使用Mac OSX上的存档实用程序,流式zip下载不会解压缩_Php_Macos_Symfony_Amazon S3_Zipstream - Fatal编程技术网

Php 在Symfony中使用ZipStream:使用Mac OSX上的存档实用程序,流式zip下载不会解压缩

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上看到

我有一个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库:

$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();是在我的代码中,只是不在上面的示例中。我已经编辑了上面的内容。您可能在该库中做了一些不符合顺序的事情。