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