PHP ZIP files on the fly

前端 未结 7 1743
有刺的猬
有刺的猬 2020-12-02 17:06

What\'s the easiest way to zip, say 2 files, from a folder on the server and force download? Without saving the \"zip\" to the server.

    $zip = new ZipArc         


        
相关标签:
7条回答
  • 2020-12-02 17:17

    To create ZIP files on the fly (in memory), you can use ZipFile class from phpMyAdmin:

    • PMA\libraries\ZipFile.php

    An example of how to use it in your own application:

    • https://stackoverflow.com/a/9648562/767871

    Note: Your ZIP files will be limited by PHP's memory limit, resulting in corrupted archive if you exceed the limit.

    0 讨论(0)
  • 2020-12-02 17:21

    itsols If you want to insert the 'Content-Length' do it like this:

    $length = filesize($file);
    header('Content-Length: ' . $length);
    

    I don't know why, but it crashes if you put it in the same line.

    0 讨论(0)
  • 2020-12-02 17:28

    If you have access to the zip commandline utility you can try

    <?php
    $zipped_data = `zip -q - files`;
    header('Content-type: application/zip');
    header('Content-Disposition: attachment; filename="download.zip"');
    echo $zipped_data;
    ?>
    

    where files is the things you want to zip and zip the location to the zip executable.

    This assumes Linux or similar, of course. In Windows you might be able to do similar with another compression tool, I guess.

    There's also a zip extension, usage shown here.

    0 讨论(0)
  • 2020-12-02 17:30

    Unfortunately w/ PHP 5.3.4-dev and Zend Engine v2.3.0 on CentOS 5.x I couldn't get the code above to work. An "Invalid or unitialized Zip object" error message was all I could get. So, in order to make it work, I had to use following snippet (taken from the example by Jonathan Baltazar on PHP.net manual, at the ZipArchive::open page):

    // Prepare File
    $file = tempnam("tmp", "zip");
    $zip = new ZipArchive();
    $zip->open($file, ZipArchive::OVERWRITE);
    
    // Stuff with content
    $zip->addFromString('file_name_within_archive.ext', $your_string_data);
    $zip->addFile('file_on_server.ext', 'second_file_name_within_archive.ext');
    
    // Close and send to users
    $zip->close();
    header('Content-Type: application/zip');
    header('Content-Length: ' . filesize($file));
    header('Content-Disposition: attachment; filename="file.zip"');
    readfile($file);
    unlink($file); 
    

    I know this is different than working w/ memory only - unless you have your tmp area in ram ;-) - but maybe this can help out someone else, who's struggling with the solution above, like I was; and for which performance penalty is not an issue.

    0 讨论(0)
  • 2020-12-02 17:33

    maraspin's Answer is what I tried. Strangely, I got it working by removing the header line that references the file size:

    header('Content-Length: ' . filesize($file));
    

    With the above change, the code works like a breeze! Without this change, I used to get the following error message:

    End-of-central-directory signature not found. Either this file is not a zipfile, or it constitutes one disk of a multi-part archive. In the latter case the central directory and zipfile comment will be found on the last disk(s) of this archive.

    Test environment:

    OS: Ubuntu 10.10 Browser: Firefox And the default LAMP stack.

    0 讨论(0)
  • 2020-12-02 17:35

    This works for me (nothing is written to disk)

    $tmp_file = tmpfile(); //temp file in memory
    $tmp_location = stream_get_meta_data($tmp_file)['uri']; //"location" of temp file
    
    $zip = new ZipArchive;
    $res = $zip->open($tmp_location, ZipArchive::CREATE);
    $zip->addFile($filepath1, 'file1');
    $zip->close();
    
    header('Content-type: application/zip');
    header('Content-Disposition: attachment; filename="download.zip"');
    echo(file_get_contents($tmp_location));
    
    0 讨论(0)
提交回复
热议问题