2 /* vim: set expandtab sw=4 ts=4 sts=4: */
6 * ZIP file unpack classes. Contributed to the phpMyAdmin project.
9 * @package File-Formats-ZIP
11 * @filesource unzip.lib.php
14 * @author Holger Boskugel <vbwebprofi@gmx.de>
15 * @copyright Copyright © 2003, Holger Boskugel, Berlin, Germany
16 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
19 * 2003-12-02 - HB : Patched : naming bug : Time/Size of file
20 * Added : ZIP file comment
21 * Added : Check BZIP2 support of PHP
22 * 2003-11-29 - HB * Initial version
26 * Unzip class, which retrieves entries from ZIP files.
28 * Supports only the compression modes
35 * {@link http://www.pkware.com/products/enterprise/white_papers/appnote.html
36 * * Official ZIP file format}<BR>
37 * {@link http://msdn.microsoft.com/library/en-us/w98ddk/hh/w98ddk/storage_5l4m.asp
38 * * Microsoft DOS date/time format}
41 * @package File-Formats-ZIP
44 * @author Holger Boskugel <vbwebprofi@gmx.de>
45 * @uses SimpleUnzipEntry
46 * @example example.unzip.php Two examples
51 * Array to store file entries
62 * Array to store file entries
69 var $Entries = array();
72 * Name of the ZIP file
82 * Size of the ZIP file
92 * Time of the ZIP file (unix timestamp)
102 * Contructor of the class
104 * @param string File name
105 * @return SimpleUnzip Instanced class
107 * @uses SimpleUnzip::ReadFile() Opens file on new if specified
110 function SimpleUnzip($in_FileName = '')
112 if ($in_FileName !== '') {
113 SimpleUnzip
::ReadFile($in_FileName);
115 } // end of the 'SimpleUnzip' constructor
120 * @return integer Count of ZIP entries
127 return count($this->Entries
);
128 } // end of the 'Count()' method
131 * Gets data of the specified ZIP entry
133 * @param integer Index of the ZIP entry
134 * @return mixed Data for the ZIP entry
135 * @uses SimpleUnzipEntry::$Data
139 function GetData($in_Index)
141 return $this->Entries
[$in_Index]->Data
;
142 } // end of the 'GetData()' method
145 * Gets an entry of the ZIP file
147 * @param integer Index of the ZIP entry
148 * @return SimpleUnzipEntry Entry of the ZIP file
153 function GetEntry($in_Index)
155 return $this->Entries
[$in_Index];
156 } // end of the 'GetEntry()' method
159 * Gets error code for the specified ZIP entry
161 * @param integer Index of the ZIP entry
162 * @return integer Error code for the ZIP entry
163 * @uses SimpleUnzipEntry::$Error
167 function GetError($in_Index)
169 return $this->Entries
[$in_Index]->Error
;
170 } // end of the 'GetError()' method
173 * Gets error message for the specified ZIP entry
175 * @param integer Index of the ZIP entry
176 * @return string Error message for the ZIP entry
177 * @uses SimpleUnzipEntry::$ErrorMsg
181 function GetErrorMsg($in_Index)
183 return $this->Entries
[$in_Index]->ErrorMsg
;
184 } // end of the 'GetErrorMsg()' method
187 * Gets file name for the specified ZIP entry
189 * @param integer Index of the ZIP entry
190 * @return string File name for the ZIP entry
191 * @uses SimpleUnzipEntry::$Name
195 function GetName($in_Index)
197 return $this->Entries
[$in_Index]->Name
;
198 } // end of the 'GetName()' method
201 * Gets path of the file for the specified ZIP entry
203 * @param integer Index of the ZIP entry
204 * @return string Path of the file for the ZIP entry
205 * @uses SimpleUnzipEntry::$Path
209 function GetPath($in_Index)
211 return $this->Entries
[$in_Index]->Path
;
212 } // end of the 'GetPath()' method
215 * Gets file time for the specified ZIP entry
217 * @param integer Index of the ZIP entry
218 * @return integer File time for the ZIP entry (unix timestamp)
219 * @uses SimpleUnzipEntry::$Time
223 function GetTime($in_Index)
225 return $this->Entries
[$in_Index]->Time
;
226 } // end of the 'GetTime()' method
229 * Reads ZIP file and extracts the entries
231 * @param string File name of the ZIP archive
232 * @return array ZIP entry list (see also class variable {@link $Entries $Entries})
233 * @uses SimpleUnzipEntry For the entries
237 function ReadFile($in_FileName)
239 $this->Entries
= array();
241 // Get file parameters
242 $this->Name
= $in_FileName;
243 $this->Time
= filemtime($in_FileName);
244 $this->Size
= filesize($in_FileName);
247 $oF = fopen($in_FileName, 'rb');
248 $vZ = fread($oF, $this->Size
);
252 // Cut end of central directory
253 $aE = explode("\x50\x4b\x05\x06", $vZ);
255 // Easiest way, but not sure if format changes
256 //$this->Comment = substr($aE[1], 18);
259 $aP = unpack('x16/v1CL', $aE[1]);
260 $this->Comment
= substr($aE[1], 18, $aP['CL']);
262 // Translates end of line from other operating systems
263 $this->Comment
= strtr($this->Comment
, array("\r\n" => "\n",
267 // Cut the entries from the central directory
268 $aE = explode("\x50\x4b\x01\x02", $vZ);
269 // Explode to each part
270 $aE = explode("\x50\x4b\x03\x04", $aE[0]);
271 // Shift out spanning signature or empty entry
274 // Loop through the entries
275 foreach ($aE as $vZ) {
279 // Retrieving local file header information
280 $aP = unpack('v1VN/v1GPF/v1CM/v1FT/v1FD/V1CRC/V1CS/V1UCS/v1FNL', $vZ);
281 // Check if data is encrypted
282 $bE = ($aP['GPF'] & 0x0001) ?
TRUE : FALSE;
285 // Special case : value block after the compressed data
286 if ($aP['GPF'] & 0x0008) {
287 $aP1 = unpack('V1CRC/V1CS/V1UCS', substr($vZ, -12));
289 $aP['CRC'] = $aP1['CRC'];
290 $aP['CS'] = $aP1['CS'];
291 $aP['UCS'] = $aP1['UCS'];
293 $vZ = substr($vZ, 0, -12);
296 // Getting stored filename
297 $aI['N'] = substr($vZ, 26, $nF);
299 if (substr($aI['N'], -1) == '/') {
300 // is a directory entry - will be skipped
304 // Truncate full filename in path and filename
305 $aI['P'] = dirname($aI['N']);
306 $aI['P'] = $aI['P'] == '.' ?
'' : $aI['P'];
307 $aI['N'] = basename($aI['N']);
309 $vZ = substr($vZ, 26 +
$nF);
311 if (strlen($vZ) != $aP['CS']) {
313 $aI['EM'] = 'Compressed size is not equal with the value in header information.';
317 $aI['EM'] = 'File is encrypted, which is not supported from this class.';
321 // Here is nothing to do, the file ist flat.
325 $vZ = gzinflate($vZ);
330 if (! extension_loaded('bz2')) {
331 if (strtoupper(substr(PHP_OS
, 0, 3)) == 'WIN') {
338 if (extension_loaded('bz2')) {
340 $vZ = bzdecompress($vZ);
344 $aI['EM'] = "PHP BZIP2 extension not available.";
352 $aI['EM'] = "De-/Compression method {$aP['CM']} is not supported.";
360 $aI['EM'] = 'Decompression of data failed.';
362 if (strlen($vZ) != $aP['UCS']) {
364 $aI['EM'] = 'Uncompressed size is not equal with the value in header information.';
366 if (crc32($vZ) != $aP['CRC']) {
368 $aI['EM'] = 'CRC32 checksum is not equal with the value in header information.';
380 // DOS to UNIX timestamp
381 $aI['T'] = mktime(($aP['FT'] & 0xf800) >> 11,
382 ($aP['FT'] & 0x07e0) >> 5,
383 ($aP['FT'] & 0x001f) << 1,
384 ($aP['FD'] & 0x01e0) >> 5,
385 ($aP['FD'] & 0x001f),
386 (($aP['FD'] & 0xfe00) >> 9) +
1980);
388 $this->Entries
[] = &new SimpleUnzipEntry($aI);
389 } // end for each entries
391 return $this->Entries
;
392 } // end of the 'ReadFile()' method
393 } // end of the 'SimpleUnzip' class
396 * Entry of the ZIP file.
398 * @category phpPublic
399 * @package File-Formats-ZIP
402 * @author Holger Boskugel <vbwebprofi@gmx.de>
403 * @example example.unzip.php Two examples
405 class SimpleUnzipEntry
{
407 * Data of the file entry
411 * @see SimpleUnzipEntry()
417 * Error of the file entry
419 * - 0 : No error raised.<BR>
420 * - 1 : Compressed size is not equal with the value in header information.<BR>
421 * - 2 : Decompression of data failed.<BR>
422 * - 3 : Uncompressed size is not equal with the value in header information.<BR>
423 * - 4 : CRC32 checksum is not equal with the value in header information.<BR>
424 * - 5 : File is encrypted, which is not supported from this class.<BR>
425 * - 6 : De-/Compression method ... is not supported.<BR>
426 * - 7 : PHP BZIP2 extension not available.
430 * @see SimpleUnzipEntry()
436 * Error message of the file entry
440 * @see SimpleUnzipEntry()
446 * File name of the file entry
450 * @see SimpleUnzipEntry()
456 * File path of the file entry
460 * @see SimpleUnzipEntry()
466 * File time of the file entry (unix timestamp)
470 * @see SimpleUnzipEntry()
476 * Contructor of the class
478 * @param array Entry datas
479 * @return SimpleUnzipEntry Instanced class
483 function SimpleUnzipEntry($in_Entry)
485 $this->Data
= $in_Entry['D'];
486 $this->Error
= $in_Entry['E'];
487 $this->ErrorMsg
= $in_Entry['EM'];
488 $this->Name
= $in_Entry['N'];
489 $this->Path
= $in_Entry['P'];
490 $this->Time
= $in_Entry['T'];
491 } // end of the 'SimpleUnzipEntry' constructor
492 } // end of the 'SimpleUnzipEntry' class