[ Index ]
 

Code source de Joomla 1.0.13

Accédez au Source d'autres logiciels libres

title

Body

[fermer]

/includes/Archive/ -> Tar.php (source)

   1  <?php
   2  /* vim: set ts=4 sw=4: */

   3  // +----------------------------------------------------------------------+

   4  // | PHP Version 4                                                        |

   5  // +----------------------------------------------------------------------+

   6  // | Copyright (c) 1997-2003 The PHP Group                                |

   7  // +----------------------------------------------------------------------+

   8  // | This source file is subject to version 3.0 of the PHP license,        |

   9  // | that is bundled with this package in the file LICENSE, and is        |

  10  // | available through the world-wide-web at the following url:            |

  11  // | http://www.php.net/license/3_0.txt.                                  |

  12  // | If you did not receive a copy of the PHP license and are unable to    |

  13  // | obtain it through the world-wide-web, please send a note to          |

  14  // | license@php.net so we can mail you a copy immediately.                |

  15  // +----------------------------------------------------------------------+

  16  // | Author: Vincent Blavet <vincent@blavet.net>                          |

  17  // +----------------------------------------------------------------------+

  18  //

  19  // $Id: Tar.php 49 2005-09-15 02:55:27Z rhuk $

  20  
  21  // no direct access

  22  defined( '_VALID_MOS' ) or die( 'Restricted access' );
  23  
  24  require_once $GLOBALS['mosConfig_absolute_path'] . '/includes/PEAR/PEAR.php';
  25  
  26  define ('ARCHIVE_TAR_ATT_SEPARATOR', 90001);
  27  
  28  /**

  29  * Creates a (compressed) Tar archive

  30  *

  31  * @author    Vincent Blavet <vincent@blavet.net>

  32  * @version  $Revision: 49 $

  33  * @package  Archive

  34  */
  35  class Archive_Tar extends PEAR
  36  {
  37      /**

  38      * @var string Name of the Tar

  39      */
  40      var $_tarname='';
  41  
  42      /**

  43      * @var boolean if true, the Tar file will be gzipped

  44      */
  45      var $_compress=false;
  46  
  47      /**

  48      * @var string Type of compression : 'none', 'gz' or 'bz2'

  49      */
  50      var $_compress_type='none';
  51  
  52      /**

  53      * @var string Explode separator

  54      */
  55      var $_separator=' ';
  56  
  57      /**

  58      * @var file descriptor

  59      */
  60      var $_file=0;
  61  
  62      /**

  63      * @var string Local Tar name of a remote Tar (http:// or ftp://)

  64      */
  65      var $_temp_tarname='';
  66  
  67      // {{{ constructor

  68      /**

  69      * Archive_Tar Class constructor. This flavour of the constructor only

  70      * declare a new Archive_Tar object, identifying it by the name of the

  71      * tar file.

  72      * If the compress argument is set the tar will be read or created as a

  73      * gzip or bz2 compressed TAR file.

  74      *

  75      * @param    string  $p_tarname  The name of the tar archive to create

  76      * @param    string  $p_compress can be null, 'gz' or 'bz2'. This

  77      *                    parameter indicates if gzip or bz2 compression

  78      *                    is required.  For compatibility reason the

  79      *                    boolean value 'true' means 'gz'.

  80      * @access public

  81      */
  82  	function Archive_Tar($p_tarname, $p_compress = null)
  83      {
  84          $this->PEAR();
  85          $this->_compress = false;
  86          $this->_compress_type = 'none';
  87          if ($p_compress === null) {
  88              if (@file_exists($p_tarname)) {
  89                  if ($fp = @fopen($p_tarname, "rb")) {
  90                      // look for gzip magic cookie

  91                      $data = fread($fp, 2);
  92                      fclose($fp);
  93                      if ($data == "\37\213") {
  94                          $this->_compress = true;
  95                          $this->_compress_type = 'gz';
  96                      // No sure it's enought for a magic code ....

  97                      } elseif ($data == "BZ") {
  98                          $this->_compress = true;
  99                          $this->_compress_type = 'bz2';
 100                      }
 101                  }
 102              } else {
 103                  // probably a remote file or some file accessible

 104                  // through a stream interface

 105                  if (substr($p_tarname, -2) == 'gz') {
 106                      $this->_compress = true;
 107                      $this->_compress_type = 'gz';
 108                  } elseif ((substr($p_tarname, -3) == 'bz2') ||
 109                            (substr($p_tarname, -2) == 'bz')) {
 110                      $this->_compress = true;
 111                      $this->_compress_type = 'bz2';
 112                  }
 113              }
 114          } else {
 115              if (($p_compress === true) || ($p_compress == 'gz')) {
 116                  $this->_compress = true;
 117                  $this->_compress_type = 'gz';
 118              } else if ($p_compress == 'bz2') {
 119                  $this->_compress = true;
 120                  $this->_compress_type = 'bz2';
 121              }
 122          }
 123          $this->_tarname = $p_tarname;
 124          if ($this->_compress) { // assert zlib or bz2 extension support
 125              if ($this->_compress_type == 'gz')
 126                  $extname = 'zlib';
 127              else if ($this->_compress_type == 'bz2')
 128                  $extname = 'bz2';
 129  
 130              if (!extension_loaded($extname)) {
 131                  PEAR::loadExtension($extname);
 132              }
 133              if (!extension_loaded($extname)) {
 134                  die("The extension '$extname' couldn't be found.\n".
 135                      "Please make sure your version of PHP was built ".
 136                      "with '$extname' support.\n");
 137                  return false;
 138              }
 139          }
 140      }
 141      // }}}

 142  
 143      // {{{ destructor

 144  	function _Archive_Tar()
 145      {
 146          $this->_close();
 147          // ----- Look for a local copy to delete

 148          if ($this->_temp_tarname != '')
 149              @unlink($this->_temp_tarname);
 150          $this->_PEAR();
 151      }
 152      // }}}

 153  
 154      // {{{ create()

 155      /**

 156      * This method creates the archive file and add the files / directories

 157      * that are listed in $p_filelist.

 158      * If a file with the same name exist and is writable, it is replaced

 159      * by the new tar.

 160      * The method return false and a PEAR error text.

 161      * The $p_filelist parameter can be an array of string, each string

 162      * representing a filename or a directory name with their path if

 163      * needed. It can also be a single string with names separated by a

 164      * single blank.

 165      * For each directory added in the archive, the files and

 166      * sub-directories are also added.

 167      * See also createModify() method for more details.

 168      *

 169      * @param array  $p_filelist An array of filenames and directory names, or a single

 170      *                            string with names separated by a single blank space.

 171      * @return                    true on success, false on error.

 172      * @see createModify()

 173      * @access public

 174      */
 175  	function create($p_filelist)
 176      {
 177          return $this->createModify($p_filelist, '', '');
 178      }
 179      // }}}

 180  
 181      // {{{ add()

 182      /**

 183      * This method add the files / directories that are listed in $p_filelist in

 184      * the archive. If the archive does not exist it is created.

 185      * The method return false and a PEAR error text.

 186      * The files and directories listed are only added at the end of the archive,

 187      * even if a file with the same name is already archived.

 188      * See also createModify() method for more details.

 189      *

 190      * @param array  $p_filelist An array of filenames and directory names, or a single

 191      *                            string with names separated by a single blank space.

 192      * @return                    true on success, false on error.

 193      * @see createModify()

 194      * @access public

 195      */
 196  	function add($p_filelist)
 197      {
 198          return $this->addModify($p_filelist, '', '');
 199      }
 200      // }}}

 201  
 202      // {{{ extract()

 203  	function extract($p_path='')
 204      {
 205          return $this->extractModify($p_path, '');
 206      }
 207      // }}}

 208  
 209      // {{{ listContent()

 210  	function listContent()
 211      {
 212          $v_list_detail = array();
 213  
 214          if ($this->_openRead()) {
 215              if (!$this->_extractList('', $v_list_detail, "list", '', '')) {
 216                  unset($v_list_detail);
 217                  $v_list_detail = 0;
 218              }
 219              $this->_close();
 220          }
 221  
 222          return $v_list_detail;
 223      }
 224      // }}}

 225  
 226      // {{{ createModify()

 227      /**

 228      * This method creates the archive file and add the files / directories

 229      * that are listed in $p_filelist.

 230      * If the file already exists and is writable, it is replaced by the

 231      * new tar. It is a create and not an add. If the file exists and is

 232      * read-only or is a directory it is not replaced. The method return

 233      * false and a PEAR error text.

 234      * The $p_filelist parameter can be an array of string, each string

 235      * representing a filename or a directory name with their path if

 236      * needed. It can also be a single string with names separated by a

 237      * single blank.

 238      * The path indicated in $p_remove_dir will be removed from the

 239      * memorized path of each file / directory listed when this path

 240      * exists. By default nothing is removed (empty path '')

 241      * The path indicated in $p_add_dir will be added at the beginning of

 242      * the memorized path of each file / directory listed. However it can

 243      * be set to empty ''. The adding of a path is done after the removing

 244      * of path.

 245      * The path add/remove ability enables the user to prepare an archive

 246      * for extraction in a different path than the origin files are.

 247      * See also addModify() method for file adding properties.

 248      *

 249      * @param array  $p_filelist     An array of filenames and directory names, or a single

 250      *                                string with names separated by a single blank space.

 251      * @param string $p_add_dir      A string which contains a path to be added to the

 252      *                                memorized path of each element in the list.

 253      * @param string $p_remove_dir    A string which contains a path to be removed from

 254      *                                the memorized path of each element in the list, when

 255      *                                relevant.

 256      * @return boolean                true on success, false on error.

 257      * @access public

 258      * @see addModify()

 259      */
 260  	function createModify($p_filelist, $p_add_dir, $p_remove_dir='')
 261      {
 262          $v_result = true;
 263  
 264          if (!$this->_openWrite())
 265              return false;
 266  
 267          if ($p_filelist != '') {
 268              if (is_array($p_filelist))
 269                  $v_list = $p_filelist;
 270              elseif (is_string($p_filelist))
 271                  $v_list = explode($this->_separator, $p_filelist);
 272              else {
 273                  $this->_cleanFile();
 274                  $this->_error('Invalid file list');
 275                  return false;
 276              }
 277  
 278              $v_result = $this->_addList($v_list, $p_add_dir, $p_remove_dir);
 279          }
 280  
 281          if ($v_result) {
 282              $this->_writeFooter();
 283              $this->_close();
 284          } else
 285              $this->_cleanFile();
 286  
 287          return $v_result;
 288      }
 289      // }}}

 290  
 291      // {{{ addModify()

 292      /**

 293      * This method add the files / directories listed in $p_filelist at the

 294      * end of the existing archive. If the archive does not yet exists it

 295      * is created.

 296      * The $p_filelist parameter can be an array of string, each string

 297      * representing a filename or a directory name with their path if

 298      * needed. It can also be a single string with names separated by a

 299      * single blank.

 300      * The path indicated in $p_remove_dir will be removed from the

 301      * memorized path of each file / directory listed when this path

 302      * exists. By default nothing is removed (empty path '')

 303      * The path indicated in $p_add_dir will be added at the beginning of

 304      * the memorized path of each file / directory listed. However it can

 305      * be set to empty ''. The adding of a path is done after the removing

 306      * of path.

 307      * The path add/remove ability enables the user to prepare an archive

 308      * for extraction in a different path than the origin files are.

 309      * If a file/dir is already in the archive it will only be added at the

 310      * end of the archive. There is no update of the existing archived

 311      * file/dir. However while extracting the archive, the last file will

 312      * replace the first one. This results in a none optimization of the

 313      * archive size.

 314      * If a file/dir does not exist the file/dir is ignored. However an

 315      * error text is send to PEAR error.

 316      * If a file/dir is not readable the file/dir is ignored. However an

 317      * error text is send to PEAR error.

 318      *

 319      * @param array      $p_filelist     An array of filenames and directory names, or a single

 320      *                                    string with names separated by a single blank space.

 321      * @param string     $p_add_dir      A string which contains a path to be added to the

 322      *                                    memorized path of each element in the list.

 323      * @param string     $p_remove_dir    A string which contains a path to be removed from

 324      *                                    the memorized path of each element in the list, when

 325      *                                    relevant.

 326      * @return                            true on success, false on error.

 327      * @access public

 328      */
 329  	function addModify($p_filelist, $p_add_dir, $p_remove_dir='')
 330      {
 331          $v_result = true;
 332  
 333          if (!@is_file($this->_tarname))
 334              $v_result = $this->createModify($p_filelist, $p_add_dir, $p_remove_dir);
 335          else {
 336              if (is_array($p_filelist))
 337                  $v_list = $p_filelist;
 338              elseif (is_string($p_filelist))
 339                  $v_list = explode($this->_separator, $p_filelist);
 340              else {
 341                  $this->_error('Invalid file list');
 342                  return false;
 343              }
 344  
 345              $v_result = $this->_append($v_list, $p_add_dir, $p_remove_dir);
 346          }
 347  
 348          return $v_result;
 349      }
 350      // }}}

 351  
 352      // {{{ addString()

 353      /**

 354      * This method add a single string as a file at the

 355      * end of the existing archive. If the archive does not yet exists it

 356      * is created.

 357      *

 358      * @param string     $p_filename     A string which contains the full filename path

 359      *                                    that will be associated with the string.

 360      * @param string     $p_string        The content of the file added in the archive.

 361      * @return                            true on success, false on error.

 362      * @access public

 363      */
 364  	function addString($p_filename, $p_string)
 365      {
 366          $v_result = true;
 367  
 368          if (!@is_file($this->_tarname)) {
 369              if (!$this->_openWrite()) {
 370                  return false;
 371              }
 372              $this->_close();
 373          }
 374  
 375          if (!$this->_openAppend())
 376              return false;
 377  
 378          // Need to check the get back to the temporary file ? ....

 379          $v_result = $this->_addString($p_filename, $p_string);
 380  
 381          $this->_writeFooter();
 382  
 383          $this->_close();
 384  
 385          return $v_result;
 386      }
 387      // }}}

 388  
 389      // {{{ extractModify()

 390      /**

 391      * This method extract all the content of the archive in the directory

 392      * indicated by $p_path. When relevant the memorized path of the

 393      * files/dir can be modified by removing the $p_remove_path path at the

 394      * beginning of the file/dir path.

 395      * While extracting a file, if the directory path does not exists it is

 396      * created.

 397      * While extracting a file, if the file already exists it is replaced

 398      * without looking for last modification date.

 399      * While extracting a file, if the file already exists and is write

 400      * protected, the extraction is aborted.

 401      * While extracting a file, if a directory with the same name already

 402      * exists, the extraction is aborted.

 403      * While extracting a directory, if a file with the same name already

 404      * exists, the extraction is aborted.

 405      * While extracting a file/directory if the destination directory exist

 406      * and is write protected, or does not exist but can not be created,

 407      * the extraction is aborted.

 408      * If after extraction an extracted file does not show the correct

 409      * stored file size, the extraction is aborted.

 410      * When the extraction is aborted, a PEAR error text is set and false

 411      * is returned. However the result can be a partial extraction that may

 412      * need to be manually cleaned.

 413      *

 414      * @param string $p_path         The path of the directory where the files/dir need to by

 415      *                                extracted.

 416      * @param string $p_remove_path  Part of the memorized path that can be removed if

 417      *                                present at the beginning of the file/dir path.

 418      * @return boolean                true on success, false on error.

 419      * @access public

 420      * @see extractList()

 421      */
 422  	function extractModify($p_path, $p_remove_path)
 423      {
 424          $v_result = true;
 425          $v_list_detail = array();
 426  
 427          if ($v_result = $this->_openRead()) {
 428              $v_result = $this->_extractList($p_path, $v_list_detail, "complete", 0, $p_remove_path);
 429              $this->_close();
 430          }
 431  
 432          return $v_result;
 433      }
 434      // }}}

 435  
 436      // {{{ extractInString()

 437      /**

 438      * This method extract from the archive one file identified by $p_filename.

 439      * The return value is a string with the file content, or NULL on error.

 440      * @param string $p_filename     The path of the file to extract in a string.

 441      * @return                        a string with the file content or NULL.

 442      * @access public

 443      */
 444  	function extractInString($p_filename)
 445      {
 446          if ($this->_openRead()) {
 447              $v_result = $this->_extractInString($p_filename);
 448              $this->_close();
 449          } else {
 450              $v_result = NULL;
 451          }
 452  
 453          return $v_result;
 454      }
 455      // }}}

 456  
 457      // {{{ extractList()

 458      /**

 459      * This method extract from the archive only the files indicated in the

 460      * $p_filelist. These files are extracted in the current directory or

 461      * in the directory indicated by the optional $p_path parameter.

 462      * If indicated the $p_remove_path can be used in the same way as it is

 463      * used in extractModify() method.

 464      * @param array  $p_filelist     An array of filenames and directory names, or a single

 465      *                                string with names separated by a single blank space.

 466      * @param string $p_path         The path of the directory where the files/dir need to by

 467      *                                extracted.

 468      * @param string $p_remove_path  Part of the memorized path that can be removed if

 469      *                                present at the beginning of the file/dir path.

 470      * @return                        true on success, false on error.

 471      * @access public

 472      * @see extractModify()

 473      */
 474  	function extractList($p_filelist, $p_path='', $p_remove_path='')
 475      {
 476          $v_result = true;
 477          $v_list_detail = array();
 478  
 479          if (is_array($p_filelist))
 480              $v_list = $p_filelist;
 481          elseif (is_string($p_filelist))
 482              $v_list = explode($this->_separator, $p_filelist);
 483          else {
 484              $this->_error('Invalid string list');
 485              return false;
 486          }
 487  
 488          if ($v_result = $this->_openRead()) {
 489              $v_result = $this->_extractList($p_path, $v_list_detail, "partial", $v_list, $p_remove_path);
 490              $this->_close();
 491          }
 492  
 493          return $v_result;
 494      }
 495      // }}}

 496  
 497      // {{{ setAttribute()

 498      /**

 499      * This method set specific attributes of the archive. It uses a variable

 500      * list of parameters, in the format attribute code + attribute values :

 501      * $arch->setAttribute(ARCHIVE_TAR_ATT_SEPARATOR, ',');

 502      * @param mixed $argv            variable list of attributes and values

 503      * @return                        true on success, false on error.

 504      * @access public

 505      */
 506  	function setAttribute()
 507      {
 508          $v_result = true;
 509  
 510          // ----- Get the number of variable list of arguments

 511          if (($v_size = func_num_args()) == 0) {
 512              return true;
 513          }
 514  
 515          // ----- Get the arguments

 516          $v_att_list = &func_get_args();
 517  
 518          // ----- Read the attributes

 519          $i=0;
 520          while ($i<$v_size) {
 521  
 522              // ----- Look for next option

 523              switch ($v_att_list[$i]) {
 524                  // ----- Look for options that request a string value

 525                  case ARCHIVE_TAR_ATT_SEPARATOR :
 526                      // ----- Check the number of parameters

 527                      if (($i+1) >= $v_size) {
 528                          $this->_error('Invalid number of parameters for attribute ARCHIVE_TAR_ATT_SEPARATOR');
 529                          return false;
 530                      }
 531  
 532                      // ----- Get the value

 533                      $this->_separator = $v_att_list[$i+1];
 534                      $i++;
 535                  break;
 536  
 537                  default :
 538                      $this->_error('Unknow attribute code '.$v_att_list[$i].'');
 539                      return false;
 540              }
 541  
 542              // ----- Next attribute

 543              $i++;
 544          }
 545  
 546          return $v_result;
 547      }
 548      // }}}

 549  
 550      // {{{ _error()

 551  	function _error($p_message)
 552      {
 553          // ----- To be completed

 554          $this->raiseError($p_message);
 555      }
 556      // }}}

 557  
 558      // {{{ _warning()

 559  	function _warning($p_message)
 560      {
 561          // ----- To be completed

 562          $this->raiseError($p_message);
 563      }
 564      // }}}

 565  
 566      // {{{ _openWrite()

 567  	function _openWrite()
 568      {
 569          if ($this->_compress_type == 'gz')
 570              $this->_file = @gzopen($this->_tarname, "wb");
 571          else if ($this->_compress_type == 'bz2')
 572              $this->_file = @bzopen($this->_tarname, "wb");
 573          else if ($this->_compress_type == 'none')
 574              $this->_file = @fopen($this->_tarname, "wb");
 575          else
 576              $this->_error('Unknown or missing compression type ('.$this->_compress_type.')');
 577  
 578          if ($this->_file == 0) {
 579              $this->_error('Unable to open in write mode \''.$this->_tarname.'\'');
 580              return false;
 581          }
 582  
 583          return true;
 584      }
 585      // }}}

 586  
 587      // {{{ _openRead()

 588  	function _openRead()
 589      {
 590          if (strtolower(substr($this->_tarname, 0, 7)) == 'http://') {
 591  
 592            // ----- Look if a local copy need to be done

 593            if ($this->_temp_tarname == '') {
 594                $this->_temp_tarname = uniqid('tar').'.tmp';
 595                if (!$v_file_from = @fopen($this->_tarname, 'rb')) {
 596                  $this->_error('Unable to open in read mode \''.$this->_tarname.'\'');
 597                  $this->_temp_tarname = '';
 598                  return false;
 599                }
 600                if (!$v_file_to = @fopen($this->_temp_tarname, 'wb')) {
 601                  $this->_error('Unable to open in write mode \''.$this->_temp_tarname.'\'');
 602                  $this->_temp_tarname = '';
 603                  return false;
 604                }
 605                while ($v_data = @fread($v_file_from, 1024))
 606                    @fwrite($v_file_to, $v_data);
 607                @fclose($v_file_from);
 608                @fclose($v_file_to);
 609            }
 610  
 611            // ----- File to open if the local copy

 612            $v_filename = $this->_temp_tarname;
 613  
 614          } else
 615            // ----- File to open if the normal Tar file

 616            $v_filename = $this->_tarname;
 617  
 618          if ($this->_compress_type == 'gz')
 619              $this->_file = @gzopen($v_filename, "rb");
 620          else if ($this->_compress_type == 'bz2')
 621              $this->_file = @bzopen($v_filename, "rb");
 622          else if ($this->_compress_type == 'none')
 623              $this->_file = @fopen($v_filename, "rb");
 624          else
 625              $this->_error('Unknown or missing compression type ('.$this->_compress_type.')');
 626  
 627          if ($this->_file == 0) {
 628              $this->_error('Unable to open in read mode \''.$v_filename.'\'');
 629              return false;
 630          }
 631  
 632          return true;
 633      }
 634      // }}}

 635  
 636      // {{{ _openReadWrite()

 637  	function _openReadWrite()
 638      {
 639          if ($this->_compress_type == 'gz')
 640              $this->_file = @gzopen($this->_tarname, "r+b");
 641          else if ($this->_compress_type == 'bz2')
 642              $this->_file = @bzopen($this->_tarname, "r+b");
 643          else if ($this->_compress_type == 'none')
 644              $this->_file = @fopen($this->_tarname, "r+b");
 645          else
 646              $this->_error('Unknown or missing compression type ('.$this->_compress_type.')');
 647  
 648          if ($this->_file == 0) {
 649              $this->_error('Unable to open in read/write mode \''.$this->_tarname.'\'');
 650              return false;
 651          }
 652  
 653          return true;
 654      }
 655      // }}}

 656  
 657      // {{{ _close()

 658  	function _close()
 659      {
 660          //if (isset($this->_file)) {

 661          if (is_resource($this->_file)) {
 662              if ($this->_compress_type == 'gz')
 663                  @gzclose($this->_file);
 664              else if ($this->_compress_type == 'bz2')
 665                  @bzclose($this->_file);
 666              else if ($this->_compress_type == 'none')
 667                  @fclose($this->_file);
 668              else
 669                  $this->_error('Unknown or missing compression type ('.$this->_compress_type.')');
 670  
 671              $this->_file = 0;
 672          }
 673  
 674          // ----- Look if a local copy need to be erase

 675          // Note that it might be interesting to keep the url for a time : ToDo

 676          if ($this->_temp_tarname != '') {
 677              @unlink($this->_temp_tarname);
 678              $this->_temp_tarname = '';
 679          }
 680  
 681          return true;
 682      }
 683      // }}}

 684  
 685      // {{{ _cleanFile()

 686  	function _cleanFile()
 687      {
 688          $this->_close();
 689  
 690          // ----- Look for a local copy

 691          if ($this->_temp_tarname != '') {
 692              // ----- Remove the local copy but not the remote tarname

 693              @unlink($this->_temp_tarname);
 694              $this->_temp_tarname = '';
 695          } else {
 696              // ----- Remove the local tarname file

 697              @unlink($this->_tarname);
 698          }
 699          $this->_tarname = '';
 700  
 701          return true;
 702      }
 703      // }}}

 704  
 705      // {{{ _writeBlock()

 706  	function _writeBlock($p_binary_data, $p_len=null)
 707      {
 708        if (is_resource($this->_file)) {
 709            if ($p_len === null) {
 710                if ($this->_compress_type == 'gz')
 711                    @gzputs($this->_file, $p_binary_data);
 712                else if ($this->_compress_type == 'bz2')
 713                    @bzwrite($this->_file, $p_binary_data);
 714                else if ($this->_compress_type == 'none')
 715                    @fputs($this->_file, $p_binary_data);
 716                else
 717                    $this->_error('Unknown or missing compression type ('.$this->_compress_type.')');
 718            } else {
 719                if ($this->_compress_type == 'gz')
 720                    @gzputs($this->_file, $p_binary_data, $p_len);
 721                else if ($this->_compress_type == 'bz2')
 722                    @bzwrite($this->_file, $p_binary_data, $p_len);
 723                else if ($this->_compress_type == 'none')
 724                    @fputs($this->_file, $p_binary_data, $p_len);
 725                else
 726                    $this->_error('Unknown or missing compression type ('.$this->_compress_type.')');
 727  
 728            }
 729        }
 730        return true;
 731      }
 732      // }}}

 733  
 734      // {{{ _readBlock()

 735  	function _readBlock($p_len=null)
 736      {
 737        $v_block = null;
 738        if (is_resource($this->_file)) {
 739            if ($p_len === null)
 740                $p_len = 512;
 741  
 742            if ($this->_compress_type == 'gz')
 743                $v_block = @gzread($this->_file, 512);
 744            else if ($this->_compress_type == 'bz2')
 745                $v_block = @bzread($this->_file, 512);
 746            else if ($this->_compress_type == 'none')
 747                $v_block = @fread($this->_file, 512);
 748            else
 749                $this->_error('Unknown or missing compression type ('.$this->_compress_type.')');
 750  
 751        }
 752        return $v_block;
 753      }
 754      // }}}

 755  
 756      // {{{ _jumpBlock()

 757  	function _jumpBlock($p_len=null)
 758      {
 759        if (is_resource($this->_file)) {
 760            if ($p_len === null)
 761                $p_len = 1;
 762  
 763            if ($this->_compress_type == 'gz')
 764                @gzseek($this->_file, @gztell($this->_file)+($p_len*512));
 765            else if ($this->_compress_type == 'bz2') {
 766                // ----- Replace missing bztell() and bzseek()

 767                for ($i=0; $i<$p_len; $i++)
 768                    $this->_readBlock();
 769            } else if ($this->_compress_type == 'none')
 770                @fseek($this->_file, @ftell($this->_file)+($p_len*512));
 771            else
 772                $this->_error('Unknown or missing compression type ('.$this->_compress_type.')');
 773  
 774        }
 775        return true;
 776      }
 777      // }}}

 778  
 779      // {{{ _writeFooter()

 780  	function _writeFooter()
 781      {
 782        if (is_resource($this->_file)) {
 783            // ----- Write the last 0 filled block for end of archive

 784            $v_binary_data = pack("a512", '');
 785            $this->_writeBlock($v_binary_data);
 786        }
 787        return true;
 788      }
 789      // }}}

 790  
 791      // {{{ _addList()

 792  	function _addList($p_list, $p_add_dir, $p_remove_dir)
 793      {
 794        $v_result=true;
 795        $v_header = array();
 796  
 797        // ----- Remove potential windows directory separator

 798        $p_add_dir = $this->_translateWinPath($p_add_dir);
 799        $p_remove_dir = $this->_translateWinPath($p_remove_dir, false);
 800  
 801        if (!$this->_file) {
 802            $this->_error('Invalid file descriptor');
 803            return false;
 804        }
 805  
 806        if (sizeof($p_list) == 0)
 807            return true;
 808  
 809        for ($j=0; ($j<count($p_list)) && ($v_result); $j++) {
 810          $v_filename = $p_list[$j];
 811  
 812          // ----- Skip the current tar name

 813          if ($v_filename == $this->_tarname)
 814              continue;
 815  
 816          if ($v_filename == '')
 817              continue;
 818  
 819          if (!file_exists($v_filename)) {
 820              $this->_warning("File '$v_filename' does not exist");
 821              continue;
 822          }
 823  
 824          // ----- Add the file or directory header

 825          if (!$this->_addFile($v_filename, $v_header, $p_add_dir, $p_remove_dir))
 826              return false;
 827  
 828          if (@is_dir($v_filename)) {
 829              if (!($p_hdir = opendir($v_filename))) {
 830                  $this->_warning("Directory '$v_filename' can not be read");
 831                  continue;
 832              }
 833              $p_hitem = readdir($p_hdir); // '.' directory

 834              $p_hitem = readdir($p_hdir); // '..' directory

 835              while (false !== ($p_hitem = readdir($p_hdir))) {
 836                  if ($v_filename != ".")
 837                      $p_temp_list[0] = $v_filename.'/'.$p_hitem;
 838                  else
 839                      $p_temp_list[0] = $p_hitem;
 840  
 841                  $v_result = $this->_addList($p_temp_list, $p_add_dir, $p_remove_dir);
 842              }
 843  
 844              unset($p_temp_list);
 845              unset($p_hdir);
 846              unset($p_hitem);
 847          }
 848        }
 849  
 850        return $v_result;
 851      }
 852      // }}}

 853  
 854      // {{{ _addFile()

 855  	function _addFile($p_filename, &$p_header, $p_add_dir, $p_remove_dir)
 856      {
 857        if (!$this->_file) {
 858            $this->_error('Invalid file descriptor');
 859            return false;
 860        }
 861  
 862        if ($p_filename == '') {
 863            $this->_error('Invalid file name');
 864            return false;
 865        }
 866  
 867        // ----- Calculate the stored filename

 868        $p_filename = $this->_translateWinPath($p_filename, false);;
 869        $v_stored_filename = $p_filename;
 870        if (strcmp($p_filename, $p_remove_dir) == 0) {
 871            return true;
 872        }
 873        if ($p_remove_dir != '') {
 874            if (substr($p_remove_dir, -1) != '/')
 875                $p_remove_dir .= '/';
 876  
 877            if (substr($p_filename, 0, strlen($p_remove_dir)) == $p_remove_dir)
 878                $v_stored_filename = substr($p_filename, strlen($p_remove_dir));
 879        }
 880        $v_stored_filename = $this->_translateWinPath($v_stored_filename);
 881        if ($p_add_dir != '') {
 882            if (substr($p_add_dir, -1) == '/')
 883                $v_stored_filename = $p_add_dir.$v_stored_filename;
 884            else
 885                $v_stored_filename = $p_add_dir.'/'.$v_stored_filename;
 886        }
 887  
 888        $v_stored_filename = $this->_pathReduction($v_stored_filename);
 889  
 890        if (is_file($p_filename)) {
 891            if (($v_file = @fopen($p_filename, "rb")) == 0) {
 892                $this->_warning("Unable to open file '$p_filename' in binary read mode");
 893                return true;
 894            }
 895  
 896            if (!$this->_writeHeader($p_filename, $v_stored_filename))
 897                return false;
 898  
 899            while (($v_buffer = fread($v_file, 512)) != '') {
 900                $v_binary_data = pack("a512", "$v_buffer");
 901                $this->_writeBlock($v_binary_data);
 902            }
 903  
 904            fclose($v_file);
 905  
 906        } else {
 907            // ----- Only header for dir

 908            if (!$this->_writeHeader($p_filename, $v_stored_filename))
 909                return false;
 910        }
 911  
 912        return true;
 913      }
 914      // }}}

 915  
 916      // {{{ _addString()

 917  	function _addString($p_filename, $p_string)
 918      {
 919        if (!$this->_file) {
 920            $this->_error('Invalid file descriptor');
 921            return false;
 922        }
 923  
 924        if ($p_filename == '') {
 925            $this->_error('Invalid file name');
 926            return false;
 927        }
 928  
 929        // ----- Calculate the stored filename

 930        $p_filename = $this->_translateWinPath($p_filename, false);;
 931  
 932        if (!$this->_writeHeaderBlock($p_filename, strlen($p_string), 0, 0, "", 0, 0))
 933            return false;
 934  
 935        $i=0;
 936        while (($v_buffer = substr($p_string, (($i++)*512), 512)) != '') {
 937            $v_binary_data = pack("a512", $v_buffer);
 938            $this->_writeBlock($v_binary_data);
 939        }
 940  
 941        return true;
 942      }
 943      // }}}

 944  
 945      // {{{ _writeHeader()

 946  	function _writeHeader($p_filename, $p_stored_filename)
 947      {
 948          if ($p_stored_filename == '')
 949              $p_stored_filename = $p_filename;
 950          $v_reduce_filename = $this->_pathReduction($p_stored_filename);
 951  
 952          if (strlen($v_reduce_filename) > 99) {
 953            if (!$this->_writeLongHeader($v_reduce_filename))
 954              return false;
 955          }
 956  
 957          $v_info = stat($p_filename);
 958          $v_uid = sprintf("%6s ", DecOct($v_info[4]));
 959          $v_gid = sprintf("%6s ", DecOct($v_info[5]));
 960          $v_perms = sprintf("%6s ", DecOct(fileperms($p_filename)));
 961  
 962          $v_mtime = sprintf("%11s", DecOct(filemtime($p_filename)));
 963  
 964          if (@is_dir($p_filename)) {
 965            $v_typeflag = "5";
 966            $v_size = sprintf("%11s ", DecOct(0));
 967          } else {
 968            $v_typeflag = '';
 969            clearstatcache();
 970            $v_size = sprintf("%11s ", DecOct(filesize($p_filename)));
 971          }
 972  
 973          $v_linkname = '';
 974  
 975          $v_magic = '';
 976  
 977          $v_version = '';
 978  
 979          $v_uname = '';
 980  
 981          $v_gname = '';
 982  
 983          $v_devmajor = '';
 984  
 985          $v_devminor = '';
 986  
 987          $v_prefix = '';
 988  
 989          $v_binary_data_first = pack("a100a8a8a8a12A12", $v_reduce_filename, $v_perms, $v_uid, $v_gid, $v_size, $v_mtime);
 990          $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12", $v_typeflag, $v_linkname, $v_magic, $v_version, $v_uname, $v_gname, $v_devmajor, $v_devminor, $v_prefix, '');
 991  
 992          // ----- Calculate the checksum

 993          $v_checksum = 0;
 994          // ..... First part of the header

 995          for ($i=0; $i<148; $i++)
 996              $v_checksum += ord(substr($v_binary_data_first,$i,1));
 997          // ..... Ignore the checksum value and replace it by ' ' (space)

 998          for ($i=148; $i<156; $i++)
 999              $v_checksum += ord(' ');
1000          // ..... Last part of the header

1001          for ($i=156, $j=0; $i<512; $i++, $j++)
1002              $v_checksum += ord(substr($v_binary_data_last,$j,1));
1003  
1004          // ----- Write the first 148 bytes of the header in the archive

1005          $this->_writeBlock($v_binary_data_first, 148);
1006  
1007          // ----- Write the calculated checksum

1008          $v_checksum = sprintf("%6s ", DecOct($v_checksum));
1009          $v_binary_data = pack("a8", $v_checksum);
1010          $this->_writeBlock($v_binary_data, 8);
1011  
1012          // ----- Write the last 356 bytes of the header in the archive

1013          $this->_writeBlock($v_binary_data_last, 356);
1014  
1015          return true;
1016      }
1017      // }}}

1018  
1019      // {{{ _writeHeaderBlock()

1020  	function _writeHeaderBlock($p_filename, $p_size, $p_mtime=0, $p_perms=0, $p_type='', $p_uid=0, $p_gid=0)
1021      {
1022          $p_filename = $this->_pathReduction($p_filename);
1023  
1024          if (strlen($p_filename) > 99) {
1025            if (!$this->_writeLongHeader($p_filename))
1026              return false;
1027          }
1028  
1029          if ($p_type == "5") {
1030            $v_size = sprintf("%11s ", DecOct(0));
1031          } else {
1032            $v_size = sprintf("%11s ", DecOct($p_size));
1033          }
1034  
1035          $v_uid = sprintf("%6s ", DecOct($p_uid));
1036          $v_gid = sprintf("%6s ", DecOct($p_gid));
1037          $v_perms = sprintf("%6s ", DecOct($p_perms));
1038  
1039          $v_mtime = sprintf("%11s", DecOct($p_mtime));
1040  
1041          $v_linkname = '';
1042  
1043          $v_magic = '';
1044  
1045          $v_version = '';
1046  
1047          $v_uname = '';
1048  
1049          $v_gname = '';
1050  
1051          $v_devmajor = '';
1052  
1053          $v_devminor = '';
1054  
1055          $v_prefix = '';
1056  
1057          $v_binary_data_first = pack("a100a8a8a8a12A12", $p_filename, $v_perms, $v_uid, $v_gid, $v_size, $v_mtime);
1058          $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12", $p_type, $v_linkname, $v_magic, $v_version, $v_uname, $v_gname, $v_devmajor, $v_devminor, $v_prefix, '');
1059  
1060          // ----- Calculate the checksum

1061          $v_checksum = 0;
1062          // ..... First part of the header

1063          for ($i=0; $i<148; $i++)
1064              $v_checksum += ord(substr($v_binary_data_first,$i,1));
1065          // ..... Ignore the checksum value and replace it by ' ' (space)

1066          for ($i=148; $i<156; $i++)
1067              $v_checksum += ord(' ');
1068          // ..... Last part of the header

1069          for ($i=156, $j=0; $i<512; $i++, $j++)
1070              $v_checksum += ord(substr($v_binary_data_last,$j,1));
1071  
1072          // ----- Write the first 148 bytes of the header in the archive

1073          $this->_writeBlock($v_binary_data_first, 148);
1074  
1075          // ----- Write the calculated checksum

1076          $v_checksum = sprintf("%6s ", DecOct($v_checksum));
1077          $v_binary_data = pack("a8", $v_checksum);
1078          $this->_writeBlock($v_binary_data, 8);
1079  
1080          // ----- Write the last 356 bytes of the header in the archive

1081          $this->_writeBlock($v_binary_data_last, 356);
1082  
1083          return true;
1084      }
1085      // }}}

1086  
1087      // {{{ _writeLongHeader()

1088  	function _writeLongHeader($p_filename)
1089      {
1090          $v_size = sprintf("%11s ", DecOct(strlen($p_filename)));
1091  
1092          $v_typeflag = 'L';
1093  
1094          $v_linkname = '';
1095  
1096          $v_magic = '';
1097  
1098          $v_version = '';
1099  
1100          $v_uname = '';
1101  
1102          $v_gname = '';
1103  
1104          $v_devmajor = '';
1105  
1106          $v_devminor = '';
1107  
1108          $v_prefix = '';
1109  
1110          $v_binary_data_first = pack("a100a8a8a8a12A12", '././@LongLink', 0, 0, 0, $v_size, 0);
1111          $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12", $v_typeflag, $v_linkname, $v_magic, $v_version, $v_uname, $v_gname, $v_devmajor, $v_devminor, $v_prefix, '');
1112  
1113          // ----- Calculate the checksum

1114          $v_checksum = 0;
1115          // ..... First part of the header

1116          for ($i=0; $i<148; $i++)
1117              $v_checksum += ord(substr($v_binary_data_first,$i,1));
1118          // ..... Ignore the checksum value and replace it by ' ' (space)

1119          for ($i=148; $i<156; $i++)
1120              $v_checksum += ord(' ');
1121          // ..... Last part of the header

1122          for ($i=156, $j=0; $i<512; $i++, $j++)
1123              $v_checksum += ord(substr($v_binary_data_last,$j,1));
1124  
1125          // ----- Write the first 148 bytes of the header in the archive

1126          $this->_writeBlock($v_binary_data_first, 148);
1127  
1128          // ----- Write the calculated checksum

1129          $v_checksum = sprintf("%6s ", DecOct($v_checksum));
1130          $v_binary_data = pack("a8", $v_checksum);
1131          $this->_writeBlock($v_binary_data, 8);
1132  
1133          // ----- Write the last 356 bytes of the header in the archive

1134          $this->_writeBlock($v_binary_data_last, 356);
1135  
1136          // ----- Write the filename as content of the block

1137          $i=0;
1138          while (($v_buffer = substr($p_filename, (($i++)*512), 512)) != '') {
1139              $v_binary_data = pack("a512", "$v_buffer");
1140              $this->_writeBlock($v_binary_data);
1141          }
1142  
1143          return true;
1144      }
1145      // }}}

1146  
1147      // {{{ _readHeader()

1148  	function _readHeader($v_binary_data, &$v_header)
1149      {
1150          if (strlen($v_binary_data)==0) {
1151              $v_header['filename'] = '';
1152              return true;
1153          }
1154  
1155          if (strlen($v_binary_data) != 512) {
1156              $v_header['filename'] = '';
1157              $this->_error('Invalid block size : '.strlen($v_binary_data));
1158              return false;
1159          }
1160  
1161          // ----- Calculate the checksum

1162          $v_checksum = 0;
1163          // ..... First part of the header

1164          for ($i=0; $i<148; $i++)
1165              $v_checksum+=ord(substr($v_binary_data,$i,1));
1166          // ..... Ignore the checksum value and replace it by ' ' (space)

1167          for ($i=148; $i<156; $i++)
1168              $v_checksum += ord(' ');
1169          // ..... Last part of the header

1170          for ($i=156; $i<512; $i++)
1171              $v_checksum+=ord(substr($v_binary_data,$i,1));
1172  
1173          $v_data = unpack("a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/a8checksum/a1typeflag/a100link/a6magic/a2version/a32uname/a32gname/a8devmajor/a8devminor", $v_binary_data);
1174  
1175          // ----- Extract the checksum

1176          $v_header['checksum'] = OctDec(trim($v_data['checksum']));
1177          if ($v_header['checksum'] != $v_checksum) {
1178              $v_header['filename'] = '';
1179  
1180              // ----- Look for last block (empty block)

1181              if (($v_checksum == 256) && ($v_header['checksum'] == 0))
1182                  return true;
1183  
1184              $this->_error('Invalid checksum for file "'.$v_data['filename'].'" : '.$v_checksum.' calculated, '.$v_header['checksum'].' expected');
1185              return false;
1186          }
1187  
1188          // ----- Extract the properties

1189          $v_header['filename'] = trim($v_data['filename']);
1190          $v_header['mode'] = OctDec(trim($v_data['mode']));
1191          $v_header['uid'] = OctDec(trim($v_data['uid']));
1192          $v_header['gid'] = OctDec(trim($v_data['gid']));
1193          $v_header['size'] = OctDec(trim($v_data['size']));
1194          $v_header['mtime'] = OctDec(trim($v_data['mtime']));
1195          if (($v_header['typeflag'] = $v_data['typeflag']) == "5") {
1196            $v_header['size'] = 0;
1197          }
1198          /* ----- All these fields are removed form the header because they do not carry interesting info

1199          $v_header[link] = trim($v_data[link]);

1200          $v_header[magic] = trim($v_data[magic]);

1201          $v_header[version] = trim($v_data[version]);

1202          $v_header[uname] = trim($v_data[uname]);

1203          $v_header[gname] = trim($v_data[gname]);

1204          $v_header[devmajor] = trim($v_data[devmajor]);

1205          $v_header[devminor] = trim($v_data[devminor]);

1206          */
1207  
1208          return true;
1209      }
1210      // }}}

1211  
1212      // {{{ _readLongHeader()

1213  	function _readLongHeader(&$v_header)
1214      {
1215        $v_filename = '';
1216        $n = floor($v_header['size']/512);
1217        for ($i=0; $i<$n; $i++) {
1218          $v_content = $this->_readBlock();
1219          $v_filename .= $v_content;
1220        }
1221        if (($v_header['size'] % 512) != 0) {
1222          $v_content = $this->_readBlock();
1223          $v_filename .= $v_content;
1224        }
1225  
1226        // ----- Read the next header

1227        $v_binary_data = $this->_readBlock();
1228  
1229        if (!$this->_readHeader($v_binary_data, $v_header))
1230          return false;
1231  
1232        $v_header['filename'] = $v_filename;
1233  
1234        return true;
1235      }
1236      // }}}

1237  
1238      // {{{ _extractInString()

1239      /**

1240      * This method extract from the archive one file identified by $p_filename.

1241      * The return value is a string with the file content, or NULL on error.

1242      * @param string $p_filename     The path of the file to extract in a string.

1243      * @return                        a string with the file content or NULL.

1244      * @access private

1245      */
1246  	function _extractInString($p_filename)
1247      {
1248          $v_result_str = "";
1249  
1250          While (strlen($v_binary_data = $this->_readBlock()) != 0)
1251          {
1252            if (!$this->_readHeader($v_binary_data, $v_header))
1253              return NULL;
1254  
1255            if ($v_header['filename'] == '')
1256              continue;
1257  
1258            // ----- Look for long filename

1259            if ($v_header['typeflag'] == 'L') {
1260              if (!$this->_readLongHeader($v_header))
1261                return NULL;
1262            }
1263  
1264            if ($v_header['filename'] == $p_filename) {
1265                if ($v_header['typeflag'] == "5") {
1266                    $this->_error('Unable to extract in string a directory entry {'.$v_header['filename'].'}');
1267                    return NULL;
1268                } else {
1269                    $n = floor($v_header['size']/512);
1270                    for ($i=0; $i<$n; $i++) {
1271                        $v_result_str .= $this->_readBlock();
1272                    }
1273                    if (($v_header['size'] % 512) != 0) {
1274                        $v_content = $this->_readBlock();
1275                        $v_result_str .= substr($v_content, 0, ($v_header['size'] % 512));
1276                    }
1277                    return $v_result_str;
1278                }
1279            } else {
1280                $this->_jumpBlock(ceil(($v_header['size']/512)));
1281            }
1282          }
1283  
1284          return NULL;
1285      }
1286      // }}}

1287  
1288      // {{{ _extractList()

1289  	function _extractList($p_path, &$p_list_detail, $p_mode, $p_file_list, $p_remove_path)
1290      {
1291      $v_result=true;
1292      $v_nb = 0;
1293      $v_extract_all = true;
1294      $v_listing = false;
1295  
1296      $p_path = $this->_translateWinPath($p_path, false);
1297      if ($p_path == '' || (substr($p_path, 0, 1) != '/' && substr($p_path, 0, 3) != "../" && !strpos($p_path, ':'))) {
1298        $p_path = "./".$p_path;
1299      }
1300      $p_remove_path = $this->_translateWinPath($p_remove_path);
1301  
1302      // ----- Look for path to remove format (should end by /)

1303      if (($p_remove_path != '') && (substr($p_remove_path, -1) != '/'))
1304        $p_remove_path .= '/';
1305      $p_remove_path_size = strlen($p_remove_path);
1306  
1307      switch ($p_mode) {
1308        case "complete" :
1309          $v_extract_all = TRUE;
1310          $v_listing = FALSE;
1311        break;
1312        case "partial" :
1313            $v_extract_all = FALSE;
1314            $v_listing = FALSE;
1315        break;
1316        case "list" :
1317            $v_extract_all = FALSE;
1318            $v_listing = TRUE;
1319        break;
1320        default :
1321          $this->_error('Invalid extract mode ('.$p_mode.')');
1322          return false;
1323      }
1324  
1325      clearstatcache();
1326  
1327      While (strlen($v_binary_data = $this->_readBlock()) != 0)
1328      {
1329        $v_extract_file = FALSE;
1330        $v_extraction_stopped = 0;
1331  
1332        if (!$this->_readHeader($v_binary_data, $v_header))
1333          return false;
1334  
1335        if ($v_header['filename'] == '')
1336          continue;
1337  
1338        // ----- Look for long filename

1339        if ($v_header['typeflag'] == 'L') {
1340          if (!$this->_readLongHeader($v_header))
1341            return false;
1342        }
1343  
1344        if ((!$v_extract_all) && (is_array($p_file_list))) {
1345          // ----- By default no unzip if the file is not found

1346          $v_extract_file = false;
1347  
1348          for ($i=0; $i<sizeof($p_file_list); $i++) {
1349            // ----- Look if it is a directory

1350            if (substr($p_file_list[$i], -1) == '/') {
1351              // ----- Look if the directory is in the filename path

1352              if ((strlen($v_header['filename']) > strlen($p_file_list[$i])) && (substr($v_header['filename'], 0, strlen($p_file_list[$i])) == $p_file_list[$i])) {
1353                $v_extract_file = TRUE;
1354                break;
1355              }
1356            }
1357  
1358            // ----- It is a file, so compare the file names

1359            elseif ($p_file_list[$i] == $v_header['filename']) {
1360              $v_extract_file = TRUE;
1361              break;
1362            }
1363          }
1364        } else {
1365          $v_extract_file = TRUE;
1366        }
1367  
1368        // ----- Look if this file need to be extracted

1369        if (($v_extract_file) && (!$v_listing))
1370        {
1371          if (($p_remove_path != '')
1372              && (substr($v_header['filename'], 0, $p_remove_path_size) == $p_remove_path))
1373            $v_header['filename'] = substr($v_header['filename'], $p_remove_path_size);
1374          if (($p_path != './') && ($p_path != '/')) {
1375            while (substr($p_path, -1) == '/')
1376              $p_path = substr($p_path, 0, strlen($p_path)-1);
1377  
1378            if (substr($v_header['filename'], 0, 1) == '/')
1379                $v_header['filename'] = $p_path.$v_header['filename'];
1380            else
1381              $v_header['filename'] = $p_path.'/'.$v_header['filename'];
1382          }
1383          if (file_exists($v_header['filename'])) {
1384            if ((@is_dir($v_header['filename'])) && ($v_header['typeflag'] == '')) {
1385              $this->_error('File '.$v_header['filename'].' already exists as a directory');
1386              return false;
1387            }
1388            if ((is_file($v_header['filename'])) && ($v_header['typeflag'] == "5")) {
1389              $this->_error('Directory '.$v_header['filename'].' already exists as a file');
1390              return false;
1391            }
1392            if (!is_writeable($v_header['filename'])) {
1393              $this->_error('File '.$v_header['filename'].' already exists and is write protected');
1394              return false;
1395            }
1396            if (filemtime($v_header['filename']) > $v_header['mtime']) {
1397              // To be completed : An error or silent no replace ?

1398            }
1399          }
1400  
1401          // ----- Check the directory availability and create it if necessary

1402          elseif (($v_result = $this->_dirCheck(($v_header['typeflag'] == "5"?$v_header['filename']:dirname($v_header['filename'])))) != 1) {
1403              $this->_error('Unable to create path for '.$v_header['filename']);
1404              return false;
1405          }
1406  
1407          if ($v_extract_file) {
1408            if ($v_header['typeflag'] == "5") {
1409              if (!@file_exists($v_header['filename'])) {
1410                  if (!@mkdir($v_header['filename'], 0777)) {
1411                      $this->_error('Unable to create directory {'.$v_header['filename'].'}');
1412                      return false;
1413                  }
1414              }
1415            } else {
1416                if (($v_dest_file = @fopen($v_header['filename'], "wb")) == 0) {
1417                    $this->_error('Error while opening {'.$v_header['filename'].'} in write binary mode');
1418                    return false;
1419                } else {
1420                    $n = floor($v_header['size']/512);
1421                    for ($i=0; $i<$n; $i++) {
1422                        $v_content = $this->_readBlock();
1423                        fwrite($v_dest_file, $v_content, 512);
1424                    }
1425              if (($v_header['size'] % 512) != 0) {
1426                $v_content = $this->_readBlock();
1427                fwrite($v_dest_file, $v_content, ($v_header['size'] % 512));
1428              }
1429  
1430              @fclose($v_dest_file);
1431  
1432              // ----- Change the file mode, mtime

1433              @touch($v_header['filename'], $v_header['mtime']);
1434              // To be completed

1435              //chmod($v_header[filename], DecOct($v_header[mode]));

1436            }
1437  
1438            // ----- Check the file size

1439            clearstatcache();
1440            if (filesize($v_header['filename']) != $v_header['size']) {
1441                $this->_error('Extracted file '.$v_header['filename'].' does not have the correct file size \''.filesize($v_filename).'\' ('.$v_header['size'].' expected). Archive may be corrupted.');
1442                return false;
1443            }
1444            }
1445          } else {
1446            $this->_jumpBlock(ceil(($v_header['size']/512)));
1447          }
1448        } else {
1449            $this->_jumpBlock(ceil(($v_header['size']/512)));
1450        }
1451  
1452        /* TBC : Seems to be unused ...

1453        if ($this->_compress)

1454          $v_end_of_file = @gzeof($this->_file);

1455        else

1456          $v_end_of_file = @feof($this->_file);

1457          */
1458  
1459        if ($v_listing || $v_extract_file || $v_extraction_stopped) {
1460          // ----- Log extracted files

1461          if (($v_file_dir = dirname($v_header['filename'])) == $v_header['filename'])
1462            $v_file_dir = '';
1463          if ((substr($v_header['filename'], 0, 1) == '/') && ($v_file_dir == ''))
1464            $v_file_dir = '/';
1465  
1466          $p_list_detail[$v_nb++] = $v_header;
1467        }
1468      }
1469  
1470          return true;
1471      }
1472      // }}}

1473  
1474      // {{{ _openAppend()

1475  	function _openAppend()
1476      {
1477          if (filesize($this->_tarname) == 0)
1478            return $this->_openWrite();
1479  
1480          if ($this->_compress) {
1481              $this->_close();
1482  
1483              if (!@rename($this->_tarname, $this->_tarname.".tmp")) {
1484                  $this->_error('Error while renaming \''.$this->_tarname.'\' to temporary file \''.$this->_tarname.'.tmp\'');
1485                  return false;
1486              }
1487  
1488              if ($this->_compress_type == 'gz')
1489                  $v_temp_tar = @gzopen($this->_tarname.".tmp", "rb");
1490              elseif ($this->_compress_type == 'bz2')
1491                  $v_temp_tar = @bzopen($this->_tarname.".tmp", "rb");
1492  
1493              if ($v_temp_tar == 0) {
1494                  $this->_error('Unable to open file \''.$this->_tarname.'.tmp\' in binary read mode');
1495                  @rename($this->_tarname.".tmp", $this->_tarname);
1496                  return false;
1497              }
1498  
1499              if (!$this->_openWrite()) {
1500                  @rename($this->_tarname.".tmp", $this->_tarname);
1501                  return false;
1502              }
1503  
1504              if ($this->_compress_type == 'gz') {
1505                  $v_buffer = @gzread($v_temp_tar, 512);
1506  
1507                  // ----- Read the following blocks but not the last one

1508                  if (!@gzeof($v_temp_tar)) {
1509                      do{
1510                          $v_binary_data = pack("a512", $v_buffer);
1511                          $this->_writeBlock($v_binary_data);
1512                          $v_buffer = @gzread($v_temp_tar, 512);
1513  
1514                      } while (!@gzeof($v_temp_tar));
1515                  }
1516  
1517                  @gzclose($v_temp_tar);
1518              }
1519              elseif ($this->_compress_type == 'bz2') {
1520                  $v_buffered_lines    = array();
1521                  $v_buffered_lines[] = @bzread($v_temp_tar, 512);
1522  
1523                  // ----- Read the following blocks but not the last one

1524                  while (strlen($v_buffered_lines[] = @bzread($v_temp_tar, 512)) > 0) {
1525                      $v_binary_data = pack("a512", array_shift($v_buffered_lines));
1526                      $this->_writeBlock($v_binary_data);
1527                  }
1528  
1529                  @bzclose($v_temp_tar);
1530              }
1531  
1532              if (!@unlink($this->_tarname.".tmp")) {
1533                  $this->_error('Error while deleting temporary file \''.$this->_tarname.'.tmp\'');
1534              }
1535  
1536          } else {
1537              // ----- For not compressed tar, just add files before the last 512 bytes block

1538              if (!$this->_openReadWrite())
1539                  return false;
1540  
1541              clearstatcache();
1542              $v_size = filesize($this->_tarname);
1543              fseek($this->_file, $v_size-512);
1544          }
1545  
1546          return true;
1547      }
1548      // }}}

1549  
1550      // {{{ _append()

1551  	function _append($p_filelist, $p_add_dir='', $p_remove_dir='')
1552      {
1553          if (!$this->_openAppend())
1554              return false;
1555  
1556          if ($this->_addList($p_filelist, $p_add_dir, $p_remove_dir))
1557              $this->_writeFooter();
1558  
1559          $this->_close();
1560  
1561          return true;
1562      }
1563      // }}}

1564  
1565      // {{{ _dirCheck()

1566  
1567      /**

1568       * Check if a directory exists and create it (including parent

1569       * dirs) if not.

1570       *

1571       * @param string $p_dir directory to check

1572       *

1573       * @return bool TRUE if the directory exists or was created

1574       */
1575  	function _dirCheck($p_dir)
1576      {
1577          if ((@is_dir($p_dir)) || ($p_dir == ''))
1578              return true;
1579  
1580          $p_parent_dir = dirname($p_dir);
1581  
1582          if (($p_parent_dir != $p_dir) &&
1583              ($p_parent_dir != '') &&
1584              (!$this->_dirCheck($p_parent_dir)))
1585               return false;
1586  
1587          if (!@mkdir($p_dir, 0777)) {
1588              $this->_error("Unable to create directory '$p_dir'");
1589              return false;
1590          }
1591  
1592          return true;
1593      }
1594  
1595      // }}}

1596  
1597      // {{{ _pathReduction()

1598  
1599      /**

1600       * Compress path by changing for example "/dir/foo/../bar" to "/dir/bar", and

1601       * remove double slashes.

1602       *

1603       * @param string $p_dir path to reduce

1604       *

1605       * @return string reduced path

1606       *

1607       * @access private

1608       *

1609       */
1610  	function _pathReduction($p_dir)
1611      {
1612          $v_result = '';
1613  
1614          // ----- Look for not empty path

1615          if ($p_dir != '') {
1616              // ----- Explode path by directory names

1617              $v_list = explode('/', $p_dir);
1618  
1619              // ----- Study directories from last to first

1620              for ($i=sizeof($v_list)-1; $i>=0; $i--) {
1621                  // ----- Look for current path

1622                  if ($v_list[$i] == ".") {
1623                      // ----- Ignore this directory

1624                      // Should be the first $i=0, but no check is done

1625                  }
1626                  else if ($v_list[$i] == "..") {
1627                      // ----- Ignore it and ignore the $i-1

1628                      $i--;
1629                  }
1630                  else if (($v_list[$i] == '') && ($i!=(sizeof($v_list)-1)) && ($i!=0)) {
1631                      // ----- Ignore only the double '//' in path,

1632                      // but not the first and last /

1633                  } else {
1634                      $v_result = $v_list[$i].($i!=(sizeof($v_list)-1)?'/'.$v_result:'');
1635                  }
1636              }
1637          }
1638          $v_result = strtr($v_result, '\\', '/');
1639          return $v_result;
1640      }
1641  
1642      // }}}

1643  
1644      // {{{ _translateWinPath()

1645  	function _translateWinPath($p_path, $p_remove_disk_letter=true)
1646      {
1647        if (OS_WINDOWS) {
1648            // ----- Look for potential disk letter

1649            if (($p_remove_disk_letter) && (($v_position = strpos($p_path, ':')) != false)) {
1650                $p_path = substr($p_path, $v_position+1);
1651            }
1652            // ----- Change potential windows directory separator

1653            if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0,1) == '\\')) {
1654                $p_path = strtr($p_path, '\\', '/');
1655            }
1656        }
1657        return $p_path;
1658      }
1659      // }}}

1660  
1661  }
1662  ?>


Généré le : Wed Nov 21 14:43:32 2007 par Balluche grâce à PHPXref 0.7
  Clicky Web Analytics