1: <?php
2: // $Id: class.zipfile.php,v 1.1 2007/05/15 02:34:21 minahito Exp $
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: *
29: * @package kernel
30: * @subpackage core
31: */
32: class zipfile
33: {
34: /**
35: * Array to store compressed data
36: *
37: * @var array $datasec
38: */
39: var $datasec = array();
40:
41: /**
42: * Central directory
43: *
44: * @var array $ctrl_dir
45: */
46: var $ctrl_dir = array();
47:
48: /**
49: * End of central directory record
50: *
51: * @var string $eof_ctrl_dir
52: */
53: var $eof_ctrl_dir = "\x50\x4b\x05\x06\x00\x00\x00\x00";
54:
55: /**
56: * Last offset position
57: *
58: * @var integer $old_offset
59: */
60: var $old_offset = 0;
61:
62:
63: /**
64: * Converts an Unix timestamp to a four byte DOS date and time format (date
65: * in high two bytes, time in low two bytes allowing magnitude comparison).
66: *
67: * @param integer the current Unix timestamp
68: *
69: * @return integer the current date in a four byte DOS format
70: *
71: * @access private
72: */
73: function unix2DosTime($unixtime = 0)
74: {
75: $timearray = ($unixtime == 0) ? getdate() : getdate($unixtime);
76:
77: if ($timearray['year'] < 1980) {
78: $timearray['year'] = 1980;
79: $timearray['mon'] = 1;
80: $timearray['mday'] = 1;
81: $timearray['hours'] = 0;
82: $timearray['minutes'] = 0;
83: $timearray['seconds'] = 0;
84: } // end if
85:
86: return (($timearray['year'] - 1980) << 25) | ($timearray['mon'] << 21) | ($timearray['mday'] << 16) |
87: ($timearray['hours'] << 11) | ($timearray['minutes'] << 5) | ($timearray['seconds'] >> 1);
88: } // end of the 'unix2DosTime()' method
89:
90:
91: /**
92: * Adds "file" to archive
93: *
94: * @param string file contents
95: * @param string name of the file in the archive (may contains the path)
96: * @param integer the current timestamp
97: *
98: * @access public
99: */
100: function addFile($data, $name, $time = 0)
101: {
102: $name = str_replace('\\', '/', $name);
103:
104: $dtime = dechex($this->unix2DosTime($time));
105: $hexdtime = '\x' . $dtime[6] . $dtime[7]
106: . '\x' . $dtime[4] . $dtime[5]
107: . '\x' . $dtime[2] . $dtime[3]
108: . '\x' . $dtime[0] . $dtime[1];
109: eval('$hexdtime = "' . $hexdtime . '";');
110:
111: $fr = "\x50\x4b\x03\x04";
112: $fr .= "\x14\x00"; // ver needed to extract
113: $fr .= "\x00\x00"; // gen purpose bit flag
114: $fr .= "\x08\x00"; // compression method
115: $fr .= $hexdtime; // last mod time and date
116:
117: // "local file header" segment
118: $unc_len = strlen($data);
119: $crc = crc32($data);
120: $zdata = gzcompress($data);
121: $zdata = substr(substr($zdata, 0, strlen($zdata) - 4), 2); // fix crc bug
122: $c_len = strlen($zdata);
123: $fr .= pack('V', $crc); // crc32
124: $fr .= pack('V', $c_len); // compressed filesize
125: $fr .= pack('V', $unc_len); // uncompressed filesize
126: $fr .= pack('v', strlen($name)); // length of filename
127: $fr .= pack('v', 0); // extra field length
128: $fr .= $name;
129:
130: // "file data" segment
131: $fr .= $zdata;
132:
133: // "data descriptor" segment (optional but necessary if archive is not
134: // served as file)
135: $fr .= pack('V', $crc); // crc32
136: $fr .= pack('V', $c_len); // compressed filesize
137: $fr .= pack('V', $unc_len); // uncompressed filesize
138:
139: // add this entry to array
140: $this -> datasec[] = $fr;
141: $new_offset = strlen(implode('', $this->datasec));
142:
143: // now add to central directory record
144: $cdrec = "\x50\x4b\x01\x02";
145: $cdrec .= "\x00\x00"; // version made by
146: $cdrec .= "\x14\x00"; // version needed to extract
147: $cdrec .= "\x00\x00"; // gen purpose bit flag
148: $cdrec .= "\x08\x00"; // compression method
149: $cdrec .= $hexdtime; // last mod time & date
150: $cdrec .= pack('V', $crc); // crc32
151: $cdrec .= pack('V', $c_len); // compressed filesize
152: $cdrec .= pack('V', $unc_len); // uncompressed filesize
153: $cdrec .= pack('v', strlen($name) ); // length of filename
154: $cdrec .= pack('v', 0 ); // extra field length
155: $cdrec .= pack('v', 0 ); // file comment length
156: $cdrec .= pack('v', 0 ); // disk number start
157: $cdrec .= pack('v', 0 ); // internal file attributes
158: $cdrec .= pack('V', 32 ); // external file attributes - 'archive' bit set
159:
160: $cdrec .= pack('V', $this -> old_offset ); // relative offset of local header
161: $this -> old_offset = $new_offset;
162:
163: $cdrec .= $name;
164:
165: // optional extra field, file comment goes here
166: // save to central directory
167: $this -> ctrl_dir[] = $cdrec;
168: } // end of the 'addFile()' method
169:
170:
171: /**
172: * Dumps out file
173: *
174: * @return string the zipped file
175: *
176: * @access public
177: */
178: function file()
179: {
180: $data = implode('', $this -> datasec);
181: $ctrldir = implode('', $this -> ctrl_dir);
182:
183: return
184: $data .
185: $ctrldir .
186: $this -> eof_ctrl_dir .
187: pack('v', count($this -> ctrl_dir)) . // total # of entries "on this disk"
188: pack('v', count($this -> ctrl_dir)) . // total # of entries overall
189: pack('V', strlen($ctrldir)) . // size of central dir
190: pack('V', strlen($data)) . // offset to start of central dir
191: "\x00\x00"; // .zip file comment length
192: } // end of the 'file()' method
193:
194: } // end of the 'zipfile' class
195:
196: ?>