在服务器上压缩多个文件并回显压缩文件

时间:2020-05-17 12:16:33

标签: php jquery

考虑一个允许用户存储文件的站点(仅pdf,docx,jpeg,png,gif)。 html的一部分:

<ul>
    <li><a href="../folder/lola.doc" target="_blank">lola.doc</a></li>
    <li><a href="../folder/lola.pdf" target="_blank">lola.pdf</a></li>
    <li><a href="../folder/lola.jpeg" target="_blank">lola.jpeg</a></li>
    <li><a href="../folder/lola.docx" target="_blank">lola.docx</a></li>
</ul>

当用户单击以上任何一项时,文件将打开或出现一个保存Dialpg。很好。

现在,我希望用户能够选择其中一些文件(位于服务器上)。文件将被压缩并回显给用户,并提示保存。我不能在上面使用,所以我有这个选项:

html:

<select class="multiple_select " multiple>
    <option value="../folder/lola.doc">lola.doc</option>
    <option value="../folder/lola.pdf">lola.pdf</option>
    <option value="../folder/lola.jpeg">lola.jpeg</option>
    <option value="../folder/lola.docx">lola.docx</option>
</select>
<button id="btn" type="button">Download</button>

js:

js:

$('#btn').on('click', function() {
    var options_selected = $('select').find('option:selected');
    options_selected_le = options_selected.length;
    var i;
    var options_selected_arr = [];
    var options_names_arr = [];
    for (i=0; i<options_selected_le; i++) {
        options_selected_arr.push(options_selected.eq(i).val());
        options_names_arr.push(options_selected.eq(i).text());
    }

    var fd = new FormData();
    fd.append('zipname', zipname);
    fd.append('options_selected_arr', JSON.stringify(options_selected_arr));
    fd.append('options_names_arr', JSON.stringify(options_names_arr));
    $.ajax({
        url: 'download_multiple_files.php', 
        type: 'post', 
        data: fd,
        cache: false,
        contentType: false, 
        processData: false,
        beforeSend: function(xhr) { 
            xhr.setRequestHeader("X-Download", "yes"); 
        },
        success: function(response){
            alert(response); //I am sure this is wrong
            // Do I need js to handle zip file here. I guess php should automatically do this
        }
    }); 
});

<?php
  session_start();
  require 'server_conn.php'; // for connection and holds test_input function
  // do some security checks ...

  $zipname = 'file.zip';
  $arr = json_decode($_POST['options_selected_arr']);
  $file_arr = [];
  foreach ($arr as $obj) {
    array_push($files_arr, test_input($obj));
  }  

  $arr = json_decode($_POST['options_names_arr']);
  $files_names_arr = [];
  foreach ($arr as $obj) {
    array_push($files_names_arr, test_input($obj));
  }

  $zip = new ZipArchive;
  $zip->open($zipname, ZipArchive::CREATE);
  for ($i=0; $i<$c; $i++) {
    $zip->addFile($file_arr[$i], $files_names_arr[$i]);
  }  
  $zip->close();

  header('Content-Type: application/zip');
  header('Content-Length: ' . filesize($zipname));
  header('Content-Disposition: attachment; filename="file.zip"');
  readfile($zipname);
  unlink($zipname);   
?>

来自服务器的响应是随机的,没有错误指示。我怀疑我的php有缺陷。

1 个答案:

答案 0 :(得分:0)

我已经使用2种方法解决了这个问题: 方法1: 没有php的JSZip(每个选择选项已经包含文件路径作为值) 这种方法的优点:它不会在服务器上存储新的zip文件,因此存储不是问题。 我相信使用Blob还可以压缩大型文件,最大大小我不知道。 要使用此方法,需要下载Filesaver,jszip和jszip实用程序,并将以下行添加到html文档正文中

    <script src="../js/lib/jszip.min.js"></script>
    <script src="../js/lib/jszip-utils.min.js"></script>
    <script src="../js/lib/FileSaver.js"></script>

js脚本利用了Promisejs,我之前没有研究过(但是现在可以使用)。下面是js:

$('#btn').on('click', function() {
    function urlToPromise(url) {
        return new Promise(function(resolve, reject) {
            JSZipUtils.getBinaryContent(url, function (err, data) {
                if(err) {
                    reject(err);
                } else {
                    resolve(data);
                }
            });
        });
    }

    var options_selected = $('select').find('option:selected');
    options_selected_le = options_selected.length;

    var zipname = 'file.zip';

    var Promise = window.Promise;
    if (!Promise) {
        Promise = JSZip.external.Promise;
    }

    var i;
    var zip = new JSZip();
    for (i=0; i<options_selected_le; i++) {
        var url = options_selected.eq(i).val();
        var filename = options_selected.eq(i).text();
        zip.file(filename, urlToPromise(url), {binary:true});
    }

    zip.generateAsync({type:"blob"}).then(function callback(blob) {
        //see FileSaver.js
        saveAs(blob, zipname);
        //alert('success'); 
    }, function (e) {
        alert('Error zipping file(s). Retry');
    }); 
});

方法2: 使用js和PHP: 首先在服务器上创建一个文件夹来保存zip文件,我将文件夹命名为“ archive” 这就是为什么我可能不赞成这种方法的原因。 新的js:

$('#btn').on('click', function() {
    var options_selected = $('select').find('option:selected');
    options_selected_le = options_selected.length;

    var zipname = 'file.zip';       
    var fd = new FormData();
    fd.append('zipname', zipname);
    fd.append('options_selected_arr', JSON.stringify(options_selected_arr));
    fd.append('options_names_arr', JSON.stringify(options_names_arr));

    $.ajax ({
        url: 'download_multiple_files.php', 
        type: 'post', 
        data: fd,
        cache: false,
        contentType: false, 
        processData: false,
        success: function(response){
            window.location = response;
        }
    });
});

新的php:

<?php
  session_start();
  // connect to server, scan input data and do some security checks ...

  $zipname = 'file.zip';
  $arr = json_decode($_POST['options_selected_arr']);
  $file_arr = [];
  foreach ($arr as $obj) {
    array_push($files_arr, test_input($obj));
  }  

  $arr = json_decode($_POST['options_names_arr']);
  $files_names_arr = [];
  foreach ($arr as $obj) {
    array_push($files_names_arr, test_input($obj));
  }

  $zip = new ZipArchive();
  $path = '/archive/'.$zipname;
  if ($zip->open($path, ZipArchive::CREATE)!==TRUE) {
    echo 'Cannot zip files'; die;
  }

  $c = count($file_arr);
  for ($i=0; $i<$c; $i++) {
    $zip->addFile($file_arr[$i], $files_names_arr[$i]);
  }

  $zip->close();
  echo $path;
  mysqli_close($conn);
?>

这将强制显示保存对话框。我对这种方法有两个尚待解决的挑战: 禁止打开新窗口 出现保存对话框,下载为文件名,但没有扩展名.zip。因此,用户应输入.zip及其名称。我希望将计算出的zip文件名显示在“保存”对话框中