| 1 | <?php
|
|---|
| 2 | /* $Id: zip.lib.php 6461 2004-11-03 13:56:52Z garvinhicking $ */
|
|---|
| 3 | // vim: expandtab sw=4 ts=4 sts=4:
|
|---|
| 4 |
|
|---|
| 5 |
|
|---|
| 6 | /**
|
|---|
| 7 | * Zip file creation class.
|
|---|
| 8 | * Makes zip files.
|
|---|
| 9 | *
|
|---|
| 10 | * Based on :
|
|---|
| 11 | *
|
|---|
| 12 | * http://www.zend.com/codex.php?id=535&single=1
|
|---|
| 13 | * By Eric Mueller <eric@themepark.com>
|
|---|
| 14 | *
|
|---|
| 15 | * http://www.zend.com/codex.php?id=470&single=1
|
|---|
| 16 | * by Denis125 <webmaster@atlant.ru>
|
|---|
| 17 | *
|
|---|
| 18 | * a patch from Peter Listiak <mlady@users.sourceforge.net> for last modified
|
|---|
| 19 | * date and time of the compressed file
|
|---|
| 20 | *
|
|---|
| 21 | * Official ZIP file format: http://www.pkware.com/appnote.txt
|
|---|
| 22 | *
|
|---|
| 23 | * @access public
|
|---|
| 24 | */
|
|---|
| 25 | class zipfile
|
|---|
| 26 | {
|
|---|
| 27 | /**
|
|---|
| 28 | * Array to store compressed data
|
|---|
| 29 | *
|
|---|
| 30 | * @var array $datasec
|
|---|
| 31 | */
|
|---|
| 32 | var $datasec = array();
|
|---|
| 33 |
|
|---|
| 34 | /**
|
|---|
| 35 | * Central directory
|
|---|
| 36 | *
|
|---|
| 37 | * @var array $ctrl_dir
|
|---|
| 38 | */
|
|---|
| 39 | var $ctrl_dir = array();
|
|---|
| 40 |
|
|---|
| 41 | /**
|
|---|
| 42 | * End of central directory record
|
|---|
| 43 | *
|
|---|
| 44 | * @var string $eof_ctrl_dir
|
|---|
| 45 | */
|
|---|
| 46 | var $eof_ctrl_dir = "\x50\x4b\x05\x06\x00\x00\x00\x00";
|
|---|
| 47 |
|
|---|
| 48 | /**
|
|---|
| 49 | * Last offset position
|
|---|
| 50 | *
|
|---|
| 51 | * @var integer $old_offset
|
|---|
| 52 | */
|
|---|
| 53 | var $old_offset = 0;
|
|---|
| 54 |
|
|---|
| 55 |
|
|---|
| 56 | /**
|
|---|
| 57 | * Converts an Unix timestamp to a four byte DOS date and time format (date
|
|---|
| 58 | * in high two bytes, time in low two bytes allowing magnitude comparison).
|
|---|
| 59 | *
|
|---|
| 60 | * @param integer the current Unix timestamp
|
|---|
| 61 | *
|
|---|
| 62 | * @return integer the current date in a four byte DOS format
|
|---|
| 63 | *
|
|---|
| 64 | * @access private
|
|---|
| 65 | */
|
|---|
| 66 | function unix2DosTime($unixtime = 0) {
|
|---|
| 67 | $timearray = ($unixtime == 0) ? getdate() : getdate($unixtime);
|
|---|
| 68 |
|
|---|
| 69 | if ($timearray['year'] < 1980) {
|
|---|
| 70 | $timearray['year'] = 1980;
|
|---|
| 71 | $timearray['mon'] = 1;
|
|---|
| 72 | $timearray['mday'] = 1;
|
|---|
| 73 | $timearray['hours'] = 0;
|
|---|
| 74 | $timearray['minutes'] = 0;
|
|---|
| 75 | $timearray['seconds'] = 0;
|
|---|
| 76 | } // end if
|
|---|
| 77 |
|
|---|
| 78 | return (($timearray['year'] - 1980) << 25) | ($timearray['mon'] << 21) | ($timearray['mday'] << 16) |
|
|---|
| 79 | ($timearray['hours'] << 11) | ($timearray['minutes'] << 5) | ($timearray['seconds'] >> 1);
|
|---|
| 80 | } // end of the 'unix2DosTime()' method
|
|---|
| 81 |
|
|---|
| 82 |
|
|---|
| 83 | /**
|
|---|
| 84 | * Adds "file" to archive
|
|---|
| 85 | *
|
|---|
| 86 | * @param string file contents
|
|---|
| 87 | * @param string name of the file in the archive (may contains the path)
|
|---|
| 88 | * @param integer the current timestamp
|
|---|
| 89 | *
|
|---|
| 90 | * @access public
|
|---|
| 91 | */
|
|---|
| 92 | function addFile($data, $name, $time = 0)
|
|---|
| 93 | {
|
|---|
| 94 | $name = str_replace('\\', '/', $name);
|
|---|
| 95 |
|
|---|
| 96 | $dtime = dechex($this->unix2DosTime($time));
|
|---|
| 97 | $hexdtime = '\x' . $dtime[6] . $dtime[7]
|
|---|
| 98 | . '\x' . $dtime[4] . $dtime[5]
|
|---|
| 99 | . '\x' . $dtime[2] . $dtime[3]
|
|---|
| 100 | . '\x' . $dtime[0] . $dtime[1];
|
|---|
| 101 | eval('$hexdtime = "' . $hexdtime . '";');
|
|---|
| 102 |
|
|---|
| 103 | $fr = "\x50\x4b\x03\x04";
|
|---|
| 104 | $fr .= "\x14\x00"; // ver needed to extract
|
|---|
| 105 | $fr .= "\x00\x00"; // gen purpose bit flag
|
|---|
| 106 | $fr .= "\x08\x00"; // compression method
|
|---|
| 107 | $fr .= $hexdtime; // last mod time and date
|
|---|
| 108 |
|
|---|
| 109 | // "local file header" segment
|
|---|
| 110 | $unc_len = strlen($data);
|
|---|
| 111 | $crc = crc32($data);
|
|---|
| 112 | $zdata = gzcompress($data);
|
|---|
| 113 | $zdata = substr(substr($zdata, 0, strlen($zdata) - 4), 2); // fix crc bug
|
|---|
| 114 | $c_len = strlen($zdata);
|
|---|
| 115 | $fr .= pack('V', $crc); // crc32
|
|---|
| 116 | $fr .= pack('V', $c_len); // compressed filesize
|
|---|
| 117 | $fr .= pack('V', $unc_len); // uncompressed filesize
|
|---|
| 118 | $fr .= pack('v', strlen($name)); // length of filename
|
|---|
| 119 | $fr .= pack('v', 0); // extra field length
|
|---|
| 120 | $fr .= $name;
|
|---|
| 121 |
|
|---|
| 122 | // "file data" segment
|
|---|
| 123 | $fr .= $zdata;
|
|---|
| 124 |
|
|---|
| 125 | // "data descriptor" segment (optional but necessary if archive is not
|
|---|
| 126 | // served as file)
|
|---|
| 127 | // nijel(2004-10-19): this seems not to be needed at all and causes
|
|---|
| 128 | // problems in some cases (bug #1037737)
|
|---|
| 129 | //$fr .= pack('V', $crc); // crc32
|
|---|
| 130 | //$fr .= pack('V', $c_len); // compressed filesize
|
|---|
| 131 | //$fr .= pack('V', $unc_len); // uncompressed filesize
|
|---|
| 132 |
|
|---|
| 133 | // add this entry to array
|
|---|
| 134 | $this -> datasec[] = $fr;
|
|---|
| 135 |
|
|---|
| 136 | // now add to central directory record
|
|---|
| 137 | $cdrec = "\x50\x4b\x01\x02";
|
|---|
| 138 | $cdrec .= "\x00\x00"; // version made by
|
|---|
| 139 | $cdrec .= "\x14\x00"; // version needed to extract
|
|---|
| 140 | $cdrec .= "\x00\x00"; // gen purpose bit flag
|
|---|
| 141 | $cdrec .= "\x08\x00"; // compression method
|
|---|
| 142 | $cdrec .= $hexdtime; // last mod time & date
|
|---|
| 143 | $cdrec .= pack('V', $crc); // crc32
|
|---|
| 144 | $cdrec .= pack('V', $c_len); // compressed filesize
|
|---|
| 145 | $cdrec .= pack('V', $unc_len); // uncompressed filesize
|
|---|
| 146 | $cdrec .= pack('v', strlen($name) ); // length of filename
|
|---|
| 147 | $cdrec .= pack('v', 0 ); // extra field length
|
|---|
| 148 | $cdrec .= pack('v', 0 ); // file comment length
|
|---|
| 149 | $cdrec .= pack('v', 0 ); // disk number start
|
|---|
| 150 | $cdrec .= pack('v', 0 ); // internal file attributes
|
|---|
| 151 | $cdrec .= pack('V', 32 ); // external file attributes - 'archive' bit set
|
|---|
| 152 |
|
|---|
| 153 | $cdrec .= pack('V', $this -> old_offset ); // relative offset of local header
|
|---|
| 154 | $this -> old_offset += strlen($fr);
|
|---|
| 155 |
|
|---|
| 156 | $cdrec .= $name;
|
|---|
| 157 |
|
|---|
| 158 | // optional extra field, file comment goes here
|
|---|
| 159 | // save to central directory
|
|---|
| 160 | $this -> ctrl_dir[] = $cdrec;
|
|---|
| 161 | } // end of the 'addFile()' method
|
|---|
| 162 |
|
|---|
| 163 |
|
|---|
| 164 | /**
|
|---|
| 165 | * Dumps out file
|
|---|
| 166 | *
|
|---|
| 167 | * @return string the zipped file
|
|---|
| 168 | *
|
|---|
| 169 | * @access public
|
|---|
| 170 | */
|
|---|
| 171 | function file()
|
|---|
| 172 | {
|
|---|
| 173 | $data = implode('', $this -> datasec);
|
|---|
| 174 | $ctrldir = implode('', $this -> ctrl_dir);
|
|---|
| 175 |
|
|---|
| 176 | return
|
|---|
| 177 | $data .
|
|---|
| 178 | $ctrldir .
|
|---|
| 179 | $this -> eof_ctrl_dir .
|
|---|
| 180 | pack('v', sizeof($this -> ctrl_dir)) . // total # of entries "on this disk"
|
|---|
| 181 | pack('v', sizeof($this -> ctrl_dir)) . // total # of entries overall
|
|---|
| 182 | pack('V', strlen($ctrldir)) . // size of central dir
|
|---|
| 183 | pack('V', strlen($data)) . // offset to start of central dir
|
|---|
| 184 | "\x00\x00"; // .zip file comment length
|
|---|
| 185 | } // end of the 'file()' method
|
|---|
| 186 |
|
|---|
| 187 | } // end of the 'zipfile' class
|
|---|