Source for file Tar.php

Documentation is available at Tar.php

  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,v 1.2 2005/07/22 03:24:02 eddieajau Exp $
  20.  
  21. /** ensure this file is being included by a parent file */
  22. defined'_VALID_MOS' or die'Direct Access to this location is not allowed.' );
  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: 1.2 $
  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($fp2);
  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                       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->_tarname07)) == '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_from1024))
  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->_file512);
  744.           else if ($this->_compress_type == 'bz2')
  745.               $v_block @bzread($this->_file512);
  746.           else if ($this->_compress_type == 'none')
  747.               $v_block @fread($this->_file512);
  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_dirfalse);
  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_filenamefalse);;
  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_filename0strlen($p_remove_dir)) == $p_remove_dir)
  878.               $v_stored_filename substr($p_filenamestrlen($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_file512)) != ''{
  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_filenamefalse);;
  931.  
  932.       if (!$this->_writeHeaderBlock($p_filenamestrlen($p_string)00""00))
  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_filename99{
  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_first148);
  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_data8);
  1011.  
  1012.         // ----- Write the last 356 bytes of the header in the archive
  1013.         $this->_writeBlock($v_binary_data_last356);
  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_filename99{
  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_first148);
  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_data8);
  1079.  
  1080.         // ----- Write the last 356 bytes of the header in the archive
  1081.         $this->_writeBlock($v_binary_data_last356);
  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'000$v_size0);
  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_first148);
  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_data8);
  1132.  
  1133.         // ----- Write the last 356 bytes of the header in the archive
  1134.         $this->_writeBlock($v_binary_data_last356);
  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                       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_content0($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_pathfalse);
  1297.     if ($p_path == '' || (substr($p_path01!= '/' && substr($p_path03!= "../" && !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']0strlen($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_path0strlen($p_path)-1);
  1377.  
  1378.           if (substr($v_header['filename']01== '/')
  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_content512);
  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']01== '/'&& ($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_tar512);
  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_tar512);
  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_tar512);
  1522.  
  1523.                 // ----- Read the following blocks but not the last one
  1524.                 while (strlen($v_buffered_lines[@bzread($v_temp_tar512)) 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_dir0777)) {
  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_path0,1== '\\')) {
  1654.               $p_path strtr($p_path'\\''/');
  1655.           }
  1656.       }
  1657.       return $p_path;
  1658.     }
  1659.     // }}}
  1660.  
  1661. }
  1662. ?>

Documentation generated on Mon, 05 May 2008 16:23:01 +0400 by phpDocumentor 1.4.0