[ Index ] |
PHP Cross Reference of DokuWiki |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * @author bouchon 5 * @link http://dev.maxg.info 6 * @link http://forum.maxg.info 7 * 8 * Modified for Dokuwiki 9 * @deprecated 2015-05-15 - use splitbrain\PHPArchive\Zip instead 10 * @author Christopher Smith <chris@jalakai.co.uk> 11 */ 12 class ZipLib { 13 14 var $datasec; 15 var $ctrl_dir = array(); 16 var $eof_ctrl_dir = "\x50\x4b\x05\x06\x00\x00\x00\x00"; 17 var $old_offset = 0; 18 var $dirs = Array("."); 19 20 /** 21 * @param string $zip_name filename path to file 22 * @return array|int 23 */ 24 function get_List($zip_name) { 25 $zip = @fopen($zip_name, 'rb'); 26 if(!$zip) return(0); 27 $centd = $this->ReadCentralDir($zip,$zip_name); 28 29 @rewind($zip); 30 @fseek($zip, $centd['offset']); 31 32 $ret = array(); 33 for ($i=0; $i<$centd['entries']; $i++) { 34 $header = $this->ReadCentralFileHeaders($zip); 35 $header['index'] = $i; 36 37 $info = array(); 38 $info['filename'] = $header['filename']; 39 $info['stored_filename'] = $header['stored_filename']; 40 $info['size'] = $header['size']; 41 $info['compressed_size'] = $header['compressed_size']; 42 $info['crc'] = strtoupper(dechex( $header['crc'] )); 43 $info['mtime'] = $header['mtime']; 44 $info['comment'] = $header['comment']; 45 $info['folder'] = ($header['external']==0x41FF0010||$header['external']==16)?1:0; 46 $info['index'] = $header['index']; 47 $info['status'] = $header['status']; 48 $ret[]=$info; 49 50 unset($header); 51 } 52 return $ret; 53 } 54 55 /** 56 * @param array $files array filled with array(string filename, string data) 57 * @param bool $compact 58 * @return array 59 */ 60 function Add($files,$compact) { 61 if(!is_array($files[0])) $files=Array($files); 62 63 $ret = array(); 64 for($i=0;$files[$i];$i++){ 65 $fn = $files[$i]; 66 if(!in_Array(dirname($fn[0]),$this->dirs)) 67 $this->add_Dir(dirname($fn[0])); 68 if(utf8_basename($fn[0])) 69 $ret[utf8_basename($fn[0])]=$this->add_File($fn[1],$fn[0],$compact); 70 } 71 return $ret; 72 } 73 74 /** 75 * Zips recursively the $folder directory, from the $basedir directory 76 * 77 * @param string $folder filename path to file 78 * @param string|null $basedir 79 * @param string|null $parent 80 */ 81 function Compress($folder, $basedir=null, $parent=null) { 82 $full_path = $basedir."/".$parent.$folder; 83 $zip_path = $parent.$folder; 84 if ($zip_path) { 85 $zip_path .= "/"; 86 $this->add_dir($zip_path); 87 } 88 $dir = new DirectoryIterator($full_path); 89 foreach($dir as $file) { 90 /** @var DirectoryIterator $file */ 91 if(!$file->isDot()) { 92 $filename = $file->getFilename(); 93 if($file->isDir()) { 94 $this->Compress($filename, $basedir, $zip_path); 95 } else { 96 $content = join('', file($full_path.'/'.$filename)); 97 $this->add_File($content, $zip_path.$filename); 98 } 99 } 100 } 101 } 102 103 /** 104 * Returns the Zip file 105 * 106 * @return string 107 */ 108 function get_file() { 109 $data = implode('', $this -> datasec); 110 $ctrldir = implode('', $this -> ctrl_dir); 111 112 return $data . $ctrldir . $this -> eof_ctrl_dir . 113 pack('v', count($this->ctrl_dir)).pack('v', count($this->ctrl_dir)). 114 pack('V', strlen($ctrldir)) . pack('V', strlen($data)) . "\x00\x00"; 115 } 116 117 /** 118 * @param string $name the name of the directory 119 */ 120 function add_dir($name) { 121 $name = str_replace("\\", "/", $name); 122 $fr = "\x50\x4b\x03\x04\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00"; 123 124 $fr .= pack("V",0).pack("V",0).pack("V",0).pack("v", strlen($name) ); 125 $fr .= pack("v", 0 ).$name.pack("V", 0).pack("V", 0).pack("V", 0); 126 $this -> datasec[] = $fr; 127 128 $new_offset = strlen(implode("", $this->datasec)); 129 130 $cdrec = "\x50\x4b\x01\x02\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00"; 131 $cdrec .= pack("V",0).pack("V",0).pack("V",0).pack("v", strlen($name) ); 132 $cdrec .= pack("v", 0 ).pack("v", 0 ).pack("v", 0 ).pack("v", 0 ); 133 $ext = "\xff\xff\xff\xff"; 134 $cdrec .= pack("V", 16 ).pack("V", $this -> old_offset ).$name; 135 136 $this -> ctrl_dir[] = $cdrec; 137 $this -> old_offset = $new_offset; 138 $this -> dirs[] = $name; 139 } 140 141 /** 142 * Add a file named $name from a string $data 143 * 144 * @param string $data 145 * @param string $name filename 146 * @param bool $compact 147 * @return bool 148 */ 149 function add_File($data, $name, $compact = true) { 150 $name = str_replace('\\', '/', $name); 151 $dtime = dechex($this->DosTime()); 152 153 $hexdtime = pack('H*',$dtime[6].$dtime[7]. 154 $dtime[4].$dtime[5]. 155 $dtime[2].$dtime[3]. 156 $dtime[0].$dtime[1]); 157 158 if($compact){ 159 $fr = "\x50\x4b\x03\x04\x14\x00\x00\x00\x08\x00".$hexdtime; 160 }else{ 161 $fr = "\x50\x4b\x03\x04\x0a\x00\x00\x00\x00\x00".$hexdtime; 162 } 163 $unc_len = strlen($data); 164 $crc = crc32($data); 165 166 if($compact){ 167 $zdata = gzcompress($data); 168 $c_len = strlen($zdata); 169 $zdata = substr(substr($zdata, 0, strlen($zdata) - 4), 2); 170 }else{ 171 $zdata = $data; 172 } 173 $c_len=strlen($zdata); 174 $fr .= pack('V', $crc).pack('V', $c_len).pack('V', $unc_len); 175 $fr .= pack('v', strlen($name)).pack('v', 0).$name.$zdata; 176 177 $fr .= pack('V', $crc).pack('V', $c_len).pack('V', $unc_len); 178 179 $this -> datasec[] = $fr; 180 $new_offset = strlen(implode('', $this->datasec)); 181 if($compact) { 182 $cdrec = "\x50\x4b\x01\x02\x00\x00\x14\x00\x00\x00\x08\x00"; 183 } else { 184 $cdrec = "\x50\x4b\x01\x02\x14\x00\x0a\x00\x00\x00\x00\x00"; 185 } 186 $cdrec .= $hexdtime.pack('V', $crc).pack('V', $c_len).pack('V', $unc_len); 187 $cdrec .= pack('v', strlen($name) ).pack('v', 0 ).pack('v', 0 ); 188 $cdrec .= pack('v', 0 ).pack('v', 0 ).pack('V', 32 ); 189 $cdrec .= pack('V', $this -> old_offset ); 190 191 $this -> old_offset = $new_offset; 192 $cdrec .= $name; 193 $this -> ctrl_dir[] = $cdrec; 194 return true; 195 } 196 197 /** 198 * @return int 199 */ 200 function DosTime() { 201 $timearray = getdate(); 202 if ($timearray['year'] < 1980) { 203 $timearray['year'] = 1980; 204 $timearray['mon'] = 1; 205 $timearray['mday'] = 1; 206 $timearray['hours'] = 0; 207 $timearray['minutes'] = 0; 208 $timearray['seconds'] = 0; 209 } 210 return (($timearray['year'] - 1980) << 25) | 211 ($timearray['mon'] << 21) | 212 ($timearray['mday'] << 16) | 213 ($timearray['hours'] << 11) | 214 ($timearray['minutes'] << 5) | 215 ($timearray['seconds'] >> 1); 216 } 217 218 /** 219 * Extract a zip file $zn to the $to directory 220 * 221 * @param string $zn filename 222 * @param string $to filename path to file 223 * @param array $index 224 * @return array|int 225 */ 226 function Extract ( $zn, $to, $index = Array(-1) ) { 227 if(!@is_dir($to)) $this->_mkdir($to); 228 $zip = @fopen($zn,'rb'); 229 if(!$zip) return(-1); 230 $cdir = $this->ReadCentralDir($zip,$zn); 231 $pos_entry = $cdir['offset']; 232 233 if(!is_array($index)){ 234 $index = array($index); 235 } 236 for($i=0; isset($index[$i]);$i++){ 237 if(intval($index[$i])!=$index[$i]||$index[$i]>$cdir['entries']) 238 return(-1); 239 } 240 241 $stat = array(); 242 for ($i=0; $i<$cdir['entries']; $i++) { 243 @fseek($zip, $pos_entry); 244 $header = $this->ReadCentralFileHeaders($zip); 245 $header['index'] = $i; 246 $pos_entry = ftell($zip); 247 @rewind($zip); 248 fseek($zip, $header['offset']); 249 if(in_array("-1",$index)||in_array($i,$index)){ 250 $stat[$header['filename']]=$this->ExtractFile($header, $to, $zip); 251 } 252 } 253 fclose($zip); 254 return $stat; 255 } 256 257 /** 258 * @param resource $zip 259 * @param array $header 260 * @return array 261 */ 262 function ReadFileHeader($zip, $header) { 263 $binary_data = fread($zip, 30); 264 $data = unpack('vchk/vid/vversion/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len', $binary_data); 265 266 $header['filename'] = fread($zip, $data['filename_len']); 267 if ($data['extra_len'] != 0) { 268 $header['extra'] = fread($zip, $data['extra_len']); 269 } else { 270 $header['extra'] = ''; 271 } 272 273 $header['compression'] = $data['compression']; 274 foreach (array('size','compressed_size','crc') as $hd) { // On ODT files, these headers are 0. Keep the previous value. 275 if ($data[$hd] != 0) $header[$hd] = $data[$hd]; 276 } 277 $header['flag'] = $data['flag']; 278 $header['mdate'] = $data['mdate']; 279 $header['mtime'] = $data['mtime']; 280 281 if ($header['mdate'] && $header['mtime']){ 282 $hour = ($header['mtime']&0xF800)>>11; 283 $minute = ($header['mtime']&0x07E0)>>5; 284 $seconde = ($header['mtime']&0x001F)*2; 285 $year = (($header['mdate']&0xFE00)>>9)+1980; 286 $month = ($header['mdate']&0x01E0)>>5; 287 $day = $header['mdate']&0x001F; 288 $header['mtime'] = mktime($hour, $minute, $seconde, $month, $day, $year); 289 } else { 290 $header['mtime'] = time(); 291 } 292 293 $header['stored_filename'] = $header['filename']; 294 $header['status'] = "ok"; 295 return $header; 296 } 297 298 /** 299 * @param resource $zip 300 * @return array 301 */ 302 function ReadCentralFileHeaders($zip){ 303 $binary_data = fread($zip, 46); 304 $header = unpack('vchkid/vid/vversion/vversion_extracted/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len/vcomment_len/vdisk/vinternal/Vexternal/Voffset', $binary_data); 305 306 if ($header['filename_len'] != 0){ 307 $header['filename'] = fread($zip,$header['filename_len']); 308 }else{ 309 $header['filename'] = ''; 310 } 311 312 if ($header['extra_len'] != 0){ 313 $header['extra'] = fread($zip, $header['extra_len']); 314 }else{ 315 $header['extra'] = ''; 316 } 317 318 if ($header['comment_len'] != 0){ 319 $header['comment'] = fread($zip, $header['comment_len']); 320 }else{ 321 $header['comment'] = ''; 322 } 323 324 if ($header['mdate'] && $header['mtime']) { 325 $hour = ($header['mtime'] & 0xF800) >> 11; 326 $minute = ($header['mtime'] & 0x07E0) >> 5; 327 $seconde = ($header['mtime'] & 0x001F)*2; 328 $year = (($header['mdate'] & 0xFE00) >> 9) + 1980; 329 $month = ($header['mdate'] & 0x01E0) >> 5; 330 $day = $header['mdate'] & 0x001F; 331 $header['mtime'] = mktime($hour, $minute, $seconde, $month, $day, $year); 332 } else { 333 $header['mtime'] = time(); 334 } 335 336 $header['stored_filename'] = $header['filename']; 337 $header['status'] = 'ok'; 338 if (substr($header['filename'], -1) == '/') $header['external'] = 0x41FF0010; 339 340 return $header; 341 } 342 343 /** 344 * @param resource $zip 345 * @param string $zip_name filename path to file 346 * @return array 347 */ 348 function ReadCentralDir($zip,$zip_name) { 349 $size = filesize($zip_name); 350 if ($size < 277){ 351 $maximum_size = $size; 352 } else { 353 $maximum_size=277; 354 } 355 356 @fseek($zip, $size-$maximum_size); 357 $pos = ftell($zip); 358 $bytes = 0x00000000; 359 360 while ($pos < $size) { 361 $byte = @fread($zip, 1); 362 $bytes=(($bytes << 8) & 0xFFFFFFFF) | Ord($byte); 363 if ($bytes == 0x504b0506){ 364 $pos++; 365 break; 366 } 367 $pos++; 368 } 369 370 $data=unpack('vdisk/vdisk_start/vdisk_entries/ventries/Vsize/Voffset/vcomment_size', 371 fread($zip, 18)); 372 373 $centd = array(); 374 if ($data['comment_size'] != 0){ 375 $centd['comment'] = fread($zip, $data['comment_size']); 376 } else { 377 $centd['comment'] = ''; 378 } 379 $centd['entries'] = $data['entries']; 380 $centd['disk_entries'] = $data['disk_entries']; 381 $centd['offset'] = $data['offset']; 382 $centd['disk_start'] = $data['disk_start']; 383 $centd['size'] = $data['size']; 384 $centd['disk'] = $data['disk']; 385 return $centd; 386 } 387 388 /** 389 * @param array $header 390 * @param string $to filename path to file 391 * @param resource $zip 392 * @return bool|int 393 */ 394 function ExtractFile($header,$to,$zip) { 395 $header = $this->readfileheader($zip, $header); 396 397 if(substr($to,-1)!="/") $to.="/"; 398 if(substr($header['filename'],-1)=="/") { 399 $this->_mkdir($to.$header['filename']); 400 return +2; 401 } 402 403 if (!$this->_mkdir($to.dirname($header['filename']))) return (-1); 404 405 if (!array_key_exists("external", $header) || (!($header['external']==0x41FF0010)&&!($header['external']==16))) { 406 if ($header['compression']==0) { 407 $fp = @fopen($to.$header['filename'], 'wb'); 408 if(!$fp) return(-1); 409 $size = $header['compressed_size']; 410 411 while ($size != 0) { 412 $read_size = ($size < 2048 ? $size : 2048); 413 $buffer = fread($zip, $read_size); 414 $binary_data = pack('a'.$read_size, $buffer); 415 @fwrite($fp, $binary_data, $read_size); 416 $size -= $read_size; 417 } 418 fclose($fp); 419 touch($to.$header['filename'], $header['mtime']); 420 421 }else{ 422 if (!is_dir(dirname($to.$header['filename']))) $this->_mkdir(dirname($to.$header['filename'])); 423 $fp = fopen($to.$header['filename'].'.gz','wb'); 424 if(!$fp) return(-1); 425 $binary_data = pack('va1a1Va1a1', 0x8b1f, Chr($header['compression']), 426 Chr(0x00), time(), Chr(0x00), Chr(3)); 427 428 fwrite($fp, $binary_data, 10); 429 $size = $header['compressed_size']; 430 431 while ($size != 0) { 432 $read_size = ($size < 1024 ? $size : 1024); 433 $buffer = fread($zip, $read_size); 434 $binary_data = pack('a'.$read_size, $buffer); 435 @fwrite($fp, $binary_data, $read_size); 436 $size -= $read_size; 437 } 438 439 $binary_data = pack('VV', $header['crc'], $header['size']); 440 fwrite($fp, $binary_data,8); 441 fclose($fp); 442 443 $gzp = @gzopen($to.$header['filename'].'.gz','rb'); 444 if(!$gzp){ 445 @gzclose($gzp); 446 @unlink($to.$header['filename']); 447 die("Archive is compressed whereas ZLIB is not enabled."); 448 } 449 $fp = @fopen($to.$header['filename'],'wb'); 450 if(!$fp) return(-1); 451 $size = $header['size']; 452 453 while ($size != 0) { 454 $read_size = ($size < 2048 ? $size : 2048); 455 $buffer = gzread($gzp, $read_size); 456 $binary_data = pack('a'.$read_size, $buffer); 457 @fwrite($fp, $binary_data, $read_size); 458 $size -= $read_size; 459 } 460 fclose($fp); 461 gzclose($gzp); 462 463 touch($to.$header['filename'], $header['mtime']); 464 @unlink($to.$header['filename'].'.gz'); 465 } 466 } 467 return true; 468 } 469 470 /** 471 * centralize mkdir calls and use dokuwiki io functions 472 * 473 * @author Christopher Smith <chris@jalakai.co.uk> 474 * 475 * @param string $d filename path to file 476 * @return bool|int|string 477 */ 478 function _mkdir($d) { 479 return io_mkdir_p($d); 480 } 481 482 /** 483 * @param string $zn 484 * @param string $name 485 * @return null|string 486 */ 487 function ExtractStr($zn, $name) { 488 $zip = @fopen($zn,'rb'); 489 if(!$zip) return(null); 490 $cdir = $this->ReadCentralDir($zip,$zn); 491 $pos_entry = $cdir['offset']; 492 493 for ($i=0; $i<$cdir['entries']; $i++) { 494 @fseek($zip, $pos_entry); 495 $header = $this->ReadCentralFileHeaders($zip); 496 $header['index'] = $i; 497 $pos_entry = ftell($zip); 498 @rewind($zip); 499 fseek($zip, $header['offset']); 500 if ($name == $header['stored_filename'] || $name == $header['filename']) { 501 $str = $this->ExtractStrFile($header, $zip); 502 fclose($zip); 503 return $str; 504 } 505 506 } 507 fclose($zip); 508 return null; 509 } 510 511 /** 512 * @param array $header 513 * @param resource $zip 514 * @return null|string 515 */ 516 function ExtractStrFile($header,$zip) { 517 $hdr = $this->readfileheader($zip, $header); 518 $binary_data = ''; 519 if (!($header['external']==0x41FF0010) && !($header['external']==16)) { 520 if ($header['compression']==0) { 521 while ($size != 0) { 522 $read_size = ($size < 2048 ? $size : 2048); 523 $buffer = fread($zip, $read_size); 524 $binary_data .= pack('a'.$read_size, $buffer); 525 $size -= $read_size; 526 } 527 return $binary_data; 528 } else { 529 $size = $header['compressed_size']; 530 if ($size == 0) { 531 return ''; 532 } 533 //Just in case 534 if ($size > ($this->_ret_bytes(ini_get('memory_limit'))/2)) { 535 die("Compressed file is to huge to be uncompress in memory."); 536 } 537 while ($size != 0) 538 { 539 $read_size = ($size < 2048 ? $size : 2048); 540 $buffer = fread($zip, $read_size); 541 $binary_data .= pack('a'.$read_size, $buffer); 542 $size -= $read_size; 543 } 544 $str = gzinflate($binary_data, $header['size']); 545 if ($header['crc'] == crc32($str)) { 546 return $str; 547 } else { 548 die("Crc Error"); 549 } 550 } 551 } 552 return null; 553 } 554 555 /** 556 * @param string $val 557 * @return int|string 558 */ 559 function _ret_bytes($val) { 560 $val = trim($val); 561 $last = $val{strlen($val)-1}; 562 switch($last) { 563 case 'k': 564 case 'K': 565 return (int) $val * 1024; 566 break; 567 case 'm': 568 case 'M': 569 return (int) $val * 1048576; 570 break; 571 default: 572 return $val; 573 } 574 } 575 } 576
title
Description
Body
title
Description
Body
title
Description
Body
title
Body