Page 1 of 1
To Zip Folder
Posted: Wed Dec 08, 2004 6:08 pm
by Shendemiar
How do i zip a folder, and all of it's contents (maintaining the structure)
I cannot use EXEC
The file can stay at the server and be overwritten each time.
[EDITED]
Posted: Wed Dec 08, 2004 6:14 pm
by redmonkey
Depends on which zip class you are using (there are plenty out there)? some (most) will work by you scripting something to parse each directory in question and then read each file in and pass it to the zip class.
I very much doubt you can continually write the output to the same zip file as you may end up with two or more people requesting the page within a short space of time which could result in one user trying to download a file that is currently being written to.
Posted: Wed Dec 08, 2004 7:31 pm
by dull1554
so have a database where for every zip file that would be created and downloaded there is a row with file name and a status value, when the script starts running set the status to 1 for active, and that way you could have the script check if its active, if its active that person will have to wait till the first user is done downloading the file and the have that script update the db and set status back to 0
something like that might work.....
Posted: Wed Dec 08, 2004 8:14 pm
by Christopher
їphp]if (file_exists($filename)) {
unlink($filename);
}
exec("zip $filename $directory");
header('Content-type: application/zip');
header('Content-Transfer-Encoding: Binary');
header('Content-length: ' . filesize($filename));
readfile($filename);
ї/php]
?>
Posted: Thu Dec 09, 2004 9:52 am
by Shendemiar
No problem about multiple users, so i can just skip that problem. The last post seems promising, thanks.
Posted: Wed Dec 29, 2004 8:18 am
by Shendemiar
Couldnt i just execute the system's zip command with parameters?
Posted: Wed Dec 29, 2004 8:24 am
by feyd
that's what arborint's example does.

