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
|
---|