[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/inc/ -> ZipLib.class.php (source)

   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