[ Index ]

PHP Cross Reference of phpBB 3.0 Beta 3

title

Body

[close]

/includes/ -> functions_compress.php (source)

   1  <?php
   2  /** 
   3  *
   4  * @package phpBB3
   5  * @version $Id: functions_compress.php,v 1.43 2006/11/03 23:09:15 davidmj Exp $ 
   6  * @copyright (c) 2005 phpBB Group 
   7  * @license http://opensource.org/licenses/gpl-license.php GNU Public License 
   8  *
   9  */
  10  
  11  /**
  12  * Class for handling archives (compression/decompression)
  13  * @package phpBB3
  14  */
  15  class compress 
  16  {
  17      var $fp = 0;
  18  
  19      /**
  20      * Add file to archive
  21      */
  22  	function add_file($src, $src_rm_prefix = '', $src_add_prefix = '', $skip_files = '')
  23      {
  24          global $phpbb_root_path;
  25  
  26          $skip_files = explode(',', $skip_files);
  27  
  28          // Remove rm prefix from src path
  29          $src_path = ($src_rm_prefix) ? preg_replace('#^(' . preg_quote($src_rm_prefix, '#') . ')#', '', $src) : $src;
  30          // Add src prefix
  31          $src_path = ($src_add_prefix) ? ($src_add_prefix . ((substr($src_add_prefix, -1) != '/') ? '/' : '') . $src_path) : $src_path;
  32          // Remove initial "/" if present
  33          $src_path = (substr($src_path, 0, 1) == '/') ? substr($src_path, 1) : $src_path;
  34  
  35          if (is_file($phpbb_root_path . $src))
  36          {
  37              $this->data($src_path, file_get_contents("$phpbb_root_path$src"), false, stat("$phpbb_root_path$src"));
  38          }
  39          else if (is_dir($phpbb_root_path . $src))
  40          {
  41              // Clean up path, add closing / if not present
  42              $src_path = ($src_path && substr($src_path, -1) != '/') ? $src_path . '/' : $src_path;
  43  
  44              $filelist = array();
  45              $filelist = filelist("$phpbb_root_path$src", '', '*');
  46              krsort($filelist);
  47  
  48              if ($src_path)
  49              {
  50                  $this->data($src_path, '', true, stat("$phpbb_root_path$src"));
  51              }
  52  
  53              foreach ($filelist as $path => $file_ary)
  54              {
  55                  if ($path)
  56                  {
  57                      // Same as for src_path
  58                      $path = (substr($path, 0, 1) == '/') ? substr($path, 1) : $path;
  59                      $path = ($path && substr($path, -1) != '/') ? $path . '/' : $path;
  60  
  61                      $this->data("$src_path$path", '', true, stat("$phpbb_root_path$src$path"));
  62                  }
  63  
  64                  foreach ($file_ary as $file)
  65                  {
  66                      if (in_array($path . $file, $skip_files))
  67                      {
  68                          continue;
  69                      }
  70  
  71                      $this->data("$src_path$path$file", file_get_contents("$phpbb_root_path$src$path$file"), false, stat("$phpbb_root_path$src$path$file"));
  72                  }
  73              }
  74          }
  75  
  76          return true;
  77      }
  78  
  79      /**
  80      * Add custom file (the filepath will not be adjusted)
  81      */
  82  	function add_custom_file($src, $filename)
  83      {
  84          $this->data($filename, file_get_contents($src), false, stat($src));
  85          return true;
  86      }
  87  
  88      /**
  89      * Add file data
  90      */
  91  	function add_data($src, $name)
  92      {
  93          $stat = array();
  94          $stat[2] = 436; //384
  95          $stat[4] = $stat[5] = 0;
  96          $stat[7] = strlen($src);
  97          $stat[9] = time();
  98          $this->data($name, $src, false, $stat);
  99          return true;
 100      }
 101  
 102      /**
 103      * Return available methods
 104      */
 105  	function methods()
 106      {
 107          $methods = array('.tar');
 108          $available_methods = array('.tar.gz' => 'zlib', '.tar.bz2' => 'bz2', '.zip' => 'zlib');
 109  
 110          foreach ($available_methods as $type => $module)
 111          {
 112              if (!@extension_loaded($module))
 113              {
 114                  continue;
 115              }
 116              $methods[] = $type;
 117          }
 118  
 119          return $methods;
 120      }
 121  }
 122  
 123  /**
 124  * Zip creation class from phpMyAdmin 2.3.0 (c) Tobias Ratschiller, Olivier Müller, Loïc Chapeaux, 
 125  * Marc Delisle, http://www.phpmyadmin.net/
 126  *
 127  * Zip extraction function by Alexandre Tedeschi, alexandrebr at gmail dot com
 128  *
 129  * Modified extensively by psoTFX and DavidMJ, (c) phpBB Group, 2003
 130  *
 131  * Based on work by Eric Mueller and Denis125
 132  * Official ZIP file format: http://www.pkware.com/appnote.txt
 133  *
 134  * @package phpBB3
 135  */
 136  class compress_zip extends compress
 137  {
 138      var $datasec = array();
 139      var $ctrl_dir = array();
 140      var $eof_cdh = "\x50\x4b\x05\x06\x00\x00\x00\x00";
 141  
 142      var $old_offset = 0;
 143      var $datasec_len = 0;
 144  
 145      /**
 146      * Constructor
 147      */
 148  	function compress_zip($mode, $file)
 149      {
 150          return $this->fp = @fopen($file, $mode . 'b');
 151      }
 152  
 153      /**
 154      * Convert unix to dos time
 155      */
 156  	function unix_to_dos_time($time)
 157      {
 158          $timearray = (!$time) ? getdate() : getdate($time);
 159  
 160          if ($timearray['year'] < 1980)
 161          {
 162              $timearray['year'] = 1980;
 163              $timearray['mon'] = $timearray['mday'] = 1;
 164              $timearray['hours'] = $timearray['minutes'] = $timearray['seconds'] = 0;
 165          }
 166  
 167          return (($timearray['year'] - 1980) << 25) | ($timearray['mon'] << 21) | ($timearray['mday'] << 16) | ($timearray['hours'] << 11) | ($timearray['minutes'] << 5) | ($timearray['seconds'] >> 1);
 168      }
 169  
 170      /**
 171      * Extract archive
 172      */
 173  	function extract($dst)
 174      {        
 175          // Loop the file, looking for files and folders
 176          $dd_try = false;
 177          rewind($this->fp);
 178  
 179          while (!feof($this->fp))
 180          {
 181              // Check if the signature is valid...
 182              $signature = fread($this->fp, 4);
 183  
 184              switch ($signature)
 185              {
 186                  // 'Local File Header'
 187                  case "\x50\x4b\x03\x04":
 188                      // Lets get everything we need.
 189                      // We don't store the version needed to extract, the general purpose bit flag or the date and time fields
 190                      $data = unpack("@4/vc_method/@10/Vcrc/Vc_size/Vuc_size/vname_len/vextra_field", fread($this->fp, 26));
 191                      $file_name = fread($this->fp, $data['name_len']); // filename
 192  
 193                      if ($data['extra_field'])
 194                      {
 195                          fread($this->fp, $data['extra_field']); // extra field
 196                      }
 197  
 198                      $target_filename = "$dst$file_name";
 199  
 200                      if (!$data['uc_size'] && !$data['crc'] && substr($file_name, -1, 1) == '/')
 201                      {
 202                          if (!is_dir($target_filename))
 203                          {
 204                              $str = '';
 205                              $folders = explode('/', $target_filename);
 206  
 207                              // Create and folders and subfolders if they do not exist
 208                              foreach ($folders as $folder)
 209                              {
 210                                  $str = (!empty($str)) ? $str . '/' . $folder : $folder;
 211                                  if (!is_dir($str))
 212                                  {
 213                                      if (!@mkdir($str, 0777))
 214                                      {
 215                                          trigger_error("Could not create directory $folder");
 216                                      }
 217                                      @chmod($str, 0777);
 218                                  }
 219                              }
 220                          }
 221                          // This is a directory, we are not writting files
 222                          continue;
 223                      }
 224                      else
 225                      {
 226                          // Some archivers are punks, they don't don't include folders in their archives!
 227                          $str = '';
 228                          $folders = explode('/', pathinfo($target_filename, PATHINFO_DIRNAME));
 229  
 230                          // Create and folders and subfolders if they do not exist
 231                          foreach ($folders as $folder)
 232                          {
 233                              $str = (!empty($str)) ? $str . '/' . $folder : $folder;
 234                              if (!is_dir($str))
 235                              {
 236                                  if (!@mkdir($str, 0777))
 237                                  {
 238                                      trigger_error("Could not create directory $folder");
 239                                  }
 240                                  @chmod($str, 0777);
 241                              }
 242                          }
 243                      }
 244  
 245                      if (!$data['uc_size'])
 246                      {
 247                          $content = '';
 248                      }
 249                      else
 250                      {
 251                          $content = fread($this->fp, $data['c_size']);
 252                      }
 253  
 254                      $fp = fopen($target_filename, "w");
 255  
 256                      switch ($data['c_method'])
 257                      {
 258                          case 0:
 259                              // Not compressed
 260                              fwrite($fp, $content);
 261                          break;
 262                      
 263                          case 8:
 264                              // Deflate
 265                              fwrite($fp, gzinflate($content, $data['uc_size']));
 266                          break;
 267  
 268                          case 12:
 269                              // Bzip2
 270                              fwrite($fp, bzdecompress($content));
 271                          break;
 272                      }
 273                      
 274                      fclose($fp);
 275                  break;
 276  
 277                  // We hit the 'Central Directory Header', we can stop because nothing else in here requires our attention
 278                  // or we hit the end of the central directory record, we can safely end the loop as we are totally finished with looking for files and folders
 279                  case "\x50\x4b\x01\x02":
 280                  // This case should simply never happen.. but it does exist..
 281                  case "\x50\x4b\x05\x06":
 282                  break 2;
 283                  
 284                  // 'Packed to Removable Disk', ignore it and look for the next signature...
 285                  case 'PK00':
 286                  continue 2;
 287                  
 288                  // We have encountered a header that is weird. Lets look for better data...
 289                  default:
 290                      if (!$dd_try)
 291                      {
 292                          // Unexpected header. Trying to detect wrong placed 'Data Descriptor';
 293                          $dd_try = true;
 294                          fseek($this->fp, 8, SEEK_CUR); // Jump over 'crc-32'(4) 'compressed-size'(4), 'uncompressed-size'(4)
 295                          continue 2;
 296                      }
 297                      trigger_error("Unexpected header, ending loop");
 298                  break 2;
 299              }
 300  
 301              $dd_try = false;
 302          }
 303      }
 304  
 305      /**
 306      * Close archive
 307      */
 308  	function close()
 309      {
 310          // Write out central file directory and footer ... if it exists
 311          if (sizeof($this->ctrl_dir))
 312          {
 313              fwrite($this->fp, $this->file());
 314          }
 315          fclose($this->fp);
 316      }
 317  
 318      /**
 319      * Create the structures ... note we assume version made by is MSDOS
 320      */
 321  	function data($name, $data, $is_dir = false, $stat)
 322      {
 323          $name = str_replace('\\', '/', $name);
 324  
 325          $hexdtime = pack('V', $this->unix_to_dos_time($stat[9]));
 326  
 327          if ($is_dir)
 328          {
 329              $unc_len = $c_len = $crc = 0;
 330              $zdata = '';
 331              $var_ext = 10;
 332          }
 333          else
 334          {
 335              $unc_len = strlen($data);
 336              $crc = crc32($data);
 337              $zdata = gzdeflate($data);
 338              $c_len = strlen($zdata);
 339              $var_ext = 20;
 340  
 341              // Did we compress? No, then use data as is
 342              if ($c_len >= $unc_len)
 343              {
 344                  $zdata = $data;
 345                  $c_len = $unc_len;
 346                  $var_ext = 10;
 347              }
 348          }
 349          unset($data);
 350  
 351          // If we didn't compress set method to store, else deflate
 352          $c_method = ($c_len == $unc_len) ? "\x00\x00" : "\x08\x00";
 353  
 354          // Are we a file or a directory? Set archive for file
 355          $attrib = ($is_dir) ? 16 : 32;
 356  
 357          // File Record Header
 358          $fr = "\x50\x4b\x03\x04";        // Local file header 4bytes
 359          $fr .= pack('v', $var_ext);        // ver needed to extract 2bytes
 360          $fr .= "\x00\x00";                // gen purpose bit flag 2bytes
 361          $fr .= $c_method;                // compression method 2bytes
 362          $fr .= $hexdtime;                // last mod time and date 2+2bytes
 363          $fr .= pack('V', $crc);            // crc32 4bytes
 364          $fr .= pack('V', $c_len);        // compressed filesize 4bytes
 365          $fr .= pack('V', $unc_len);        // uncompressed filesize 4bytes
 366          $fr .= pack('v', strlen($name));// length of filename 2bytes
 367  
 368          $fr .= pack('v', 0);            // extra field length 2bytes
 369          $fr .= $name;
 370          $fr .= $zdata;
 371          unset($zdata);
 372  
 373          $this->datasec_len += strlen($fr);
 374  
 375          // Add data to file ... by writing data out incrementally we save some memory
 376          fwrite($this->fp, $fr);
 377          unset($fr);
 378  
 379          // Central Directory Header
 380          $cdrec = "\x50\x4b\x01\x02";        // header 4bytes
 381          $cdrec .= "\x00\x00";                // version made by
 382          $cdrec .= pack('v', $var_ext);        // version needed to extract
 383          $cdrec .= "\x00\x00";                // gen purpose bit flag
 384          $cdrec .= $c_method;                // compression method
 385          $cdrec .= $hexdtime;                // last mod time & date
 386          $cdrec .= pack('V', $crc);            // crc32
 387          $cdrec .= pack('V', $c_len);        // compressed filesize
 388          $cdrec .= pack('V', $unc_len);        // uncompressed filesize
 389          $cdrec .= pack('v', strlen($name));    // length of filename
 390          $cdrec .= pack('v', 0);                // extra field length
 391          $cdrec .= pack('v', 0);                // file comment length
 392          $cdrec .= pack('v', 0);                // disk number start
 393          $cdrec .= pack('v', 0);                // internal file attributes
 394          $cdrec .= pack('V', $attrib);        // external file attributes
 395          $cdrec .= pack('V', $this->old_offset);    // relative offset of local header
 396          $cdrec .= $name;
 397  
 398          // Save to central directory
 399          $this->ctrl_dir[] = $cdrec;
 400  
 401          $this->old_offset = $this->datasec_len;
 402      }
 403  
 404      /**
 405      * file
 406      */
 407  	function file()
 408      {
 409          $ctrldir = implode('', $this->ctrl_dir);
 410  
 411          return $ctrldir . $this->eof_cdh .
 412              pack('v', sizeof($this->ctrl_dir)) .    // total # of entries "on this disk"
 413              pack('v', sizeof($this->ctrl_dir)) .    // total # of entries overall
 414              pack('V', strlen($ctrldir)) .            // size of central dir
 415              pack('V', $this->datasec_len) .            // offset to start of central dir
 416              "\x00\x00";                                // .zip file comment length
 417      }
 418  
 419      /**
 420      * Download archive
 421      */
 422  	function download($filename)
 423      {
 424          global $phpbb_root_path;
 425  
 426          $mimetype = 'application/zip';
 427  
 428          header('Pragma: no-cache');
 429          header("Content-Type: $mimetype; name=\"$filename.zip\"");
 430          header("Content-disposition: attachment; filename=$filename.zip");
 431  
 432          $fp = fopen("{$phpbb_root_path}store/$filename.zip", 'rb');
 433          while ($buffer = fread($fp, 1024))
 434          {
 435              echo $buffer;
 436          }
 437          fclose($fp);
 438      }
 439  }
 440  
 441  /**
 442  * Tar/tar.gz compression routine
 443  * Header/checksum creation derived from tarfile.pl, (c) Tom Horsley, 1994
 444  *
 445  * @package phpBB3
 446  */
 447  class compress_tar extends compress 
 448  {
 449      var $isgz = false;
 450      var $isbz = false;
 451      var $filename = '';
 452      var $mode = '';
 453      var $type = '';
 454      var $wrote = false;
 455  
 456      /**
 457      * Constructor
 458      */
 459  	function compress_tar($mode, $file, $type = '')
 460      {
 461          $type = (!$type) ? $file : $type;
 462          $this->isgz = (strpos($type, '.tar.gz') !== false || strpos($type, '.tgz') !== false) ? true : false;
 463          $this->isbz = (strpos($type, '.tar.bz2') !== false) ? true : false;
 464  
 465          $this->mode = &$mode;
 466          $this->file = &$file;
 467          $this->type = &$type;
 468          $this->open();
 469      }
 470  
 471      /**
 472      * Extract archive
 473      */
 474  	function extract($dst)
 475      {
 476          $fzread = ($this->isbz && function_exists('bzread')) ? 'bzread' : (($this->isgz && @extension_loaded('zlib')) ? 'gzread' : 'fread');
 477  
 478          // Run through the file and grab directory entries
 479          while ($buffer = $fzread($this->fp, 512))
 480          {
 481              $tmp = unpack('A6magic', substr($buffer, 257, 6));
 482  
 483              if (trim($tmp['magic']) == 'ustar')
 484              {
 485                  $tmp = unpack('A100name', $buffer);
 486                  $filename = trim($tmp['name']);
 487  
 488                  $tmp = unpack('Atype', substr($buffer, 156, 1));
 489                  $filetype = (int) trim($tmp['type']);
 490  
 491                  $tmp = unpack('A12size', substr($buffer, 124, 12));
 492                  $filesize = octdec((int) trim($tmp['size']));
 493  
 494                  if ($filetype == 5)
 495                  {
 496                      if (!is_dir("$dst$filename"))
 497                      {
 498                          $str = '';
 499                          $folders = explode('/', "$dst$filename");
 500  
 501                          // Create and folders and subfolders if they do not exist
 502                          foreach ($folders as $folder)
 503                          {
 504                              $str = (!empty($str)) ? $str . '/' . $folder : $folder;
 505                              if (!is_dir($str))
 506                              {
 507                                  if (!@mkdir($str, 0777))
 508                                  {
 509                                      trigger_error("Could not create directory $folder");
 510                                  }
 511                                  @chmod($str, 0777);
 512                              }
 513                          }
 514                      }
 515                  }
 516                  else if ($filesize != 0 && ($filetype == 0 || $filetype == "\0"))
 517                  {
 518                      // Write out the files
 519                      if (!($fp = fopen("$dst$filename", 'wb')))
 520                      {
 521                          trigger_error("Couldn't create file $filename");
 522                      }
 523                      @chmod("$dst$filename", 0777);
 524  
 525                      // Grab the file contents
 526                      fwrite($fp, $fzread($this->fp, ($filesize + 511) &~ 511), $filesize);
 527                      fclose($fp);
 528                  }
 529              }
 530          }
 531      }
 532  
 533      /**
 534      * Close archive
 535      */
 536  	function close()
 537      {
 538          $fzclose = ($this->isbz && function_exists('bzclose')) ? 'bzclose' : (($this->isgz && @extension_loaded('zlib')) ? 'gzclose' : 'fclose');
 539  
 540          if ($this->wrote) 
 541          {
 542              $fzwrite = ($this->isbz && function_exists('bzwrite')) ? 'bzwrite' : (($this->isgz && @extension_loaded('zlib')) ? 'gzwrite' : 'fwrite');
 543  
 544              // Symbolizes that there are no more files
 545              $fzwrite($this->fp, str_repeat("\0", 512));
 546          }
 547  
 548          $fzclose($this->fp);
 549      }
 550  
 551      /**
 552      * Create the structures
 553      */
 554  	function data($name, $data, $is_dir = false, $stat)
 555      {
 556          $this->wrote = true;
 557          $fzwrite =     ($this->isbz && function_exists('bzwrite')) ? 'bzwrite' : (($this->isgz && @extension_loaded('zlib')) ? 'gzwrite' : 'fwrite');
 558  
 559          $typeflag = ($is_dir) ? '5' : '';
 560  
 561          // This is the header data, it contains all the info we know about the file or folder that we are about to archive
 562          $header = '';
 563          $header .= pack('a100', $name);                        // file name
 564          $header .= pack('a8', sprintf("%07o", $stat[2]));    // file mode
 565          $header .= pack('a8', sprintf("%07o", $stat[4]));    // owner id
 566          $header .= pack('a8', sprintf("%07o", $stat[5]));    // group id
 567          $header .= pack('a12', sprintf("%011o", $stat[7]));    // file size
 568          $header .= pack('a12', sprintf("%011o", $stat[9]));    // last mod time
 569  
 570          // Checksum
 571          $checksum = 0;
 572          for ($i = 0; $i < 148; $i++)
 573          {
 574              $checksum += ord($header[$i]);
 575          }
 576  
 577          // We precompute the rest of the hash, this saves us time in the loop and allows us to insert our hash without resorting to string functions
 578          $checksum += 2415 + (($is_dir) ? 53 : 0);
 579  
 580          $header .= pack('a8', sprintf("%07o", $checksum));    // checksum
 581          $header .= pack('a1', $typeflag);                    // link indicator
 582          $header .= pack('a100', '');                        // name of linked file
 583          $header .= pack('a6', 'ustar');                        // ustar indicator
 584          $header .= pack('a2', '00');                        // ustar version
 585          $header .= pack('a32', 'Unknown');                    // owner name
 586          $header .= pack('a32', 'Unknown');                    // group name
 587          $header .= pack('a8', '');                            // device major number
 588          $header .= pack('a8', '');                            // device minor number
 589          $header .= pack('a155', '');                        // filename prefix
 590          $header .= pack('a12', '');                            // end
 591  
 592          // This writes the entire file in one shot. Header, followed by data and then null padded to a multiple of 512
 593          $fzwrite($this->fp, $header . (($stat[7] !== 0 && !$is_dir) ? $data . str_repeat("\0", (($stat[7] + 511) &~ 511) - $stat[7]) : ''));
 594          unset($data);
 595      }
 596  
 597      /**
 598      * Open archive
 599      */
 600  	function open()
 601      {
 602          $fzopen = ($this->isbz && function_exists('bzopen')) ? 'bzopen' : (($this->isgz && @extension_loaded('zlib')) ? 'gzopen' : 'fopen');
 603          $this->fp = @$fzopen($this->file, $this->mode . 'b' . (($fzopen == 'gzopen') ? '9' : ''));
 604  
 605          if (!$this->fp)
 606          {
 607              trigger_error('Unable to open file ' . $this->file . ' [' . $fzopen . ' - ' . $this->mode . 'b]');
 608          }
 609      }
 610  
 611      /**
 612      * Download archive
 613      */
 614  	function download($filename)
 615      {
 616          global $phpbb_root_path;
 617  
 618          switch ($this->type)
 619          {
 620              case '.tar':
 621                  $mimetype = 'application/x-tar';
 622              break;
 623  
 624              case '.tar.gz':
 625                  $mimetype = 'application/x-gzip';
 626              break;
 627  
 628              case '.tar.bz2':
 629                  $mimetype = 'application/x-bzip2';
 630              break;
 631  
 632              default:
 633                  $mimetype = 'application/octet-stream';
 634              break;
 635          }
 636  
 637          header('Pragma: no-cache');
 638          header("Content-Type: $mimetype; name=\"$filename$this->type\"");
 639          header("Content-disposition: attachment; filename=$filename$this->type");
 640  
 641          $fp = fopen("{$phpbb_root_path}store/$filename$this->type", 'rb');
 642          while ($buffer = fread($fp, 1024))
 643          {
 644              echo $buffer;
 645          }
 646          fclose($fp);
 647      }
 648  }
 649  
 650  ?>


Generated: Wed Nov 22 00:35:05 2006 Cross-referenced by PHPXref 0.6