[ Index ] |
|
Code source de Horde 3.1.3 |
1 <?php 2 3 /** 4 * For decompress(), return a list of files/information about the zipfile. 5 */ 6 define('HORDE_COMPRESS_ZIP_LIST', 1); 7 8 /** 9 * For decompress(), return the data for an individual file in the zipfile. 10 */ 11 define('HORDE_COMPRESS_ZIP_DATA', 2); 12 13 /** 14 * The Horde_Compress_zip class allows ZIP files to be created and 15 * read. 16 * 17 * $Horde: framework/Compress/Compress/zip.php,v 1.11.12.16 2006/06/29 08:34:30 jan Exp $ 18 * 19 * The ZIP compression code is partially based on code from: 20 * Eric Mueller <eric@themepark.com> 21 * http://www.zend.com/codex.php?id=535&single=1 22 * 23 * Deins125 <webmaster@atlant.ru> 24 * http://www.zend.com/codex.php?id=470&single=1 25 * 26 * The ZIP compression date code is partially based on code from 27 * Peter Listiak <mlady@users.sourceforge.net> 28 * 29 * Copyright 2000-2006 Chuck Hagenbuch <chuck@horde.org> 30 * Copyright 2002-2006 Michael Cochrane <mike@graftonhall.co.nz> 31 * Copyright 2003-2006 Michael Slusarz <slusarz@bigworm.colorado.edu> 32 * 33 * See the enclosed file COPYING for license information (LGPL). If you 34 * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. 35 * 36 * @author Chuck Hagenbuch <chuck@horde.org> 37 * @author Michael Cochrane <mike@graftonhall.co.nz> 38 * @author Michael Slusarz <slusarz@bigworm.colorado.edu> 39 * @since Horde 3.0 40 * @package Horde_Compress 41 */ 42 class Horde_Compress_zip extends Horde_Compress { 43 44 /** 45 * ZIP compression methods. 46 * 47 * @var array 48 */ 49 var $_methods = array( 50 0x0 => 'None', 51 0x1 => 'Shrunk', 52 0x2 => 'Super Fast', 53 0x3 => 'Fast', 54 0x4 => 'Normal', 55 0x5 => 'Maximum', 56 0x6 => 'Imploded', 57 0x8 => 'Deflated' 58 ); 59 60 /** 61 * Beginning of central directory record. 62 * 63 * @var string 64 */ 65 var $_ctrlDirHeader = "\x50\x4b\x01\x02"; 66 67 /** 68 * End of central directory record. 69 * 70 * @var string 71 */ 72 var $_ctrlDirEnd = "\x50\x4b\x05\x06\x00\x00\x00\x00"; 73 74 /** 75 * Beginning of file contents. 76 * 77 * @var string 78 */ 79 var $_fileHeader = "\x50\x4b\x03\x04"; 80 81 /** 82 * Create a ZIP compressed file from an array of file data. 83 * 84 * @param array $data The data to compress. 85 * <pre> 86 * Requires an array of arrays - each subarray should contain the 87 * following fields: 88 * 'data' (string) -- The data to compress. 89 * 'name' (string) -- The pathname to the file. 90 * 'time' (integer) -- [optional] The timestamp to use for the file. 91 * </pre> 92 * @param array $params The parameter array (Unused). 93 * 94 * @return string The ZIP file. 95 */ 96 function compress($data, $params = array()) 97 { 98 $contents = $ctrldir = array(); 99 100 foreach ($data as $val) { 101 $this->_addToZIPFile($val, $contents, $ctrldir); 102 } 103 104 return $this->_createZIPFile($contents, $ctrldir); 105 } 106 107 /** 108 * Decompress a ZIP file and get information from it. 109 * 110 * @param string $data The zipfile data. 111 * @param array $params The parameter array. 112 * <pre> 113 * The following parameters are REQUIRED: 114 * 'action' (integer) => The action to take on the data. Either 115 * HORDE_COMPRESS_ZIP_LIST or 116 * HORDE_COMPRESS_ZIP_DATA. 117 * 118 * The following parameters are REQUIRED for HORDE_COMPRESS_ZIP_DATA also: 119 * 'info' (array) => The zipfile list. 120 * 'key' (integer) => The position of the file in the archive list. 121 * </pre> 122 * 123 * @return mixed The requested data. 124 */ 125 function decompress($data, $params) 126 { 127 if (isset($params['action'])) { 128 if ($params['action'] == HORDE_COMPRESS_ZIP_LIST) { 129 return $this->_getZipInfo($data); 130 } elseif ($params['action'] == HORDE_COMPRESS_ZIP_DATA) { 131 // TODO: Check for parameters. 132 return $this->_getZipData($data, $params['info'], $params['key']); 133 } else { 134 return PEAR::raiseError(_("Incorrect action code given."), 'horde.error'); 135 } 136 } 137 138 return PEAR::raiseError(_("You must specify what action to perform."), 'horde.error'); 139 } 140 141 /** 142 * Get the list of files/data from the zip archive. 143 * 144 * @access private 145 * 146 * @param string &$data The zipfile data. 147 * 148 * @return array KEY: Position in zipfile 149 * VALUES: 'attr' -- File attributes 150 * 'crc' -- CRC checksum 151 * 'csize' -- Compressed file size 152 * 'date' -- File modification time 153 * 'name' -- Filename 154 * 'method' -- Compression method 155 * 'size' -- Original file size 156 * 'type' -- File type 157 */ 158 function _getZipInfo(&$data) 159 { 160 $entries = array(); 161 162 /* Get details from Central directory structure. */ 163 $fhStart = strpos($data, $this->_ctrlDirHeader); 164 165 do { 166 if (strlen($data) < $fhStart + 31) { 167 return PEAR::raiseError(_("Invalid ZIP data")); 168 } 169 $info = unpack('vMethod/VTime/VCRC32/VCompressed/VUncompressed/vLength', substr($data, $fhStart + 10, 20)); 170 $name = substr($data, $fhStart + 46, $info['Length']); 171 172 $entries[$name] = array( 173 'attr' => null, 174 'crc' => sprintf("%08s", dechex($info['CRC32'])), 175 'csize' => $info['Compressed'], 176 'date' => null, 177 '_dataStart' => null, 178 'name' => $name, 179 'method' => $this->_methods[$info['Method']], 180 '_method' => $info['Method'], 181 'size' => $info['Uncompressed'], 182 'type' => null 183 ); 184 185 $entries[$name]['date'] = 186 mktime((($info['Time'] >> 11) & 0x1f), 187 (($info['Time'] >> 5) & 0x3f), 188 (($info['Time'] << 1) & 0x3e), 189 (($info['Time'] >> 21) & 0x07), 190 (($info['Time'] >> 16) & 0x1f), 191 ((($info['Time'] >> 25) & 0x7f) + 1980)); 192 193 if (strlen($data) < $fhStart + 43) { 194 return PEAR::raiseError(_("Invalid ZIP data")); 195 } 196 $info = unpack('vInternal/VExternal', substr($data, $fhStart + 36, 6)); 197 198 $entries[$name]['type'] = ($info['Internal'] & 0x01) ? 'text' : 'binary'; 199 $entries[$name]['attr'] = 200 (($info['External'] & 0x10) ? 'D' : '-') . 201 (($info['External'] & 0x20) ? 'A' : '-') . 202 (($info['External'] & 0x03) ? 'S' : '-') . 203 (($info['External'] & 0x02) ? 'H' : '-') . 204 (($info['External'] & 0x01) ? 'R' : '-'); 205 } while (($fhStart = strpos($data, $this->_ctrlDirHeader, $fhStart + 46)) !== false); 206 207 /* Get details from local file header. */ 208 $fhStart = strpos($data, $this->_fileHeader); 209 210 do { 211 if (strlen($data) < $fhStart + 34) { 212 return PEAR::raiseError(_("Invalid ZIP data")); 213 } 214 $info = unpack('vMethod/VTime/VCRC32/VCompressed/VUncompressed/vLength/vExtraLength', substr($data, $fhStart + 8, 25)); 215 $name = substr($data, $fhStart + 30, $info['Length']); 216 $entries[$name]['_dataStart'] = $fhStart + 30 + $info['Length'] + $info['ExtraLength']; 217 } while (strlen($data) > $fhStart + 30 + $info['Length'] && 218 ($fhStart = strpos($data, $this->_fileHeader, $fhStart + 30 + $info['Length'])) !== false); 219 220 return array_values($entries); 221 } 222 223 /** 224 * Returns the data for a specific archived file. 225 * 226 * @access private 227 * 228 * @param string &$data The zip archive contents. 229 * @param array &$info The information array from _getZipInfo(). 230 * @param integer $key The position of the file in the archive. 231 * 232 * @return string The file data. 233 */ 234 function _getZipData(&$data, &$info, $key) 235 { 236 if (($info[$key]['_method'] == 0x8) && Util::extensionExists('zlib')) { 237 /* If the file has been deflated, and zlib is installed, 238 then inflate the data again. */ 239 return @gzinflate(substr($data, $info[$key]['_dataStart'], $info[$key]['csize'])); 240 } elseif ($info[$key]['_method'] == 0x0) { 241 /* Files that aren't compressed. */ 242 return substr($data, $info[$key]['_dataStart'], $info[$key]['csize']); 243 } 244 245 return ''; 246 } 247 248 /** 249 * Checks to see if the data is a valid ZIP file. 250 * 251 * @param string &$data The ZIP file data. 252 * 253 * @return boolean True if valid, false if invalid. 254 */ 255 function checkZipData(&$data) 256 { 257 if (strpos($data, $this->_fileHeader) === false) { 258 return false; 259 } else { 260 return true; 261 } 262 } 263 264 /** 265 * Converts a UNIX timestamp to a 4-byte DOS date and time format 266 * (date in high 2-bytes, time in low 2-bytes allowing magnitude 267 * comparison). 268 * 269 * @access private 270 * 271 * @param integer $unixtime The current UNIX timestamp. 272 * 273 * @return integer The current date in a 4-byte DOS format. 274 */ 275 function _unix2DOSTime($unixtime = null) 276 { 277 $timearray = (is_null($unixtime)) ? getdate() : getdate($unixtime); 278 279 if ($timearray['year'] < 1980) { 280 $timearray['year'] = 1980; 281 $timearray['mon'] = 1; 282 $timearray['mday'] = 1; 283 $timearray['hours'] = 0; 284 $timearray['minutes'] = 0; 285 $timearray['seconds'] = 0; 286 } 287 288 return (($timearray['year'] - 1980) << 25) | 289 ($timearray['mon'] << 21) | 290 ($timearray['mday'] << 16) | 291 ($timearray['hours'] << 11) | 292 ($timearray['minutes'] << 5) | 293 ($timearray['seconds'] >> 1); 294 } 295 296 /** 297 * Adds a "file" to the ZIP archive. 298 * 299 * @access private 300 * 301 * @param array &$file See Horde_Compress_zip::createZipFile(). 302 * @param array &$contents An array of existing zipped files. 303 * @param array &$ctrldir An array of central directory information. 304 */ 305 function _addToZIPFile(&$file, &$contents, &$ctrldir) 306 { 307 $data = &$file['data']; 308 $name = str_replace('\\', '/', $file['name']); 309 310 /* See if time/date information has been provided. */ 311 $ftime = null; 312 if (isset($file['time'])) { 313 $ftime = $file['time']; 314 } 315 316 /* Get the hex time. */ 317 $dtime = dechex($this->_unix2DosTime($ftime)); 318 $hexdtime = chr(hexdec($dtime[6] . $dtime[7])) . 319 chr(hexdec($dtime[4] . $dtime[5])) . 320 chr(hexdec($dtime[2] . $dtime[3])) . 321 chr(hexdec($dtime[0] . $dtime[1])); 322 323 $fr = $this->_fileHeader; /* Begin creating the ZIP data. */ 324 $fr .= "\x14\x00"; /* Version needed to extract. */ 325 $fr .= "\x00\x00"; /* General purpose bit flag. */ 326 $fr .= "\x08\x00"; /* Compression method. */ 327 $fr .= $hexdtime; /* Last modification time/date. */ 328 329 /* "Local file header" segment. */ 330 $unc_len = strlen($data); 331 $crc = crc32($data); 332 $zdata = gzcompress($data); 333 $zdata = substr(substr($zdata, 0, strlen($zdata) - 4), 2); 334 $c_len = strlen($zdata); 335 336 $fr .= pack('V', $crc); /* CRC 32 information. */ 337 $fr .= pack('V', $c_len); /* Compressed filesize. */ 338 $fr .= pack('V', $unc_len); /* Uncompressed filesize. */ 339 $fr .= pack('v', strlen($name)); /* Length of filename. */ 340 $fr .= pack('v', 0); /* Extra field length. */ 341 $fr .= $name; /* File name. */ 342 343 /* "File data" segment. */ 344 $fr .= $zdata; 345 346 /* "Data descriptor" segment (optional but necessary if archive is 347 not served as file). */ 348 $fr .= pack('V', $crc); 349 $fr .= pack('V', $c_len); 350 $fr .= pack('V', $unc_len); 351 352 /* Add this entry to array. */ 353 $old_offset = strlen(implode('', $contents)); 354 $contents[] = &$fr; 355 356 /* Add to central directory record. */ 357 $cdrec = $this->_ctrlDirHeader; 358 $cdrec .= "\x00\x00"; /* Version made by. */ 359 $cdrec .= "\x14\x00"; /* Version needed to extract */ 360 $cdrec .= "\x00\x00"; /* General purpose bit flag */ 361 $cdrec .= "\x08\x00"; /* Compression method */ 362 $cdrec .= $hexdtime; /* Last mod time/date. */ 363 $cdrec .= pack('V', $crc); /* CRC 32 information. */ 364 $cdrec .= pack('V', $c_len); /* Compressed filesize. */ 365 $cdrec .= pack('V', $unc_len); /* Uncompressed filesize. */ 366 $cdrec .= pack('v', strlen($name)); /* Length of filename. */ 367 $cdrec .= pack('v', 0); /* Extra field length. */ 368 $cdrec .= pack('v', 0); /* File comment length. */ 369 $cdrec .= pack('v', 0); /* Disk number start. */ 370 $cdrec .= pack('v', 0); /* Internal file attributes. */ 371 $cdrec .= pack('V', 32); /* External file attributes - 372 'archive' bit set. */ 373 $cdrec .= pack('V', $old_offset); /* Relative offset of local 374 header. */ 375 $cdrec .= $name; /* File name. */ 376 /* Optional extra field, file comment goes here. */ 377 378 // Save to central directory array. */ 379 $ctrldir[] = &$cdrec; 380 } 381 382 /** 383 * Creates the ZIP file. 384 * Official ZIP file format: http://www.pkware.com/appnote.txt 385 * 386 * @access private 387 * 388 * @return string The ZIP file. 389 */ 390 function _createZIPFile(&$contents, &$ctrlDir) 391 { 392 $data = implode('', $contents); 393 $dir = implode('', $ctrlDir); 394 395 return $data . $dir . $this->_ctrlDirEnd . 396 /* Total # of entries "on this disk". */ 397 pack('v', count($ctrlDir)) . 398 /* Total # of entries overall. */ 399 pack('v', count($ctrlDir)) . 400 /* Size of central directory. */ 401 pack('V', strlen($dir)) . 402 /* Offset to start of central dir. */ 403 pack('V', strlen($data)) . 404 /* ZIP file comment length. */ 405 "\x00\x00"; 406 } 407 408 }
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Sun Feb 25 18:01:28 2007 | par Balluche grâce à PHPXref 0.7 |