The search for a PHP class to zip files has taken me well over 2 years. Going from not being able to find ANY to being able to find some that worked but wouldn’t unzip on MAC, the search seemed as if it would go on forever. A lot of web hosts don’t have the PHP zip function installed yet creating zip’s is quite important and handy to a lot of project. Today my search is finally over and I have finally found an easy + working PHP class for zipping files.
Download The Class
Upload the unzipped class to your site (Click here to download the class)
The Code – Download File
The following is the base code of how the script works. All you need to do is replace the $fileonserver and $filename to the file(s) you wish to zip.
include("zip_min.inc");
$zipfile = new zipfile();
$fileonserver = "path/to/file/oldfilename.txt";
$filename = "newfilename.txt";
$zipfile -> addFile(file_get_contents($fileonserver), $filename);
// Force download the zip
header("Content-type: application/octet-stream");
header("Content-disposition: attachment; filename=test.zip");
echo $zipfile -> file();
You may add more files by repeating the “$zipfile -> addFile” script with more files. The above will send the file straight to the user (not create a file on your server).
The Code – Save File To Server
You can save the zip to the server by using the file_put_contents() function as follows:
include("zip_min.inc");
$zipfile = new zipfile();
$fileonserver = "path/to/file/oldfilename.txt";
$filename = "newfilename.txt";
$zipfile -> addFile(file_get_contents($fileonserver), $filename);
$contents = $zipfile -> file();
file_put_contents("test.zip", $contents);
As you can see it’s a short and simple process. Script seems to work quite fast too. I’ve tested the downloaded files on both Mac and Windows and it seems to work beautifully.
Notes
- If you get an error with memory you’ll need to allow more PHP memory by updating your php.ini file or by using a .htaccess script. (Google it)
- Requires gzcompress PHP function (most hosts have this installed already)
- If you change the file name of the download in the header script make sure there are no spaces in the file name.





