UPDATE: You are better off using the library mentioned in this post.
As part of my previously mentioned OpenVPN CA I want to deliver keys, certs and config files to users in a single zip file that they can just extract onto their computers. PHP's own ZIP File Functions only supports reading zip files and not making them.
Some Googling discovered an article by John Coggeshall that can create zip files. It does this by creating the binary data on the fly and can output the zip files directly to the browser from memory or by writing it to disk.
I had some troubles getting hold of a usable version of this code since all these PHP code collection sites have this annoying habit of only showing the syntax highlighted versions of the code rather than give a download link. Eventually got one though and I figured I'll host a mirror of it here to help people out.
Using it is very simple, this is a quick sample that will create a ZIP file and add one directory and one file into then send it directly to the client.
<?
require ("incl/zipfile.inc.php");
$zipfile = new zipfile();
$filedata = implode("", file("incl/zipfile.inc.php"));
$zipfile->add_dir("incl/");
$zipfile->add_file($filedata, "incl/zipfile.inc.php");
header("Content-type: application/octet-stream");
header("Content-disposition: attachment; filename=zipfile.zip");
echo $zipfile->file();
?>

What's wrong with using gzcompress()/gzdeflate()/gzencode() in the zlib extension?
In the class it uses the gzcompress() function to compress the actual data, but this also puts all the various bits in to make a actual ZIP file as usable by Windows rather than gzip files.
some aprovement .. anyhow .. thx a lot
Hendrik
>> zipfile.inc.php datasec[] = $fr;
$new_offset = strlen(implode("", $this->datasec));
// ext. file attributes mirrors MS-DOS directory attr byte, detailed
// at http://support.microsoft.com/support/kb/articles/Q125/0/19.asp
// now add to central record
$cdrec = "\x50\x4b\x01\x02";
$cdrec .="\x00\x00"; // version made by
if (strtoupper($type) == "DIRECTORY") {
$cdrec .="\x0a\x00"; // version needed to extract
$cdrec .="\x00\x00"; // gen purpose bit flag
$cdrec .="\x00\x00"; // compression method
}
if (strtoupper($type) == "FILE") {
$cdrec .="\x14\x00"; // version needed to extract
$cdrec .="\x00\x00"; // gen purpose bit flag
$cdrec .="\x08\x00"; // compression method
}
$cdrec .="\x00\x00\x00\x00"; // last mod time & date
$cdrec .= pack("V",$crc); // crc32
$cdrec .= pack("V",$c_len); // compressed filesize
$cdrec .= pack("V",$unc_len); // uncompressed filesize
$cdrec .= pack("v", strlen($name) ); // length of filename
$cdrec .= pack("v", 0 ); // extra field length
$cdrec .= pack("v", 0 ); // file comment length
$cdrec .= pack("v", 0 ); // disk number start
$cdrec .= pack("v", 0 ); // internal file attributes
if (strtoupper($type) == "DIRECTORY") {
$cdrec .= pack("V", 16 ); // external file attributes - 'directory' bit set
}
if (strtoupper($type) == "FILE") {
$cdrec .= pack("V", 32 ); // external file attributes - 'archive' bit set
}
$cdrec .= pack("V", $this -> old_offset ); // relative offset of local header
// echo "old offset is ".$this->old_offset.", new offset is $new_offset";
$this -> old_offset = $new_offset;
$cdrec .= $name;
// optional extra field, file comment goes here
// save to central directory
$this -> ctrl_dir[] = $cdrec;
}
function file() {
// dump out file
$data = implode("", $this -> datasec);
$ctrldir = implode("", $this -> ctrl_dir);
return
$data.
$ctrldir.
$this -> eof_ctrl_dir.
pack("v", sizeof($this -> ctrl_dir)). // total # of entries "on this disk"
pack("v", sizeof($this -> ctrl_dir)). // total # of entries overall
pack("V", strlen($ctrldir)). // size of central dir
pack("V", strlen($data)). // offset to start of central dir
"\x00\x00"; // .zip file comment length
}
}
#--------------------------------------------- Hendrik Muus
# require ("zipfile.inc.php");
#
# $zipfile = new zipfile();
#
# $zipfile->add_entry("directory", "testme/", "");
# $zipfile->add_entry("file", "testme/test.file.bin", implode("", file("test.file.bin")));
#
# header("Content-Type: archive/zip\n\n"); // this gives you a nice open / save dialog ;o)
# header("Content-disposition: attachment; filename=zipfile.zip");
#
# echo $zipfile->file();
#---------------------------------------------
?>
Hi, can we use this class in commercial products ?
I don't see any licence info.
Unsure, but like I said on the first line of this posting, its shitty, use the other one, see the link right on top of this post.
Here you can find class + demo + class manual
http://www.smiledsoft.com/demos/phpzip/
for class which you will start using in minutes after installation.
Clear demos explain how to use every function.
A lot of features.
Free version is capable of creating ZIPs only.
Pro is capable to extract files and more.
Please visit
http://www.smiledsoft.com/demos/phpzip/
How can you put all the files of a directory into a zip file without knowing the files?
Hello,
Is there a limit to the number of files that can be zipped up as I am using this script and I get an error "Allowed memory size of 16777216 bytes exhausted" when trying it with a large number of files.
Thanks
Do somebody nkow how could we ask the script to copy the generated zipped file somewhere else on the server rather than user the headers to force the download of the file?
The poster commented in his alternate solution:
"I did some more testing with the code I posted yesterday and found it isn't 100% compatible with some unzip programs. Works with unix unzip, Mac OS X default tool, WinZip, WinRAR but annoyingly not with the default XP zip folder thing."
I had this problem as well but then I discovered that I was accidentally putting superfluous data in my zip file -- some php warning messages were being included as part of the zip file that the user was downloading.
I cleaned up the warnings and now my zip files are working even with the default XP zip folder thing (I don't actually have a better name for that than the one used above ;).
If you have a problem with the zip file you create using this script open the zip file with wordpad and take a look to see if you aren't accidentally putting in data that you don't need.
W
Does this lib support password protection for the zip.?
Problem at hand was to use PEAR Spreadsheet Excel Writer to have php generate multiple spreadsheets, put them in a zip file, and provide the zip file as a download to a user. After about 2 days I got it all to work including using IE.
Basically, first I generate the spreadsheets and save them in a tmp location on the server. Then I insert them into a zip file class one by one and delete the original spreadsheet files. After repeating the process for a few spreadsheets, I dump the zip file.
Hope it helps someone. Here's the code:
===================================================================
export.php
require_once 'class.zipfile.php';
require_once 'Spreadsheet/Excel/Writer.php';
// Generate zip file with containg current spreadsheet file
$zipfile = new zipfile();
//$filedata = 'testing direct input';
// Zip file http headers
$user_browser = $root->check_user_browser();
if ($user_browser == 'IE') header("Content-type: application/zip");
else header("Content-type: application/octet-stream");
header("Content-disposition: attachment; filename=\"filename.zip\"");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0,pre-check=0");
header("Pragma: public"); // IE doesn't work without this
foreach($report_names as $name) {
$filename = $name;
// Generate report for current name and save to /tmp
include './export.excelfile.php';
// Add temp spreadsheet from the include above to the zip file
$filedata = implode("", file('/tmp/'.$filename.'.xls'));
// Add the filedata to the zip file with the correct filename
$zipfile->add_file($filedata, $filename.'.xls');
// delete the current file from temporary storage
unlink('/tmp/'.$filename.'.xls');
}
// Send the zip file to browser
echo $zipfile->file();
===================================================================
export.excelfile.php
Note: "/tmp" must be world writable, ie. apache must be able to write (777)
// Save current spreadsheet to the server hard drive
unset($workbook);
$workbook = new Spreadsheet_Excel_Writer('/tmp/'.$filename.'.xls');
$workbook->setVersion(8);
$workbook->setTempDir(/tmp);
// Set styles and formats
include "export.format.php";
$worksheet =& $workbook->addWorksheet('sheet_name');
$worksheet->setLandscape();
// Grab actual data
$query = 'SELECT DISTINCT * FROM `' . $table_name . '`';
$res = $db->_query($query);
// Data Header Row and similar for data
for ($i = 0; $i mysql_num_fields($res); ++$i) {
$worksheet->writeString(0, $i, $db->mysql_field_name($res, $i), $formats[DATA_HEADER]);
}
// Close the file
$workbook->close();
===================================================================
export.format.php
// defines and custom colours
define('DATA_HEADER', 1);
$workbook->setCustomColor(63, 117, 151, 170); // header text color
// Global style and font
$formats = array();
$common_format = array('font' => 'Arial',
'size' => 8,
'align' => 'center',
'valign' => 'bottom',
'textwrap' => 1
);
// EXCEL DATA HEADER
$formats[DATA_HEADER] =& $workbook->addformat($common_format);
$formats[DATA_HEADER]->setColor(1); // text color
$formats[DATA_HEADER]->setBold();
$formats[DATA_HEADER]->setFgColor(63); // cell color
$formats[DATA_HEADER]->setBorderColor(60); // border styling
$formats[DATA_HEADER]->setTop(2);
$formats[DATA_HEADER]->setBottom(2);
$formats[DATA_HEADER]->setLeft(1);
$formats[DATA_HEADER]->setRight(1);
===================================================================
class.zipfile.php
by Eric Mueller
http://www.themepark.com
http://www.devco.net/archives/2005/05/24/creating_zip_files_with_php.php
http://www.devco.net/code/zipfile.inc.txt
but where is the zipfile.inc.php