Вход Регистрация
Файл: sys/classes/Tar.class.php
Строк: 1748
<?php

require_once 'PEAR.class.php';

define('ARCHIVE_TAR_ATT_SEPARATOR'90001);
define('ARCHIVE_TAR_END_BLOCK'pack("a512"''));

if (!
function_exists('gzopen') && function_exists('gzopen64')) {
    function 
gzopen($filename$mode$use_include_path 0)
    {
        return 
gzopen64($filename$mode$use_include_path);
    }
}

if (!
function_exists('gztell') && function_exists('gztell64')) {
    function 
gztell($zp)
    {
        return 
gztell64($zp);
    }
}

if (!
function_exists('gzseek') && function_exists('gzseek64')) {
    function 
gzseek($zp$offset$whence SEEK_SET)
    {
        return 
gzseek64($zp$offset$whence);
    }
}

/**
 * Creates a (compressed) Tar archive
 *
 * @package Archive_Tar
 * @author  Vincent Blavet <vincent@phpconcept.net>
 * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
 * @version $Revision$
 */
class Archive_Tar extends PEAR
{
    
/**
     * @var string Name of the Tar
     */
    
public $_tarname '';

    
/**
     * @var boolean if true, the Tar file will be gzipped
     */
    
public $_compress false;

    
/**
     * @var string Type of compression : 'none', 'gz', 'bz2' or 'lzma2'
     */
    
public $_compress_type 'none';

    
/**
     * @var string Explode separator
     */
    
public $_separator ' ';

    
/**
     * @var file descriptor
     */
    
public $_file 0;

    
/**
     * @var string Local Tar name of a remote Tar (http:// or ftp://)
     */
    
public $_temp_tarname '';

    
/**
     * @var string regular expression for ignoring files or directories
     */
    
public $_ignore_regexp '';

    
/**
     * @var object PEAR_Error object
     */
    
public $error_object null;

    
/**
     * Archive_Tar Class constructor. This flavour of the constructor only
     * declare a new Archive_Tar object, identifying it by the name of the
     * tar file.
     * If the compress argument is set the tar will be read or created as a
     * gzip or bz2 compressed TAR file.
     *
     * @param string $p_tarname The name of the tar archive to create
     * @param string $p_compress can be null, 'gz', 'bz2' or 'lzma2'. This
     *               parameter indicates if gzip, bz2 or lzma2 compression
     *               is required.  For compatibility reason the
     *               boolean value 'true' means 'gz'.
     *
     * @return bool
     */
    
public function __construct($p_tarname$p_compress null)
    {
        
parent::__construct();
        
        
$this->_compress false;
        
$this->_compress_type 'none';
        if ((
$p_compress === null) || ($p_compress == '')) {
            if (@
file_exists($p_tarname)) {
                if (
$fp = @fopen($p_tarname"rb")) {
                    
// look for gzip magic cookie
                    
$data fread($fp2);
                    
fclose($fp);
                    if (
$data == "37213") {
                        
$this->_compress true;
                        
$this->_compress_type 'gz';
                        
// No sure it's enought for a magic code ....
                    
} elseif ($data == "BZ") {
                        
$this->_compress true;
                        
$this->_compress_type 'bz2';
                    } elseif (
file_get_contents($p_tarnamefalsenull14) == '7zXZ') {
                        
$this->_compress true;
                        
$this->_compress_type 'lzma2';
                    }
                }
            } else {
                
// probably a remote file or some file accessible
                // through a stream interface
                
if (substr($p_tarname, -2) == 'gz') {
                    
$this->_compress true;
                    
$this->_compress_type 'gz';
                } elseif ((
substr($p_tarname, -3) == 'bz2') ||
                    (
substr($p_tarname, -2) == 'bz')
                ) {
                    
$this->_compress true;
                    
$this->_compress_type 'bz2';
                } else {
                    if (
substr($p_tarname, -2) == 'xz') {
                        
$this->_compress true;
                        
$this->_compress_type 'lzma2';
                    }
                }
            }
        } else {
            if ((
$p_compress === true) || ($p_compress == 'gz')) {
                
$this->_compress true;
                
$this->_compress_type 'gz';
            } else {
                if (
$p_compress == 'bz2') {
                    
$this->_compress true;
                    
$this->_compress_type 'bz2';
                } else {
                    if (
$p_compress == 'lzma2') {
                        
$this->_compress true;
                        
$this->_compress_type 'lzma2';
                    } else {
                        
$this->_error(
                            
"Unsupported compression type '$p_compress'n" .
                            
"Supported types are 'gz', 'bz2' and 'lzma2'.n"
                        
);
                        return 
false;
                    }
                }
            }
        }
        
$this->_tarname $p_tarname;
        if (
$this->_compress) { // assert zlib or bz2 or xz extension support
            
if ($this->_compress_type == 'gz') {
                
$extname 'zlib';
            } else {
                if (
$this->_compress_type == 'bz2') {
                    
$extname 'bz2';
                } else {
                    if (
$this->_compress_type == 'lzma2') {
                        
$extname 'xz';
                    }
                }
            }

            if (!
extension_loaded($extname)) {
                
PEAR::loadExtension($extname);
            }
            if (!
extension_loaded($extname)) {
                
$this->_error(
                    
"The extension '$extname' couldn't be found.n" .
                    
"Please make sure your version of PHP was built " .
                    
"with '$extname' support.n"
                
);
                return 
false;
            }
        }
    }

