[ Index ]
 

Code source de PRADO 3.0.6

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/framework/IO/ -> TTarFileExtractor.php (source)

   1  <?php
   2  /**
   3   * TTarFileExtractor class file
   4   *
   5   * @author Vincent Blavet <vincent@phpconcept.net>
   6   * @copyright Copyright &copy; 1997-2003 The PHP Group
   7   * @version $Id: TTarFileExtractor.php 1397 2006-09-07 07:55:53Z wei $
   8   * @package System.IO
   9   */
  10  
  11  /* vim: set ts=4 sw=4: */
  12  // +----------------------------------------------------------------------+
  13  // | PHP Version 4                                                        |
  14  // +----------------------------------------------------------------------+
  15  // | Copyright (c) 1997-2003 The PHP Group                                |
  16  // +----------------------------------------------------------------------+
  17  // | This source file is subject to version 3.0 of the PHP license,       |
  18  // | that is bundled with this package in the file LICENSE, and is        |
  19  // | available through the world-wide-web at the following url:           |
  20  // | http://www.php.net/license/3_0.txt.                                  |
  21  // | If you did not receive a copy of the PHP license and are unable to   |
  22  // | obtain it through the world-wide-web, please send a note to          |
  23  // | license@php.net so we can mail you a copy immediately.               |
  24  // +----------------------------------------------------------------------+
  25  // | Author: Vincent Blavet <vincent@phpconcept.net>                      |
  26  // +----------------------------------------------------------------------+
  27  //
  28  // $Id: TTarFileExtractor.php 1397 2006-09-07 07:55:53Z wei $
  29  
  30  /**
  31   * TTarFileExtractor class
  32   *
  33   * @author Vincent Blavet <vincent@phpconcept.net>
  34   * @version $Id: TTarFileExtractor.php 1397 2006-09-07 07:55:53Z wei $
  35   * @package System.IO
  36   * @since 3.0
  37   */
  38  class TTarFileExtractor
  39  {
  40      /**
  41      * @var string Name of the Tar
  42      */
  43      private $_tarname='';
  44  
  45      /**
  46      * @var file descriptor
  47      */
  48      private $_file=0;
  49  
  50      /**
  51      * @var string Local Tar name of a remote Tar (http:// or ftp://)
  52      */
  53      private $_temp_tarname='';
  54  
  55      /**
  56      * Archive_Tar Class constructor. This flavour of the constructor only
  57      * declare a new Archive_Tar object, identifying it by the name of the
  58      * tar file.
  59      *
  60      * @param    string  $p_tarname  The name of the tar archive to create
  61      * @access public
  62      */
  63      public function __construct($p_tarname)
  64      {
  65          $this->_tarname = $p_tarname;
  66      }
  67  
  68      public function __destruct()
  69      {
  70          $this->_close();
  71          // ----- Look for a local copy to delete
  72          if ($this->_temp_tarname != '')
  73              @unlink($this->_temp_tarname);
  74      }
  75  
  76      public function extract($p_path='')
  77      {
  78          return $this->extractModify($p_path, '');
  79      }
  80  
  81      /**
  82      * This method extract all the content of the archive in the directory
  83      * indicated by $p_path. When relevant the memorized path of the
  84      * files/dir can be modified by removing the $p_remove_path path at the
  85      * beginning of the file/dir path.
  86      * While extracting a file, if the directory path does not exists it is
  87      * created.
  88      * While extracting a file, if the file already exists it is replaced
  89      * without looking for last modification date.
  90      * While extracting a file, if the file already exists and is write
  91      * protected, the extraction is aborted.
  92      * While extracting a file, if a directory with the same name already
  93      * exists, the extraction is aborted.
  94      * While extracting a directory, if a file with the same name already
  95      * exists, the extraction is aborted.
  96      * While extracting a file/directory if the destination directory exist
  97      * and is write protected, or does not exist but can not be created,
  98      * the extraction is aborted.
  99      * If after extraction an extracted file does not show the correct
 100      * stored file size, the extraction is aborted.
 101      * When the extraction is aborted, a PEAR error text is set and false
 102      * is returned. However the result can be a partial extraction that may
 103      * need to be manually cleaned.
 104      *
 105      * @param string $p_path         The path of the directory where the
 106      *                               files/dir need to by extracted.
 107      * @param string $p_remove_path  Part of the memorized path that can be
 108      *                               removed if present at the beginning of
 109      *                               the file/dir path.
 110      * @return boolean               true on success, false on error.
 111      * @access public
 112      */
 113      protected function extractModify($p_path, $p_remove_path)
 114      {
 115          $v_result = true;
 116          $v_list_detail = array();
 117  
 118          if ($v_result = $this->_openRead()) {
 119              $v_result = $this->_extractList($p_path, $v_list_detail,
 120                                              "complete", 0, $p_remove_path);
 121              $this->_close();
 122          }
 123  
 124          return $v_result;
 125      }
 126  
 127      protected function _error($p_message)
 128      {
 129          throw new Exception($p_message);
 130      }
 131  
 132      private function _isArchive($p_filename=null)
 133      {
 134          if ($p_filename == null) {
 135              $p_filename = $this->_tarname;
 136          }
 137          clearstatcache();
 138          return @is_file($p_filename);
 139      }
 140  
 141      private function _openRead()
 142      {
 143          if (strtolower(substr($this->_tarname, 0, 7)) == 'http://') {
 144  
 145            // ----- Look if a local copy need to be done
 146            if ($this->_temp_tarname == '') {
 147                $this->_temp_tarname = uniqid('tar').'.tmp';
 148                if (!$v_file_from = @fopen($this->_tarname, 'rb')) {
 149                  $this->_error('Unable to open in read mode \''
 150                                .$this->_tarname.'\'');
 151                  $this->_temp_tarname = '';
 152                  return false;
 153                }
 154                if (!$v_file_to = @fopen($this->_temp_tarname, 'wb')) {
 155                  $this->_error('Unable to open in write mode \''
 156                                .$this->_temp_tarname.'\'');
 157                  $this->_temp_tarname = '';
 158                  return false;
 159                }
 160                while ($v_data = @fread($v_file_from, 1024))
 161                    @fwrite($v_file_to, $v_data);
 162                @fclose($v_file_from);
 163                @fclose($v_file_to);
 164            }
 165  
 166            // ----- File to open if the local copy
 167            $v_filename = $this->_temp_tarname;
 168  
 169          } else
 170            // ----- File to open if the normal Tar file
 171            $v_filename = $this->_tarname;
 172  
 173          $this->_file = @fopen($v_filename, "rb");
 174  
 175          if ($this->_file == 0) {
 176              $this->_error('Unable to open in read mode \''.$v_filename.'\'');
 177              return false;
 178          }
 179  
 180          return true;
 181      }
 182  
 183      private function _close()
 184      {
 185          //if (isset($this->_file)) {
 186          if (is_resource($this->_file))
 187          {
 188                 @fclose($this->_file);
 189              $this->_file = 0;
 190          }
 191  
 192          // ----- Look if a local copy need to be erase
 193          // Note that it might be interesting to keep the url for a time : ToDo
 194          if ($this->_temp_tarname != '') {
 195              @unlink($this->_temp_tarname);
 196              $this->_temp_tarname = '';
 197          }
 198  
 199          return true;
 200      }
 201  
 202      private function _cleanFile()
 203      {
 204          $this->_close();
 205  
 206          // ----- Look for a local copy
 207          if ($this->_temp_tarname != '') {
 208              // ----- Remove the local copy but not the remote tarname
 209              @unlink($this->_temp_tarname);
 210              $this->_temp_tarname = '';
 211          } else {
 212              // ----- Remove the local tarname file
 213              @unlink($this->_tarname);
 214          }
 215          $this->_tarname = '';
 216  
 217          return true;
 218      }
 219  
 220      private function _readBlock()
 221      {
 222        $v_block = null;
 223        if (is_resource($this->_file)) {
 224                $v_block = @fread($this->_file, 512);
 225        }
 226        return $v_block;
 227      }
 228  
 229      private function _jumpBlock($p_len=null)
 230      {
 231        if (is_resource($this->_file)) {
 232            if ($p_len === null)
 233                $p_len = 1;
 234  
 235                @fseek($this->_file, @ftell($this->_file)+($p_len*512));
 236        }
 237        return true;
 238      }
 239  
 240      private function _readHeader($v_binary_data, &$v_header)
 241      {
 242          if (strlen($v_binary_data)==0) {
 243              $v_header['filename'] = '';
 244              return true;
 245          }
 246  
 247          if (strlen($v_binary_data) != 512) {
 248              $v_header['filename'] = '';
 249              $this->_error('Invalid block size : '.strlen($v_binary_data));
 250              return false;
 251          }
 252  
 253          // ----- Calculate the checksum
 254          $v_checksum = 0;
 255          // ..... First part of the header
 256          for ($i=0; $i<148; $i++)
 257              $v_checksum+=ord(substr($v_binary_data,$i,1));
 258          // ..... Ignore the checksum value and replace it by ' ' (space)
 259          for ($i=148; $i<156; $i++)
 260              $v_checksum += ord(' ');
 261          // ..... Last part of the header
 262          for ($i=156; $i<512; $i++)
 263             $v_checksum+=ord(substr($v_binary_data,$i,1));
 264  
 265          $v_data = unpack("a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/"
 266                           ."a8checksum/a1typeflag/a100link/a6magic/a2version/"
 267                           ."a32uname/a32gname/a8devmajor/a8devminor",
 268                           $v_binary_data);
 269  
 270          // ----- Extract the checksum
 271          $v_header['checksum'] = OctDec(trim($v_data['checksum']));
 272          if ($v_header['checksum'] != $v_checksum) {
 273              $v_header['filename'] = '';
 274  
 275              // ----- Look for last block (empty block)
 276              if (($v_checksum == 256) && ($v_header['checksum'] == 0))
 277                  return true;
 278  
 279              $this->_error('Invalid checksum for file "'.$v_data['filename']
 280                            .'" : '.$v_checksum.' calculated, '
 281                            .$v_header['checksum'].' expected');
 282              return false;
 283          }
 284  
 285          // ----- Extract the properties
 286          $v_header['filename'] = trim($v_data['filename']);
 287          $v_header['mode'] = OctDec(trim($v_data['mode']));
 288          $v_header['uid'] = OctDec(trim($v_data['uid']));
 289          $v_header['gid'] = OctDec(trim($v_data['gid']));
 290          $v_header['size'] = OctDec(trim($v_data['size']));
 291          $v_header['mtime'] = OctDec(trim($v_data['mtime']));
 292          if (($v_header['typeflag'] = $v_data['typeflag']) == "5") {
 293            $v_header['size'] = 0;
 294          }
 295          return true;
 296      }
 297  
 298      private function _readLongHeader(&$v_header)
 299      {
 300        $v_filename = '';
 301        $n = floor($v_header['size']/512);
 302        for ($i=0; $i<$n; $i++) {
 303          $v_content = $this->_readBlock();
 304          $v_filename .= $v_content;
 305        }
 306        if (($v_header['size'] % 512) != 0) {
 307          $v_content = $this->_readBlock();
 308          $v_filename .= $v_content;
 309        }
 310  
 311        // ----- Read the next header
 312        $v_binary_data = $this->_readBlock();
 313  
 314        if (!$this->_readHeader($v_binary_data, $v_header))
 315          return false;
 316  
 317        $v_header['filename'] = $v_filename;
 318  
 319        return true;
 320      }
 321  
 322      protected function _extractList($p_path, &$p_list_detail, $p_mode,
 323                            $p_file_list, $p_remove_path)
 324      {
 325      $v_result=true;
 326      $v_nb = 0;
 327      $v_extract_all = true;
 328      $v_listing = false;
 329  
 330      $p_path = $this->_translateWinPath($p_path, false);
 331      if ($p_path == '' || (substr($p_path, 0, 1) != '/'
 332          && substr($p_path, 0, 3) != "../" && !strpos($p_path, ':'))) {
 333        $p_path = "./".$p_path;
 334      }
 335      $p_remove_path = $this->_translateWinPath($p_remove_path);
 336  
 337      // ----- Look for path to remove format (should end by /)
 338      if (($p_remove_path != '') && (substr($p_remove_path, -1) != '/'))
 339        $p_remove_path .= '/';
 340      $p_remove_path_size = strlen($p_remove_path);
 341  
 342      switch ($p_mode) {
 343        case "complete" :
 344          $v_extract_all = true;
 345          $v_listing = false;
 346        break;
 347        case "partial" :
 348            $v_extract_all = false;
 349            $v_listing = false;
 350        break;
 351        case "list" :
 352            $v_extract_all = false;
 353            $v_listing = true;
 354        break;
 355        default :
 356          $this->_error('Invalid extract mode ('.$p_mode.')');
 357          return false;
 358      }
 359  
 360      clearstatcache();
 361  
 362      while (strlen($v_binary_data = $this->_readBlock()) != 0)
 363      {
 364        $v_extract_file = false;
 365        $v_extraction_stopped = 0;
 366  
 367        if (!$this->_readHeader($v_binary_data, $v_header))
 368          return false;
 369  
 370        if ($v_header['filename'] == '') {
 371          continue;
 372        }
 373  
 374        // ----- Look for long filename
 375        if ($v_header['typeflag'] == 'L') {
 376          if (!$this->_readLongHeader($v_header))
 377            return false;
 378        }
 379  
 380        if ((!$v_extract_all) && (is_array($p_file_list))) {
 381          // ----- By default no unzip if the file is not found
 382          $v_extract_file = false;
 383  
 384          for ($i=0; $i<sizeof($p_file_list); $i++) {
 385            // ----- Look if it is a directory
 386            if (substr($p_file_list[$i], -1) == '/') {
 387              // ----- Look if the directory is in the filename path
 388              if ((strlen($v_header['filename']) > strlen($p_file_list[$i]))
 389                  && (substr($v_header['filename'], 0, strlen($p_file_list[$i]))
 390                      == $p_file_list[$i])) {
 391                $v_extract_file = true;
 392                break;
 393              }
 394            }
 395  
 396            // ----- It is a file, so compare the file names
 397            elseif ($p_file_list[$i] == $v_header['filename']) {
 398              $v_extract_file = true;
 399              break;
 400            }
 401          }
 402        } else {
 403          $v_extract_file = true;
 404        }
 405  
 406        // ----- Look if this file need to be extracted
 407        if (($v_extract_file) && (!$v_listing))
 408        {
 409          if (($p_remove_path != '')
 410              && (substr($v_header['filename'], 0, $p_remove_path_size)
 411                  == $p_remove_path))
 412            $v_header['filename'] = substr($v_header['filename'],
 413                                           $p_remove_path_size);
 414          if (($p_path != './') && ($p_path != '/')) {
 415            while (substr($p_path, -1) == '/')
 416              $p_path = substr($p_path, 0, strlen($p_path)-1);
 417  
 418            if (substr($v_header['filename'], 0, 1) == '/')
 419                $v_header['filename'] = $p_path.$v_header['filename'];
 420            else
 421              $v_header['filename'] = $p_path.'/'.$v_header['filename'];
 422          }
 423          if (file_exists($v_header['filename'])) {
 424            if (   (@is_dir($v_header['filename']))
 425                && ($v_header['typeflag'] == '')) {
 426              $this->_error('File '.$v_header['filename']
 427                            .' already exists as a directory');
 428              return false;
 429            }
 430            if (   ($this->_isArchive($v_header['filename']))
 431                && ($v_header['typeflag'] == "5")) {
 432              $this->_error('Directory '.$v_header['filename']
 433                            .' already exists as a file');
 434              return false;
 435            }
 436            if (!is_writeable($v_header['filename'])) {
 437              $this->_error('File '.$v_header['filename']
 438                            .' already exists and is write protected');
 439              return false;
 440            }
 441            if (filemtime($v_header['filename']) > $v_header['mtime']) {
 442              // To be completed : An error or silent no replace ?
 443            }
 444          }
 445  
 446          // ----- Check the directory availability and create it if necessary
 447          elseif (($v_result
 448                   = $this->_dirCheck(($v_header['typeflag'] == "5"
 449                                      ?$v_header['filename']
 450                                      :dirname($v_header['filename'])))) != 1) {
 451              $this->_error('Unable to create path for '.$v_header['filename']);
 452              return false;
 453          }
 454  
 455          if ($v_extract_file) {
 456            if ($v_header['typeflag'] == "5") {
 457              if (!@file_exists($v_header['filename'])) {
 458                  if (!@mkdir($v_header['filename'], 0777)) {
 459                      $this->_error('Unable to create directory {'
 460                                    .$v_header['filename'].'}');
 461                      return false;
 462                  }
 463                  chmod($v_header['filename'], 0777);
 464              }
 465            } else {
 466                if (($v_dest_file = @fopen($v_header['filename'], "wb")) == 0) {
 467                    $this->_error('Error while opening {'.$v_header['filename']
 468                                  .'} in write binary mode');
 469                    return false;
 470                } else {
 471                    $n = floor($v_header['size']/512);
 472                    for ($i=0; $i<$n; $i++) {
 473                        $v_content = $this->_readBlock();
 474                        fwrite($v_dest_file, $v_content, 512);
 475                    }
 476              if (($v_header['size'] % 512) != 0) {
 477                $v_content = $this->_readBlock();
 478                fwrite($v_dest_file, $v_content, ($v_header['size'] % 512));
 479              }
 480  
 481              @fclose($v_dest_file);
 482  
 483              // ----- Change the file mode, mtime
 484              @touch($v_header['filename'], $v_header['mtime']);
 485              // To be completed
 486              //chmod($v_header[filename], DecOct($v_header[mode]));
 487            }
 488  
 489            // ----- Check the file size
 490            clearstatcache();
 491            if (filesize($v_header['filename']) != $v_header['size']) {
 492                $this->_error('Extracted file '.$v_header['filename']
 493                              .' does not have the correct file size \''
 494                              .filesize($v_header['filename'])
 495                              .'\' ('.$v_header['size']
 496                              .' expected). Archive may be corrupted.');
 497                return false;
 498            }
 499            }
 500          } else {
 501            $this->_jumpBlock(ceil(($v_header['size']/512)));
 502          }
 503        } else {
 504            $this->_jumpBlock(ceil(($v_header['size']/512)));
 505        }
 506  
 507        /* TBC : Seems to be unused ...
 508        if ($this->_compress)
 509          $v_end_of_file = @gzeof($this->_file);
 510        else
 511          $v_end_of_file = @feof($this->_file);
 512          */
 513  
 514        if ($v_listing || $v_extract_file || $v_extraction_stopped) {
 515          // ----- Log extracted files
 516          if (($v_file_dir = dirname($v_header['filename']))
 517              == $v_header['filename'])
 518            $v_file_dir = '';
 519          if ((substr($v_header['filename'], 0, 1) == '/') && ($v_file_dir == ''))
 520            $v_file_dir = '/';
 521  
 522          $p_list_detail[$v_nb++] = $v_header;
 523        }
 524      }
 525  
 526          return true;
 527      }
 528  
 529      /**
 530       * Check if a directory exists and create it (including parent
 531       * dirs) if not.
 532       *
 533       * @param string $p_dir directory to check
 534       *
 535       * @return bool true if the directory exists or was created
 536       */
 537      protected function _dirCheck($p_dir)
 538      {
 539          if ((@is_dir($p_dir)) || ($p_dir == ''))
 540              return true;
 541  
 542          $p_parent_dir = dirname($p_dir);
 543  
 544          if (($p_parent_dir != $p_dir) &&
 545              ($p_parent_dir != '') &&
 546              (!$this->_dirCheck($p_parent_dir)))
 547               return false;
 548  
 549          if (!@mkdir($p_dir, 0777)) {
 550              $this->_error("Unable to create directory '$p_dir'");
 551              return false;
 552          }
 553          chmod($p_dir,0777);
 554  
 555          return true;
 556      }
 557  
 558      protected function _translateWinPath($p_path, $p_remove_disk_letter=true)
 559      {
 560        if (substr(PHP_OS, 0, 3) == 'WIN') {
 561            // ----- Look for potential disk letter
 562            if (   ($p_remove_disk_letter)
 563                && (($v_position = strpos($p_path, ':')) != false)) {
 564                $p_path = substr($p_path, $v_position+1);
 565            }
 566            // ----- Change potential windows directory separator
 567            if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0,1) == '\\')) {
 568                $p_path = strtr($p_path, '\\', '/');
 569            }
 570        }
 571        return $p_path;
 572      }
 573  }
 574  ?>


Généré le : Sun Feb 25 21:07:04 2007 par Balluche grâce à PHPXref 0.7