Archive_Tar
[ class tree: Archive_Tar ] [ index: Archive_Tar ] [ all elements ]

Source for file Tar.php

Documentation is available at Tar.php

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  3.  
  4. /**
  5.  * File::CSV
  6.  *
  7.  * PHP versions 4 and 5
  8.  *
  9.  * Copyright (c) 1997-2008,
  10.  * Vincent Blavet <vincent@phpconcept.net>
  11.  * All rights reserved.
  12.  *
  13.  * Redistribution and use in source and binary forms, with or without
  14.  * modification, are permitted provided that the following conditions are met:
  15.  *
  16.  *     * Redistributions of source code must retain the above copyright notice,
  17.  *       this list of conditions and the following disclaimer.
  18.  *     * Redistributions in binary form must reproduce the above copyright
  19.  *       notice, this list of conditions and the following disclaimer in the
  20.  *       documentation and/or other materials provided with the distribution.
  21.  *
  22.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  23.  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  25.  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
  26.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  27.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  28.  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  29.  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  30.  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  31.  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32.  *
  33.  * @category  File_Formats
  34.  * @package   Archive_Tar
  35.  * @author    Vincent Blavet <vincent@phpconcept.net>
  36.  * @copyright 1997-2010 The Authors
  37.  * @license   http://www.opensource.org/licenses/bsd-license.php New BSD License
  38.  * @version   CVS: $Id$
  39.  * @link      http://pear.php.net/package/Archive_Tar
  40.  */
  41.  
  42. require_once 'PEAR.php';
  43.  
  44. define('ARCHIVE_TAR_ATT_SEPARATOR'90001);
  45. define('ARCHIVE_TAR_END_BLOCK'pack("a512"''));
  46.  
  47. /**
  48. * Creates a (compressed) Tar archive
  49. *
  50. @package Archive_Tar
  51. @author  Vincent Blavet <vincent@phpconcept.net>
  52. @license http://www.opensource.org/licenses/bsd-license.php New BSD License
  53. @version $Revision$
  54. */
  55. class Archive_Tar extends PEAR
  56. {
  57.     /**
  58.     * @var string Name of the Tar
  59.     */
  60.     var $_tarname='';
  61.  
  62.     /**
  63.     * @var boolean if true, the Tar file will be gzipped
  64.     */
  65.     var $_compress=false;
  66.  
  67.     /**
  68.     * @var string Type of compression : 'none', 'gz' or 'bz2'
  69.     */
  70.     var $_compress_type='none';
  71.  
  72.     /**
  73.     * @var string Explode separator
  74.     */
  75.     var $_separator=' ';
  76.  
  77.     /**
  78.     * @var file descriptor
  79.     */
  80.     var $_file=0;
  81.  
  82.     /**
  83.     * @var string Local Tar name of a remote Tar (http:// or ftp://)
  84.     */
  85.     var $_temp_tarname='';
  86.  
  87.     /**
  88.     * @var string regular expression for ignoring files or directories
  89.     */
  90.     var $_ignore_regexp='';
  91.  
  92.     /**
  93.      * @var object PEAR_Error object
  94.      */
  95.     var $error_object=null; 
  96.  
  97.     // {{{ constructor
  98.     /**
  99.     * Archive_Tar Class constructor. This flavour of the constructor only
  100.     * declare a new Archive_Tar object, identifying it by the name of the
  101.     * tar file.
  102.     * If the compress argument is set the tar will be read or created as a
  103.     * gzip or bz2 compressed TAR file.
  104.     *
  105.     * @param string $p_tarname  The name of the tar archive to create
  106.     * @param string $p_compress can be null, 'gz' or 'bz2'. This
  107.     *                parameter indicates if gzip or bz2 compression
  108.     *                is required.  For compatibility reason the
  109.     *                boolean value 'true' means 'gz'.
  110.     *
  111.     * @access public
  112.     */
  113.     function Archive_Tar($p_tarname$p_compress = null)
  114.     {
  115.         $this->PEAR();
  116.         $this->_compress = false;
  117.         $this->_compress_type 'none';
  118.         if (($p_compress === null|| ($p_compress == '')) {
  119.             if (@file_exists($p_tarname)) {
  120.                 if ($fp @fopen($p_tarname"rb")) {
  121.                     // look for gzip magic cookie
  122.                     $data fread($fp2);
  123.                     fclose($fp);
  124.                     if ($data == "\37\213"{
  125.                         $this->_compress = true;
  126.                         $this->_compress_type 'gz';
  127.                         // No sure it's enought for a magic code ....
  128.                     elseif ($data == "BZ"{
  129.                         $this->_compress = true;
  130.                         $this->_compress_type 'bz2';
  131.                     }
  132.                 }
  133.             else {
  134.                 // probably a remote file or some file accessible
  135.                 // through a stream interface
  136.                 if (substr($p_tarname-2== 'gz'{
  137.                     $this->_compress = true;
  138.                     $this->_compress_type 'gz';
  139.                 elseif ((substr($p_tarname-3== 'bz2'||
  140.                           (substr($p_tarname-2== 'bz')) {
  141.                     $this->_compress = true;
  142.                     $this->_compress_type 'bz2';
  143.                 }
  144.             }
  145.         else {
  146.             if (($p_compress === true|| ($p_compress == 'gz')) {
  147.                 $this->_compress = true;
  148.                 $this->_compress_type 'gz';
  149.             else if ($p_compress == 'bz2'{
  150.                 $this->_compress = true;
  151.                 $this->_compress_type 'bz2';
  152.             else {
  153.                 $this->_error("Unsupported compression type '$p_compress'\n".
  154.                     "Supported types are 'gz' and 'bz2'.\n");
  155.                 return false;
  156.             }
  157.         }
  158.         $this->_tarname $p_tarname;
  159.         if ($this->_compress// assert zlib or bz2 extension support
  160.             if ($this->_compress_type == 'gz')
  161.                 $extname 'zlib';
  162.             else if ($this->_compress_type == 'bz2')
  163.                 $extname 'bz2';
  164.  
  165.             if (!extension_loaded($extname)) {
  166.                 PEAR::loadExtension($extname);
  167.             }
  168.             if (!extension_loaded($extname)) {
  169.                 $this->_error("The extension '$extname' couldn't be found.\n".
  170.                     "Please make sure your version of PHP was built ".
  171.                     "with '$extname' support.\n");
  172.                 return false;
  173.             }
  174.         }
  175.     }
  176.     // }}}
  177.  
  178.     // {{{ destructor
  179.     function _Archive_Tar()
  180.     {
  181.         $this->_close();
  182.         // ----- Look for a local copy to delete
  183.         if ($this->_temp_tarname != '')
  184.             @unlink($this->_temp_tarname);
  185.         $this->_PEAR();
  186.     }
  187.     // }}}
  188.  
  189.     // {{{ create()
  190.     /**
  191.     * This method creates the archive file and add the files / directories
  192.     * that are listed in $p_filelist.
  193.     * If a file with the same name exist and is writable, it is replaced
  194.     * by the new tar.
  195.     * The method return false and a PEAR error text.
  196.     * The $p_filelist parameter can be an array of string, each string
  197.     * representing a filename or a directory name with their path if
  198.     * needed. It can also be a single string with names separated by a
  199.     * single blank.
  200.     * For each directory added in the archive, the files and
  201.     * sub-directories are also added.
  202.     * See also createModify() method for more details.
  203.     *
  204.     * @param array $p_filelist An array of filenames and directory names, or a
  205.     *               single string with names separated by a single
  206.     *               blank space.
  207.     *
  208.     * @return true on success, false on error.
  209.     * @see    createModify()
  210.     * @access public
  211.     */
  212.     function create($p_filelist)
  213.     {
  214.         return $this->createModify($p_filelist'''');
  215.     }
  216.     // }}}
  217.  
  218.     // {{{ add()
  219.     /**
  220.     * This method add the files / directories that are listed in $p_filelist in
  221.     * the archive. If the archive does not exist it is created.
  222.     * The method return false and a PEAR error text.
  223.     * The files and directories listed are only added at the end of the archive,
  224.     * even if a file with the same name is already archived.
  225.     * See also createModify() method for more details.
  226.     *
  227.     * @param array $p_filelist An array of filenames and directory names, or a
  228.     *               single string with names separated by a single
  229.     *               blank space.
  230.     *
  231.     * @return true on success, false on error.
  232.     * @see    createModify()
  233.     * @access public
  234.     */
  235.     function add($p_filelist)
  236.     {
  237.         return $this->addModify($p_filelist'''');
  238.     }
  239.     // }}}
  240.  
  241.     // {{{ extract()
  242.     function extract($p_path=''$p_preserve=false)
  243.     {
  244.         return $this->extractModify($p_path''$p_preserve);
  245.     }
  246.     // }}}
  247.  
  248.     // {{{ listContent()
  249.     function listContent()
  250.     {
  251.         $v_list_detail = array();
  252.  
  253.         if ($this->_openRead()) {
  254.             if (!$this->_extractList(''$v_list_detail"list"'''')) {
  255.                 unset($v_list_detail);
  256.                 $v_list_detail = 0;
  257.             }
  258.             $this->_close();
  259.         }
  260.  
  261.         return $v_list_detail;
  262.     }
  263.     // }}}
  264.  
  265.     // {{{ createModify()
  266.     /**
  267.     * This method creates the archive file and add the files / directories
  268.     * that are listed in $p_filelist.
  269.     * If the file already exists and is writable, it is replaced by the
  270.     * new tar. It is a create and not an add. If the file exists and is
  271.     * read-only or is a directory it is not replaced. The method return
  272.     * false and a PEAR error text.
  273.     * The $p_filelist parameter can be an array of string, each string
  274.     * representing a filename or a directory name with their path if
  275.     * needed. It can also be a single string with names separated by a
  276.     * single blank.
  277.     * The path indicated in $p_remove_dir will be removed from the
  278.     * memorized path of each file / directory listed when this path
  279.     * exists. By default nothing is removed (empty path '')
  280.     * The path indicated in $p_add_dir will be added at the beginning of
  281.     * the memorized path of each file / directory listed. However it can
  282.     * be set to empty ''. The adding of a path is done after the removing
  283.     * of path.
  284.     * The path add/remove ability enables the user to prepare an archive
  285.     * for extraction in a different path than the origin files are.
  286.     * See also addModify() method for file adding properties.
  287.     *
  288.     * @param array  $p_filelist   An array of filenames and directory names,
  289.     *                              or a single string with names separated by
  290.     *                              a single blank space.
  291.     * @param string $p_add_dir    A string which contains a path to be added
  292.     *                              to the memorized path of each element in
  293.     *                              the list.
  294.     * @param string $p_remove_dir A string which contains a path to be
  295.     *                              removed from the memorized path of each
  296.     *                              element in the list, when relevant.
  297.     *
  298.     * @return boolean true on success, false on error.
  299.     * @access public
  300.     * @see addModify()
  301.     */
  302.     function createModify($p_filelist$p_add_dir$p_remove_dir='')
  303.     {
  304.         $v_result = true;
  305.  
  306.         if (!$this->_openWrite())
  307.             return false;
  308.  
  309.         if ($p_filelist != ''{
  310.             if (is_array($p_filelist))
  311.                 $v_list $p_filelist;
  312.             elseif (is_string($p_filelist))
  313.                 $v_list explode($this->_separator$p_filelist);
  314.             else {
  315.                 $this->_cleanFile();
  316.                 $this->_error('Invalid file list');
  317.                 return false;
  318.             }
  319.  
  320.             $v_result $this->_addList($v_list$p_add_dir$p_remove_dir);
  321.         }
  322.  
  323.         if ($v_result{
  324.             $this->_writeFooter();
  325.             $this->_close();
  326.         else
  327.             $this->_cleanFile();
  328.  
  329.         return $v_result;
  330.     }
  331.     // }}}
  332.  
  333.     // {{{ addModify()
  334.     /**
  335.     * This method add the files / directories listed in $p_filelist at the
  336.     * end of the existing archive. If the archive does not yet exists it
  337.     * is created.
  338.     * The $p_filelist parameter can be an array of string, each string
  339.     * representing a filename or a directory name with their path if
  340.     * needed. It can also be a single string with names separated by a
  341.     * single blank.
  342.     * The path indicated in $p_remove_dir will be removed from the
  343.     * memorized path of each file / directory listed when this path
  344.     * exists. By default nothing is removed (empty path '')
  345.     * The path indicated in $p_add_dir will be added at the beginning of
  346.     * the memorized path of each file / directory listed. However it can
  347.     * be set to empty ''. The adding of a path is done after the removing
  348.     * of path.
  349.     * The path add/remove ability enables the user to prepare an archive
  350.     * for extraction in a different path than the origin files are.
  351.     * If a file/dir is already in the archive it will only be added at the
  352.     * end of the archive. There is no update of the existing archived
  353.     * file/dir. However while extracting the archive, the last file will
  354.     * replace the first one. This results in a none optimization of the
  355.     * archive size.
  356.     * If a file/dir does not exist the file/dir is ignored. However an
  357.     * error text is send to PEAR error.
  358.     * If a file/dir is not readable the file/dir is ignored. However an
  359.     * error text is send to PEAR error.
  360.     *
  361.     * @param array  $p_filelist   An array of filenames and directory
  362.     *                              names, or a single string with names
  363.     *                              separated by a single blank space.
  364.     * @param string $p_add_dir    A string which contains a path to be
  365.     *                              added to the memorized path of each
  366.     *                              element in the list.
  367.     * @param string $p_remove_dir A string which contains a path to be
  368.     *                              removed from the memorized path of
  369.     *                              each element in the list, when
  370.     *                              relevant.
  371.     *
  372.     * @return true on success, false on error.
  373.     * @access public
  374.     */
  375.     function addModify($p_filelist$p_add_dir$p_remove_dir='')
  376.     {
  377.         $v_result = true;
  378.  
  379.         if (!$this->_isArchive())
  380.             $v_result $this->createModify($p_filelist$p_add_dir,
  381.                                             $p_remove_dir);
  382.         else {
  383.             if (is_array($p_filelist))
  384.                 $v_list $p_filelist;
  385.             elseif (is_string($p_filelist))
  386.                 $v_list explode($this->_separator$p_filelist);
  387.             else {
  388.                 $this->_error('Invalid file list');
  389.                 return false;
  390.             }
  391.  
  392.             $v_result $this->_append($v_list$p_add_dir$p_remove_dir);
  393.         }
  394.  
  395.         return $v_result;
  396.     }
  397.     // }}}
  398.  
  399.     // {{{ addString()
  400.     /**
  401.     * This method add a single string as a file at the
  402.     * end of the existing archive. If the archive does not yet exists it
  403.     * is created.
  404.     *
  405.     * @param string $p_filename A string which contains the full
  406.     *                            filename path that will be associated
  407.     *                            with the string.
  408.     * @param string $p_string   The content of the file added in
  409.     *                            the archive.
  410.     * @param int    $p_datetime A custom date/time (unix timestamp)
  411.     *                            for the file (optional).
  412.     *
  413.     * @return true on success, false on error.
  414.     * @access public
  415.     */
  416.     function addString($p_filename$p_string$p_datetime = false)
  417.     {
  418.         $v_result = true;
  419.  
  420.         if (!$this->_isArchive()) {
  421.             if (!$this->_openWrite()) {
  422.                 return false;
  423.             }
  424.             $this->_close();
  425.         }
  426.  
  427.         if (!$this->_openAppend())
  428.             return false;
  429.  
  430.         // Need to check the get back to the temporary file ? ....
  431.         $v_result $this->_addString($p_filename$p_string$p_datetime);
  432.  
  433.         $this->_writeFooter();
  434.  
  435.         $this->_close();
  436.  
  437.         return $v_result;
  438.     }
  439.     // }}}
  440.  
  441.     // {{{ extractModify()
  442.     /**
  443.     * This method extract all the content of the archive in the directory
  444.     * indicated by $p_path. When relevant the memorized path of the
  445.     * files/dir can be modified by removing the $p_remove_path path at the
  446.     * beginning of the file/dir path.
  447.     * While extracting a file, if the directory path does not exists it is
  448.     * created.
  449.     * While extracting a file, if the file already exists it is replaced
  450.     * without looking for last modification date.
  451.     * While extracting a file, if the file already exists and is write
  452.     * protected, the extraction is aborted.
  453.     * While extracting a file, if a directory with the same name already
  454.     * exists, the extraction is aborted.
  455.     * While extracting a directory, if a file with the same name already
  456.     * exists, the extraction is aborted.
  457.     * While extracting a file/directory if the destination directory exist
  458.     * and is write protected, or does not exist but can not be created,
  459.     * the extraction is aborted.
  460.     * If after extraction an extracted file does not show the correct
  461.     * stored file size, the extraction is aborted.
  462.     * When the extraction is aborted, a PEAR error text is set and false
  463.     * is returned. However the result can be a partial extraction that may
  464.     * need to be manually cleaned.
  465.     *
  466.     * @param string  $p_path        The path of the directory where the
  467.     *                                files/dir need to by extracted.
  468.     * @param string  $p_remove_path Part of the memorized path that can be
  469.     *                                removed if present at the beginning of
  470.     *                                the file/dir path.
  471.     * @param boolean $p_preserve    Preserve user/group ownership of files
  472.     *
  473.     * @return boolean true on success, false on error.
  474.     * @access public
  475.     * @see    extractList()
  476.     */
  477.     function extractModify($p_path$p_remove_path$p_preserve=false)
  478.     {
  479.         $v_result = true;
  480.         $v_list_detail = array();
  481.  
  482.         if ($v_result $this->_openRead()) {
  483.             $v_result $this->_extractList($p_path$v_list_detail,
  484.                 "complete"0$p_remove_path$p_preserve);
  485.             $this->_close();
  486.         }
  487.  
  488.         return $v_result;
  489.     }
  490.     // }}}
  491.  
  492.     // {{{ extractInString()
  493.     /**
  494.     * This method extract from the archive one file identified by $p_filename.
  495.     * The return value is a string with the file content, or NULL on error.
  496.     *
  497.     * @param string $p_filename The path of the file to extract in a string.
  498.     *
  499.     * @return string with the file content or NULL.
  500.     * @access public
  501.     */
  502.     function extractInString($p_filename)
  503.     {
  504.         if ($this->_openRead()) {
  505.             $v_result $this->_extractInString($p_filename);
  506.             $this->_close();
  507.         else {
  508.             $v_result = null;
  509.         }
  510.  
  511.         return $v_result;
  512.     }
  513.     // }}}
  514.  
  515.     // {{{ extractList()
  516.     /**
  517.     * This method extract from the archive only the files indicated in the
  518.     * $p_filelist. These files are extracted in the current directory or
  519.     * in the directory indicated by the optional $p_path parameter.
  520.     * If indicated the $p_remove_path can be used in the same way as it is
  521.     * used in extractModify() method.
  522.     *
  523.     * @param array   $p_filelist    An array of filenames and directory names,
  524.     *                                or a single string with names separated
  525.     *                                by a single blank space.
  526.     * @param string  $p_path        The path of the directory where the
  527.     *                                files/dir need to by extracted.
  528.     * @param string  $p_remove_path Part of the memorized path that can be
  529.     *                                removed if present at the beginning of
  530.     *                                the file/dir path.
  531.     * @param boolean $p_preserve    Preserve user/group ownership of files
  532.     *
  533.     * @return true on success, false on error.
  534.     * @access public
  535.     * @see    extractModify()
  536.     */
  537.     function extractList($p_filelist$p_path=''$p_remove_path=''$p_preserve=false)
  538.     {
  539.         $v_result = true;
  540.         $v_list_detail = array();
  541.  
  542.         if (is_array($p_filelist))
  543.             $v_list $p_filelist;
  544.         elseif (is_string($p_filelist))
  545.             $v_list explode($this->_separator$p_filelist);
  546.         else {
  547.             $this->_error('Invalid string list');
  548.             return false;
  549.         }
  550.  
  551.         if ($v_result $this->_openRead()) {
  552.             $v_result $this->_extractList($p_path$v_list_detail"partial",
  553.                 $v_list$p_remove_path$p_preserve);
  554.             $this->_close();
  555.         }
  556.  
  557.         return $v_result;
  558.     }
  559.     // }}}
  560.  
  561.     // {{{ setAttribute()
  562.     /**
  563.     * This method set specific attributes of the archive. It uses a variable
  564.     * list of parameters, in the format attribute code + attribute values :
  565.     * $arch->setAttribute(ARCHIVE_TAR_ATT_SEPARATOR, ',');
  566.     *
  567.     * @param mixed $argv variable list of attributes and values
  568.     *
  569.     * @return true on success, false on error.
  570.     * @access public
  571.     */
  572.     function setAttribute()
  573.     {
  574.         $v_result = true;
  575.  
  576.         // ----- Get the number of variable list of arguments
  577.         if (($v_size func_num_args()) == 0{
  578.             return true;
  579.         }
  580.  
  581.         // ----- Get the arguments
  582.         $v_att_list &func_get_args();
  583.  
  584.         // ----- Read the attributes
  585.         $i=0;
  586.         while ($i<$v_size{
  587.  
  588.             // ----- Look for next option
  589.             switch ($v_att_list[$i]{
  590.                 // ----- Look for options that request a string value
  591.                 case ARCHIVE_TAR_ATT_SEPARATOR :
  592.                     // ----- Check the number of parameters
  593.                     if (($i+1>= $v_size{
  594.                         $this->_error('Invalid number of parameters for '
  595.                                       .'attribute ARCHIVE_TAR_ATT_SEPARATOR');
  596.                         return false;
  597.                     }
  598.  
  599.                     // ----- Get the value
  600.                     $this->_separator $v_att_list[$i+1];
  601.                     $i++;
  602.                 break;
  603.  
  604.                 default :
  605.                     $this->_error('Unknow attribute code '.$v_att_list[$i].'');
  606.                     return false;
  607.             }
  608.  
  609.             // ----- Next attribute
  610.             $i++;
  611.         }
  612.  
  613.         return $v_result;
  614.     }
  615.     // }}}
  616.  
  617.     // {{{ setIgnoreRegexp()
  618.     /**
  619.     * This method sets the regular expression for ignoring files and directories
  620.     * at import, for example:
  621.     * $arch->setIgnoreRegexp("#CVS|\.svn#");
  622.     *
  623.     * @param string $regexp regular expression defining which files or directories to ignore
  624.     *
  625.     * @access public
  626.     */
  627.     function setIgnoreRegexp($regexp)
  628.     {
  629.         $this->_ignore_regexp $regexp;
  630.     }
  631.     // }}}
  632.  
  633.     // {{{ setIgnoreList()
  634.     /**
  635.     * This method sets the regular expression for ignoring all files and directories
  636.     * matching the filenames in the array list at import, for example:
  637.     * $arch->setIgnoreList(array('CVS', '.svn', 'bin/tool'));
  638.     *
  639.     * @param array $list a list of file or directory names to ignore
  640.     *
  641.     * @access public
  642.     */
  643.     function setIgnoreList($list)
  644.     {
  645.         $regexp str_replace(array('#''.''^''$')array('\#''\.''\^''\$')$list);
  646.         $regexp '#/'.join('$|/'$list).'#';
  647.         $this->setIgnoreRegexp($regexp);
  648.     }
  649.     // }}}
  650.  
  651.     // {{{ _error()
  652.     function _error($p_message)
  653.     {
  654.         $this->error_object = &$this->raiseError($p_message)
  655.     }
  656.     // }}}
  657.  
  658.     // {{{ _warning()
  659.     function _warning($p_message)
  660.     {
  661.         $this->error_object = &$this->raiseError($p_message)
  662.     }
  663.     // }}}
  664.  
  665.     // {{{ _isArchive()
  666.     function _isArchive($p_filename=null)
  667.     {
  668.         if ($p_filename == null{
  669.             $p_filename $this->_tarname;
  670.         }
  671.         clearstatcache();
  672.         return @is_file($p_filename&& !@is_link($p_filename);
  673.     }
  674.     // }}}
  675.  
  676.     // {{{ _openWrite()
  677.     function _openWrite()
  678.     {
  679.         if ($this->_compress_type == 'gz' && function_exists('gzopen'))
  680.             $this->_file @gzopen($this->_tarname"wb9");
  681.         else if ($this->_compress_type == 'bz2' && function_exists('bzopen'))
  682.             $this->_file @bzopen($this->_tarname"w");
  683.         else if ($this->_compress_type == 'none')
  684.             $this->_file @fopen($this->_tarname"wb");
  685.         else {
  686.             $this->_error('Unknown or missing compression type ('
  687.                           .$this->_compress_type.')');
  688.             return false;
  689.         }
  690.  
  691.         if ($this->_file == 0{
  692.             $this->_error('Unable to open in write mode \''
  693.                           .$this->_tarname.'\'');
  694.             return false;
  695.         }
  696.  
  697.         return true;
  698.     }
  699.     // }}}
  700.  
  701.     // {{{ _openRead()
  702.     function _openRead()
  703.     {
  704.         if (strtolower(substr($this->_tarname07)) == 'http://'{
  705.  
  706.           // ----- Look if a local copy need to be done
  707.           if ($this->_temp_tarname == ''{
  708.               $this->_temp_tarname uniqid('tar').'.tmp';
  709.               if (!$v_file_from @fopen($this->_tarname'rb')) {
  710.                 $this->_error('Unable to open in read mode \''
  711.                               .$this->_tarname.'\'');
  712.                 $this->_temp_tarname '';
  713.                 return false;
  714.               }
  715.               if (!$v_file_to @fopen($this->_temp_tarname'wb')) {
  716.                 $this->_error('Unable to open in write mode \''
  717.                               .$this->_temp_tarname.'\'');
  718.                 $this->_temp_tarname '';
  719.                 return false;
  720.               }
  721.               while ($v_data @fread($v_file_from1024))
  722.                   @fwrite($v_file_to$v_data);
  723.               @fclose($v_file_from);
  724.               @fclose($v_file_to);
  725.           }
  726.  
  727.           // ----- File to open if the local copy
  728.           $v_filename $this->_temp_tarname;
  729.  
  730.         else
  731.           // ----- File to open if the normal Tar file
  732.           $v_filename $this->_tarname;
  733.  
  734.         if ($this->_compress_type == 'gz' && function_exists('gzopen'))
  735.             $this->_file @gzopen($v_filename"rb");
  736.         else if ($this->_compress_type == 'bz2' && function_exists('bzopen'))
  737.             $this->_file @bzopen($v_filename"r");
  738.         else if ($this->_compress_type == 'none')
  739.             $this->_file @fopen($v_filename"rb");
  740.         else {
  741.             $this->_error('Unknown or missing compression type ('
  742.                           .$this->_compress_type.')');
  743.             return false;
  744.         }
  745.  
  746.         if ($this->_file == 0{
  747.             $this->_error('Unable to open in read mode \''.$v_filename.'\'');
  748.             return false;
  749.         }
  750.  
  751.         return true;
  752.     }
  753.     // }}}
  754.  
  755.     // {{{ _openReadWrite()
  756.     function _openReadWrite()
  757.     {
  758.         if ($this->_compress_type == 'gz')
  759.             $this->_file @gzopen($this->_tarname"r+b");
  760.         else if ($this->_compress_type == 'bz2'{
  761.             $this->_error('Unable to open bz2 in read/write mode \''
  762.                           .$this->_tarname.'\' (limitation of bz2 extension)');
  763.             return false;
  764.         else if ($this->_compress_type == 'none')
  765.             $this->_file @fopen($this->_tarname"r+b");
  766.         else {
  767.             $this->_error('Unknown or missing compression type ('
  768.                           .$this->_compress_type.')');
  769.             return false;
  770.         }
  771.  
  772.         if ($this->_file == 0{
  773.             $this->_error('Unable to open in read/write mode \''
  774.                           .$this->_tarname.'\'');
  775.             return false;
  776.         }
  777.  
  778.         return true;
  779.     }
  780.     // }}}
  781.  
  782.     // {{{ _close()
  783.     function _close()
  784.     {
  785.         //if (isset($this->_file)) {
  786.         if (is_resource($this->_file)) {
  787.             if ($this->_compress_type == 'gz')
  788.                 @gzclose($this->_file);
  789.             else if ($this->_compress_type == 'bz2')
  790.                 @bzclose($this->_file);
  791.             else if ($this->_compress_type == 'none')
  792.                 @fclose($this->_file);
  793.             else
  794.                 $this->_error('Unknown or missing compression type ('
  795.                               .$this->_compress_type.')');
  796.  
  797.             $this->_file = 0;
  798.         }
  799.  
  800.         // ----- Look if a local copy need to be erase
  801.         // Note that it might be interesting to keep the url for a time : ToDo
  802.         if ($this->_temp_tarname != ''{
  803.             @unlink($this->_temp_tarname);
  804.             $this->_temp_tarname '';
  805.         }
  806.  
  807.         return true;
  808.     }
  809.     // }}}
  810.  
  811.     // {{{ _cleanFile()
  812.     function _cleanFile()
  813.     {
  814.         $this->_close();
  815.  
  816.         // ----- Look for a local copy
  817.         if ($this->_temp_tarname != ''{
  818.             // ----- Remove the local copy but not the remote tarname
  819.             @unlink($this->_temp_tarname);
  820.             $this->_temp_tarname '';
  821.         else {
  822.             // ----- Remove the local tarname file
  823.             @unlink($this->_tarname);
  824.         }
  825.         $this->_tarname '';
  826.  
  827.         return true;
  828.     }
  829.     // }}}
  830.  
  831.     // {{{ _writeBlock()
  832.     function _writeBlock($p_binary_data$p_len=null)
  833.     {
  834.       if (is_resource($this->_file)) {
  835.           if ($p_len === null{
  836.               if ($this->_compress_type == 'gz')
  837.                   @gzputs($this->_file$p_binary_data);
  838.               else if ($this->_compress_type == 'bz2')
  839.                   @bzwrite($this->_file$p_binary_data);
  840.               else if ($this->_compress_type == 'none')
  841.                   @fputs($this->_file$p_binary_data);
  842.               else
  843.                   $this->_error('Unknown or missing compression type ('
  844.                                 .$this->_compress_type.')');
  845.           else {
  846.               if ($this->_compress_type == 'gz')
  847.                   @gzputs($this->_file$p_binary_data$p_len);
  848.               else if ($this->_compress_type == 'bz2')
  849.                   @bzwrite($this->_file$p_binary_data$p_len);
  850.               else if ($this->_compress_type == 'none')
  851.                   @fputs($this->_file$p_binary_data$p_len);
  852.               else
  853.                   $this->_error('Unknown or missing compression type ('
  854.                                 .$this->_compress_type.')');
  855.  
  856.           }
  857.       }
  858.       return true;
  859.     }
  860.     // }}}
  861.  
  862.     // {{{ _readBlock()
  863.     function _readBlock()
  864.     {
  865.       $v_block = null;
  866.       if (is_resource($this->_file)) {
  867.           if ($this->_compress_type == 'gz')
  868.               $v_block @gzread($this->_file512);
  869.           else if ($this->_compress_type == 'bz2')
  870.               $v_block @bzread($this->_file512);
  871.           else if ($this->_compress_type == 'none')
  872.               $v_block @fread($this->_file512);
  873.           else
  874.               $this->_error('Unknown or missing compression type ('
  875.                             .$this->_compress_type.')');
  876.       }
  877.       return $v_block;
  878.     }
  879.     // }}}
  880.  
  881.     // {{{ _jumpBlock()
  882.     function _jumpBlock($p_len=null)
  883.     {
  884.       if (is_resource($this->_file)) {
  885.           if ($p_len === null)
  886.               $p_len = 1;
  887.  
  888.           if ($this->_compress_type == 'gz'{
  889.               @gzseek($this->_filegztell($this->_file)+($p_len*512));
  890.           }
  891.           else if ($this->_compress_type == 'bz2'{
  892.               // ----- Replace missing bztell() and bzseek()
  893.               for ($i=0; $i<$p_len$i++)
  894.                   $this->_readBlock();
  895.           else if ($this->_compress_type == 'none')
  896.               @fseek($this->_file$p_len*512SEEK_CUR);
  897.           else
  898.               $this->_error('Unknown or missing compression type ('
  899.                             .$this->_compress_type.')');
  900.  
  901.       }
  902.       return true;
  903.     }
  904.     // }}}
  905.  
  906.     // {{{ _writeFooter()
  907.     function _writeFooter()
  908.     {
  909.       if (is_resource($this->_file)) {
  910.           // ----- Write the last 0 filled block for end of archive
  911.           $v_binary_data pack('a1024''');
  912.           $this->_writeBlock($v_binary_data);
  913.       }
  914.       return true;
  915.     }
  916.     // }}}
  917.  
  918.     // {{{ _addList()
  919.     function _addList($p_list$p_add_dir$p_remove_dir)
  920.     {
  921.       $v_result=true;
  922.       $v_header = array();
  923.  
  924.       // ----- Remove potential windows directory separator
  925.       $p_add_dir $this->_translateWinPath($p_add_dir);
  926.       $p_remove_dir $this->_translateWinPath($p_remove_dirfalse);
  927.  
  928.       if (!$this->_file{
  929.           $this->_error('Invalid file descriptor');
  930.           return false;
  931.       }
  932.  
  933.       if (sizeof($p_list== 0)
  934.           return true;
  935.  
  936.       foreach ($p_list as $v_filename{
  937.           if (!$v_result{
  938.               break;
  939.           }
  940.  
  941.         // ----- Skip the current tar name
  942.         if ($v_filename == $this->_tarname)
  943.             continue;
  944.  
  945.         if ($v_filename == '')
  946.             continue;
  947.  
  948.            // ----- ignore files and directories matching the ignore regular expression
  949.            if ($this->_ignore_regexp && preg_match($this->_ignore_regexp'/'.$v_filename)) {
  950.             $this->_warning("File '$v_filename' ignored");
  951.                continue;
  952.            }
  953.  
  954.         if (!file_exists($v_filename&& !is_link($v_filename)) {
  955.             $this->_warning("File '$v_filename' does not exist");
  956.             continue;
  957.         }
  958.  
  959.         // ----- Add the file or directory header
  960.         if (!$this->_addFile($v_filename$v_header$p_add_dir$p_remove_dir))
  961.             return false;
  962.  
  963.         if (@is_dir($v_filename&& !@is_link($v_filename)) {
  964.             if (!($p_hdir opendir($v_filename))) {
  965.                 $this->_warning("Directory '$v_filename' can not be read");
  966.                 continue;
  967.             }
  968.             while (false !== ($p_hitem readdir($p_hdir))) {
  969.                 if (($p_hitem != '.'&& ($p_hitem != '..')) {
  970.                     if ($v_filename != ".")
  971.                         $p_temp_list[0$v_filename.'/'.$p_hitem;
  972.                     else
  973.                         $p_temp_list[0$p_hitem;
  974.  
  975.                     $v_result $this->_addList($p_temp_list,
  976.                                                 $p_add_dir,
  977.                                                 $p_remove_dir);
  978.                 }
  979.             }
  980.  
  981.             unset($p_temp_list);
  982.             unset($p_hdir);
  983.             unset($p_hitem);
  984.         }
  985.       }
  986.  
  987.       return $v_result;
  988.     }
  989.     // }}}
  990.  
  991.     // {{{ _addFile()
  992.     function _addFile($p_filename&$p_header$p_add_dir$p_remove_dir)
  993.     {
  994.       if (!$this->_file{
  995.           $this->_error('Invalid file descriptor');
  996.           return false;
  997.       }
  998.  
  999.       if ($p_filename == ''{
  1000.           $this->_error('Invalid file name');
  1001.           return false;
  1002.       }
  1003.  
  1004.       // ----- Calculate the stored filename
  1005.       $p_filename $this->_translateWinPath($p_filenamefalse);;
  1006.       $v_stored_filename $p_filename;
  1007.       if (strcmp($p_filename$p_remove_dir== 0{
  1008.           return true;
  1009.       }
  1010.       if ($p_remove_dir != ''{
  1011.           if (substr($p_remove_dir-1!= '/')
  1012.               $p_remove_dir .= '/';
  1013.  
  1014.           if (substr($p_filename0strlen($p_remove_dir)) == $p_remove_dir)
  1015.               $v_stored_filename substr($p_filenamestrlen($p_remove_dir));
  1016.       }
  1017.       $v_stored_filename $this->_translateWinPath($v_stored_filename);
  1018.       if ($p_add_dir != ''{
  1019.           if (substr($p_add_dir-1== '/')
  1020.               $v_stored_filename $p_add_dir.$v_stored_filename;
  1021.           else
  1022.               $v_stored_filename $p_add_dir.'/'.$v_stored_filename;
  1023.       }
  1024.  
  1025.       $v_stored_filename $this->_pathReduction($v_stored_filename);
  1026.  
  1027.       if ($this->_isArchive($p_filename)) {
  1028.           if (($v_file @fopen($p_filename"rb")) == 0{
  1029.               $this->_warning("Unable to open file '".$p_filename
  1030.                               ."' in binary read mode");
  1031.               return true;
  1032.           }
  1033.  
  1034.           if (!$this->_writeHeader($p_filename$v_stored_filename))
  1035.               return false;
  1036.  
  1037.           while (($v_buffer fread($v_file512)) != ''{
  1038.               $v_binary_data pack("a512""$v_buffer");
  1039.               $this->_writeBlock($v_binary_data);
  1040.           }
  1041.  
  1042.           fclose($v_file);
  1043.  
  1044.       else {
  1045.           // ----- Only header for dir
  1046.           if (!$this->_writeHeader($p_filename$v_stored_filename))
  1047.               return false;
  1048.       }
  1049.  
  1050.       return true;
  1051.     }
  1052.     // }}}
  1053.  
  1054.     // {{{ _addString()
  1055.     function _addString($p_filename$p_string$p_datetime = false)
  1056.     {
  1057.       if (!$this->_file{
  1058.           $this->_error('Invalid file descriptor');
  1059.           return false;
  1060.       }
  1061.  
  1062.       if ($p_filename == ''{
  1063.           $this->_error('Invalid file name');
  1064.           return false;
  1065.       }
  1066.  
  1067.       // ----- Calculate the stored filename
  1068.       $p_filename $this->_translateWinPath($p_filenamefalse);;
  1069.       
  1070.       // ----- If datetime is not specified, set current time
  1071.       if ($p_datetime === false{
  1072.           $p_datetime time();
  1073.       }
  1074.  
  1075.       if (!$this->_writeHeaderBlock($p_filenamestrlen($p_string),
  1076.                                     $p_datetime384""00))
  1077.           return false;
  1078.  
  1079.       $i=0;
  1080.       while (($v_buffer substr($p_string(($i++)*512)512)) != ''{
  1081.           $v_binary_data pack("a512"$v_buffer);
  1082.           $this->_writeBlock($v_binary_data);
  1083.       }
  1084.  
  1085.       return true;
  1086.     }
  1087.     // }}}
  1088.  
  1089.     // {{{ _writeHeader()
  1090.     function _writeHeader($p_filename$p_stored_filename)
  1091.     {
  1092.         if ($p_stored_filename == '')
  1093.             $p_stored_filename $p_filename;
  1094.         $v_reduce_filename $this->_pathReduction($p_stored_filename);
  1095.  
  1096.         if (strlen($v_reduce_filename> 99{
  1097.           if (!$this->_writeLongHeader($v_reduce_filename))
  1098.             return false;
  1099.         }
  1100.  
  1101.         $v_info lstat($p_filename);
  1102.         $v_uid sprintf("%07s"DecOct($v_info[4]));
  1103.         $v_gid sprintf("%07s"DecOct($v_info[5]));
  1104.         $v_perms sprintf("%07s"DecOct($v_info['mode'000777));
  1105.  
  1106.         $v_mtime sprintf("%011s"DecOct($v_info['mtime']));
  1107.  
  1108.         $v_linkname '';
  1109.  
  1110.         if (@is_link($p_filename)) {
  1111.           $v_typeflag '2';
  1112.           $v_linkname readlink($p_filename);
  1113.           $v_size sprintf("%011s"DecOct(0));
  1114.         elseif (@is_dir($p_filename)) {
  1115.           $v_typeflag "5";
  1116.           $v_size sprintf("%011s"DecOct(0));
  1117.         else {
  1118.           $v_typeflag '0';
  1119.           clearstatcache();
  1120.           $v_size sprintf("%011s"DecOct($v_info['size']));
  1121.         }
  1122.  
  1123.         $v_magic 'ustar ';
  1124.  
  1125.         $v_version ' ';
  1126.         
  1127.         if (function_exists('posix_getpwuid'))
  1128.         {
  1129.           $userinfo posix_getpwuid($v_info[4]);
  1130.           $groupinfo posix_getgrgid($v_info[5]);
  1131.           
  1132.           $v_uname $userinfo['name'];
  1133.           $v_gname $groupinfo['name'];
  1134.         }
  1135.         else
  1136.         {
  1137.           $v_uname '';
  1138.           $v_gname '';
  1139.         }
  1140.  
  1141.         $v_devmajor '';
  1142.  
  1143.         $v_devminor '';
  1144.  
  1145.         $v_prefix '';
  1146.  
  1147.         $v_binary_data_first pack("a100a8a8a8a12a12",
  1148.                                     $v_reduce_filename$v_perms$v_uid,
  1149.                                     $v_gid$v_size$v_mtime);
  1150.         $v_binary_data_last pack("a1a100a6a2a32a32a8a8a155a12",
  1151.                                    $v_typeflag$v_linkname$v_magic,
  1152.                                    $v_version$v_uname$v_gname,
  1153.                                    $v_devmajor$v_devminor$v_prefix'');
  1154.  
  1155.         // ----- Calculate the checksum
  1156.         $v_checksum = 0;
  1157.         // ..... First part of the header
  1158.         for ($i=0; $i<148; $i++)
  1159.             $v_checksum += ord(substr($v_binary_data_first,$i,1));
  1160.         // ..... Ignore the checksum value and replace it by ' ' (space)
  1161.         for ($i=148; $i<156; $i++)
  1162.             $v_checksum += ord(' ');
  1163.         // ..... Last part of the header
  1164.         for ($i=156$j=0; $i<512; $i++$j++)
  1165.             $v_checksum += ord(substr($v_binary_data_last,$j,1));
  1166.  
  1167.         // ----- Write the first 148 bytes of the header in the archive
  1168.         $this->_writeBlock($v_binary_data_first148);
  1169.  
  1170.         // ----- Write the calculated checksum
  1171.         $v_checksum sprintf("%06s "DecOct($v_checksum));
  1172.         $v_binary_data pack("a8"$v_checksum);
  1173.         $this->_writeBlock($v_binary_data8);
  1174.  
  1175.         // ----- Write the last 356 bytes of the header in the archive
  1176.         $this->_writeBlock($v_binary_data_last356);
  1177.  
  1178.         return true;
  1179.     }
  1180.     // }}}
  1181.  
  1182.     // {{{ _writeHeaderBlock()
  1183.     function _writeHeaderBlock($p_filename$p_size$p_mtime=0$p_perms=0,
  1184.                                $p_type=''$p_uid=0$p_gid=0)
  1185.     {
  1186.         $p_filename $this->_pathReduction($p_filename);
  1187.  
  1188.         if (strlen($p_filename> 99{
  1189.           if (!$this->_writeLongHeader($p_filename))
  1190.             return false;
  1191.         }
  1192.  
  1193.         if ($p_type == "5"{
  1194.           $v_size sprintf("%011s"DecOct(0));
  1195.         else {
  1196.           $v_size sprintf("%011s"DecOct($p_size));
  1197.         }
  1198.  
  1199.         $v_uid sprintf("%07s"DecOct($p_uid));
  1200.         $v_gid sprintf("%07s"DecOct($p_gid));
  1201.         $v_perms sprintf("%07s"DecOct($p_perms 000777));
  1202.  
  1203.         $v_mtime sprintf("%11s"DecOct($p_mtime));
  1204.  
  1205.         $v_linkname '';
  1206.  
  1207.         $v_magic 'ustar ';
  1208.  
  1209.         $v_version ' ';
  1210.  
  1211.         if (function_exists('posix_getpwuid'))
  1212.         {
  1213.           $userinfo posix_getpwuid($p_uid);
  1214.           $groupinfo posix_getgrgid($p_gid);
  1215.           
  1216.           $v_uname $userinfo['name'];
  1217.           $v_gname $groupinfo['name'];
  1218.         }
  1219.         else
  1220.         {
  1221.           $v_uname '';
  1222.           $v_gname '';
  1223.         }
  1224.         
  1225.         $v_devmajor '';
  1226.  
  1227.         $v_devminor '';
  1228.  
  1229.         $v_prefix '';
  1230.  
  1231.         $v_binary_data_first pack("a100a8a8a8a12A12",
  1232.                                     $p_filename$v_perms$v_uid$v_gid,
  1233.                                     $v_size$v_mtime);
  1234.         $v_binary_data_last pack("a1a100a6a2a32a32a8a8a155a12",
  1235.                                    $p_type$v_linkname$v_magic,
  1236.                                    $v_version$v_uname$v_gname,
  1237.                                    $v_devmajor$v_devminor$v_prefix'');
  1238.  
  1239.         // ----- Calculate the checksum
  1240.         $v_checksum = 0;
  1241.         // ..... First part of the header
  1242.         for ($i=0; $i<148; $i++)
  1243.             $v_checksum += ord(substr($v_binary_data_first,$i,1));
  1244.         // ..... Ignore the checksum value and replace it by ' ' (space)
  1245.         for ($i=148; $i<156; $i++)
  1246.             $v_checksum += ord(' ');
  1247.         // ..... Last part of the header
  1248.         for ($i=156$j=0; $i<512; $i++$j++)
  1249.             $v_checksum += ord(substr($v_binary_data_last,$j,1));
  1250.  
  1251.         // ----- Write the first 148 bytes of the header in the archive
  1252.         $this->_writeBlock($v_binary_data_first148);
  1253.  
  1254.         // ----- Write the calculated checksum
  1255.         $v_checksum sprintf("%06s "DecOct($v_checksum));
  1256.         $v_binary_data pack("a8"$v_checksum);
  1257.         $this->_writeBlock($v_binary_data8);
  1258.  
  1259.         // ----- Write the last 356 bytes of the header in the archive
  1260.         $this->_writeBlock($v_binary_data_last356);
  1261.  
  1262.         return true;
  1263.     }
  1264.     // }}}
  1265.  
  1266.     // {{{ _writeLongHeader()
  1267.     function _writeLongHeader($p_filename)
  1268.     {
  1269.         $v_size sprintf("%11s "DecOct(strlen($p_filename)));
  1270.  
  1271.         $v_typeflag 'L';
  1272.  
  1273.         $v_linkname '';
  1274.  
  1275.         $v_magic '';
  1276.  
  1277.         $v_version '';
  1278.  
  1279.         $v_uname '';
  1280.  
  1281.         $v_gname '';
  1282.  
  1283.         $v_devmajor '';
  1284.  
  1285.         $v_devminor '';
  1286.  
  1287.         $v_prefix '';
  1288.  
  1289.         $v_binary_data_first pack("a100a8a8a8a12a12",
  1290.                                     '././@LongLink'000$v_size0);
  1291.         $v_binary_data_last pack("a1a100a6a2a32a32a8a8a155a12",
  1292.                                    $v_typeflag$v_linkname$v_magic,
  1293.                                    $v_version$v_uname$v_gname,
  1294.                                    $v_devmajor$v_devminor$v_prefix'');
  1295.  
  1296.         // ----- Calculate the checksum
  1297.         $v_checksum = 0;
  1298.         // ..... First part of the header
  1299.         for ($i=0; $i<148; $i++)
  1300.             $v_checksum += ord(substr($v_binary_data_first,$i,1));
  1301.         // ..... Ignore the checksum value and replace it by ' ' (space)
  1302.         for ($i=148; $i<156; $i++)
  1303.             $v_checksum += ord(' ');
  1304.         // ..... Last part of the header
  1305.         for ($i=156$j=0; $i<512; $i++$j++)
  1306.             $v_checksum += ord(substr($v_binary_data_last,$j,1));
  1307.  
  1308.         // ----- Write the first 148 bytes of the header in the archive
  1309.         $this->_writeBlock($v_binary_data_first148);
  1310.  
  1311.         // ----- Write the calculated checksum
  1312.         $v_checksum sprintf("%06s "DecOct($v_checksum));
  1313.         $v_binary_data pack("a8"$v_checksum);
  1314.         $this->_writeBlock($v_binary_data8);
  1315.  
  1316.         // ----- Write the last 356 bytes of the header in the archive
  1317.         $this->_writeBlock($v_binary_data_last356);
  1318.  
  1319.         // ----- Write the filename as content of the block
  1320.         $i=0;
  1321.         while (($v_buffer substr($p_filename(($i++)*512)512)) != ''{
  1322.             $v_binary_data pack("a512""$v_buffer");
  1323.             $this->_writeBlock($v_binary_data);
  1324.         }
  1325.  
  1326.         return true;
  1327.     }
  1328.     // }}}
  1329.  
  1330.     // {{{ _readHeader()
  1331.     function _readHeader($v_binary_data&$v_header)
  1332.     {
  1333.         if (strlen($v_binary_data)==0{
  1334.             $v_header['filename''';
  1335.             return true;
  1336.         }
  1337.  
  1338.         if (strlen($v_binary_data!= 512{
  1339.             $v_header['filename''';
  1340.             $this->_error('Invalid block size : '.strlen($v_binary_data));
  1341.             return false;
  1342.         }
  1343.  
  1344.         if (!is_array($v_header)) {
  1345.             $v_header = array();
  1346.         }
  1347.         // ----- Calculate the checksum
  1348.         $v_checksum = 0;
  1349.         // ..... First part of the header
  1350.         for ($i=0; $i<148; $i++)
  1351.             $v_checksum+=ord(substr($v_binary_data,$i,1));
  1352.         // ..... Ignore the checksum value and replace it by ' ' (space)
  1353.         for ($i=148; $i<156; $i++)
  1354.             $v_checksum += ord(' ');
  1355.         // ..... Last part of the header
  1356.         for ($i=156; $i<512; $i++)
  1357.            $v_checksum+=ord(substr($v_binary_data,$i,1));
  1358.  
  1359.         if (version_compare(PHP_VERSION,"5.5.0-dev")<0{
  1360.             $fmt "a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/" .
  1361.                    "a8checksum/a1typeflag/a100link/a6magic/a2version/" .
  1362.                    "a32uname/a32gname/a8devmajor/a8devminor/a131prefix";
  1363.         else {
  1364.             $fmt "Z100filename/Z8mode/Z8uid/Z8gid/Z12size/Z12mtime/" .
  1365.                    "Z8checksum/Z1typeflag/Z100link/Z6magic/Z2version/" .
  1366.                    "Z32uname/Z32gname/Z8devmajor/Z8devminor/Z131prefix";
  1367.         }
  1368.         $v_data unpack($fmt$v_binary_data);
  1369.  
  1370.         if (strlen($v_data["prefix"]> 0{
  1371.             $v_data["filename"= "$v_data[prefix]/$v_data[filename]";
  1372.         }
  1373.  
  1374.         // ----- Extract the checksum
  1375.         $v_header['checksum'= OctDec(trim($v_data['checksum']));
  1376.         if ($v_header['checksum'!= $v_checksum{
  1377.             $v_header['filename''';
  1378.  
  1379.             // ----- Look for last block (empty block)
  1380.             if (($v_checksum == 256&& ($v_header['checksum'== 0))
  1381.                 return true;
  1382.  
  1383.             $this->_error('Invalid checksum for file "'.$v_data['filename']
  1384.                           .'" : '.$v_checksum.' calculated, '
  1385.                           .$v_header['checksum'].' expected');
  1386.             return false;
  1387.         }
  1388.  
  1389.         // ----- Extract the properties
  1390.         $v_header['filename'$v_data['filename'];
  1391.         if ($this->_maliciousFilename($v_header['filename'])) {
  1392.             $this->_error('Malicious .tar detected, file "' $v_header['filename'.
  1393.                 '" will not install in desired directory tree');
  1394.             return false;
  1395.         }
  1396.         $v_header['mode'= OctDec(trim($v_data['mode']));
  1397.         $v_header['uid'= OctDec(trim($v_data['uid']));
  1398.         $v_header['gid'= OctDec(trim($v_data['gid']));
  1399.         $v_header['size'= OctDec(trim($v_data['size']));
  1400.         $v_header['mtime'= OctDec(trim($v_data['mtime']));
  1401.         if (($v_header['typeflag'$v_data['typeflag']== "5"{
  1402.           $v_header['size'= 0;
  1403.         }
  1404.         $v_header['link'trim($v_data['link']);
  1405.         /* ----- All these fields are removed form the header because
  1406.         they do not carry interesting info
  1407.         $v_header[magic] = trim($v_data[magic]);
  1408.         $v_header[version] = trim($v_data[version]);
  1409.         $v_header[uname] = trim($v_data[uname]);
  1410.         $v_header[gname] = trim($v_data[gname]);
  1411.         $v_header[devmajor] = trim($v_data[devmajor]);
  1412.         $v_header[devminor] = trim($v_data[devminor]);
  1413.         */
  1414.  
  1415.         return true;
  1416.     }
  1417.     // }}}
  1418.  
  1419.     // {{{ _maliciousFilename()
  1420.     /**
  1421.      * Detect and report a malicious file name
  1422.      *
  1423.      * @param string $file 
  1424.      *
  1425.      * @return bool 
  1426.      * @access private
  1427.      */
  1428.     function _maliciousFilename($file)
  1429.     {
  1430.         if (strpos($file'/../'!== false{
  1431.             return true;
  1432.         }
  1433.         if (strpos($file'../'=== 0{
  1434.             return true;
  1435.         }
  1436.         return false;
  1437.     }
  1438.     // }}}
  1439.  
  1440.     // {{{ _readLongHeader()
  1441.     function _readLongHeader(&$v_header)
  1442.     {
  1443.       $v_filename '';
  1444.       $n floor($v_header['size']/512);
  1445.       for ($i=0; $i<$n$i++{
  1446.         $v_content $this->_readBlock();
  1447.         $v_filename .= $v_content;
  1448.       }
  1449.       if (($v_header['size'% 512!= 0{
  1450.         $v_content $this->_readBlock();
  1451.         $v_filename .= trim($v_content);
  1452.       }
  1453.  
  1454.       // ----- Read the next header
  1455.       $v_binary_data $this->_readBlock();
  1456.  
  1457.       if (!$this->_readHeader($v_binary_data$v_header))
  1458.         return false;
  1459.  
  1460.       $v_filename trim($v_filename);
  1461.       $v_header['filename'$v_filename;
  1462.         if ($this->_maliciousFilename($v_filename)) {
  1463.             $this->_error('Malicious .tar detected, file "' $v_filename .
  1464.                 '" will not install in desired directory tree');
  1465.             return false;
  1466.       }
  1467.  
  1468.       return true;
  1469.     }
  1470.     // }}}
  1471.  
  1472.     // {{{ _extractInString()
  1473.     /**
  1474.     * This method extract from the archive one file identified by $p_filename.
  1475.     * The return value is a string with the file content, or null on error.
  1476.     *
  1477.     * @param string $p_filename The path of the file to extract in a string.
  1478.     *
  1479.     * @return string with the file content or null.
  1480.     * @access private
  1481.     */
  1482.     function _extractInString($p_filename)
  1483.     {
  1484.         $v_result_str "";
  1485.  
  1486.         While (strlen($v_binary_data $this->_readBlock()) != 0)
  1487.         {
  1488.           if (!$this->_readHeader($v_binary_data$v_header))
  1489.             return null;
  1490.  
  1491.           if ($v_header['filename'== '')
  1492.             continue;
  1493.  
  1494.           // ----- Look for long filename
  1495.           if ($v_header['typeflag'== 'L'{
  1496.             if (!$this->_readLongHeader($v_header))
  1497.               return null;
  1498.           }
  1499.  
  1500.           if ($v_header['filename'== $p_filename{
  1501.               if ($v_header['typeflag'== "5"{
  1502.                   $this->_error('Unable to extract in string a directory '
  1503.                                 .'entry {'.$v_header['filename'].'}');
  1504.                   return null;
  1505.               else {
  1506.                   $n floor($v_header['size']/512);
  1507.                   for ($i=0; $i<$n$i++{
  1508.                       $v_result_str .= $this->_readBlock();
  1509.                   }
  1510.                   if (($v_header['size'% 512!= 0{
  1511.                       $v_content $this->_readBlock();
  1512.                       $v_result_str .= substr($v_content0,
  1513.                                               ($v_header['size'% 512));
  1514.                   }
  1515.                   return $v_result_str;
  1516.               }
  1517.           else {
  1518.               $this->_jumpBlock(ceil(($v_header['size']/512)));
  1519.           }
  1520.         }
  1521.  
  1522.         return null;
  1523.     }
  1524.     // }}}
  1525.  
  1526.     // {{{ _extractList()
  1527.     function _extractList($p_path&$p_list_detail$p_mode,
  1528.                           $p_file_list$p_remove_path$p_preserve=false)
  1529.     {
  1530.     $v_result=true;
  1531.     $v_nb = 0;
  1532.     $v_extract_all = true;
  1533.     $v_listing = false;
  1534.  
  1535.     $p_path $this->_translateWinPath($p_pathfalse);
  1536.     if ($p_path == '' || (substr($p_path01!= '/'
  1537.         && substr($p_path03!= "../" && !strpos($p_path':'))) {
  1538.       $p_path "./".$p_path;
  1539.     }
  1540.     $p_remove_path $this->_translateWinPath($p_remove_path);
  1541.  
  1542.     // ----- Look for path to remove format (should end by /)
  1543.     if (($p_remove_path != ''&& (substr($p_remove_path-1!= '/'))
  1544.       $p_remove_path .= '/';
  1545.     $p_remove_path_size strlen($p_remove_path);
  1546.  
  1547.     switch ($p_mode{
  1548.       case "complete" :
  1549.         $v_extract_all = true;
  1550.         $v_listing = false;
  1551.       break;
  1552.       case "partial" :
  1553.           $v_extract_all = false;
  1554.           $v_listing = false;
  1555.       break;
  1556.       case "list" :
  1557.           $v_extract_all = false;
  1558.           $v_listing = true;
  1559.       break;
  1560.       default :
  1561.         $this->_error('Invalid extract mode ('.$p_mode.')');
  1562.         return false;
  1563.     }
  1564.  
  1565.     clearstatcache();
  1566.  
  1567.     while (strlen($v_binary_data $this->_readBlock()) != 0)
  1568.     {
  1569.       $v_extract_file = FALSE;
  1570.       $v_extraction_stopped = 0;
  1571.  
  1572.       if (!$this->_readHeader($v_binary_data$v_header))
  1573.         return false;
  1574.  
  1575.       if ($v_header['filename'== ''{
  1576.         continue;
  1577.       }
  1578.  
  1579.       // ----- Look for long filename
  1580.       if ($v_header['typeflag'== 'L'{
  1581.         if (!$this->_readLongHeader($v_header))
  1582.           return false;
  1583.       }
  1584.  
  1585.       if ((!$v_extract_all&& (is_array($p_file_list))) {
  1586.         // ----- By default no unzip if the file is not found
  1587.         $v_extract_file = false;
  1588.  
  1589.         for ($i=0; $i<sizeof($p_file_list)$i++{
  1590.           // ----- Look if it is a directory
  1591.           if (substr($p_file_list[$i]-1== '/'{
  1592.             // ----- Look if the directory is in the filename path
  1593.             if ((strlen($v_header['filename']strlen($p_file_list[$i]))
  1594.                 && (substr($v_header['filename']0strlen($p_file_list[$i]))
  1595.                     == $p_file_list[$i])) {
  1596.               $v_extract_file = true;
  1597.               break;
  1598.             }
  1599.           }
  1600.  
  1601.           // ----- It is a file, so compare the file names
  1602.           elseif ($p_file_list[$i== $v_header['filename']{
  1603.             $v_extract_file = true;
  1604.             break;
  1605.           }
  1606.         }
  1607.       else {
  1608.         $v_extract_file = true;
  1609.       }
  1610.  
  1611.       // ----- Look if this file need to be extracted
  1612.       if (($v_extract_file&& (!$v_listing))
  1613.       {
  1614.         if (($p_remove_path != '')
  1615.             && (substr($v_header['filename'].'/'0$p_remove_path_size)
  1616.                 == $p_remove_path)) {
  1617.           $v_header['filename'substr($v_header['filename'],
  1618.                                          $p_remove_path_size);
  1619.           if$v_header['filename'== '' ){
  1620.             continue;
  1621.           }
  1622.         }
  1623.         if (($p_path != './'&& ($p_path != '/')) {
  1624.           while (substr($p_path-1== '/')
  1625.             $p_path substr($p_path0strlen($p_path)-1);
  1626.  
  1627.           if (substr($v_header['filename']01== '/')
  1628.               $v_header['filename'$p_path.$v_header['filename'];
  1629.           else
  1630.             $v_header['filename'$p_path.'/'.$v_header['filename'];
  1631.         }
  1632.         if (file_exists($v_header['filename'])) {
  1633.           if (   (@is_dir($v_header['filename']))
  1634.               && ($v_header['typeflag'== '')) {
  1635.             $this->_error('File '.$v_header['filename']
  1636.                           .' already exists as a directory');
  1637.             return false;
  1638.           }
  1639.           if (   ($this->_isArchive($v_header['filename']))
  1640.               && ($v_header['typeflag'== "5")) {
  1641.             $this->_error('Directory '.$v_header['filename']
  1642.                           .' already exists as a file');
  1643.             return false;
  1644.           }
  1645.           if (!is_writeable($v_header['filename'])) {
  1646.             $this->_error('File '.$v_header['filename']
  1647.                           .' already exists and is write protected');
  1648.             return false;
  1649.           }
  1650.           if (filemtime($v_header['filename']$v_header['mtime']{
  1651.             // To be completed : An error or silent no replace ?
  1652.           }
  1653.         }
  1654.  
  1655.         // ----- Check the directory availability and create it if necessary
  1656.         elseif (($v_result
  1657.                  = $this->_dirCheck(($v_header['typeflag'== "5"
  1658.                                     ?$v_header['filename']
  1659.                                     :dirname($v_header['filename'])))) != 1{
  1660.             $this->_error('Unable to create path for '.$v_header['filename']);
  1661.             return false;
  1662.         }
  1663.  
  1664.         if ($v_extract_file{
  1665.           if ($v_header['typeflag'== "5"{
  1666.             if (!@file_exists($v_header['filename'])) {
  1667.                 if (!@mkdir($v_header['filename']0777)) {
  1668.                     $this->_error('Unable to create directory {'
  1669.                                   .$v_header['filename'].'}');
  1670.                     return false;
  1671.                 }
  1672.             }
  1673.           elseif ($v_header['typeflag'== "2"{
  1674.               if (@file_exists($v_header['filename'])) {
  1675.                   @unlink($v_header['filename']);
  1676.               }
  1677.               if (!@symlink($v_header['link']$v_header['filename'])) {
  1678.                   $this->_error('Unable to extract symbolic link {'
  1679.                                 .$v_header['filename'].'}');
  1680.                   return false;
  1681.               }
  1682.           else {
  1683.               if (($v_dest_file @fopen($v_header['filename']"wb")) == 0{
  1684.                   $this->_error('Error while opening {'.$v_header['filename']
  1685.                                 .'} in write binary mode');
  1686.                   return false;
  1687.               else {
  1688.                   $n floor($v_header['size']/512);
  1689.                   for ($i=0; $i<$n$i++{
  1690.                       $v_content $this->_readBlock();
  1691.                       fwrite($v_dest_file$v_content512);
  1692.                   }
  1693.             if (($v_header['size'% 512!= 0{
  1694.               $v_content $this->_readBlock();
  1695.               fwrite($v_dest_file$v_content($v_header['size'% 512));
  1696.             }
  1697.  
  1698.             @fclose($v_dest_file);
  1699.             
  1700.             if ($p_preserve{
  1701.                 @chown($v_header['filename']$v_header['uid']);
  1702.                 @chgrp($v_header['filename']$v_header['gid']);
  1703.             }
  1704.  
  1705.             // ----- Change the file mode, mtime
  1706.             @touch($v_header['filename']$v_header['mtime']);
  1707.             if ($v_header['mode'0111{
  1708.                 // make file executable, obey umask
  1709.                 $mode fileperms($v_header['filename'](~umask(0111);
  1710.                 @chmod($v_header['filename']$mode);
  1711.             }
  1712.           }
  1713.  
  1714.           // ----- Check the file size
  1715.           clearstatcache();
  1716.           if (!is_file($v_header['filename'])) {
  1717.               $this->_error('Extracted file '.$v_header['filename']
  1718.                             .'does not exist. Archive may be corrupted.');
  1719.               return false;
  1720.           }
  1721.           
  1722.           $filesize filesize($v_header['filename']);
  1723.           if ($filesize != $v_header['size']{
  1724.               $this->_error('Extracted file '.$v_header['filename']
  1725.                             .' does not have the correct file size \''
  1726.                             .$filesize
  1727.                             .'\' ('.$v_header['size']
  1728.                             .' expected). Archive may be corrupted.');
  1729.               return false;
  1730.           }
  1731.           }
  1732.         else {
  1733.           $this->_jumpBlock(ceil(($v_header['size']/512)));
  1734.         }
  1735.       else {
  1736.           $this->_jumpBlock(ceil(($v_header['size']/512)));
  1737.       }
  1738.  
  1739.       /* TBC : Seems to be unused ...
  1740.       if ($this->_compress)
  1741.         $v_end_of_file = @gzeof($this->_file);
  1742.       else
  1743.         $v_end_of_file = @feof($this->_file);
  1744.         */
  1745.  
  1746.       if ($v_listing || $v_extract_file || $v_extraction_stopped{
  1747.         // ----- Log extracted files
  1748.         if (($v_file_dir dirname($v_header['filename']))
  1749.             == $v_header['filename'])
  1750.           $v_file_dir '';
  1751.         if ((substr($v_header['filename']01== '/'&& ($v_file_dir == ''))
  1752.           $v_file_dir '/';
  1753.  
  1754.         $p_list_detail[$v_nb++$v_header;
  1755.         if (is_array($p_file_list&& (count($p_list_detail== count($p_file_list))) {
  1756.             return true;
  1757.         }
  1758.       }
  1759.     }
  1760.  
  1761.         return true;
  1762.     }
  1763.     // }}}
  1764.  
  1765.     // {{{ _openAppend()
  1766.     function _openAppend()
  1767.     {
  1768.         if (filesize($this->_tarname== 0)
  1769.           return $this->_openWrite();
  1770.  
  1771.         if ($this->_compress{
  1772.             $this->_close();
  1773.  
  1774.             if (!@rename($this->_tarname$this->_tarname.".tmp")) {
  1775.                 $this->_error('Error while renaming \''.$this->_tarname
  1776.                               .'\' to temporary file \''.$this->_tarname
  1777.                               .'.tmp\'');
  1778.                 return false;
  1779.             }
  1780.  
  1781.             if ($this->_compress_type == 'gz')
  1782.                 $v_temp_tar @gzopen($this->_tarname.".tmp""rb");
  1783.             elseif ($this->_compress_type == 'bz2')
  1784.                 $v_temp_tar @bzopen($this->_tarname.".tmp""r");
  1785.  
  1786.             if ($v_temp_tar == 0{
  1787.                 $this->_error('Unable to open file \''.$this->_tarname
  1788.                               .'.tmp\' in binary read mode');
  1789.                 @rename($this->_tarname.".tmp"$this->_tarname);
  1790.                 return false;
  1791.             }
  1792.  
  1793.             if (!$this->_openWrite()) {
  1794.                 @rename($this->_tarname.".tmp"$this->_tarname);
  1795.                 return false;
  1796.             }
  1797.  
  1798.             if ($this->_compress_type == 'gz'{
  1799.                 $end_blocks = 0;
  1800.                 
  1801.                 while (!@gzeof($v_temp_tar)) {
  1802.                     $v_buffer @gzread($v_temp_tar512);
  1803.                     if ($v_buffer == ARCHIVE_TAR_END_BLOCK || strlen($v_buffer== 0{
  1804.                         $end_blocks++;
  1805.                         // do not copy end blocks, we will re-make them
  1806.                         // after appending
  1807.                         continue;
  1808.                     elseif ($end_blocks > 0{
  1809.                         for ($i = 0; $i $end_blocks$i++{
  1810.                             $this->_writeBlock(ARCHIVE_TAR_END_BLOCK);
  1811.                         }
  1812.                         $end_blocks = 0;
  1813.                     }
  1814.                     $v_binary_data pack("a512"$v_buffer);
  1815.                     $this->_writeBlock($v_binary_data);
  1816.                 }
  1817.  
  1818.                 @gzclose($v_temp_tar);
  1819.             }
  1820.             elseif ($this->_compress_type == 'bz2'{
  1821.                 $end_blocks = 0;
  1822.                 
  1823.                 while (strlen($v_buffer @bzread($v_temp_tar512)) > 0{
  1824.                     if ($v_buffer == ARCHIVE_TAR_END_BLOCK || strlen($v_buffer== 0{
  1825.                         $end_blocks++;
  1826.                         // do not copy end blocks, we will re-make them
  1827.                         // after appending
  1828.                         continue;
  1829.                     elseif ($end_blocks > 0{
  1830.                         for ($i = 0; $i $end_blocks$i++{
  1831.                             $this->_writeBlock(ARCHIVE_TAR_END_BLOCK);
  1832.                         }
  1833.                         $end_blocks = 0;
  1834.                     }
  1835.                     $v_binary_data pack("a512"$v_buffer);
  1836.                     $this->_writeBlock($v_binary_data);
  1837.                 }
  1838.  
  1839.                 @bzclose($v_temp_tar);
  1840.             }
  1841.  
  1842.             if (!@unlink($this->_tarname.".tmp")) {
  1843.                 $this->_error('Error while deleting temporary file \''
  1844.                               .$this->_tarname.'.tmp\'');
  1845.             }
  1846.  
  1847.         else {
  1848.             // ----- For not compressed tar, just add files before the last
  1849.             //       one or two 512 bytes block
  1850.             if (!$this->_openReadWrite())
  1851.                return false;
  1852.  
  1853.             clearstatcache();
  1854.             $v_size filesize($this->_tarname);
  1855.  
  1856.             // We might have zero, one or two end blocks.
  1857.             // The standard is two, but we should try to handle
  1858.             // other cases.
  1859.             fseek($this->_file$v_size - 1024);
  1860.             if (fread($this->_file512== ARCHIVE_TAR_END_BLOCK{
  1861.                 fseek($this->_file$v_size - 1024);
  1862.             }
  1863.             elseif (fread($this->_file512== ARCHIVE_TAR_END_BLOCK{
  1864.                 fseek($this->_file$v_size - 512);
  1865.             }
  1866.         }
  1867.  
  1868.         return true;
  1869.     }
  1870.     // }}}
  1871.  
  1872.     // {{{ _append()
  1873.     function _append($p_filelist$p_add_dir=''$p_remove_dir='')
  1874.     {
  1875.         if (!$this->_openAppend())
  1876.             return false;
  1877.  
  1878.         if ($this->_addList($p_filelist$p_add_dir$p_remove_dir))
  1879.            $this->_writeFooter();
  1880.  
  1881.         $this->_close();
  1882.  
  1883.         return true;
  1884.     }
  1885.     // }}}
  1886.  
  1887.     // {{{ _dirCheck()
  1888.  
  1889.     /**
  1890.      * Check if a directory exists and create it (including parent
  1891.      * dirs) if not.
  1892.      *
  1893.      * @param string $p_dir directory to check
  1894.      *
  1895.      * @return bool true if the directory exists or was created
  1896.      */
  1897.     function _dirCheck($p_dir)
  1898.     {
  1899.         clearstatcache();
  1900.         if ((@is_dir($p_dir)) || ($p_dir == ''))
  1901.             return true;
  1902.  
  1903.         $p_parent_dir dirname($p_dir);
  1904.  
  1905.         if (($p_parent_dir != $p_dir&&
  1906.             ($p_parent_dir != ''&&
  1907.             (!$this->_dirCheck($p_parent_dir)))
  1908.              return false;
  1909.  
  1910.         if (!@mkdir($p_dir0777)) {
  1911.             $this->_error("Unable to create directory '$p_dir'");
  1912.             return false;
  1913.         }
  1914.  
  1915.         return true;
  1916.     }
  1917.  
  1918.     // }}}
  1919.  
  1920.     // {{{ _pathReduction()
  1921.  
  1922.     /**
  1923.      * Compress path by changing for example "/dir/foo/../bar" to "/dir/bar",
  1924.      * rand emove double slashes.
  1925.      *
  1926.      * @param string $p_dir path to reduce
  1927.      *
  1928.      * @return string reduced path
  1929.      *
  1930.      * @access private
  1931.      *
  1932.      */
  1933.     function _pathReduction($p_dir)
  1934.     {
  1935.         $v_result '';
  1936.  
  1937.         // ----- Look for not empty path
  1938.         if ($p_dir != ''{
  1939.             // ----- Explode path by directory names
  1940.             $v_list explode('/'$p_dir);
  1941.  
  1942.             // ----- Study directories from last to first
  1943.             for ($i=sizeof($v_list)-1; $i>=0; $i--{
  1944.                 // ----- Look for current path
  1945.                 if ($v_list[$i== "."{
  1946.                     // ----- Ignore this directory
  1947.                     // Should be the first $i=0, but no check is done
  1948.                 }
  1949.                 else if ($v_list[$i== ".."{
  1950.                     // ----- Ignore it and ignore the $i-1
  1951.                     $i--;
  1952.                 }
  1953.                 else if (   ($v_list[$i== '')
  1954.                          && ($i!=(sizeof($v_list)-1))
  1955.                          && ($i!=0)) {
  1956.                     // ----- Ignore only the double '//' in path,
  1957.                     // but not the first and last /
  1958.                 else {
  1959.                     $v_result $v_list[$i].($i!=(sizeof($v_list)-1)?'/'
  1960.                                 .$v_result:'');
  1961.                 }
  1962.             }
  1963.         }
  1964.         
  1965.         if (defined('OS_WINDOWS'&& OS_WINDOWS{
  1966.             $v_result strtr($v_result'\\''/');
  1967.         }
  1968.         
  1969.         return $v_result;
  1970.     }
  1971.  
  1972.     // }}}
  1973.  
  1974.     // {{{ _translateWinPath()
  1975.     function _translateWinPath($p_path$p_remove_disk_letter=true)
  1976.     {
  1977.       if (defined('OS_WINDOWS'&& OS_WINDOWS{
  1978.           // ----- Look for potential disk letter
  1979.           if (   ($p_remove_disk_letter)
  1980.               && (($v_position strpos($p_path':')) != false)) {
  1981.               $p_path substr($p_path$v_position+1);
  1982.           }
  1983.           // ----- Change potential windows directory separator
  1984.           if ((strpos($p_path'\\'> 0|| (substr($p_path0,1== '\\')) {
  1985.               $p_path strtr($p_path'\\''/');
  1986.           }
  1987.       }
  1988.       return $p_path;
  1989.     }
  1990.     // }}}
  1991.  
  1992. }
  1993. ?>

Documentation generated on Sat, 09 Feb 2013 12:00:05 +0000 by phpDocumentor 1.4.3. PEAR Logo Copyright © PHP Group 2004.