Hi Kim,
Thanks for your comment.
This class is much the same, as it creates the file on the fly only reads out the file contents and doesn’t create a file (unless you tell it to). So it is much the same as the class you’re using now except it is Mac friendly.
I’m very much a fan of not having to make customers do work (ie download a specific app) to access what they need. Hence why I continued the search until I found a class that works on Mac.
Very much worth you looking into.
Thanks Again!
Jason S
Well the disadvantage of this class is that it creates a file and if you can’t delete it again automatically (of safe mode is on for instance) then you’ll have to clean up manually.
I’m using a different class that creates zip on the fly in memory. That of course have the disadvantage of using a lot of memory while creating the zip file.
I too had the problem on mac, it’s the BomArchiver that’s the problem, on commandline unzip works just fine. My customers solution is to inform users of the flaw in BomArchiver and suggest for instance guitar or Zipeg, if unzip is not a solution.
Kind regards.
Kim Emax
Well in that case I better have another look at it. From the example here it just shows that the Addfile() function takes a physic file as a param. I too am very much into not demanding specific programs has to be installed by the enduser. On the other hand I suggested it to my customer in order to prevent him from using too many development hours on a workaround for a mac issue with a specific program. Like if a customer would complain on the chaotic view if he looked at a linux maillog or apache logfile in notepad
So if you make the zipfile on the fly, do you add a filesize header too? That troubled me a bit so it’s been skipped for now…
/Kim
I haven’t looked too much into the filesize for it because no actual file is being created, so it would be tricky getting the filesize without there being a physical file. Would be better to have it in there, if I can find a solution one day I’ll add it in.
Cheers
Jason S
Hi,
I try your script but the size of the files inside is always 0KB…
have you a solution for it?
here is my code
[code]
$zipfile = new zipfile();
// get image-paths
foreach($attached_imgs as $image) :
$zipfile -> addFile(file_get_contents($image->path), $image->name);
endforeach;
// Force download the zip
$zipname = urlencode($sitename) . '-' . urlencode($title) . '-' . date("YmdHi") . '.zip';
header("Content-type: application/octet-stream");
header("Content-disposition: attachment; filename=$zipname");
echo $zipfile -> file();
[/code]
cheers
Jörn
Hi Jörn,
I’d suggest you comment out the header and creation of the zip file, and echo each file name that’s been read out (perhaps add in if(file_exists($file)){ before you echo so you know the files that are being read out exist).
The only reason I can see it reading out 0kb is if the files are empty (or don’t exist). So make sure the files are being read out correctly.
Cheers,
Jason S
Hi,
I tried the code given and it unzip the files very nicely on windows & MAC.
Great work !!!
But when I open the unzipped file it is empty and of 0KB. Please go thru the code below and provide any help.
addFile(file_get_contents($filepath), $filename);
// Force download the zip
header(“Content-type: application/octet-stream”);
header(“Content-disposition: attachment; filename=\”test.zip\”");
echo $zipfile->file();
?>
Hi Shaz,
Make sure you put:
$zipfile -> addFile(file_get_contents($filepath), $filename);
This should fix your problem. If not, make sure the contents is being read out correctly.
Hope this helps!
Jason S
Here is my full code. When I echo the file_get_contents it will show the file contents properly but again after unzip the file is of zero bytes.
addFile(file_get_contents($filepath), $filename);
// Force download the zip
header(“Content-type: application/octet-stream”);
header(“Content-disposition: attachment; filename=\”test.zip\”");
echo $zipfile->file();
?>
It seems the code is not getting posted properly. Hope the below code will come proper.
include(“zip_min.inc”);
$zipfile = new zipfile();
$filepath = “”;
$filename = “newfilename.txt”;
//echo file_get_contents($filepath.$filename);exit; WHEN I ECHO THIS IT WILL SHOW ME THE FILE CONTENTS
$zipfile->addFile(file_get_contents($filepath), $filename);
// Force download the zip
header(“Content-type: application/octet-stream”);
header(“Content-disposition: attachment; filename=\”test.zip\”");
echo $zipfile->file();
Oh okay,
I see where the confusion is now!
You need to get the contents of the file to send it through, currently you’re just giving it the folder contents. It needs the file contents.
Below is what you need.
$zipfile->addFile(file_get_contents($filepath.$filename), $filename);
Reading out the file path alone won’t send any content through, hence why your files are coming out at 0kb. I will update my blog to be less mis-leading.
Jörn, this was also the issue with your script.
Let me know if this fixes your issue.
Cheers,
Jason S
Hey Thanks a lot Jason !!!
It’s working now.
Not a problem Shaz, happy to help.
I’ve updated the blog so hopefully it’s clearer now. I also added an example of how to save the zip to the server.
Enjoy,
Jason S
There’s a version of this class floating around that has addDir (add directory) support, but I’ve found that it causes the built-in mac OSX unarchiver to die. Assuming it’s because of the addDir stuff, as the addFile code is identical.
http://www.weberdev.com/get_example-4499.html
Anyone find a zip class that allows you to do files and directories, AND opens on a Mac (without having to use stuffit)?
Great class. I had problems with that other class in my mac too. Then I found this one. I had it includes within 5 minutes and it was working perfectly. Thanks alot.
Hi Jason,
do you have your own server and could you try and step up the memory_limit to like 256-512mb and then create a file of for instance mp3 files that would be around 50-100mb? I have a strange problem now, when I activate a zip download in this size, I can’t navigate around on the site until the download has completed. If I, instead of pushing the file with a header, create a link to the file on the server, then I can easily nagivate on the site while the file is downloading, very odd!
Regarding the content-length I haven’t found a way to get the filesize, when creating files on the fly, but save it to disk first, then use filesize() and then echo readfile(“test.zip”) instead of $zipfile -> file();, then you have the content-length and the user can see how far the download is. Also Transfer-Encoding: chunked is a useful header.
Kind regards
Kim
Hi Kim,
You can usually step up the memory limit to something like 128 or 256 using a .htaccess file or the phpini which would easily handle files of that size.
The reason for your content-length issue not allowing navigation is because you’re constantly trying to get the content-length on a file that is being created on the fly. That is, the file is being created as you download, hence why you can’t navigate. If you absolutely need the content-length in there, then it’s best to create the file on the server first, then send it out to the user.
Hope that makes sense
hehe, I was asking if _you_ could change it, in order to test
I’ve also tried to write to the server first in order to get the content-length and the result is the same. Here’s my example: http://lps.netlinq.dk/test010/test_zip.class.php. The testlink servers the purpose of testing if you can navigate on the page without problems while the download occurs. It works fine as it’s suppose to, but later on… in the site, where it’s suppose to run it stops for further navigation while downloading, pretty annoying!
I’ve been looking further into it and it seems that its a header problem, in the cache area. A download that doesn’t freeze the site looks like this:
HTTP/1.x 200 OK
Date: Sat, 03 Oct 2009 22:26:45 GMT
Server: Apache/2.2.8 (Ubuntu) PHP/5.2.4-2ubuntu5.6 with Suhosin-Patch mod_ruby/1.2.6 Ruby/1.8.6(2007-09-24) mod_ssl/2.2.8 OpenSSL/0.9.8g
X-Powered-By: PHP/5.2.4-2ubuntu5.6
Accept-Ranges: bytes
Content-Length: 7083675
Content-Disposition: attachment; filename=”Maxwell – Bad Habits (Remixes).zip”
Content-Transfer-Encoding: binary
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Content-Type: application/zip
via download.php, headers set in function.inc, doesn’t work
HTTP/1.x 200 OK
Date: Sat, 03 Oct 2009 21:41:49 GMT
Server: Apache/2.2.8 (Ubuntu) PHP/5.2.4-2ubuntu5.6 with Suhosin-Patch mod_ruby/1.2.6 Ruby/1.8.6(2007-09-24) mod_ssl/2.2.8 OpenSSL/0.9.8g
X-Powered-By: PHP/5.2.4-2ubuntu5.6
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Accept-Ranges: bytes
Content-Length: 35756585
Content-Disposition: attachment; filename=”Maxwell – Bad Habits (Remixes).zip”
Content-Transfer-Encoding: binary
Keep-Alive: timeout=15, max=98
Connection: Keep-Alive
Content-Type: application/zip
even after pragma, cache-control and expires headers has been removed from download.php, they’re still set:
HTTP/1.x 200 OK
Date: Sat, 03 Oct 2009 22:25:36 GMT
Server: Apache/2.2.8 (Ubuntu) PHP/5.2.4-2ubuntu5.6 with Suhosin-Patch mod_ruby/1.2.6 Ruby/1.8.6(2007-09-24) mod_ssl/2.2.8 OpenSSL/0.9.8g
X-Powered-By: PHP/5.2.4-2ubuntu5.6
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Accept-Ranges: bytes
Content-Length: 7083675
Content-Disposition: attachment; filename=”Maxwell – Bad Habits (Remixes).zip”
Content-Transfer-Encoding: binary
Keep-Alive: timeout=15, max=96
Connection: Keep-Alive
Content-Type: application/zip
Hi Jason,
The below code works well on windows browsers as well as on MAC firefox. But on MAC Safari the zip file is not generated thru below code. It is downloading directly a text file instead of generating zip of that text file.
Please do the needful.
include(“zip_min.inc”);
$zipfile = new zipfile();
$fileonserver = “zip1.txt”;
$filename = “newzip1.txt”;
$zipfile -> addFile(file_get_contents($fileonserver), $filename);
// Force download the zip
header(“Content-type: application/octet-stream”);
header(“Content-disposition: attachment; filename=zip1.zip”);
echo $zipfile -> file();
Shaz: try use “application/zip” as Content-Type instead, IE: header(“Content-Type: application/zip”);
Hey Jason.
Thanks for this lovely zip class.
I would like to use this as part of a WordPress plugin.
What is the licensing procedure for including this class in a freely distributed WordPress Plugin?
Please let me know.
Thanks again for your solid work.
@Shaz
Try the different header Kim suggested however all my testings been done in Safari mainly without any issues so I’d say there will be something else that is the issue. In the past Safari occasionally put .txt on the end of various files, but the problem didn’t persist and was purely a bug in Safari. So I’m not sure if that what you’re encountering, but I’m doubtful that it’s something specific to the class.
@Mongushu
You’re free to do this without any issues from my part. As long as it’s free – there’s no issues from me.
Thanks Kim & Jason for the updates.
I tried with “application/zip” but it didn’t worked. I tried to zip a .php file instead of text file thru below code. But on Safari instead of generating zip1.zip it is giving the option to download .php file.
include(“zip_min.inc”);
$zipfile = new zipfile();
$fileonserver = “test.php”;
$filename = “newtest.php”;
$zipfile -> addFile(file_get_contents($fileonserver), $filename);
header(“Content-type: application/zip”);
header(“Content-disposition: attachment; filename=zip1.zip”);
echo $zipfile -> file();
I also tried to create a zip file using PHP’s inbuild zip fucntions (ZipArchive). The below code not worked either.
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/zip”);
header(“Content-Disposition: attachment; filename=”.basename($destination).”;” );
header(“Content-Transfer-Encoding: binary”);
header(“Content-Length: “.filesize($destination));
readfile($destination);
@unlink($destination);
Here $destination is the folder name that has to be ziped.
I am using safari version 3.2.3 (5525.28.3) and Mac version 10.5.7
Definitely sounds specific to your version of Safari, try downloading Safari 4 and see if that gives you any grief. Probably change the header content type back to “application/octet-stream” as well.
If you’re still having troubles if you could provide a link for me to see if I have the same downloading issue in safari then we’ll be able to work out if the issue is browser based or script based.
I chekched on MAC Safari Version 4.0.3 (5531.9) with the content type “application/octet-stream”. But still giving the same problem.
You can have a look thru the below link.
http://75.127.135.77:10026/ziptest/zip1.php
Shaz: try haveing “” around the zipfilename too, IE: header(”Content-disposition: attachment; filename=\”zip1.zip\);
Also the abostrofs you use(”) looks different from mine(“)
Do you get _the_ php file from mac or just some regular file?
Shaz: BTW i’ve experienced several problems with Mac OS10.x with PHP and a zipclass like this one, the BomArchiver has a flaw, and the default zip utility for mac (think it’s called archive utility) relies on this function… Just be aware of that
/Kim
@Shaz: It appears to be working correctly. I’ll explain what’s happening. Safari on Mac automatically unzips and removes a zip file after download (the zip files will be in your trash). Because your file is so small it’s doing this practically instantly thus appearing as it isn’t zipped. If you did some larger files I think you’ll find that it is actually getting the zip file and not just the file itself.
Hi Kim,
I tried with “” around the zipfilename. But it’s downloading the .php file instead of zip.
Hi Jason,
Thanks a lot for such a valuable explanation. I checked the Trash and it shows the zip file in trash.
Hi Jason.
I’ve solved my problem, it turned out to be the sessions that made the download hang, so a session_write_close() call made the trick.
Regarding filesize, do you have any idea how to calculate it on the fly or is only solution to save the file to disk and readfile() it from there…? (that’s what I’ve come up with)
Kind regards
Kim
Saving the file is the best and only accurate way of doing it. So I’d suggest you do that if you want to send through the file size. I’d probably suggest avoiding readfile() and just do a straight link to the file on the server to save some server resources, they’ll effectively have the same outcome.
The PHP to do so would be reading out the following:
Header(“HTTP/1.1 301 Moved Permanently”);
Header(“Location: http://www.fullurltofile.com/this/file.zip“);
…and would open the potentiel risk of distributing the link (unless the location could be outta webscope, but that wouldn’t be possible
Moved permanently is also not the way around this, it’s a one time download file based on user selected and with watermarking of each file, but that you didn’t know.
I think the best solution is to build the file outside webscope, and readfile it from there… then delete it or run a clean up script once an hour, if safe mode is on (as it is now) if the customer want the users to see how far their downloads have progressed.
Kind regards
Kim
I’m pretty sure you can just take out the 301 header, but if you’re removing the file after it doesn’t matter because the file won’t exist anymore – it all functions the same as if you were to read the file out. Because it’s a server side redirect, they’re not actually presented with the URL, it will just download the file.
I’d just suggest giving it a go to save some server resources. But it’s totally up to you how you want to do it.
Cheers
Jason S
I’ll give it a try, thanks Jason
Works great, but you can’t add directories
I very rarely put comments on people sites but today it is worth it.
Your code works a treat on mac and pc.
Thanks
Andrew
This script just saved me!! I was using the one from Rochak Chauhan found at PHP Classes and couldn’t figure out how to implement the MAC end of it. Your script rocks. It was a piece of cake to work it into my code.
Thanks
Excelent code!! It saves my time
…I can use it to add multiple files in a zip. The final zip file opens properly even in PHP+window+localserver.
I’m using your zip method, but still getting:
Unable to unarchive “test.zip” into “test”.
(Error 1 – Operation not permitted.)
The code to zip I’m using is:
http://gist.github.com/353351
The archive ends up the proper size, but gives me the error. Am I missing a step?
Helps to get your || and && right doesn’t it
Edited the code to skip both “.” or “..”. All good.
Hi,
I have searched more than one days for mac os download zip issues.
Finally, i go the your script, it’s working prefectly.
Thanks for your support
Nice.
Got something weird though. If I run it on my WAMP installation on my desktop it works fine. However if I upload it to my hosting providers Linux based server the zipfile is a bit weird.
If I open the zipfile created from my hosting provider it seems to contain only a single file with the filename exactly the same as the zipfile itself but without an extension. If I open this with zip the actual zip comes out. It appears as if online it is zipped twice, or more likely the zipfile confuses my zip programs. I tried with WinRar and 7-zip. Both do exactly the same thing.
Hi Herman,
Make sure you have the files you’re zipping on your hosting providers site as this is likely the cause of the issue.
Any chance of getting the source? I really need to be able to add folders in my zip. Or, maybe, you could add the feature?
Nevermind, thought it was compressed.