Posted: Wed Dec 29, 2004 8:58 am
by Shendemiar
Seems like i cant exec anything.
What's the alternative?
Somekind of recursive funtion to collect the stuff and then zip it. With memory reservation/problems etc. Way out of my league...
And yes, lets drop the download for now.
Posted: Wed Dec 29, 2004 12:25 pm
by Joe
This class works great: (with thanks to Zend)
Code: Select all
<?php
class PHPZip
{
function Zip($dir, $zipfilename)
{
if (function_exists('gzcompress'))
$curdir = getcwd();
if (is_array($dir))
{
$filelist = $dir;
}
else
{
$filelist = $this -> GetFileList($dir);
}
if ((!empty($dir))&&(!is_array($dir))&&(file_exists($dir))) chdir($dir);
else chdir($curdir);
if (count($filelist)>0)
{
foreach($filelist as $filename)
{
if (is_file($filename))
{
$fd = fopen ($filename, "r");
$content = fread ($fd, filesize ($filename));
fclose ($fd);
if (is_array($dir)) $filename = basename($filename);
$this -> addFile($content, $filename);
}
}
$out = $this -> file();
chdir($curdir);
$fp = fopen($zipfilename, "w");
fwrite($fp, $out, strlen($out));
fclose($fp);
}
return 1;
}
function GetFileList($dir)
{
if (file_exists($dir))
{
$args = func_get_args();
$pref = $args[1];
$dh = opendir($dir);
while($files = readdir($dh))
{
if (($files!=".")&&($files!=".."))
{
if (is_dir($dir.$files))
{
$curdir = getcwd();
chdir($dir.$files);
$file = array_merge($file, $this -> GetFileList("", "$pref$files/"));
chdir($curdir);
}
else $file[]=$pref.$files;
}
}
closedir($dh);
}
return $file;
}
var $datasec = array();
var $ctrl_dir = array();
var $eof_ctrl_dir = "\x50\x4b\x05\x06\x00\x00\x00\x00";
var $old_offset = 0;
/**
* Converts an Unix timestamp to a four byte DOS date and time format
(date
* in high two bytes, time in low two bytes allowing magnitude
comparison).
*
* param integer the current Unix timestamp
*
* return integer the current date in a four byte DOS format
*
* access private
*/
function unix2DosTime($unixtime = 0) {
$timearray = ($unixtime == 0) ? getdate() : getdate($unixtime);
if ($timearray['year'] < 1980) {
$timearray['year'] = 1980;
$timearray['mon'] = 1;
$timearray['mday'] = 1;
$timearray['hours'] = 0;
$timearray['minutes'] = 0;
$timearray['seconds'] = 0;
} // end if
return (($timearray['year'] - 1980) << 25) | ($timearray['mon'] <<
21) | ($timearray['mday'] << 16) |
($timearray['hours'] << 11) | ($timearray['minutes'] << 5) |
($timearray['seconds'] >> 1);
} // end of the 'unix2DosTime()' method
/**
* Adds "file" to archive
*
* param string file contents
* param string name of the file in the archive (may contains the
path)
* param integer the current timestamp
*
* access public
*/
function addFile($data, $name, $time = 0)
{
$data = str_replace("\x0a", "\x0d\x0a", $data);
$name = str_replace('\'', '/', $name);
$dtime = dechex($this->unix2DosTime($time));
$hexdtime = '\x' . $dtime[6] . $dtime[7]
. '\x' . $dtime[4] . $dtime[5]
. '\x' . $dtime[2] . $dtime[3]
. '\x' . $dtime[0] . $dtime[1];
eval('$hexdtime = "' . $hexdtime . '";');
$fr = "\x50\x4b\x03\x04";
$fr .= "\x14\x00"; // ver needed to extract
$fr .= "\x00\x00"; // gen purpose bit flag
$fr .= "\x08\x00"; // compression method
$fr .= $hexdtime; // last mod time and date
// "local file header" segment
$unc_len = strlen($data);
$crc = crc32($data);
$zdata = gzcompress($data);
$c_len = strlen($zdata);
$zdata = substr(substr($zdata, 0, strlen($zdata) - 4), 2);
$fr .= pack('V', $crc); // crc32
$fr .= pack('V', $c_len); // compressed filesize
$fr .= pack('V', $unc_len); // uncompressed filesize
$fr .= pack('v', strlen($name)); // length of filename
$fr .= pack('v', 0); // extra field length
$fr .= $name;
// "file data" segment
$fr .= $zdata;
$fr .= pack('V', $crc); // crc32
$fr .= pack('V', $c_len); // compressed filesize
$fr .= pack('V', $unc_len); // uncompressed filesize
// add this entry to array
$this -> datasec[] = $fr;
$new_offset = strlen(implode('', $this->datasec));
// now add to central directory record
$cdrec = "\x50\x4b\x01\x02";
$cdrec .= "\x00\x00"; // version made by
$cdrec .= "\x14\x00"; // version needed to extract
$cdrec .= "\x00\x00"; // gen purpose bit flag
$cdrec .= "\x08\x00"; // compression method
$cdrec .= $hexdtime; // 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
$cdrec .= pack('V', 32 );
$cdrec .= pack('V', $this -> old_offset );
$this -> old_offset = $new_offset;
$cdrec .= $name;
// optional extra field, file comment goes here
// save to central directory
$this -> ctrl_dir[] = $cdrec;
} // end of the 'addFile()' method
/**
* Dumps out file
*
* return string the zipped file
*
* access public
*/
function file()
{
$data = implode('', $this -> datasec);
$ctrldir = implode('', $this -> ctrl_dir);
return
$data .
$ctrldir .
$this -> eof_ctrl_dir .
pack('v', sizeof($this -> ctrl_dir)) .
pack('v', sizeof($this -> ctrl_dir)) .
pack('V', strlen($ctrldir)) . // size of central dir
pack('V', strlen($data)) .
"\x00\x00";
} // end of the 'file()' method
} // end of the 'PHPZip' class
?>
And zip a dir by implementing the class using this procedure:
Code: Select all
$directory = "home/public_html";
$filename = "file.zip";
$zipfile = new PHPZip();
$zipfile -> Zip($directory, $filename);
I have used this many times with no problems.
Posted: Wed Dec 29, 2004 12:38 pm
by Shendemiar
Joe wrote:This class works great: (with thanks to Zend)
Great thanks.
(I can't stop wondering this forum's greatness...)
Posted: Wed Dec 29, 2004 12:44 pm
by Joe
No problem

Posted: Wed Dec 29, 2004 5:46 pm
by Shendemiar
Works ok for some folders but for one i need it gives:
I get undefined offset in line 56 (of that code)
Posted: Thu Dec 30, 2004 9:45 am
by redmonkey
I could be wrong as I haven't tested it but I suspect the above class will have problems with recursion into sub directories (i.e. it won't). It also uses some strange choices of functions (in my mind).