/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Copyright ©2006 by sTEFANs
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* This file contains a classes for creating ZIP archive files.ed.
* @license http://opensource.org/licenses/lgpl-license.php GNU General Public License
* Zip file creation class.
* http://www.zend.com/codex.php?id=535&single=1
* By Eric Mueller <eric@themepark.com>
* http://www.zend.com/codex.php?id=470&single=1
* by Denis125 <webmaster@atlant.ru>
* http://www.traum-projekt.com/forum/sitemap/t-62354.html
* by Peter Listiak <mlady@users.sourceforge.net>, pathch for last modified
* date and time of the compressed file
* Interface and public methods by Stefan Schraml
* Official ZIP file format: http://www.pkware.com/appnote.txt
* Array to store compressed data
private $datasec =
array(); // array to store compressed data
private $ctrl_dir =
array(); // central directory
* End of central directory record
* @var string $eof_ctrl_dir
private $eof_ctrl_dir =
"\x50\x4b\x05\x06\x00\x00\x00\x00"; //end of Central directory record
* @var integer $old_offset
* Adds the given file or directory tree to the archive.
* @param string $path File or directory to zip. If a directory is given, the content
* (all the files and subdirectories) will be added to the archive.
* @param boolean $recursive If set to TRUE, content of the given directory and all its
* sub directories will be added to the archive. Otherwise only the content of directory is added.
* Has no effect $path is a file.
* @return boolean TRUE if zipping was successful.
function zip($path, $recursive =
true){
* Adds the given file or directory tree to the archive.
* @param string $path File or directory to zip. If a directory is given, the content
* (all the files and subdirectories) will be added to the archive.
* @param string $search_pattern If it is not NULL, it defines the part of $path which will
* be replaced by $replace_pattern.
* @param string $replace_pattern Text which is substituted for $search_pattern. If it is
* set NULL, $search_pattern will be replaced by empty ("").
* @param boolean $recursive If set to TRUE, content of the given directory and all its
* sub directories will be added to the archive. Otherwise only the content of directory is added.
* Has no effect $path is a file.
* @return boolean TRUE if zipping was successful.
function zipReplacePath($path, $search_pattern, $replace_pattern, $recursive =
true){
if ($search_pattern !=
NULL){
$replace_pattern =
($replace_pattern ==
NULL ?
"" :
$replace_pattern);
$name =
str_replace($search_pattern, $replace_pattern, $path);
if (strpos($name, "/") ===
0){
// Removed because it doesn't work
// $this->addDir($name, filemtime($src));
while ($rc &&
$obj =
@readdir($dh)){
if($obj !=
'.' &&
$obj !=
'..'){
if ($recursive ||
!@is_dir($path)){
$rc =
$this->zipReplacePath($path, $search_pattern, $replace_pattern, $recursive);
* Writes the archive to the given path.
* @param string $path Path for the ZIP-File (e.g. /mydir/myfile.zip).
$fh =
fopen($path, 'wb');
* Don't really know what it does. If method is invoked to add a directory
* to the archive, LINUX zip (Zip 2.3 (November 29th 1999), by Info-ZIP)
* is not able to extract the archive. I leave it for the reason
* of completness but it's not invoked anymore (and this works great!).
* <b>Note: The following description is wrong!</b><br>
* Adds the given directory path into archive.
* Do this before putting any files in directory!
* E.g. add "path/" before adding file "path/file.txt".
* @param string name of the directory in the archive (e.g. "path/").
* @param integer the current unix-style timestamp
function addDir($name, $timestamp =
0){
$fr =
"\x50\x4b\x03\x04";
$fr .=
"\x0a\x00"; // ver needed to extract
$fr .=
"\x00\x00"; // gen purpose bit flag
$fr .=
"\x00\x00"; // compression method
$fr .=
$hexdtime; // last mod time and date
$fr .=
pack("V",0); // crc32
$fr .=
pack("V",0); //compressed filesize
$fr .=
pack("V",0); //uncompressed filesize
$fr .=
pack("v", strlen($name) ); //length of pathname
$fr .=
pack("v", 0 ); //extra field length
// end of "local file header" segment
// no "file data" segment for path
// "data descriptor" segment (optional but necessary if archive is not served as file)
$fr .=
pack("V",$crc); //crc32
$fr .=
pack("V",$c_len); //compressed filesize
$fr .=
pack("V",$unc_len); //uncompressed filesize
// add this entry to array
// 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
$cdrec .=
"\x0a\x00"; // version needed to extract
$cdrec .=
"\x00\x00"; // gen purpose bit flag
$cdrec .=
"\x00\x00"; // compression method
$cdrec .=
$hexdtime; // last mod time & date
$cdrec .=
pack("V",0); // crc32
$cdrec .=
pack("V",0); //compressed filesize
$cdrec .=
pack("V",0); //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
$ext =
"\x00\x00\x10\x00";
$ext =
"\xff\xff\xff\xff";
$cdrec .=
pack("V", 16 ); //external file attributes - 'directory' bit set
$cdrec .=
pack("V", $this -> old_offset ); //relative offset of local header
// optional extra field, file comment goes here
* @param string data content
* @param string name of the file in the archive (may contains the path).
* Path must have been added previously via <i>addDir</i>
* @param integer the current unix-style timestamp
function addFile($data, $name, $timestamp =
0)
$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
$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
// end of "local file header" segment
// "data descriptor" segment (optional but necessary if archive is not served as file)
$fr .=
pack("V",$crc); //crc32
$fr .=
pack("V",$c_len); //compressed filesize
$fr .=
pack("V",$unc_len); //uncompressed filesize
// add this entry to array
// 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 ); //external file attributes - 'archive' bit set
$cdrec .=
pack("V", $this -> old_offset ); //relative offset of local header
// &n // bsp; echo "old offset is ".$this->old_offset.", new offset is $new_offset<br>";
// optional extra field, file comment goes here
// save to central directory
* Returns the archive file content.
* @return Binary content of ZIP file.
pack("V", strlen($ctrldir)).
// size of central dir
pack("V", strlen($data)).
// offset to start of central dir
"\x00\x00"; // .zip file comment length
* Returns timestamp in format needed by zip archive.
* @param int $timestamp UNIX timestamp.
* @return string Timestamp encoded to ZIP format.
$hexdtime =
"\x00\x00\x00\x00";
$hexdtime =
'\x'.
$dtime[6].
$dtime[7]
.
'\x'.
$dtime[4].
$dtime[5]
.
'\x'.
$dtime[2].
$dtime[3]
.
'\x'.
$dtime[0].
$dtime[1];
eval
('$hexdtime = "' .
$hexdtime .
'";');
* 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
if ($timearray['year'] <
1980) {
$timearray['year'] =
1980;
$timearray['minutes'] =
0;
$timearray['seconds'] =
0;
return (($timearray['year'] -
1980) <<
25) |
($timearray['mon'] <<
21) |
($timearray['mday'] <<
16) |
($timearray['hours'] <<
11) |
($timearray['minutes'] <<
5) |
($timearray['seconds'] >>
1);