    public function 
__destruct()
    {
        
$this->_close();
        
// ----- Look for a local copy to delete
        
if ($this->_temp_tarname != '') {
            @
unlink($this->_temp_tarname);
        }
    }

    
/**
     * This method creates the archive file and add the files / directories
     * that are listed in $p_filelist.
     * If a file with the same name exist and is writable, it is replaced
     * by the new tar.
     * The method return false and a PEAR error text.
     * The $p_filelist parameter can be an array of string, each string
     * representing a filename or a directory name with their path if
     * needed. It can also be a single string with names separated by a
     * single blank.
     * For each directory added in the archive, the files and
     * sub-directories are also added.
     * See also createModify() method for more details.
     *
     * @param array $p_filelist An array of filenames and directory names, or a
     *              single string with names separated by a single
     *              blank space.
     *
     * @return true on success, false on error.
     * @see    createModify()
     */
    
public function create($p_filelist)
    {
        return 
$this->createModify($p_filelist'''');
    }

    
/**
     * This method add the files / directories that are listed in $p_filelist in
     * the archive. If the archive does not exist it is created.
     * The method return false and a PEAR error text.
     * The files and directories listed are only added at the end of the archive,
     * even if a file with the same name is already archived.
     * See also createModify() method for more details.
     *
     * @param array $p_filelist An array of filenames and directory names, or a
     *              single string with names separated by a single
     *              blank space.
     *
     * @return true on success, false on error.
     * @see    createModify()
     * @access public
     */
    
public function add($p_filelist)
    {
        return 
$this->addModify($p_filelist'''');
    }

    
/**
     * @param string $p_path
     * @param bool $p_preserve
     * @return bool
     */
    
public function extract($p_path ''$p_preserve false)
    {
        return 
$this->extractModify($p_path''$p_preserve);
    }

    
/**
     * @return array|int
     */
    
public function listContent()
    {
        
$v_list_detail = array();

        if (
$this->_openRead()) {
            if (!
$this->_extractList(''$v_list_detail"list"'''')) {
                unset(
$v_list_detail);
                
$v_list_detail 0;
            }
            
$this->_close();
        }

        return 
$v_list_detail;
    }

    
/**
     * This method creates the archive file and add the files / directories
     * that are listed in $p_filelist.
     * If the file already exists and is writable, it is replaced by the
     * new tar. It is a create and not an add. If the file exists and is
     * read-only or is a directory it is not replaced. The method return
     * false and a PEAR error text.
     * The $p_filelist parameter can be an array of string, each string
     * representing a filename or a directory name with their path if
     * needed. It can also be a single string with names separated by a
     * single blank.
     * The path indicated in $p_remove_dir will be removed from the
     * memorized path of each file / directory listed when this path
     * exists. By default nothing is removed (empty path '')
     * The path indicated in $p_add_dir will be added at the beginning of
     * the memorized path of each file / directory listed. However it can
     * be set to empty ''. The adding of a path is done after the removing
     * of path.
     * The path add/remove ability enables the user to prepare an archive
     * for extraction in a different path than the origin files are.
     * See also addModify() method for file adding properties.
     *
     * @param array $p_filelist An array of filenames and directory names,
     *                             or a single string with names separated by
     *                             a single blank space.
     * @param string $p_add_dir A string which contains a path to be added
     *                             to the memorized path of each element in
     *                             the list.
     * @param string $p_remove_dir A string which contains a path to be
     *                             removed from the memorized path of each
     *                             element in the list, when relevant.
     *
     * @return boolean true on success, false on error.
     * @see addModify()
     */
    
public function createModify($p_filelist$p_add_dir$p_remove_dir '')
    {
        
$v_result true;

        if (!
$this->_openWrite()) {
            return 
false;
        }

        if (
$p_filelist != '') {
            if (
is_array($p_filelist)) {
                
$v_list $p_filelist;
            } elseif (
is_string($p_filelist)) {
                
$v_list explode($this->_separator$p_filelist);
            } else {
                
$this->_cleanFile();
                
$this->_error('Invalid file list');
                return 
false;
            }

            
$v_result $this->_addList($v_list$p_add_dir$p_remove_dir);
        }

        if (
$v_result) {
            
$this->_writeFooter();
            
$this->_close();
        } else {
            
$this->_cleanFile();
        }

        return 
$v_result;
    }

    
/**
     * This method add the files / directories listed in $p_filelist at the
     * end of the existing archive. If the archive does not yet exists it
     * is created.
     * The $p_filelist parameter can be an array of string, each string
     * representing a filename or a directory name with their path if
     * needed. It can also be a single string with names separated by a
     * single blank.
     * The path indicated in $p_remove_dir will be removed from the
     * memorized path of each file / directory listed when this path
     * exists. By default nothing is removed (empty path '')
     * The path indicated in $p_add_dir will be added at the beginning of
     * the memorized path of each file / directory listed. However it can
     * be set to empty ''. The adding of a path is done after the removing
     * of path.
     * The path add/remove ability enables the user to prepare an archive
     * for extraction in a different path than the origin files are.
     * If a file/dir is already in the archive it will only be added at the
     * end of the archive. There is no update of the existing archived
     * file/dir. However while extracting the archive, the last file will
     * replace the first one. This results in a none optimization of the
     * archive size.
     * If a file/dir does not exist the file/dir is ignored. However an
     * error text is send to PEAR error.
     * If a file/dir is not readable the file/dir is ignored. However an
     * error text is send to PEAR error.
     *
     * @param array $p_filelist An array of filenames and directory
     *                             names, or a single string with names
     *                             separated by a single blank space.
     * @param string $p_add_dir A string which contains a path to be
     *                             added to the memorized path of each
     *                             element in the list.
     * @param string $p_remove_dir A string which contains a path to be
     *                             removed from the memorized path of
     *                             each element in the list, when
     *                             relevant.
     *
     * @return true on success, false on error.
     */
    
public function addModify($p_filelist$p_add_dir$p_remove_dir '')
    {
        
$v_result true;

        if (!
$this->_isArchive()) {
            
$v_result $this->createModify(
                
$p_filelist,
                
$p_add_dir,
                
$p_remove_dir
            
);
        } else {
            if (
is_array($p_filelist)) {
                
$v_list $p_filelist;
            } elseif (
is_string($p_filelist)) {
                
$v_list explode($this->_separator$p_filelist);
            } else {
                
$this->_error('Invalid file list');
                return 
false;
            }

            
$v_result $this->_append($v_list$p_add_dir$p_remove_dir);
        }

        return 
$v_result;
    }

    
/**
     * This method add a single string as a file at the
     * end of the existing archive. If the archive does not yet exists it
     * is created.
     *
     * @param string $p_filename A string which contains the full
     *                           filename path that will be associated
     *                           with the string.
     * @param string $p_string The content of the file added in
     *                           the archive.
     * @param bool|int $p_datetime A custom date/time (unix timestamp)
     *                           for the file (optional).
     * @param array $p_params An array of optional params:
     *                               stamp => the datetime (replaces
     *                                   datetime above if it exists)
     *                               mode => the permissions on the
     *                                   file (600 by default)
     *                               type => is this a link?  See the
     *                                   tar specification for details.
     *                                   (default = regular file)
     *                               uid => the user ID of the file
     *                                   (default = 0 = root)
     *                               gid => the group ID of the file
     *                                   (default = 0 = root)
     *
     * @return true on success, false on error.
     */
    
public function addString($p_filename$p_string$p_datetime false$p_params = array())
    {
        
$p_stamp = @$p_params["stamp"] ? $p_params["stamp"] : ($p_datetime $p_datetime time());
        
$p_mode = @$p_params["mode"] ? $p_params["mode"] : 0600;
        
$p_type = @$p_params["type"] ? $p_params["type"] : "";
        
$p_uid = @$p_params["uid"] ? $p_params["uid"] : "";
        
$p_gid = @$p_params["gid"] ? $p_params["gid"] : "";
        
$v_result true;

        if (!
$this->_isArchive()) {
            if (!
$this->_openWrite()) {
                return 
false;
            }
            
$this->_close();
        }

        if (!
$this->_openAppend()) {
            return 
false;
        }

        
// Need to check the get back to the temporary file ? ....
        
$v_result $this->_addString($p_filename$p_string$p_datetime$p_params);

        
$this->_writeFooter();

        
$this->_close();

        return 
$v_result;
    }

    
/**
     * This method extract all the content of the archive in the directory
     * indicated by $p_path. When relevant the memorized path of the
     * files/dir can be modified by removing the $p_remove_path path at the
     * beginning of the file/dir path.
     * While extracting a file, if the directory path does not exists it is
     * created.
     * While extracting a file, if the file already exists it is replaced
     * without looking for last modification date.
     * While extracting a file, if the file already exists and is write
     * protected, the extraction is aborted.
     * While extracting a file, if a directory with the same name already
     * exists, the extraction is aborted.
     * While extracting a directory, if a file with the same name already
     * exists, the extraction is aborted.
     * While extracting a file/directory if the destination directory exist
     * and is write protected, or does not exist but can not be created,
     * the extraction is aborted.
     * If after extraction an extracted file does not show the correct
     * stored file size, the extraction is aborted.
     * When the extraction is aborted, a PEAR error text is set and false
     * is returned. However the result can be a partial extraction that may
     * need to be manually cleaned.
     *
     * @param string $p_path The path of the directory where the
     *                               files/dir need to by extracted.
     * @param string $p_remove_path Part of the memorized path that can be
     *                               removed if present at the beginning of
     *                               the file/dir path.
     * @param boolean $p_preserve Preserve user/group ownership of files
     *
     * @return boolean true on success, false on error.
     * @see    extractList()
     */
    
public function extractModify($p_path$p_remove_path$p_preserve false)
    {
        
$v_result true;
        
$v_list_detail = array();

        if (
$v_result $this->_openRead()) {
            
$v_result $this->_extractList(
                
$p_path,
                
$v_list_detail,
                
"complete",
                
0,
                
$p_remove_path,
                
$p_preserve
            
);
            
$this->_close();
        }

        return 
$v_result;
    }

    
/**
     * This method extract from the archive one file identified by $p_filename.
     * The return value is a string with the file content, or NULL on error.
     *
     * @param string $p_filename The path of the file to extract in a string.
     *
     * @return a string with the file content or NULL.
     */
    
public function extractInString($p_filename)
    {
        if (
$this->_openRead()) {
            
$v_result $this->_extractInString($p_filename);
            
$this->_close();
        } else {
            
$v_result null;
        }

        return 
$v_result;
    }

    
/**
     * This method extract from the archive only the files indicated in the
     * $p_filelist. These files are extracted in the current directory or
     * in the directory indicated by the optional $p_path parameter.
     * If indicated the $p_remove_path can be used in the same way as it is
     * used in extractModify() method.
     *
     * @param array $p_filelist An array of filenames and directory names,
     *                               or a single string with names separated
     *                               by a single blank space.
     * @param string $p_path The path of the directory where the
     *                               files/dir need to by extracted.
     * @param string $p_remove_path Part of the memorized path that can be
     *                               removed if present at the beginning of
     *                               the file/dir path.
     * @param boolean $p_preserve Preserve user/group ownership of files
     *
     * @return true on success, false on error.
     * @see    extractModify()
     */
    
public function extractList($p_filelist$p_path ''$p_remove_path ''$p_preserve false)
    {
        
$v_result true;
        
$v_list_detail = array();

        if (
is_array($p_filelist)) {
            
$v_list $p_filelist;
        } elseif (
is_string($p_filelist)) {
            
$v_list explode($this->_separator$p_filelist);
        } else {
            
$this->_error('Invalid string list');
            return 
false;
        }

        if (
$v_result $this->_openRead()) {
            
$v_result $this->_extractList(
                
$p_path,
                
$v_list_detail,
                
"partial",
                
$v_list,
                
$p_remove_path,
                
$p_preserve
            
);
            
$this->_close();
        }

        return 
$v_result;
    }

    
/**
     * This method set specific attributes of the archive. It uses a variable
     * list of parameters, in the format attribute code + attribute values :
     * $arch->setAttribute(ARCHIVE_TAR_ATT_SEPARATOR, ',');
     *
     * @return true on success, false on error.
     */
    
public function setAttribute()
    {
        
$v_result true;

        
// ----- Get the number of variable list of arguments
        
if (($v_size func_num_args()) == 0) {
            return 
true;
        }

        
// ----- Get the arguments
        
$v_att_list = & func_get_args();

        
// ----- Read the attributes
        
$i 0;
        while (
$i $v_size) {

            
// ----- Look for next option
            
switch ($v_att_list[$i]) {
                
// ----- Look for options that request a string value
                
case ARCHIVE_TAR_ATT_SEPARATOR :
                    
// ----- Check the number of parameters
                    
if (($i 1) >= $v_size) {
                        
$this->_error(
                            
'Invalid number of parameters for '
                            
'attribute ARCHIVE_TAR_ATT_SEPARATOR'
                        
);
                        return 
false;
                    }

                    
// ----- Get the value
                    
$this->_separator $v_att_list[$i 1];
                    
$i++;
                    break;

                default :
                    
$this->_error('Unknown attribute code ' $v_att_list[$i] . '');
                    return 
false;
            }

            
// ----- Next attribute
            
$i++;
        }

        return 
$v_result;
    }

    
/**
     * This method sets the regular expression for ignoring files and directories
     * at import, for example:
     * $arch->setIgnoreRegexp("#CVS|.svn#");
     *
     * @param string $regexp regular expression defining which files or directories to ignore
     */
    
public function setIgnoreRegexp($regexp)
    {
        
$this->_ignore_regexp $regexp;
    }

    
/**
     * This method sets the regular expression for ignoring all files and directories
     * matching the filenames in the array list at import, for example:
     * $arch->setIgnoreList(array('CVS', '.svn', 'bin/tool'));
     *
     * @param array $list a list of file or directory names to ignore
     *
     * @access public
     */
    
public function setIgnoreList($list)
    {
        
$regexp str_replace(array('#''.''^''$'), array('#''.''^''$'), $list);
        
$regexp '#/' join('$|/'$list) . '#';
        
$this->setIgnoreRegexp($regexp);
    }

    
/**
     * @param string $p_message
     */
    
public function _error($p_message)
    {
        
$this->error_object $this->raiseError($p_message);
    }

    
/**
     * @param string $p_message
     */
    
public function _warning($p_message)
    {
        
$this->error_object $this->raiseError($p_message);
    }

    
/**
     * @param string $p_filename
     * @return bool
     */
    
public function _isArchive($p_filename null)
    {
        if (
$p_filename == null) {
            
$p_filename $this->_tarname;
        }
        
clearstatcache();
        return @
is_file($p_filename) && !@is_link($p_filename);
    }

    
/**
     * @return bool
     */
    
public function _openWrite()
    {
        if (
$this->_compress_type == 'gz' && function_exists('gzopen')) {
            
$this->_file = @gzopen($this->_tarname"wb9");
        } else {
            if (
$this->_compress_type == 'bz2' && function_exists('bzopen')) {
                
$this->_file = @bzopen($this->_tarname"w");
            } else {
                if (
$this->_compress_type == 'lzma2' && function_exists('xzopen')) {
                    
$this->_file = @xzopen($this->_tarname'w');
                } else {
                    if (
$this->_compress_type == 'none') {
                        
$this->_file = @fopen($this->_tarname"wb");
                    } else {
                        
$this->_error(
                            
'Unknown or missing compression type ('
                            
$this->_compress_type ')'
                        
);
                        return 
false;
                    }
                }
            }
        }

        if (
$this->_file == 0) {
            
$this->_error(
                
'Unable to open in write mode ''
                . $this->_tarname . '''
            
);
            return 
false;
        }

        return 
true;
    }

    
/**
     * @return bool
     */
    
public function _openRead()
    {
        if (
strtolower(substr($this->_tarname07)) == 'http://') {

            
// ----- Look if a local copy need to be done
            
if ($this->_temp_tarname == '') {
                
$this->_temp_tarname uniqid('tar') . '.tmp';
                if (!
$v_file_from = @fopen($this->_tarname'rb')) {
                    
$this->_error(
                        
'Unable to open in read mode ''
                        . $this->_tarname . '''
                    
);
                    
$this->_temp_tarname '';
                    return 
false;
                }
                if (!
$v_file_to = @fopen($this->_temp_tarname'wb')) {
                    
$this->_error(
                        
'Unable to open in write mode ''
                        . $this->_temp_tarname . '''
                    
);
                    
$this->_temp_tarname '';
                    return 
false;
                }
                while (
$v_data = @fread($v_file_from1024)) {
                    @
fwrite($v_file_to$v_data);
                }
                @
fclose($v_file_from);
                @
fclose($v_file_to);
            }

            
// ----- File to open if the local copy
            
$v_filename $this->_temp_tarname;
        } else {
            
// ----- File to open if the normal Tar file

            
$v_filename $this->_tarname;
        }

        if (
$this->_compress_type == 'gz' && function_exists('gzopen')) {
            
$this->_file = @gzopen($v_filename"rb");
        } else {
            if (
$this->_compress_type == 'bz2' && function_exists('bzopen')) {
                
$this->_file = @bzopen($v_filename"r");
            } else {
                if (
$this->_compress_type == 'lzma2' && function_exists('xzopen')) {
                    
$this->_file = @xzopen($v_filename"r");
                } else {
                    if (
$this->_compress_type == 'none') {
                        
$this->_file = @fopen($v_filename"rb");
                    } else {
                        
$this->_error(
                            
'Unknown or missing compression type ('
                            
$this->_compress_type ')'
                        
);
                        return 
false;
                    }
                }
            }
        }

        if (
$this->_file == 0) {
            
$this->_error('Unable to open in read mode '' . $v_filename . ''');
            return 
false;
        }

        return 
true;
    }

    
/**
     * @return bool
     */
    
public function _openReadWrite()
    {
        if (
$this->_compress_type == 'gz') {
            
$this->_file = @gzopen($this->_tarname"r+b");
        } else {
            if (
$this->_compress_type == 'bz2') {
                
$this->_error(
                    
'Unable to open bz2 in read/write mode ''
                    . $this->_tarname . '' (limitation of bz2 extension)'
                
);
                return 
false;
            } else {
                if (
$this->_compress_type == 'lzma2') {
                    
$this->_error(
                        
'Unable to open lzma2 in read/write mode ''
                        . $this->_tarname . '' (limitation of lzma2 extension)'
                    
);
                    return 
false;
                } else {
                    if (
$this->_compress_type == 'none') {
                        
$this->_file = @fopen($this->_tarname"r+b");
                    } else {
                        
$this->_error(
                            
'Unknown or missing compression type ('
                            
$this->_compress_type ')'
                        
);
                        return 
false;
                    }
                }
            }
        }

        if (
$this->_file == 0) {
            
$this->_error(
                
'Unable to open in read/write mode ''
                . $this->_tarname . '''
            
);
            return 
false;
        }

        return 
true;
    }

    
/**
     * @return bool
     */
    
public function _close()
    {
        
//if (isset($this->_file)) {
        
if (is_resource($this->_file)) {
            if (
$this->_compress_type == 'gz') {
                @
gzclose($this->_file);
            } else {
                if (
$this->_compress_type == 'bz2') {
                    @
bzclose($this->_file);
                } else {
                    if (
$this->_compress_type == 'lzma2') {
                        @
xzclose($this->_file);
                    } else {
                        if (
$this->_compress_type == 'none') {
                            @
fclose($this->_file);
                        } else {
                            
$this->_error(
                                
'Unknown or missing compression type ('
                                
$this->_compress_type ')'
                            
);
                        }
                    }
                }
            }

            
$this->_file 0;
        }

        
// ----- Look if a local copy need to be erase
        // Note that it might be interesting to keep the url for a time : ToDo
        
if ($this->_temp_tarname != '') {
            @
unlink($this->_temp_tarname);
            
$this->_temp_tarname '';
        }

        return 
true;
    }

    
/**
     * @return bool
     */
    
public function _cleanFile()
    {
        
$this->_close();

        
// ----- Look for a local copy
        
if ($this->_temp_tarname != '') {
            
// ----- Remove the local copy but not the remote tarname
            
@unlink($this->_temp_tarname);
            
$this->_temp_tarname '';
        } else {
            
// ----- Remove the local tarname file
            
@unlink($this->_tarname);
        }
        
$this->_tarname '';

        return 
true;
    }

    
/**
     * @param mixed $p_binary_data
     * @param integer $p_len
     * @return bool
     */
    
public function _writeBlock($p_binary_data$p_len null)
    {
        if (
is_resource($this->_file)) {
            if (
$p_len === null) {
                if (
$this->_compress_type == 'gz') {
                    @
gzputs($this->_file$p_binary_data);
                } else {
                    if (
$this->_compress_type == 'bz2') {
                        @
bzwrite($this->_file$p_binary_data);
                    } else {
                        if (
$this->_compress_type == 'lzma2') {
                            @
xzwrite($this->_file$p_binary_data);
                        } else {
                            if (
$this->_compress_type == 'none') {
                                @
fputs($this->_file$p_binary_data);
                            } else {
                                
$this->_error(
                                    
'Unknown or missing compression type ('
                                    
$this->_compress_type ')'
                                
);
                            }
                        }
                    }
                }
            } else {
                if (
$this->_compress_type == 'gz') {
                    @
gzputs($this->_file$p_binary_data$p_len);
                } else {
                    if (
$this->_compress_type == 'bz2') {
                        @
bzwrite($this->_file$p_binary_data$p_len);
                    } else {
                        if (
$this->_compress_type == 'lzma2') {
                            @
xzwrite($this->_file$p_binary_data$p_len);
                        } else {
                            if (
$this->_compress_type == 'none') {
                                @
fputs($this->_file$p_binary_data$p_len);
                            } else {
                                
$this->_error(
                                    
'Unknown or missing compression type ('
                                    
$this->_compress_type ')'
                                
);
                            }
                        }
                    }
                }
            }
        }
        return 
true;
    }

    
/**
     * @return null|string
     */
    
public function _readBlock()
    {
        
$v_block null;
        if (
is_resource($this->_file)) {
            if (
$this->_compress_type == 'gz') {
                
$v_block = @gzread($this->_file512);
            } else {
                if (
$this->_compress_type == 'bz2') {
                    
$v_block = @bzread($this->_file512);
                } else {
                    if (
$this->_compress_type == 'lzma2') {
                        
$v_block = @xzread($this->_file512);
                    } else {
                        if (
$this->_compress_type == 'none') {
                            
$v_block = @fread($this->_file512);
                        } else {
                            
$this->_error(
                                
'Unknown or missing compression type ('
                                
$this->_compress_type ')'
                            
);
                        }
                    }
                }
            }
        }
        return 
$v_block;
    }

    
/**
     * @param null $p_len
     * @return bool
     */
    
public function _jumpBlock($p_len null)
    {
        if (
is_resource($this->_file)) {
            if (
$p_len === null) {
                
$p_len 1;
            }

            if (
$this->_compress_type == 'gz') {
                @
gzseek($this->_filegztell($this->_file) + ($p_len 512));
            } else {
                if (
$this->_compress_type == 'bz2') {
                    
// ----- Replace missing bztell() and bzseek()
                    
for ($i 0$i $p_len$i++) {
                        
$this->_readBlock();
                    }
                } else {
                    if (
$this->_compress_type == 'lzma2') {
                        
// ----- Replace missing xztell() and xzseek()
                        
for ($i 0$i $p_len$i++) {
                            
$this->_readBlock();
                        }
                    } else {
                        if (
$this->_compress_type == 'none') {
                            @
fseek($this->_file$p_len 512SEEK_CUR);
                        } else {
                            
$this->_error(
                                
'Unknown or missing compression type ('
                                
$this->_compress_type ')'
                            
);
                        }
                    }
                }
            }
        }
        return 
true;
    }

    
/**
     * @return bool
     */
    
public function _writeFooter()
    {
        if (
is_resource($this->_file)) {
            
// ----- Write the last 0 filled block for end of archive
            
$v_binary_data pack('a1024''');
            
$this->_writeBlock($v_binary_data);
        }
        return 
true;
    }

    
/**
     * @param array $p_list
     * @param string $p_add_dir
     * @param string $p_remove_dir
     * @return bool
     */
    
public function _addList($p_list$p_add_dir$p_remove_dir)
    {
        
$v_result true;
        
$v_header = array();

        
// ----- Remove potential windows directory separator
        
$p_add_dir $this->_translateWinPath($p_add_dir);
        
$p_remove_dir $this->_translateWinPath($p_remove_dirfalse);

        if (!
$this->_file) {
            
$this->_error('Invalid file descriptor');
            return 
false;
        }

        if (
sizeof($p_list) == 0) {
            return 
true;
        }

        foreach (
$p_list as $v_filename) {
            if (!
$v_result) {
                break;
            }

            
// ----- Skip the current tar name
            
if ($v_filename == $this->_tarname) {
                continue;
            }

            if (
$v_filename == '') {
                continue;
            }

            
// ----- ignore files and directories matching the ignore regular expression
            
if ($this->_ignore_regexp && preg_match($this->_ignore_regexp'/' $v_filename)) {
                
$this->_warning("File '$v_filename' ignored");
                continue;
            }

            if (!
file_exists($v_filename) && !is_link($v_filename)) {
                
$this->_warning("File '$v_filename' does not exist");
                continue;
            }

            
// ----- Add the file or directory header
            
if (!$this->_addFile($v_filename$v_header$p_add_dir$p_remove_dir)) {
                return 
false;
            }

            if (@
is_dir($v_filename) && !@is_link($v_filename)) {
                if (!(
$p_hdir opendir($v_filename))) {
                    
$this->_warning("Directory '$v_filename' can not be read");
                    continue;
                }
                while (
false !== ($p_hitem readdir($p_hdir))) {
                    if ((
$p_hitem != '.') && ($p_hitem != '..')) {
                        if (
$v_filename != ".") {
                            
$p_temp_list[0] = $v_filename '/' $p_hitem;
                        } else {
                            
$p_temp_list[0] = $p_hitem;
                        }

                        
$v_result $this->_addList(
                            
$p_temp_list,
                            
$p_add_dir,
                            
$p_remove_dir
                        
);
                    }
                }

                unset(
$p_temp_list);
                unset(
$p_hdir);
                unset(
$p_hitem);
            }
        }

        return 
$v_result;
    }

    
/**
     * @param string $p_filename
     * @param mixed $p_header
     * @param string $p_add_dir
     * @param string $p_remove_dir
     * @param null $v_stored_filename
     * @return bool
     */
    
public function _addFile($p_filename, &$p_header$p_add_dir$p_remove_dir$v_stored_filename null)
    {
        if (!
$this->_file) {
            
$this->_error('Invalid file descriptor');
            return 
false;
        }

        if (
$p_filename == '') {
            
$this->_error('Invalid file name');
            return 
false;
        }

        if (
is_null($v_stored_filename)) {
            
// ----- Calculate the stored filename
            
$p_filename $this->_translateWinPath($p_filenamefalse);
            
$v_stored_filename $p_filename;

            if (
strcmp($p_filename$p_remove_dir) == 0) {
                return 
true;
            }

            if (
$p_remove_dir != '') {
                if (
substr($p_remove_dir, -1) != '/') {
                    
$p_remove_dir .= '/';
                }

                if (
substr($p_filename0strlen($p_remove_dir)) == $p_remove_dir) {
                    
$v_stored_filename substr($p_filenamestrlen($p_remove_dir));
                }
            }

            
$v_stored_filename $this->_translateWinPath($v_stored_filename);
            if (
$p_add_dir != '') {
                if (
substr($p_add_dir, -1) == '/') {
                    
$v_stored_filename $p_add_dir $v_stored_filename;
                } else {
                    
$v_stored_filename $p_add_dir '/' $v_stored_filename;
                }
            }

            
$v_stored_filename $this->_pathReduction($v_stored_filename);
        }

        if (
$this->_isArchive($p_filename)) {
            if ((
$v_file = @fopen($p_filename"rb")) == 0) {
                
$this->_warning(
                    
"Unable to open file '" $p_filename
                    
"' in binary read mode"
                
);
                return 
true;
            }

            if (!
$this->_writeHeader($p_filename$v_stored_filename)) {
                return 
false;
            }

            while ((
$v_buffer fread($v_file512)) != '') {
                
$v_binary_data pack("a512""$v_buffer");
                
$this->_writeBlock($v_binary_data);
            }

            
fclose($v_file);
        } else {
            
// ----- Only header for dir
            
if (!$this->_writeHeader($p_filename$v_stored_filename)) {
                return 
false;
            }
        }

        return 
true;
    }

    
/**
     * @param string $p_filename
     * @param string $p_string
     * @param bool $p_datetime
     * @param array $p_params
     * @return bool
     */
    
public function _addString($p_filename$p_string$p_datetime false$p_params = array())
    {
        
$p_stamp = @$p_params["stamp"] ? $p_params["stamp"] : ($p_datetime $p_datetime time());
        
$p_mode = @$p_params["mode"] ? $p_params["mode"] : 0600;
        
$p_type = @$p_params["type"] ? $p_params["type"] : "";
        
$p_uid = @$p_params["uid"] ? $p_params["uid"] : 0;
        
$p_gid = @$p_params["gid"] ? $p_params["gid"] : 0;
        if (!
$this->_file) {
            
$this->_error('Invalid file descriptor');
            return 
false;
        }

        if (
$p_filename == '') {
            
$this->_error('Invalid file name');
            return 
false;
        }

        
// ----- Calculate the stored filename
        
$p_filename $this->_translateWinPath($p_filenamefalse);

        
// ----- If datetime is not specified, set current time
        
if ($p_datetime === false) {
            
$p_datetime time();
        }

        if (!
$this->_writeHeaderBlock(
            
$p_filename,
            
strlen($p_string),
            
$p_stamp,
            
$p_mode,
            
$p_type,
            
$p_uid,
            
$p_gid
        
)
        ) {
            return 
false;
        }

        
$i 0;
        while ((
$v_buffer substr($p_string, (($i++) * 512), 512)) != '') {
            
$v_binary_data pack("a512"$v_buffer);
            
$this->_writeBlock($v_binary_data);
        }

        return 
true;
    }

    
/**
     * @param string $p_filename
     * @param string $p_stored_filename
     * @return bool
     */
    
public function _writeHeader($p_filename$p_stored_filename)
    {
        if (
$p_stored_filename == '') {
            
$p_stored_filename $p_filename;
        }
        
$v_reduce_filename $this->_pathReduction($p_stored_filename);

        if (
strlen($v_reduce_filename) > 99) {
            if (!
$this->_writeLongHeader($v_reduce_filename)) {
                return 
false;
            }
        }

        
$v_info lstat($p_filename);
        
$v_uid sprintf("%07s"DecOct($v_info[4]));
        
$v_gid sprintf("%07s"DecOct($v_info[5]));
        
$v_perms sprintf("%07s"DecOct($v_info['mode'] & 000777));

        
$v_mtime sprintf("%011s"DecOct($v_info['mtime']));

        
$v_linkname '';

        if (@
is_link($p_filename)) {
            
$v_typeflag '2';
            
$v_linkname readlink($p_filename);
            
$v_size sprintf("%011s"DecOct(0));
        } elseif (@
is_dir($p_filename)) {
            
$v_typeflag "5";
            
$v_size sprintf("%011s"DecOct(0));
        } else {
            
$v_typeflag '0';
            
clearstatcache();
            
$v_size sprintf("%011s"DecOct($v_info['size']));
        }

        
$v_magic 'ustar ';

        
$v_version ' ';

        if (
function_exists('posix_getpwuid')) {
            
$userinfo posix_getpwuid($v_info[4]);
            
$groupinfo posix_getgrgid($v_info[5]);

            
$v_uname $userinfo['name'];
            
$v_gname $groupinfo['name'];
        } else {
            
$v_uname '';
            
$v_gname '';
        }

        
$v_devmajor '';

        
$v_devminor '';

        
$v_prefix '';

        
$v_binary_data_first pack(
            
"a100a8a8a8a12a12",
            
$v_reduce_filename,
            
$v_perms,
            
$v_uid,
            
$v_gid,
            
$v_size,
            
$v_mtime
        
);
        
$v_binary_data_last pack(
            
"a1a100a6a2a32a32a8a8a155a12",
            
$v_typeflag,
            
$v_linkname,
            
$v_magic,
            
$v_version,
            
$v_uname,
            
$v_gname,
            
$v_devmajor,
            
$v_devminor,
            
$v_prefix,
            
''
        
);

        
// ----- Calculate the checksum
        
$v_checksum 0;
        
// ..... First part of the header
        
for ($i 0$i 148$i++) {
            
$v_checksum += ord(substr($v_binary_data_first$i1));
        }
        
// ..... Ignore the checksum value and replace it by ' ' (space)
        
for ($i 148$i 156$i++) {
            
$v_checksum += ord(' ');
        }
        
// ..... Last part of the header
        
for ($i 156$j 0$i 512$i++, $j++) {
            
$v_checksum += ord(substr($v_binary_data_last$j1));
        }

        
// ----- Write the first 148 bytes of the header in the archive
        
$this->_writeBlock($v_binary_data_first148);

        
// ----- Write the calculated checksum
        
$v_checksum sprintf("%06s "DecOct($v_checksum));
        
$v_binary_data pack("a8"$v_checksum);
        
$this->_writeBlock($v_binary_data8);

        
// ----- Write the last 356 bytes of the header in the archive
        
$this->_writeBlock($v_binary_data_last356);

        return 
true;
    }

    
/**
     * @param string $p_filename
     * @param int $p_size
     * @param int $p_mtime
     * @param int $p_perms
     * @param string $p_type
     * @param int $p_uid
     * @param int $p_gid
     * @return bool
     */
    
public function _writeHeaderBlock(
        
$p_filename,
        
$p_size,
        
$p_mtime 0,
        
$p_perms 0,
        
$p_type '',
        
$p_uid 0,
        
$p_gid 0
    
) {
        
$p_filename $this->_pathReduction($p_filename);

        if (
strlen($p_filename) > 99) {
            if (!
$this->_writeLongHeader($p_filename)) {
                return 
false;
            }
        }

        if (
$p_type == "5") {
            
$v_size sprintf("%011s"DecOct(0));
        } else {
            
$v_size sprintf("%011s"DecOct($p_size));
        }

        
$v_uid sprintf("%07s"DecOct($p_uid));
        
$v_gid sprintf("%07s"DecOct($p_gid));
        
$v_perms sprintf("%07s"DecOct($p_perms 000777));

        
$v_mtime sprintf("%11s"DecOct($p_mtime));

        
$v_linkname '';

        
$v_magic 'ustar ';

        
$v_version ' ';

        if (
function_exists('posix_getpwuid')) {
            
$userinfo posix_getpwuid($p_uid);
            
$groupinfo posix_getgrgid($p_gid);

            
$v_uname $userinfo['name'];
            
$v_gname $groupinfo['name'];
        } else {
            
$v_uname '';
            
$v_gname '';
        }

        
$v_devmajor '';

        
$v_devminor '';

        
$v_prefix '';

        
$v_binary_data_first pack(
            
"a100a8a8a8a12A12",
            
$p_filename,
            
$v_perms,
            
$v_uid,
            
$v_gid,
            
$v_size,
            
$v_mtime
        
);
        
$v_binary_data_last pack(
            
"a1a100a6a2a32a32a8a8a155a12",
            
$p_type,
            
$v_linkname,
            
$v_magic,
            
$v_version,
            
$v_uname,
            
$v_gname,
            
$v_devmajor,
            
$v_devminor,
            
$v_prefix,
            
''
        
);

        
// ----- Calculate the checksum
        
$v_checksum 0;
        
// ..... First part of the header
        
for ($i 0$i 148$i++) {
            
$v_checksum += ord(substr($v_binary_data_first$i1));
        }
        
// ..... Ignore the checksum value and replace it by ' ' (space)
        
for ($i 148$i 156$i++) {
            
$v_checksum += ord(' ');
        }
        
// ..... Last part of the header
        
for ($i 156$j 0$i 512$i++, $j++) {
            
$v_checksum += ord(substr($v_binary_data_last$j1));
        }

        
// ----- Write the first 148 bytes of the header in the archive
        
$this->_writeBlock($v_binary_data_first148);

        
// ----- Write the calculated checksum
        
$v_checksum sprintf("%06s "DecOct($v_checksum));
        
$v_binary_data pack("a8"$v_checksum);
        
$this->_writeBlock($v_binary_data8);

        
// ----- Write the last 356 bytes of the header in the archive
        
$this->_writeBlock($v_binary_data_last356);

        return 
true;
    }

    
/**
     * @param string $p_filename
     * @return bool
     */
    
public function _writeLongHeader($p_filename)
    {
        
$v_size sprintf("%11s "DecOct(strlen($p_filename)));

        
$v_typeflag 'L';

        
$v_linkname '';

        
$v_magic '';

        
$v_version '';

        
$v_uname '';

        
$v_gname '';

        
$v_devmajor '';

        
$v_devminor '';

        
$v_prefix '';

        
$v_binary_data_first pack(
            
"a100a8a8a8a12a12",
            
'././@LongLink',
            
0,
            
0,
            
0,
            
$v_size,
            
0
        
);
        
$v_binary_data_last pack(
            
"a1a100a6a2a32a32a8a8a155a12",
            
$v_typeflag,
            
$v_linkname,
            
$v_magic,
            
$v_version,
            
$v_uname,
            
$v_gname,
            
$v_devmajor,
            
$v_devminor,
            
$v_prefix,
            
''
        
);

        
// ----- Calculate the checksum
        
$v_checksum 0;
        
// ..... First part of the header
        
for ($i 0$i 148$i++) {
            
$v_checksum += ord(substr($v_binary_data_first$i1));
        }
        
// ..... Ignore the checksum value and replace it by ' ' (space)
        
for ($i 148$i 156$i++) {
            
$v_checksum += ord(' ');
        }
        
// ..... Last part of the header
        
for ($i 156$j 0$i 512$i++, $j++) {
            
$v_checksum += ord(substr($v_binary_data_last$j1));
        }

        
// ----- Write the first 148 bytes of the header in the archive
        
$this->_writeBlock($v_binary_data_first148);

        
// ----- Write the calculated checksum
        
$v_checksum sprintf("%06s "DecOct($v_checksum));
        
$v_binary_data pack("a8"$v_checksum);
        
$this->_writeBlock($v_binary_data8);

        
// ----- Write the last 356 bytes of the header in the archive
        
$this->_writeBlock($v_binary_data_last356);

        
// ----- Write the filename as content of the block
        
$i 0;
        while ((
$v_buffer substr($p_filename, (($i++) * 512), 512)) != '') {
            
$v_binary_data pack("a512""$v_buffer");
            
$this->_writeBlock($v_binary_data);
        }

        return 
true;
    }

    
/**
     * @param mixed $v_binary_data
     * @param mixed $v_header
     * @return bool
     */
    
public function _readHeader($v_binary_data, &$v_header)
    {
        if (
strlen($v_binary_data) == 0) {
            
$v_header['filename'] = '';
            return 
true;
        }

        if (
strlen($v_binary_data) != 512) {
            
$v_header['filename'] = '';
            
$this->_error('Invalid block size : ' strlen($v_binary_data));
            return 
false;
        }

        if (!
is_array($v_header)) {
            
$v_header = array();
        }
        
// ----- Calculate the checksum
        
$v_checksum 0;
        
// ..... First part of the header
        
for ($i 0$i 148$i++) {
            
$v_checksum += ord(substr($v_binary_data$i1));
        }
        
// ..... Ignore the checksum value and replace it by ' ' (space)
        
for ($i 148$i 156$i++) {
            
$v_checksum += ord(' ');
        }
        
// ..... Last part of the header
        
for ($i 156$i 512$i++) {
            
$v_checksum += ord(substr($v_binary_data$i1));
        }

        if (
version_compare(PHP_VERSION"5.5.0-dev") < 0) {
            
$fmt "a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/" .
                
"a8checksum/a1typeflag/a100link/a6magic/a2version/" .
                
"a32uname/a32gname/a8devmajor/a8devminor/a131prefix";
        } else {
            
$fmt "Z100filename/Z8mode/Z8uid/Z8gid/Z12size/Z12mtime/" .
                
"Z8checksum/Z1typeflag/Z100link/Z6magic/Z2version/" .
                
"Z32uname/Z32gname/Z8devmajor/Z8devminor/Z131prefix";
        }
        
$v_data unpack($fmt$v_binary_data);

        if (
strlen($v_data["prefix"]) > 0) {
            
$v_data["filename"] = "$v_data[prefix]/$v_data[filename]";
        }

        
// ----- Extract the checksum
        
$v_header['checksum'] = OctDec(trim($v_data['checksum']));
        if (
$v_header['checksum'] != $v_checksum) {
            
$v_header['filename'] = '';

            
// ----- Look for last block (empty block)
            
if (($v_checksum == 256) && ($v_header['checksum'] == 0)) {
                return 
true;
            }

            
$this->_error(
                
'Invalid checksum for file "' $v_data['filename']
                . 
'" : ' $v_checksum ' calculated, '
                
$v_header['checksum'] . ' expected'
            
);
            return 
false;
        }

        
// ----- Extract the properties
        
$v_header['filename'] = rtrim($v_data['filename'], "");
        if (
$this->_maliciousFilename($v_header['filename'])) {
            
$this->_error(
                
'Malicious .tar detected, file "' $v_header['filename'] .
                
'" will not install in desired directory tree'
            
);
            return 
false;
        }
        
$v_header['mode'] = OctDec(trim($v_data['mode']));
        
$v_header['uid'] = OctDec(trim($v_data['uid']));
        
$v_header['gid'] = OctDec(trim($v_data['gid']));
        
$v_header['size'] = OctDec(trim($v_data['size']));
        
$v_header['mtime'] = OctDec(trim($v_data['mtime']));
        if ((
$v_header['typeflag'] = $v_data['typeflag']) == "5") {
            
$v_header['size'] = 0;
        }
        
$v_header['link'] = trim($v_data['link']);
        
/* ----- All these fields are removed form the header because
        they do not carry interesting info
        $v_header[magic] = trim($v_data[magic]);
        $v_header[version] = trim($v_data[version]);
        $v_header[uname] = trim($v_data[uname]);
        $v_header[gname] = trim($v_data[gname]);
        $v_header[devmajor] = trim($v_data[devmajor]);
        $v_header[devminor] = trim($v_data[devminor]);
        */

        
return true;
    }

    
/**
     * Detect and report a malicious file name
     *
     * @param string $file
     *
     * @return bool
     */
    
private function _maliciousFilename($file)
    {
        if (
strpos($file'/../') !== false) {
            return 
true;
        }
        if (
strpos($file'../') === 0) {
            return 
true;
        }
        return 
false;
    }

    
/**
     * @param $v_header
     * @return bool
     */
    
public function _readLongHeader(&$v_header)
    {
        
$v_filename '';
        
$v_filesize $v_header['size'];
        
$n floor($v_header['size'] / 512);
        for (
$i 0$i $n$i++) {
            
$v_content $this->_readBlock();
            
$v_filename .= $v_content;
        }
        if ((
$v_header['size'] % 512) != 0) {
            
$v_content $this->_readBlock();
            
$v_filename .= $v_content;
        }

        
// ----- Read the next header
        
$v_binary_data $this->_readBlock();

        if (!
$this->_readHeader($v_binary_data$v_header)) {
            return 
false;
        }

        
$v_filename rtrim(substr($v_filename0$v_filesize), "");
        
$v_header['filename'] = $v_filename;
        if (
$this->_maliciousFilename($v_filename)) {
            
$this->_error(
                
'Malicious .tar detected, file "' $v_filename .
                
'" will not install in desired directory tree'
            
);
            return 
false;
        }

        return 
true;
    }

    
/**
     * This method extract from the archive one file identified by $p_filename.
     * The return value is a string with the file content, or null on error.
     *
     * @param string $p_filename The path of the file to extract in a string.
     *
     * @return a string with the file content or null.
     */
    
private function _extractInString($p_filename)
    {
        
$v_result_str "";

        while (
strlen($v_binary_data $this->_readBlock()) != 0) {
            if (!
$this->_readHeader($v_binary_data$v_header)) {
                return 
null;
            }

            if (
$v_header['filename'] == '') {
                continue;
            }

            
// ----- Look for long filename
            
if ($v_header['typeflag'] == 'L') {
                if (!
$this->_readLongHeader($v_header)) {
                    return 
null;
                }
            }

            if (
$v_header['filename'] == $p_filename) {
                if (
$v_header['typeflag'] == "5") {
                    
$this->_error(
                        
'Unable to extract in string a directory '
                        
'entry {' $v_header['filename'] . '}'
                    
);
                    return 
null;
                } else {
                    
$n floor($v_header['size'] / 512);
                    for (
$i 0$i $n$i++) {
                        
$v_result_str .= $this->_readBlock();
                    }
                    if ((
$v_header['size'] % 512) != 0) {
                        
$v_content $this->_readBlock();
                        
$v_result_str .= substr(
                            
$v_content,
                            
0,
                            (
$v_header['size'] % 512)
                        );
                    }
                    return 
$v_result_str;
                }
            } else {
                
$this->_jumpBlock(ceil(($v_header['size'] / 512)));
            }
        }

        return 
null;
    }

    
/**
     * @param string $p_path
     * @param string $p_list_detail
     * @param string $p_mode
     * @param string $p_file_list
     * @param string $p_remove_path
     * @param bool $p_preserve
     * @return bool
     */
    
public function _extractList(
        
$p_path,
        &
$p_list_detail,
        
$p_mode,
        
$p_file_list,
        
$p_remove_path,
        
$p_preserve false
    
) {
        
$v_result true;
        
$v_nb 0;
        
$v_extract_all true;
        
$v_listing false;

        
$p_path $this->_translateWinPath($p_pathfalse);
        if (
$p_path == '' || (substr($p_path01) != '/'
                
&& substr($p_path03) != "../" && !strpos($p_path':'))
        ) {
            
$p_path "./" $p_path;
        }
        
$p_remove_path $this->_translateWinPath($p_remove_path);

        
// ----- Look for path to remove format (should end by /)
        
if (($p_remove_path != '') && (substr($p_remove_path, -1) != '/')) {
            
$p_remove_path .= '/';
        }
        
$p_remove_path_size strlen($p_remove_path);

        switch (
$p_mode) {
            case 
"complete" :
                
$v_extract_all true;
                
$v_listing false;
                break;
            case 
"partial" :
                
$v_extract_all false;
                
$v_listing false;
                break;
            case 
"list" :
                
$v_extract_all false;
                
$v_listing true;
                break;
            default :
                
$this->_error('Invalid extract mode (' $p_mode ')');
                return 
false;
        }

        
clearstatcache();

        while (
strlen($v_binary_data $this->_readBlock()) != 0) {
            
$v_extract_file false;
            
$v_extraction_stopped 0;

            if (!
$this->_readHeader($v_binary_data$v_header)) {
                return 
false;
            }

            if (
$v_header['filename'] == '') {
                continue;
            }

            
// ----- Look for long filename
            
if ($v_header['typeflag'] == 'L') {
                if (!
$this->_readLongHeader($v_header)) {
                    return 
false;
                }
            }

            
// ignore extended / pax headers
            
if ($v_header['typeflag'] == 'x' || $v_header['typeflag'] == 'g') {
                
$this->_jumpBlock(ceil(($v_header['size'] / 512)));
                continue;
            }

            if ((!
$v_extract_all) && (is_array($p_file_list))) {
                
// ----- By default no unzip if the file is not found
                
$v_extract_file false;

                for (
$i 0$i sizeof($p_file_list); $i++) {
                    
// ----- Look if it is a directory
                    
if (substr($p_file_list[$i], -1) == '/') {
                        
// ----- Look if the directory is in the filename path
                        
if ((strlen($v_header['filename']) > strlen($p_file_list[$i]))
                            && (
substr($v_header['filename'], 0strlen($p_file_list[$i]))
                                == 
$p_file_list[$i])
                        ) {
                            
$v_extract_file true;
                            break;
                        }
                    } 
// ----- It is a file, so compare the file names
                    
elseif ($p_file_list[$i] == $v_header['filename']) {
                        
$v_extract_file true;
                        break;
                    }
                }
            } else {
                
$v_extract_file true;
            }

            
// ----- Look if this file need to be extracted
            
if (($v_extract_file) && (!$v_listing)) {
                if ((
$p_remove_path != '')
                    && (
substr($v_header['filename'] . '/'0$p_remove_path_size)
                        == 
$p_remove_path)
                ) {
                    
$v_header['filename'] = substr(
                        
$v_header['filename'],
                        
$p_remove_path_size
                    
);
                    if (
$v_header['filename'] == '') {
                        continue;
                    }
                }
                if ((
$p_path != './') && ($p_path != '/')) {
                    while (
substr($p_path, -1) == '/') {
                        
$p_path substr($p_path0strlen($p_path) - 1);
                    }

                    if (
substr($v_header['filename'], 01) == '/') {
                        
$v_header['filename'] = $p_path $v_header['filename'];
                    } else {
                        
$v_header['filename'] = $p_path '/' $v_header['filename'];
                    }
                }
                if (
file_exists($v_header['filename'])) {
                    if ((@
is_dir($v_header['filename']))
                        && (
$v_header['typeflag'] == '')
                    ) {
                        
$this->_error(
                            
'File ' $v_header['filename']
                            . 
' already exists as a directory'
                        
);
                        return 
false;
                    }
                    if ((
$this->_isArchive($v_header['filename']))
                        && (
$v_header['typeflag'] == "5")
                    ) {
                        
$this->_error(
                            
'Directory ' $v_header['filename']
                            . 
' already exists as a file'
                        
);
                        return 
false;
                    }
                    if (!
is_writeable($v_header['filename'])) {
                        
$this->_error(
                            
'File ' $v_header['filename']
                            . 
' already exists and is write protected'
                        
);
                        return 
false;
                    }
                    if (
filemtime($v_header['filename']) > $v_header['mtime']) {
                        
// To be completed : An error or silent no replace ?
                    
}
                } 
// ----- Check the directory availability and create it if necessary
                
elseif (($v_result
                        
$this->_dirCheck(
                        (
$v_header['typeflag'] == "5"
                            
$v_header['filename']
                            : 
dirname($v_header['filename']))
                    )) != 
1
                
) {
                    
$this->_error('Unable to create path for ' $v_header['filename']);
                    return 
false;
                }

                if (
$v_extract_file) {
                    if (
$v_header['typeflag'] == "5") {
                        if (!@
file_exists($v_header['filename'])) {
                            if (!@
mkdir($v_header['filename'], 0777)) {
                                
$this->_error(
                                    
'Unable to create directory {'
                                    
$v_header['filename'] . '}'
                                
);
                                return 
false;
                            }
                        }
                    } elseif (
$v_header['typeflag'] == "2") {
                        if (@
file_exists($v_header['filename'])) {
                            @
unlink($v_header['filename']);
                        }
                        if (!@
symlink($v_header['link'], $v_header['filename'])) {
                            
$this->_error(
                                
'Unable to extract symbolic link {'
                                
$v_header['filename'] . '}'
                            
);
                            return 
false;
                        }
                    } else {
                        if ((
$v_dest_file = @fopen($v_header['filename'], "wb")) == 0) {
                            
$this->_error(
                                
'Error while opening {' $v_header['filename']
                                . 
'} in write binary mode'
                            
);
                            return 
false;
                        } else {
                            
$n floor($v_header['size'] / 512);
                            for (
$i 0$i $n$i++) {
                                
$v_content $this->_readBlock();
                                
fwrite($v_dest_file$v_content512);
                            }
                            if ((
$v_header['size'] % 512) != 0) {
                                
$v_content $this->_readBlock();
                                
fwrite($v_dest_file$v_content, ($v_header['size'] % 512));
                            }

                            @
fclose($v_dest_file);

                            if (
$p_preserve) {
                                @
chown($v_header['filename'], $v_header['uid']);
                                @
chgrp($v_header['filename'], $v_header['gid']);
                            }

                            
// ----- Change the file mode, mtime
                            
@touch($v_header['filename'], $v_header['mtime']);
                            if (
$v_header['mode'] & 0111) {
                                
// make file executable, obey umask
                                
$mode fileperms($v_header['filename']) | (~umask() & 0111);
                                @
chmod($v_header['filename'], $mode);
                            }
                        }

                        
// ----- Check the file size
                        
clearstatcache();
                        if (!
is_file($v_header['filename'])) {
                            
$this->_error(
                                
'Extracted file ' $v_header['filename']
                                . 
'does not exist. Archive may be corrupted.'
                            
);
                            return 
false;
                        }

                        
$filesize filesize($v_header['filename']);
                        if (
$filesize != $v_header['size']) {
                            
$this->_error(
                                
'Extracted file ' $v_header['filename']
                                . 
' does not have the correct file size ''
                                . $filesize
                                . '' (' 
$v_header['size']
                                . 
' expected). Archive may be corrupted.'
                            
);
                            return 
false;
                        }
                    }
                } else {
                    
$this->_jumpBlock(ceil(($v_header['size'] / 512)));
                }
            } else {
                
$this->_jumpBlock(ceil(($v_header['size'] / 512)));
            }

            
/* TBC : Seems to be unused ...
            if ($this->_compress)
              $v_end_of_file = @gzeof($this->_file);
            else
              $v_end_of_file = @feof($this->_file);
              */

            
if ($v_listing || $v_extract_file || $v_extraction_stopped) {
                
// ----- Log extracted files
                
if (($v_file_dir dirname($v_header['filename']))
                    == 
$v_header['filename']
                ) {
                    
$v_file_dir '';
                }
                if ((
substr($v_header['filename'], 01) == '/') && ($v_file_dir == '')) {
                    
$v_file_dir '/';
                }

                
$p_list_detail[$v_nb++] = $v_header;
                if (
is_array($p_file_list) && (count($p_list_detail) == count($p_file_list))) {
                    return 
true;
                }
            }
        }

        return 
true;
    }

    
/**
     * @return bool
     */
    
public function _openAppend()
    {
        if (
filesize($this->_tarname) == 0) {
            return 
$this->_openWrite();
        }

        if (
$this->_compress) {
            
$this->_close();

            if (!@
rename($this->_tarname$this->_tarname ".tmp")) {
                
$this->_error(
                    
'Error while renaming '' . $this->_tarname
                    . '' to temporary file '' . $this->_tarname
                    . '
.tmp''
                
);
                return 
false;
            }

            if (
$this->_compress_type == 'gz') {
                
$v_temp_tar = @gzopen($this->_tarname ".tmp""rb");
            } elseif (
$this->_compress_type == 'bz2') {
                
$v_temp_tar = @bzopen($this->_tarname ".tmp""r");
            } elseif (
$this->_compress_type == 'lzma2') {
                
$v_temp_tar = @xzopen($this->_tarname ".tmp""r");
            }


            if (
$v_temp_tar == 0) {
                
$this->_error(
                    
'Unable to open file '' . $this->_tarname
                    . '
.tmp' in binary read mode'
                
);
                @
rename($this->_tarname ".tmp"$this->_tarname);
                return 
false;
            }

            if (!
$this->_openWrite()) {
                @
rename($this->_tarname ".tmp"$this->_tarname);
                return 
false;
            }

            if (
$this->_compress_type == 'gz') {
                
$end_blocks 0;

                while (!@
gzeof($v_temp_tar)) {
                    
$v_buffer = @gzread($v_temp_tar512);
                    if (
$v_buffer == ARCHIVE_TAR_END_BLOCK || strlen($v_buffer) == 0) {
                        
$end_blocks++;
                        
// do not copy end blocks, we will re-make them
                        // after appending
                        
continue;
                    } elseif (
$end_blocks 0) {
                        for (
$i 0$i $end_blocks$i++) {
                            
$this->_writeBlock(ARCHIVE_TAR_END_BLOCK);
                        }
                        
$end_blocks 0;
                    }
                    
$v_binary_data pack("a512"$v_buffer);
                    
$this->_writeBlock($v_binary_data);
                }

                @
gzclose($v_temp_tar);
            } elseif (
$this->_compress_type == 'bz2') {
                
$end_blocks 0;

                while (
strlen($v_buffer = @bzread($v_temp_tar512)) > 0) {
                    if (
$v_buffer == ARCHIVE_TAR_END_BLOCK || strlen($v_buffer) == 0) {
                        
$end_blocks++;
                        
// do not copy end blocks, we will re-make them
                        // after appending
                        
continue;
                    } elseif (
$end_blocks 0) {
                        for (
$i 0$i $end_blocks$i++) {
                            
$this->_writeBlock(ARCHIVE_TAR_END_BLOCK);
                        }
                        
$end_blocks 0;
                    }
                    
$v_binary_data pack("a512"$v_buffer);
                    
$this->_writeBlock($v_binary_data);
                }

                @
bzclose($v_temp_tar);
            } elseif (
$this->_compress_type == 'lzma2') {
                
$end_blocks 0;

                while (
strlen($v_buffer = @xzread($v_temp_tar512)) > 0) {
                    if (
$v_buffer == ARCHIVE_TAR_END_BLOCK || strlen($v_buffer) == 0) {
                        
$end_blocks++;
                        
// do not copy end blocks, we will re-make them
                        // after appending
                        
continue;
                    } elseif (
$end_blocks 0) {
                        for (
$i 0$i $end_blocks$i++) {
                            
$this->_writeBlock(ARCHIVE_TAR_END_BLOCK);
                        }
                        
$end_blocks 0;
                    }
                    
$v_binary_data pack("a512"$v_buffer);
                    
$this->_writeBlock($v_binary_data);
                }

                @
xzclose($v_temp_tar);
            }

            if (!@
unlink($this->_tarname ".tmp")) {
                
$this->_error(
                    
'Error while deleting temporary file ''
                    . $this->_tarname . '
.tmp''
                
);
            }
        } else {
            
// ----- For not compressed tar, just add files before the last
            //       one or two 512 bytes block
            
if (!$this->_openReadWrite()) {
                return 
false;
            }

            
clearstatcache();
            
$v_size filesize($this->_tarname);

            
// We might have zero, one or two end blocks.
            // The standard is two, but we should try to handle
            // other cases.
            
fseek($this->_file$v_size 1024);
            if (
fread($this->_file512) == ARCHIVE_TAR_END_BLOCK) {
                
fseek($this->_file$v_size 1024);
            } elseif (
fread($this->_file512) == ARCHIVE_TAR_END_BLOCK) {
                
fseek($this->_file$v_size 512);
            }
        }

        return 
true;
    }

    
/**
     * @param $p_filelist
     * @param string $p_add_dir
     * @param string $p_remove_dir
     * @return bool
     */
    
public function _append($p_filelist$p_add_dir ''$p_remove_dir '')
    {
        if (!
$this->_openAppend()) {
            return 
false;
        }

        if (
$this->_addList($p_filelist$p_add_dir$p_remove_dir)) {
            
$this->_writeFooter();
        }

        
$this->_close();

        return 
true;
    }

    
/**
     * Check if a directory exists and create it (including parent
     * dirs) if not.
     *
     * @param string $p_dir directory to check
     *
     * @return bool true if the directory exists or was created
     */
    
public function _dirCheck($p_dir)
    {
        
clearstatcache();
        if ((@
is_dir($p_dir)) || ($p_dir == '')) {
            return 
true;
        }

        
$p_parent_dir dirname($p_dir);

        if ((
$p_parent_dir != $p_dir) &&
            (
$p_parent_dir != '') &&
            (!
$this->_dirCheck($p_parent_dir))
        ) {
            return 
false;
        }

        if (!@
mkdir($p_dir0777)) {
            
$this->_error("Unable to create directory '$p_dir'");
            return 
false;
        }

        return 
true;
    }

    
/**
     * Compress path by changing for example "/dir/foo/../bar" to "/dir/bar",
     * rand emove double slashes.
     *
     * @param string $p_dir path to reduce
     *
     * @return string reduced path
     */
    
private function _pathReduction($p_dir)
    {
        
$v_result '';

        
// ----- Look for not empty path
        
if ($p_dir != '') {
            
// ----- Explode path by directory names
            
$v_list explode('/'$p_dir);

            
// ----- Study directories from last to first
            
for ($i sizeof($v_list) - 1$i >= 0$i--) {
                
// ----- Look for current path
                
if ($v_list[$i] == ".") {
                    
// ----- Ignore this directory
                    // Should be the first $i=0, but no check is done
                
} else {
                    if (
$v_list[$i] == "..") {
                        
// ----- Ignore it and ignore the $i-1
                        
$i--;
                    } else {
                        if ((
$v_list[$i] == '')
                            && (
$i != (sizeof($v_list) - 1))
                            && (
$i != 0)
                        ) {
                            
// ----- Ignore only the double '//' in path,
                            // but not the first and last /
                        
} else {
                            
$v_result $v_list[$i] . ($i != (sizeof($v_list) - 1) ? '/'
                                    
$v_result '');
                        }
                    }
                }
            }
        }

        if (
defined('OS_WINDOWS') && OS_WINDOWS) {
            
$v_result strtr($v_result'\', '/');
        }

        return $v_result;
    }

    /**
     * @param $p_path
     * @param bool $p_remove_disk_letter
     * @return string
     */
    public function _translateWinPath($p_path, $p_remove_disk_letter = true)
    {
        if (defined('
OS_WINDOWS') && OS_WINDOWS) {
            // ----- Look for potential disk letter
            if (($p_remove_disk_letter)
                && (($v_position = strpos($p_path, '
:')) != false)
            ) {
                $p_path = substr($p_path, $v_position + 1);
            }
            // ----- Change potential windows directory separator
            if ((strpos($p_path, '
\') > 0) || (substr($p_path, 0, 1) == '\')) {
                $p_path = strtr($p_path, '
\', '/');
            }
        }
        return $p_path;
    }
}
Онлайн: 0
Реклама