Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating and serving zipped files with php

Tags:

php

zip

gzip

unzip

I'm trying to use the following code to create a zip file from a directory and serve it to the user via an http download:

 // write the file
file_put_contents($path . "/index.html", $output);

// zip up the contents
chdir($path);
exec("zip -r {$course->name} ./");

$filename = "{$course->name}.zip";

header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' .urlencode($filename));
header('Content-Transfer-Encoding: binary');

readfile($filename);

I am able to create the zip file, but downloading it over http is not working. If I download the zip file that's created using an ftp client then Mac's Stuffit Expander unzips the files just fine, but if I download it over http, the mac unzipper creates an endless loop. What I mean by this is say the file I download is called course.zip, then unzipping the file gives course.zip.cpgz and unzipping that file gives course.zip again..and on and on.

Anyone have any ideas?

Thanks!

like image 652
Eric Conner Avatar asked Dec 29 '22 15:12

Eric Conner


2 Answers

I had this problem and it turned out the downloaded zip file had a new line inserted at the very beginning.

Solved by using ob_clean and flush functions

    header("Pragma: public");
    header("Expires: 0");
    header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
    header("Cache-Control: private",false);
    header("Content-Type: application/octet-stream");
    header("Content-Disposition: attachment; filename=".basename($archive_file_name));
    header("Content-Transfer-Encoding: binary");
    header("Content-Length: ".filesize($archive_file_name));
    ob_clean();
    flush();
    echo readfile("$archive_file_name");
like image 66
adam Avatar answered Jan 09 '23 11:01

adam


  1. Re-zipping it every time it is requested is not a good idea. Try doing that only if the ZIP file does not exist already.

  2. If is a volatile file or just a single small file you want to transfer compressed, try using ob_start('ob_gzhandler') instead, simplier, smaller, cleaner. The file is transfered compressed, but it is saved in its original format by the client-side.

  3. Specifying the Content-Length header is needed to allow the downloader to know the end of the file, allowing progress control, detection of corruption of the file and avoiding the hang of the HTTP session (if Connection is in Keep-Alive mode), maybe the lack of this header is the root of the problem.

like image 24
Havenard Avatar answered Jan 09 '23 12:01

Havenard