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

Source for file Zip.php

Documentation is available at Zip.php

  1. <?php
  2. /* vim: set ts=4 sw=4: */
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 4                                                        |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2003 The PHP Group                                |
  7. // +----------------------------------------------------------------------+
  8. // | This library is free software; you can redistribute it and/or        |
  9. // | modify it under the terms of the GNU Lesser General Public           |
  10. // | License as published by the Free Software Foundation; either         |
  11. // | version 2.1 of the License, or (at your option) any later version.   |
  12. // |                                                                      |
  13. // | This library is distributed in the hope that it will be useful,      |
  14. // | but WITHOUT ANY WARRANTY; without even the implied warranty of       |
  15. // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    |
  16. // | Lesser General Public License for more details.                      |
  17. // |                                                                      |
  18. // | You should have received a copy of the GNU Lesser General Public     |
  19. // | License along with this library; if not, write to the Free Software  |
  20. // | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,           |
  21. // | MA  02110-1301  USA                                                  |
  22. // +----------------------------------------------------------------------+
  23. // | Author: Vincent Blavet <vincent@phpconcept.net>                      |
  24. // +----------------------------------------------------------------------+
  25. //
  26. // $Id: Zip.php 302924 2010-08-31 14:45:47Z clockwerx $
  27.  
  28. require_once 'PEAR.php';
  29.  
  30. // ----- Constants
  31. define('ARCHIVE_ZIP_READ_BLOCK_SIZE'2048);
  32.  
  33. // ----- File list separator
  34. define('ARCHIVE_ZIP_SEPARATOR'',');
  35.  
  36. // ----- Optional static temporary directory
  37. //       By default temporary files are generated in the script current
  38. //       path.
  39. //       If defined :
  40. //       - MUST BE terminated by a '/'.
  41. //       - MUST be a valid, already created directory
  42. //       Samples :
  43. // define('ARCHIVE_ZIP_TEMPORARY_DIR', '/temp/');
  44. // define('ARCHIVE_ZIP_TEMPORARY_DIR', 'C:/Temp/');
  45. define('ARCHIVE_ZIP_TEMPORARY_DIR''');
  46.  
  47. // ----- Error codes
  48. define('ARCHIVE_ZIP_ERR_NO_ERROR'0);
  49. define('ARCHIVE_ZIP_ERR_WRITE_OPEN_FAIL'-1);
  50. define('ARCHIVE_ZIP_ERR_READ_OPEN_FAIL'-2);
  51. define('ARCHIVE_ZIP_ERR_INVALID_PARAMETER'-3);
  52. define('ARCHIVE_ZIP_ERR_MISSING_FILE'-4);
  53. define('ARCHIVE_ZIP_ERR_FILENAME_TOO_LONG'-5);
  54. define('ARCHIVE_ZIP_ERR_INVALID_ZIP'-6);
  55. define('ARCHIVE_ZIP_ERR_BAD_EXTRACTED_FILE'-7);
  56. define('ARCHIVE_ZIP_ERR_DIR_CREATE_FAIL'-8);
  57. define('ARCHIVE_ZIP_ERR_BAD_EXTENSION'-9);
  58. define('ARCHIVE_ZIP_ERR_BAD_FORMAT'-10);
  59. define('ARCHIVE_ZIP_ERR_DELETE_FILE_FAIL'-11);
  60. define('ARCHIVE_ZIP_ERR_RENAME_FILE_FAIL'-12);
  61. define('ARCHIVE_ZIP_ERR_BAD_CHECKSUM'-13);
  62. define('ARCHIVE_ZIP_ERR_INVALID_ARCHIVE_ZIP'-14);
  63. define('ARCHIVE_ZIP_ERR_MISSING_OPTION_VALUE'-15);
  64. define('ARCHIVE_ZIP_ERR_INVALID_PARAM_VALUE'-16);
  65.  
  66. // ----- Warning codes
  67. define('ARCHIVE_ZIP_WARN_NO_WARNING'0);
  68. define('ARCHIVE_ZIP_WARN_FILE_EXIST'1);
  69.  
  70. // ----- Methods parameters
  71. define('ARCHIVE_ZIP_PARAM_PATH''path');
  72. define('ARCHIVE_ZIP_PARAM_ADD_PATH''add_path');
  73. define('ARCHIVE_ZIP_PARAM_REMOVE_PATH''remove_path');
  74. define('ARCHIVE_ZIP_PARAM_REMOVE_ALL_PATH''remove_all_path');
  75. define('ARCHIVE_ZIP_PARAM_SET_CHMOD''set_chmod');
  76. define('ARCHIVE_ZIP_PARAM_EXTRACT_AS_STRING''extract_as_string');
  77. define('ARCHIVE_ZIP_PARAM_NO_COMPRESSION''no_compression');
  78. define('ARCHIVE_ZIP_PARAM_BY_NAME''by_name');
  79. define('ARCHIVE_ZIP_PARAM_BY_INDEX''by_index');
  80. define('ARCHIVE_ZIP_PARAM_BY_PREG''by_preg');
  81.  
  82. define('ARCHIVE_ZIP_PARAM_PRE_EXTRACT''callback_pre_extract');
  83. define('ARCHIVE_ZIP_PARAM_POST_EXTRACT''callback_post_extract');
  84. define('ARCHIVE_ZIP_PARAM_PRE_ADD''callback_pre_add');
  85. define('ARCHIVE_ZIP_PARAM_POST_ADD''callback_post_add');
  86.  
  87.  
  88.  
  89. /**
  90. * Class for manipulating zip archive files
  91. *
  92. * A class which provided common methods to manipulate ZIP formatted
  93. * archive files.
  94. * It provides creation, extraction, deletion and add features.
  95. *
  96. @author   Vincent Blavet <vincent@blavet.net>
  97. @version  $Revision: 302924 $
  98. @package  Archive_Zip
  99. @category Archive
  100. */
  101. {
  102.     /**
  103.      * The filename of the zip archive.
  104.      *
  105.      * @var string Name of the Zip file
  106.      */
  107.     var $_zipname '';
  108.  
  109.     /**
  110.      * File descriptor of the opened Zip file.
  111.      *
  112.      * @var int Internal zip file descriptor
  113.      */
  114.     var $_zip_fd = 0;
  115.  
  116.     /**
  117.      * @var int last error code
  118.      */
  119.     var $_error_code = 1;
  120.  
  121.     /**
  122.      * @var string Last error description
  123.      */
  124.     var $_error_string '';
  125.  
  126.     // {{{ constructor
  127.     /**
  128.      * Archive_Zip Class constructor. This flavour of the constructor only
  129.      * declare a new Archive_Zip object, identifying it by the name of the
  130.      * zip file.
  131.      *
  132.      * @param string $p_zipname The name of the zip archive to create
  133.      *
  134.      * @access public
  135.      */
  136.     function Archive_Zip($p_zipname)
  137.     {
  138.  
  139.         // ----- Check the zlib
  140.         if (!extension_loaded('zlib')) {
  141.             PEAR::loadExtension('zlib');
  142.         }
  143.         if (!extension_loaded('zlib')) {
  144.             die("The extension 'zlib' couldn't be found.\n".
  145.                 "Please make sure your version of PHP was built ".
  146.                 "with 'zlib' support.\n");
  147.             return false;
  148.         }
  149.  
  150.         // ----- Set the attributes
  151.         $this->_zipname $p_zipname;
  152.         $this->_zip_fd  = 0;
  153.  
  154.         return;
  155.     }
  156.     // }}}
  157.  
  158.     // {{{ create()
  159.     /**
  160.      * This method creates a Zip Archive with the filename set with
  161.      * the constructor.
  162.      * The files and directories indicated in $p_filelist
  163.      * are added in the archive.
  164.      * When a directory is in the list, the directory and its content is added
  165.      * in the archive.
  166.      * The methods takes a variable list of parameters in $p_params.
  167.      * The supported parameters for this method are :
  168.      *   'add_path' : Add a path to the archived files.
  169.      *   'remove_path' : Remove the specified 'root' path of the archived files.
  170.      *   'remove_all_path' : Remove all the path of the archived files.
  171.      *   'no_compression' : The archived files will not be compressed.
  172.      *
  173.      *
  174.      * @param mixed $p_filelist The list of the files or folders to add.
  175.      *                              It can be a string with filenames separated
  176.      *                              by a comma, or an array of filenames.
  177.      * @param mixed $p_params   An array of variable parameters and values.
  178.      *
  179.      * @return mixed An array of file description on success,
  180.      *                an error code on error
  181.      */
  182.     function create($p_filelist$p_params = 0)
  183.     {
  184.         $this->_errorReset();
  185.  
  186.         // ----- Set default values
  187.         if ($p_params === 0{
  188.             $p_params = array();
  189.         }
  190.         if ($this->_check_parameters($p_params,
  191.                                      array('no_compression' => false,
  192.                                            'add_path' => "",
  193.                                            'remove_path' => "",
  194.                                            'remove_all_path' => false)) != 1{
  195.             return 0;
  196.         }
  197.  
  198.         // ----- Look if the $p_filelist is really an array
  199.         $p_result_list = array();
  200.         if (is_array($p_filelist)) {
  201.             $v_result $this->_create($p_filelist$p_result_list$p_params);
  202.         else if (is_string($p_filelist)) {
  203.             // ----- Create a list with the elements from the string
  204.             $v_list explode(ARCHIVE_ZIP_SEPARATOR$p_filelist);
  205.  
  206.             $v_result $this->_create($v_list$p_result_list$p_params);
  207.         else {
  208.             $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER,
  209.                              'Invalid variable type p_filelist');
  210.             $v_result ARCHIVE_ZIP_ERR_INVALID_PARAMETER;
  211.         }
  212.  
  213.         if ($v_result != 1{
  214.             return 0;
  215.         }
  216.  
  217.         return $p_result_list;
  218.     }
  219.     // }}}
  220.  
  221.     // {{{ add()
  222.     /**
  223.      * This method add files or directory in an existing Zip Archive.
  224.      * If the Zip Archive does not exist it is created.
  225.      * The files and directories to add are indicated in $p_filelist.
  226.      * When a directory is in the list, the directory and its content is added
  227.      * in the archive.
  228.      * The methods takes a variable list of parameters in $p_params.
  229.      * The supported parameters for this method are :
  230.      *   'add_path' : Add a path to the archived files.
  231.      *   'remove_path' : Remove the specified 'root' path of the archived files.
  232.      *   'remove_all_path' : Remove all the path of the archived files.
  233.      *   'no_compression' : The archived files will not be compressed.
  234.      *   'callback_pre_add' : A callback function that will be called before
  235.      *                        each entry archiving.
  236.      *   'callback_post_add' : A callback function that will be called after
  237.      *                         each entry archiving.
  238.      *
  239.      * @param mixed $p_filelist The list of the files or folders to add.
  240.      *                                It can be a string with filenames separated
  241.      *                                by a comma, or an array of filenames.
  242.      * @param mixed $p_params   An array of variable parameters and values.
  243.      *
  244.      * @return mixed An array of file description on success,
  245.      *                0 on an unrecoverable failure, an error code is logged.
  246.      * @access public
  247.      */
  248.     function add($p_filelist$p_params = 0)
  249.     {
  250.         $this->_errorReset();
  251.  
  252.         // ----- Set default values
  253.         if ($p_params === 0{
  254.             $p_params = array();
  255.         }
  256.         if ($this->_check_parameters($p_params,
  257.                                      array ('no_compression' => false,
  258.                                             'add_path' => '',
  259.                                             'remove_path' => '',
  260.                                             'remove_all_path' => false,
  261.                                              'callback_pre_add' => '',
  262.                                             'callback_post_add' => '')) != 1{
  263.             return 0;
  264.         }
  265.  
  266.         // ----- Look if the $p_filelist is really an array
  267.         $p_result_list = array();
  268.         if (is_array($p_filelist)) {
  269.             // ----- Call the create fct
  270.             $v_result $this->_add($p_filelist$p_result_list$p_params);
  271.         else if (is_string($p_filelist)) {
  272.             // ----- Create a list with the elements from the string
  273.             $v_list explode(ARCHIVE_ZIP_SEPARATOR$p_filelist);
  274.  
  275.             // ----- Call the create fct
  276.             $v_result $this->_add($v_list$p_result_list$p_params);
  277.         else {
  278.             $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER,
  279.                              "add() : Invalid variable type p_filelist");
  280.             $v_result ARCHIVE_ZIP_ERR_INVALID_PARAMETER;
  281.         }
  282.  
  283.         if ($v_result != 1{
  284.             return 0;
  285.         }
  286.  
  287.         return $p_result_list;
  288.     }
  289.     // }}}
  290.  
  291.     // {{{ listContent()
  292.     /**
  293.      * This method gives the names and properties of the files and directories
  294.      * which are present in the zip archive.
  295.      * The properties of each entries in the list are :
  296.      *   filename : Name of the file.
  297.      *              For create() or add() it's the filename given by the user.
  298.      *              For an extract() it's the filename of the extracted file.
  299.      *   stored_filename : Name of the file / directory stored in the archive.
  300.      *   size : Size of the stored file.
  301.      *   compressed_size : Size of the file's data compressed in the archive
  302.      *                     (without the zip headers overhead)
  303.      *   mtime : Last known modification date of the file (UNIX timestamp)
  304.      *   comment : Comment associated with the file
  305.      *   folder : true | false (indicates if the entry is a folder)
  306.      *   index : index of the file in the archive (-1 when not available)
  307.      *   status : status of the action on the entry (depending of the action) :
  308.      *            Values are :
  309.      *              ok : OK !
  310.      *              filtered : the file/dir was not extracted (filtered by user)
  311.      *              already_a_directory : the file can't be extracted because a
  312.      *                                    directory with the same name already
  313.      *                                    exists
  314.      *              write_protected : the file can't be extracted because a file
  315.      *                                with the same name already exists and is
  316.      *                                write protected
  317.      *              newer_exist : the file was not extracted because a newer
  318.      *                            file already exists
  319.      *              path_creation_fail : the file is not extracted because the
  320.      *                                   folder does not exists and can't be
  321.      *                                   created
  322.      *              write_error : the file was not extracted because there was a
  323.      *                            error while writing the file
  324.      *              read_error : the file was not extracted because there was a
  325.      *                           error while reading the file
  326.      *              invalid_header : the file was not extracted because of an
  327.      *                               archive format error (bad file header)
  328.      * Note that each time a method can continue operating when there
  329.      * is an error on a single file, the error is only logged in the file status.
  330.      *
  331.      * @access public
  332.      * @return mixed An array of file description on success,
  333.      *                0 on an unrecoverable failure, an error code is logged.
  334.      */
  335.     function listContent()
  336.     {
  337.         $this->_errorReset();
  338.  
  339.         // ----- Check archive
  340.         if (!$this->_checkFormat()) {
  341.             return(0);
  342.         }
  343.  
  344.         $v_list = array();
  345.         if ($this->_list($v_list!= 1{
  346.             unset($v_list);
  347.             return(0);
  348.         }
  349.  
  350.         return $v_list;
  351.     }
  352.     // }}}
  353.  
  354.     // {{{ extract()
  355.     /**
  356.      * This method extract the files and folders which are in the zip archive.
  357.      * It can extract all the archive or a part of the archive by using filter
  358.      * feature (extract by name, by index, by preg). The extraction
  359.      * can occur in the current path or an other path.
  360.      * All the advanced features are activated by the use of variable
  361.      * parameters.
  362.      * The return value is an array of entry descriptions which gives
  363.      * information on extracted files (See listContent()).
  364.      * The method may return a success value (an array) even if some files
  365.      * are not correctly extracted (see the file status in listContent()).
  366.      * The supported variable parameters for this method are :
  367.      *   'add_path' : Path where the files and directories are to be extracted
  368.      *   'remove_path' : First part ('root' part) of the memorized path
  369.      *                   (if similar) to remove while extracting.
  370.      *   'remove_all_path' : Remove all the memorized path while extracting.
  371.      *   'extract_as_string' :
  372.      *   'set_chmod' : After the extraction of the file the indicated mode
  373.      *                 will be set.
  374.      *   'by_name' : It can be a string with file/dir names separated by ',',
  375.      *               or an array of file/dir names to extract from the archive.
  376.      *   'by_index' : A string with range of indexes separated by ',',
  377.      *                (sample "1,3-5,12").
  378.      *   'by_preg' : A regular expression (preg) that must match the extracted
  379.      *               filename.
  380.      *   'callback_pre_extract' : A callback function that will be called before
  381.      *                            each entry extraction.
  382.      *   'callback_post_extract' : A callback function that will be called after
  383.      *                            each entry extraction.
  384.      *
  385.      * @param mixed $p_params An array of variable parameters and values.
  386.      *
  387.      * @return mixed An array of file description on success,
  388.      *                0 on an unrecoverable failure, an error code is logged.
  389.      */
  390.     function extract($p_params = 0)
  391.     {
  392.  
  393.         $this->_errorReset();
  394.  
  395.         // ----- Check archive
  396.         if (!$this->_checkFormat()) {
  397.             return(0);
  398.         }
  399.  
  400.         // ----- Set default values
  401.         if ($p_params === 0{
  402.             $p_params = array();
  403.         }
  404.  
  405.         if ($this->_check_parameters($p_params,
  406.                                      array ('extract_as_string' => false,
  407.                                             'add_path' => '',
  408.                                             'remove_path' => '',
  409.                                             'remove_all_path' => false,
  410.                                              'callback_pre_extract' => '',
  411.                                             'callback_post_extract' => '',
  412.                                             'set_chmod' => 0,
  413.                                             'by_name' => '',
  414.                                             'by_index' => '',
  415.                                             'by_preg' => '') ) != 1{
  416.             return 0;
  417.         }
  418.  
  419.         // ----- Call the extracting fct
  420.         $v_list = array();
  421.         if ($this->_extractByRule($v_list$p_params!= 1{
  422.             unset($v_list);
  423.             return(0);
  424.         }
  425.  
  426.         return $v_list;
  427.     }
  428.     // }}}
  429.  
  430.  
  431.     // {{{ delete()
  432.     /**
  433.      * This methods delete archive entries in the zip archive.
  434.      * Notice that at least one filtering rule (set by the variable parameter
  435.      * list) must be set.
  436.      * Also notice that if you delete a folder entry, only the folder entry
  437.      * is deleted, not all the files bellonging to this folder.
  438.      * The supported variable parameters for this method are :
  439.      *   'by_name' : It can be a string with file/dir names separated by ',',
  440.      *               or an array of file/dir names to delete from the archive.
  441.      *   'by_index' : A string with range of indexes separated by ',',
  442.      *                (sample "1,3-5,12").
  443.      *   'by_preg' : A regular expression (preg) that must match the extracted
  444.      *               filename.
  445.      *
  446.      * @param mixed $p_params An array of variable parameters and values.
  447.      *
  448.      * @return mixed An array of file description on success,
  449.      *                0 on an unrecoverable failure, an error code is logged.
  450.      */
  451.     function delete($p_params)
  452.     {
  453.         $this->_errorReset();
  454.  
  455.         // ----- Check archive
  456.         if (!$this->_checkFormat()) {
  457.             return(0);
  458.         }
  459.  
  460.         // ----- Set default values
  461.         if ($this->_check_parameters($p_params,
  462.                                      array ('by_name' => '',
  463.                                             'by_index' => '',
  464.                                             'by_preg' => '') ) != 1{
  465.             return 0;
  466.         }
  467.  
  468.         // ----- Check that at least one rule is set
  469.         if (($p_params['by_name'== '')
  470.             && ($p_params['by_index'== '')
  471.             && ($p_params['by_preg'== '')) {
  472.             $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER,
  473.                              'At least one filtering rule must'
  474.                              .' be set as parameter');
  475.             return 0;
  476.         }
  477.  
  478.         // ----- Call the delete fct
  479.         $v_list = array();
  480.         if ($this->_deleteByRule($v_list$p_params!= 1{
  481.             unset($v_list);
  482.             return(0);
  483.         }
  484.  
  485.         return $v_list;
  486.     }
  487.     // }}}
  488.  
  489.     // {{{ properties()
  490.     /**
  491.      * This method gives the global properties of the archive.
  492.      *  The properties are :
  493.      *    nb : Number of files in the archive
  494.      *    comment : Comment associated with the archive file
  495.      *    status : not_exist, ok
  496.      *
  497.      * @return mixed An array with the global properties or 0 on error.
  498.      */
  499.     function properties()
  500.     {
  501.         $this->_errorReset();
  502.  
  503.         // ----- Check archive
  504.         if (!$this->_checkFormat()) {
  505.             return(0);
  506.         }
  507.  
  508.         // ----- Default properties
  509.         $v_prop            = array();
  510.         $v_prop['comment''';
  511.         $v_prop['nb']      = 0;
  512.         $v_prop['status']  'not_exist';
  513.  
  514.         // ----- Look if file exists
  515.         if (@is_file($this->_zipname)) {
  516.             // ----- Open the zip file
  517.             if (($this->_zip_fd @fopen($this->_zipname'rb')) == 0{
  518.                 $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL,
  519.                                  'Unable to open archive \''.$this->_zipname
  520.                                  .'\' in binary read mode');
  521.                 return 0;
  522.             }
  523.  
  524.             // ----- Read the central directory informations
  525.             $v_central_dir = array();
  526.             if (($v_result $this->_readEndCentralDir($v_central_dir)) != 1{
  527.                 return 0;
  528.             }
  529.  
  530.             $this->_closeFd();
  531.  
  532.             // ----- Set the user attributes
  533.             $v_prop['comment'$v_central_dir['comment'];
  534.             $v_prop['nb']      $v_central_dir['entries'];
  535.             $v_prop['status']  'ok';
  536.         }
  537.  
  538.         return $v_prop;
  539.     }
  540.     // }}}
  541.  
  542.  
  543.     // {{{ duplicate()
  544.     /**
  545.      * This method creates an archive by copying the content of an other one.
  546.      * If the archive already exist, it is replaced by the new one without
  547.      * any warning.
  548.      *
  549.      *
  550.      * @param mixed $p_archive It can be a valid Archive_Zip object or
  551.      *                             the filename of a valid zip archive.
  552.      *
  553.      * @return integer 1 on success, 0 on failure.
  554.      */
  555.     function duplicate($p_archive)
  556.     {
  557.         $this->_errorReset();
  558.  
  559.         // ----- Look if the $p_archive is a Archive_Zip object
  560.         if ((is_object($p_archive))
  561.             && (strtolower(get_class($p_archive)) == 'archive_zip')) {
  562.             $v_result $this->_duplicate($p_archive->_zipname);
  563.         else if (is_string($p_archive)) {
  564.             // ----- Check that $p_archive is a valid zip file
  565.             // TBC : Should also check the archive format
  566.             if (!is_file($p_archive)) {
  567.                 $this->_errorLog(ARCHIVE_ZIP_ERR_MISSING_FILE,
  568.                                  "No file with filename '".$p_archive."'");
  569.                 $v_result ARCHIVE_ZIP_ERR_MISSING_FILE;
  570.             else {
  571.                 $v_result $this->_duplicate($p_archive);
  572.             }
  573.         else {
  574.             $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER,
  575.                              "Invalid variable type p_archive_to_add");
  576.             $v_result ARCHIVE_ZIP_ERR_INVALID_PARAMETER;
  577.         }
  578.  
  579.         return $v_result;
  580.     }
  581.     // }}}
  582.  
  583.     // {{{ merge()
  584.     /**
  585.      *  This method merge a valid zip archive at the end of the
  586.      *  archive identified by the Archive_Zip object.
  587.      *  If the archive ($this) does not exist, the merge becomes a duplicate.
  588.      *  If the archive to add does not exist, the merge is a success.
  589.      *
  590.      * @param mixed $p_archive_to_add It can be a valid Archive_Zip object or
  591.      *                                  the filename of a valid zip archive.
  592.      *
  593.      * @return integer 1 on success, 0 on failure.
  594.      */
  595.     function merge($p_archive_to_add)
  596.     {
  597.         $v_result = 1;
  598.         $this->_errorReset();
  599.  
  600.         // ----- Check archive
  601.         if (!$this->_checkFormat()) {
  602.             return(0);
  603.         }
  604.  
  605.         // ----- Look if the $p_archive_to_add is a Archive_Zip object
  606.         if ((is_object($p_archive_to_add))
  607.             && (strtolower(get_class($p_archive_to_add)) == 'archive_zip')) {
  608.             $v_result $this->_merge($p_archive_to_add);
  609.         else if (is_string($p_archive_to_add)) {
  610.             // ----- Create a temporary archive
  611.             $v_object_archive = new Archive_Zip($p_archive_to_add);
  612.  
  613.             // ----- Merge the archive
  614.             $v_result $this->_merge($v_object_archive);
  615.         else {
  616.             $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER,
  617.                              "Invalid variable type p_archive_to_add");
  618.             $v_result ARCHIVE_ZIP_ERR_INVALID_PARAMETER;
  619.         }
  620.  
  621.         return $v_result;
  622.     }
  623.     // }}}
  624.  
  625.     // {{{ errorCode()
  626.     /**
  627.      * Method that gives the lastest error code.
  628.      *
  629.      * @access public
  630.      * @return integer The error code value.
  631.      */
  632.     function errorCode()
  633.     {
  634.         return($this->_error_code);
  635.     }
  636.     // }}}
  637.  
  638.     // {{{ errorName()
  639.     /**
  640.      * This method gives the latest error code name.
  641.      *
  642.      * @param boolean $p_with_code If true, gives the name and the int value.
  643.      *
  644.      * @access public
  645.      * @return string The error name.
  646.      */
  647.     function errorName($p_with_code = false)
  648.     {
  649.         $v_const_list get_defined_constants();
  650.  
  651.         // ----- Extract error constants from all const.
  652.         for (reset($v_const_list);
  653.             list($v_key$v_valueeach($v_const_list);{
  654.             if (substr($v_key0strlen('ARCHIVE_ZIP_ERR_')) =='ARCHIVE_ZIP_ERR_'{
  655.                 $v_error_list[$v_key$v_value;
  656.             }
  657.         }
  658.  
  659.         // ----- Search the name form the code value
  660.         $v_key array_search($this->_error_code$v_error_listtrue);
  661.         if ($v_key!=false{
  662.             $v_value $v_key;
  663.         else {
  664.             $v_value 'NoName';
  665.         }
  666.  
  667.         if ($p_with_code{
  668.             return($v_value.' ('.$this->_error_code.')');
  669.         else {
  670.             return($v_value);
  671.         }
  672.     }
  673.     // }}}
  674.  
  675.     // {{{ errorInfo()
  676.     /**
  677.      * This method returns the description associated with the latest error.
  678.      *
  679.      * @param boolean $p_full If set to true gives the description with the
  680.      *                          error code, the name and the description.
  681.      *                          If set to false gives only the description
  682.      *                          and the error code.
  683.      *
  684.      * @access public
  685.      * @return string The error description.
  686.      */
  687.     function errorInfo($p_full = false)
  688.     {
  689.         if ($p_full{
  690.             return($this->errorName(true)." : ".$this->_error_string);
  691.         else {
  692.             return($this->_error_string." [code ".$this->_error_code."]");
  693.         }
  694.     }
  695.     // }}}
  696.  
  697.  
  698.     // -----------------------------------------------------------------------------
  699.     // ***** UNDER THIS LINE ARE DEFINED PRIVATE INTERNAL FUNCTIONS *****
  700.     // *****                                                        *****
  701.     // *****       THESES FUNCTIONS MUST NOT BE USED DIRECTLY       *****
  702.     // -----------------------------------------------------------------------------
  703.  
  704.     // ---------------------------------------------------------------------------
  705.     // Function : _checkFormat()
  706.     // Description :
  707.     //   This method check that the archive exists and is a valid zip archive.
  708.     //   Several level of check exists. (futur)
  709.     // Parameters :
  710.     //   $p_level : Level of check. Default 0.
  711.     //              0 : Check the first bytes (magic codes) (default value))
  712.     //              1 : 0 + Check the central directory (futur)
  713.     //              2 : 1 + Check each file header (futur)
  714.     // Return Values :
  715.     //   true on success,
  716.     //   false on error, the error code is set.
  717.     // ---------------------------------------------------------------------------
  718.     /**
  719.      * Archive_Zip::_checkFormat()
  720.      *
  721.      * { Description }
  722.      *
  723.      * @param integer $p_level 
  724.      *
  725.      * @return bool 
  726.      */
  727.     function _checkFormat($p_level = 0)
  728.     {
  729.         $v_result = true;
  730.  
  731.         // ----- Reset the error handler
  732.         $this->_errorReset();
  733.  
  734.         // ----- Look if the file exits
  735.         if (!is_file($this->_zipname)) {
  736.             // ----- Error log
  737.             $this->_errorLog(ARCHIVE_ZIP_ERR_MISSING_FILE,
  738.                              "Missing archive file '".$this->_zipname."'");
  739.             return(false);
  740.         }
  741.  
  742.         // ----- Check that the file is readeable
  743.         if (!is_readable($this->_zipname)) {
  744.             // ----- Error log
  745.             $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL,
  746.                              "Unable to read archive '".$this->_zipname."'");
  747.             return(false);
  748.         }
  749.  
  750.         // ----- Check the magic code
  751.         // TBC
  752.  
  753.         // ----- Check the central header
  754.         // TBC
  755.  
  756.         // ----- Check each file header
  757.         // TBC
  758.  
  759.  
  760.         return $v_result;
  761.     }
  762.     // ---------------------------------------------------------------------------
  763.  
  764.     // ---------------------------------------------------------------------------
  765.     // Function : _create()
  766.     // Description :
  767.     // Parameters :
  768.     // Return Values :
  769.     // ---------------------------------------------------------------------------
  770.     /**
  771.      * Archive_Zip::_create()
  772.      *
  773.      * { Description }
  774.      *
  775.      * @return int 
  776.      */
  777.     function _create($p_list&$p_result_list&$p_params)
  778.     {
  779.         $v_result = 1;
  780.  
  781.         $v_list_detail = array();
  782.  
  783.         $p_add_dir        $p_params['add_path'];
  784.         $p_remove_dir     $p_params['remove_path'];
  785.         $p_remove_all_dir $p_params['remove_all_path'];
  786.  
  787.         // ----- Open the file in write mode
  788.         if (($v_result $this->_openFd('wb')) != 1{
  789.  
  790.             return $v_result;
  791.         }
  792.  
  793.         // ----- Add the list of files
  794.         $v_result $this->_addList($p_list$p_result_list$p_add_dir$p_remove_dir$p_remove_all_dir$p_params);
  795.  
  796.         // ----- Close
  797.         $this->_closeFd();
  798.  
  799.  
  800.         return $v_result;
  801.     }
  802.     // ---------------------------------------------------------------------------
  803.  
  804.     // ---------------------------------------------------------------------------
  805.     // Function : _add()
  806.     // Description :
  807.     // Parameters :
  808.     // Return Values :
  809.     // ---------------------------------------------------------------------------
  810.     /**
  811.      * Archive_Zip::_add()
  812.      *
  813.      * { Description }
  814.      *
  815.      * @return int 
  816.      */
  817.     function _add($p_list&$p_result_list&$p_params)
  818.     {
  819.         $v_result = 1;
  820.  
  821.         $v_list_detail = array();
  822.  
  823.         $p_add_dir        $p_params['add_path'];
  824.         $p_remove_dir     $p_params['remove_path'];
  825.         $p_remove_all_dir $p_params['remove_all_path'];
  826.  
  827.         // ----- Look if the archive exists or is empty and need to be created
  828.         if ((!is_file($this->_zipname)) || (filesize($this->_zipname== 0)) {
  829.             $v_result $this->_create($p_list$p_result_list$p_params);
  830.             return $v_result;
  831.         }
  832.  
  833.         // ----- Open the zip file
  834.         if (($v_result $this->_openFd('rb')) != 1{
  835.             return $v_result;
  836.         }
  837.  
  838.         // ----- Read the central directory informations
  839.         $v_central_dir = array();
  840.         if (($v_result $this->_readEndCentralDir($v_central_dir)) != 1{
  841.             $this->_closeFd();
  842.             return $v_result;
  843.         }
  844.  
  845.         // ----- Go to beginning of File
  846.         @rewind($this->_zip_fd);
  847.  
  848.         // ----- Creates a temporay file
  849.         $v_zip_temp_name ARCHIVE_ZIP_TEMPORARY_DIR.uniqid('archive_zip-').'.tmp';
  850.  
  851.         // ----- Open the temporary file in write mode
  852.         if (($v_zip_temp_fd @fopen($v_zip_temp_name'wb')) == 0{
  853.             $this->_closeFd();
  854.  
  855.             $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL,
  856.                            'Unable to open temporary file \''
  857.                            .$v_zip_temp_name.'\' in binary write mode');
  858.             return Archive_Zip::errorCode();
  859.         }
  860.  
  861.         // ----- Copy the files from the archive to the temporary file
  862.         // TBC : Here I should better append the file and go back to erase the
  863.         // central dir
  864.         $v_size $v_central_dir['offset'];
  865.         while ($v_size != 0{
  866.             $v_read_size ($v_size ARCHIVE_ZIP_READ_BLOCK_SIZE
  867.                             ? $v_size ARCHIVE_ZIP_READ_BLOCK_SIZE);
  868.  
  869.             $v_buffer fread($this->_zip_fd$v_read_size);
  870.  
  871.             @fwrite($v_zip_temp_fd$v_buffer$v_read_size);
  872.             $v_size -= $v_read_size;
  873.         }
  874.  
  875.         // ----- Swap the file descriptor
  876.         // Here is a trick : I swap the temporary fd with the zip fd, in order to
  877.         // use the following methods on the temporary fil and not the real archive
  878.         $v_swap $this->_zip_fd;
  879.  
  880.         $this->_zip_fd $v_zip_temp_fd;
  881.         $v_zip_temp_fd $v_swap;
  882.  
  883.         // ----- Add the files
  884.         $v_header_list = array();
  885.         if (($v_result $this->_addFileList($p_list$v_header_list,
  886.                                              $p_add_dir$p_remove_dir,
  887.                                              $p_remove_all_dir$p_params)) != 1{
  888.             fclose($v_zip_temp_fd);
  889.             $this->_closeFd();
  890.             @unlink($v_zip_temp_name);
  891.  
  892.  
  893.             return $v_result;
  894.         }
  895.  
  896.         // ----- Store the offset of the central dir
  897.         $v_offset @ftell($this->_zip_fd);
  898.  
  899.         // ----- Copy the block of file headers from the old archive
  900.         $v_size $v_central_dir['size'];
  901.         while ($v_size != 0{
  902.             $v_read_size ($v_size ARCHIVE_ZIP_READ_BLOCK_SIZE
  903.                             ? $v_size ARCHIVE_ZIP_READ_BLOCK_SIZE);
  904.  
  905.             $v_buffer @fread($v_zip_temp_fd$v_read_size);
  906.  
  907.             @fwrite($this->_zip_fd$v_buffer$v_read_size);
  908.             $v_size -= $v_read_size;
  909.         }
  910.  
  911.         // ----- Create the Central Dir files header
  912.         for ($i = 0$v_count = 0; $i<sizeof($v_header_list)$i++{
  913.             // ----- Create the file header
  914.             if ($v_header_list[$i]['status'== 'ok'{
  915.                 if (($v_result $this->_writeCentralFileHeader($v_header_list[$i]))!=1{
  916.                     fclose($v_zip_temp_fd);
  917.                     $this->_closeFd();
  918.                     @unlink($v_zip_temp_name);
  919.  
  920.  
  921.                     return $v_result;
  922.                 }
  923.                 $v_count++;
  924.             }
  925.  
  926.             // ----- Transform the header to a 'usable' info
  927.             $this->_convertHeader2FileInfo($v_header_list[$i]$p_result_list[$i]);
  928.         }
  929.  
  930.         // ----- Zip file comment
  931.         $v_comment '';
  932.  
  933.         // ----- Calculate the size of the central header
  934.         $v_size @ftell($this->_zip_fd)-$v_offset;
  935.  
  936.         // ----- Create the central dir footer
  937.         if (($v_result $this->_writeCentralHeader($v_count
  938.                                                       +$v_central_dir['entries'],
  939.                                                     $v_size$v_offset,
  940.                                                     $v_comment)) != 1{
  941.             // ----- Reset the file list
  942.             unset($v_header_list);
  943.  
  944.  
  945.             return $v_result;
  946.         }
  947.  
  948.         // ----- Swap back the file descriptor
  949.         $v_swap $this->_zip_fd;
  950.  
  951.         $this->_zip_fd $v_zip_temp_fd;
  952.         $v_zip_temp_fd $v_swap;
  953.  
  954.         // ----- Close
  955.         $this->_closeFd();
  956.  
  957.         // ----- Close the temporary file
  958.         @fclose($v_zip_temp_fd);
  959.  
  960.         // ----- Delete the zip file
  961.         // TBC : I should test the result ...
  962.         @unlink($this->_zipname);
  963.  
  964.         // ----- Rename the temporary file
  965.         // TBC : I should test the result ...
  966.         //@rename($v_zip_temp_name, $this->_zipname);
  967.         $this->_tool_Rename($v_zip_temp_name$this->_zipname);
  968.  
  969.  
  970.         return $v_result;
  971.     }
  972.     // ---------------------------------------------------------------------------
  973.  
  974.     // ---------------------------------------------------------------------------
  975.     // Function : _openFd()
  976.     // Description :
  977.     // Parameters :
  978.     // ---------------------------------------------------------------------------
  979.     /**
  980.      * Archive_Zip::_openFd()
  981.      *
  982.      * { Description }
  983.      *
  984.      * @return int 
  985.      */
  986.     function _openFd($p_mode)
  987.     {
  988.         $v_result = 1;
  989.  
  990.         // ----- Look if already open
  991.         if ($this->_zip_fd != 0{
  992.             $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL,
  993.                              'Zip file \''.$this->_zipname.'\' already open');
  994.             return Archive_Zip::errorCode();
  995.         }
  996.  
  997.         // ----- Open the zip file
  998.         if (($this->_zip_fd @fopen($this->_zipname$p_mode)) == 0{
  999.             $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL,
  1000.                              'Unable to open archive \''.$this->_zipname
  1001.                              .'\' in '.$p_mode.' mode');
  1002.             return Archive_Zip::errorCode();
  1003.         }
  1004.  
  1005.  
  1006.         return $v_result;
  1007.     }
  1008.     // ---------------------------------------------------------------------------
  1009.  
  1010.     // ---------------------------------------------------------------------------
  1011.     // Function : _closeFd()
  1012.     // Description :
  1013.     // Parameters :
  1014.     // ---------------------------------------------------------------------------
  1015.     /**
  1016.      * Archive_Zip::_closeFd()
  1017.      *
  1018.      * { Description }
  1019.      *
  1020.      * @return int 
  1021.      */
  1022.     function _closeFd()
  1023.     {
  1024.         $v_result = 1;
  1025.  
  1026.         if ($this->_zip_fd != 0{
  1027.             @fclose($this->_zip_fd);
  1028.         }
  1029.         $this->_zip_fd = 0;
  1030.  
  1031.  
  1032.         return $v_result;
  1033.     }
  1034.     // ---------------------------------------------------------------------------
  1035.  
  1036.     // ---------------------------------------------------------------------------
  1037.     // Function : _addList()
  1038.     // Description :
  1039.     //   $p_add_dir and $p_remove_dir will give the ability to memorize a path which is
  1040.     //   different from the real path of the file. This is usefull if you want to have PclTar
  1041.     //   running in any directory, and memorize relative path from an other directory.
  1042.     // Parameters :
  1043.     //   $p_list : An array containing the file or directory names to add in the tar
  1044.     //   $p_result_list : list of added files with their properties (specially the status field)
  1045.     //   $p_add_dir : Path to add in the filename path archived
  1046.     //   $p_remove_dir : Path to remove in the filename path archived
  1047.     // Return Values :
  1048.     // ---------------------------------------------------------------------------
  1049.     /**
  1050.      * Archive_Zip::_addList()
  1051.      *
  1052.      * { Description }
  1053.      *
  1054.      * @return int 
  1055.      */
  1056.     function _addList($p_list&$p_result_list,
  1057.                     $p_add_dir$p_remove_dir$p_remove_all_dir&$p_params)
  1058.     {
  1059.         $v_result = 1;
  1060.  
  1061.         // ----- Add the files
  1062.         $v_header_list = array();
  1063.         if (($v_result $this->_addFileList($p_list$v_header_list,
  1064.                                              $p_add_dir$p_remove_dir,
  1065.                                              $p_remove_all_dir$p_params)) != 1{
  1066.             return $v_result;
  1067.         }
  1068.  
  1069.         // ----- Store the offset of the central dir
  1070.         $v_offset @ftell($this->_zip_fd);
  1071.  
  1072.         // ----- Create the Central Dir files header
  1073.         for ($i = 0$v_count = 0; $i<sizeof($v_header_list)$i++{
  1074.             // ----- Create the file header
  1075.             if ($v_header_list[$i]['status'== 'ok'{
  1076.                 if (($v_result $this->_writeCentralFileHeader($v_header_list[$i])) != 1{
  1077.                     return $v_result;
  1078.                 }
  1079.                 $v_count++;
  1080.             }
  1081.  
  1082.             // ----- Transform the header to a 'usable' info
  1083.             $this->_convertHeader2FileInfo($v_header_list[$i]$p_result_list[$i]);
  1084.         }
  1085.  
  1086.         // ----- Zip file comment
  1087.         $v_comment '';
  1088.  
  1089.         // ----- Calculate the size of the central header
  1090.         $v_size @ftell($this->_zip_fd)-$v_offset;
  1091.  
  1092.         // ----- Create the central dir footer
  1093.         if (($v_result $this->_writeCentralHeader($v_count$v_size$v_offset,
  1094.                                                     $v_comment)) != 1{
  1095.             // ----- Reset the file list
  1096.             unset($v_header_list);
  1097.  
  1098.  
  1099.             return $v_result;
  1100.         }
  1101.  
  1102.  
  1103.         return $v_result;
  1104.     }
  1105.     // ---------------------------------------------------------------------------
  1106.  
  1107.     // ---------------------------------------------------------------------------
  1108.     // Function : _addFileList()
  1109.     // Description :
  1110.     //   $p_add_dir and $p_remove_dir will give the ability to memorize a path which is
  1111.     //   different from the real path of the file. This is usefull if you want to
  1112.     //   run the lib in any directory, and memorize relative path from an other directory.
  1113.     // Parameters :
  1114.     //   $p_list : An array containing the file or directory names to add in the tar
  1115.     //   $p_result_list : list of added files with their properties (specially the status field)
  1116.     //   $p_add_dir : Path to add in the filename path archived
  1117.     //   $p_remove_dir : Path to remove in the filename path archived
  1118.     // Return Values :
  1119.     // ---------------------------------------------------------------------------
  1120.     /**
  1121.      * Archive_Zip::_addFileList()
  1122.      *
  1123.      * { Description }
  1124.      *
  1125.      * @return int 
  1126.      */
  1127.     function _addFileList($p_list&$p_result_list,
  1128.                         $p_add_dir$p_remove_dir$p_remove_all_dir,
  1129.                         &$p_params)
  1130.     {
  1131.         $v_result = 1;
  1132.         $v_header = array();
  1133.  
  1134.         // ----- Recuperate the current number of elt in list
  1135.         $v_nb sizeof($p_result_list);
  1136.  
  1137.         // ----- Loop on the files
  1138.         for ($j = 0; ($j<count($p_list)) && ($v_result == 1)$j++{
  1139.             // ----- Recuperate the filename
  1140.             $p_filename $this->_tool_TranslateWinPath($p_list[$j]false);
  1141.  
  1142.             // ----- Skip empty file names
  1143.             if ($p_filename == ""{
  1144.                 continue;
  1145.             }
  1146.  
  1147.             // ----- Check the filename
  1148.             if (!file_exists($p_filename)) {
  1149.                 $this->_errorLog(ARCHIVE_ZIP_ERR_MISSING_FILE,
  1150.                                  "File '$p_filename' does not exists");
  1151.                 return Archive_Zip::errorCode();
  1152.             }
  1153.  
  1154.             // ----- Look if it is a file or a dir with no all pathnre move
  1155.             if ((is_file($p_filename)) || ((is_dir($p_filename)) && !$p_remove_all_dir)) {
  1156.                 // ----- Add the file
  1157.                 if (($v_result $this->_addFile($p_filename$v_header$p_add_dir$p_remove_dir$p_remove_all_dir$p_params)) != 1{
  1158.                     return $v_result;
  1159.                 }
  1160.  
  1161.                 // ----- Store the file infos
  1162.                 $p_result_list[$v_nb++$v_header;
  1163.             }
  1164.  
  1165.             // ----- Look for directory
  1166.             if (is_dir($p_filename)) {
  1167.  
  1168.                 // ----- Look for path
  1169.                 if ($p_filename != "."{
  1170.                     $v_path $p_filename."/";
  1171.                 else {
  1172.                     $v_path "";
  1173.                 }
  1174.  
  1175.                 // ----- Read the directory for files and sub-directories
  1176.                 $p_hdir  opendir($p_filename);
  1177.                 $p_hitem readdir($p_hdir)// '.' directory
  1178.                 $p_hitem readdir($p_hdir)// '..' directory
  1179.  
  1180.                 while ($p_hitem readdir($p_hdir)) {
  1181.  
  1182.                     // ----- Look for a file
  1183.                     if (is_file($v_path.$p_hitem)) {
  1184.  
  1185.                         // ----- Add the file
  1186.                         if (($v_result $this->_addFile($v_path.$p_hitem$v_header$p_add_dir$p_remove_dir$p_remove_all_dir$p_params)) != 1{
  1187.                             return $v_result;
  1188.                         }
  1189.  
  1190.                         // ----- Store the file infos
  1191.                         $p_result_list[$v_nb++$v_header;
  1192.                     else {
  1193.                         // ----- Recursive call to _addFileList()
  1194.                         // ----- Need an array as parameter
  1195.                         $p_temp_list[0$v_path.$p_hitem;
  1196.  
  1197.                         $v_result $this->_addFileList($p_temp_list$p_result_list$p_add_dir$p_remove_dir$p_remove_all_dir$p_params);
  1198.  
  1199.                         // ----- Update the number of elements of the list
  1200.                         $v_nb sizeof($p_result_list);
  1201.                     }
  1202.                 }
  1203.  
  1204.                 // ----- Free memory for the recursive loop
  1205.                 unset($p_temp_list);
  1206.                 unset($p_hdir);
  1207.                 unset($p_hitem);
  1208.             }
  1209.         }
  1210.  
  1211.         return $v_result;
  1212.     }
  1213.     // ---------------------------------------------------------------------------
  1214.  
  1215.     // ---------------------------------------------------------------------------
  1216.     // Function : _addFile()
  1217.     // Description :
  1218.     // Parameters :
  1219.     // Return Values :
  1220.     // ---------------------------------------------------------------------------
  1221.     /**
  1222.      * Archive_Zip::_addFile()
  1223.      *
  1224.      * { Description }
  1225.      *
  1226.      * @return int 
  1227.      */
  1228.     function _addFile($p_filename&$p_header$p_add_dir$p_remove_dir$p_remove_all_dir&$p_params)
  1229.     {
  1230.         $v_result = 1;
  1231.  
  1232.         if ($p_filename == ""{
  1233.             // ----- Error log
  1234.             $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER"Invalid file list parameter (invalid or empty list)");
  1235.  
  1236.  
  1237.             return Archive_Zip::errorCode();
  1238.         }
  1239.  
  1240.         // ----- Calculate the stored filename
  1241.         $v_stored_filename $p_filename;
  1242.  
  1243.         // ----- Look for all path to remove
  1244.         if ($p_remove_all_dir{
  1245.             $v_stored_filename basename($p_filename);
  1246.         else if ($p_remove_dir != ""{
  1247.             if (substr($p_remove_dir-1!= '/'{
  1248.                 $p_remove_dir .= "/";
  1249.             }
  1250.  
  1251.             if ((substr($p_filename02== "./"|| (substr($p_remove_dir02== "./")) {
  1252.                 if ((substr($p_filename02== "./"&& (substr($p_remove_dir02!= "./")) {
  1253.                     $p_remove_dir "./".$p_remove_dir;
  1254.                 }
  1255.                 if ((substr($p_filename02!= "./"&& (substr($p_remove_dir02== "./")) {
  1256.                     $p_remove_dir substr($p_remove_dir2);
  1257.                 }
  1258.             }
  1259.  
  1260.             $v_compare $this->_tool_PathInclusion($p_remove_dir$p_filename);
  1261.             if ($v_compare > 0{
  1262.                 if ($v_compare == 2{
  1263.                     $v_stored_filename "";
  1264.                 else {
  1265.                     $v_stored_filename substr($p_filenamestrlen($p_remove_dir));
  1266.                 }
  1267.             }
  1268.         }
  1269.         // ----- Look for path to add
  1270.         if ($p_add_dir != ""{
  1271.             if (substr($p_add_dir-1== "/"{
  1272.                 $v_stored_filename $p_add_dir.$v_stored_filename;
  1273.             else {
  1274.                 $v_stored_filename $p_add_dir."/".$v_stored_filename;
  1275.             }
  1276.         }
  1277.  
  1278.         // ----- Filename (reduce the path of stored name)
  1279.         $v_stored_filename $this->_tool_PathReduction($v_stored_filename);
  1280.  
  1281.  
  1282.             /* filename length moved after call-back in release 1.3
  1283.             // ----- Check the path length
  1284.                 if (strlen($v_stored_filename) > 0xFF) {
  1285.                     // ----- Error log
  1286.                     $this->_errorLog(-5, "Stored file name is too long (max. 255) : '$v_stored_filename'");
  1287.  
  1288.                     return Archive_Zip::errorCode();
  1289.                 }
  1290.              */
  1291.  
  1292.         // ----- Set the file properties
  1293.         clearstatcache();
  1294.         $p_header['comment']           '';
  1295.         $p_header['comment_len']       = 0;
  1296.         $p_header['compressed_size']   = 0;
  1297.         $p_header['compression']       = 0;
  1298.         $p_header['crc']               = 0;
  1299.         $p_header['disk']              = 0;
  1300.         $p_header['external']          (is_file($p_filename)?0xFE49FFE0:0x41FF0010);
  1301.         $p_header['extra']             '';
  1302.         $p_header['extra_len']         = 0;
  1303.         $p_header['filename']          $p_filename;
  1304.         $p_header['filename_len']      strlen($p_filename);
  1305.         $p_header['flag']              = 0;
  1306.         $p_header['index']             = -1;
  1307.         $p_header['internal']          = 0;
  1308.         $p_header['mtime']             filemtime($p_filename);
  1309.         $p_header['offset']            = 0;
  1310.         $p_header['size']              filesize($p_filename);
  1311.         $p_header['status']            'ok';
  1312.         $p_header['stored_filename']   $v_stored_filename;
  1313.         $p_header['version']           = 20;
  1314.         $p_header['version_extracted'= 10;
  1315.  
  1316.         // ----- Look for pre-add callback
  1317.         if ((isset($p_params[ARCHIVE_ZIP_PARAM_PRE_ADD]))
  1318.             && ($p_params[ARCHIVE_ZIP_PARAM_PRE_ADD!= '')) {
  1319.  
  1320.             // ----- Generate a local information
  1321.             $v_local_header = array();
  1322.             $this->_convertHeader2FileInfo($p_header$v_local_header);
  1323.  
  1324.             // ----- Call the callback
  1325.             // Here I do not use call_user_func() because I need to send a reference to the
  1326.             // header.
  1327.             eval('$v_result = '.$p_params[ARCHIVE_ZIP_PARAM_PRE_ADD].'(ARCHIVE_ZIP_PARAM_PRE_ADD, $v_local_header);');
  1328.             if ($v_result == 0{
  1329.                 // ----- Change the file status
  1330.                 $p_header['status'"skipped";
  1331.  
  1332.                 $v_result = 1;
  1333.             }
  1334.  
  1335.             // ----- Update the informations
  1336.             // Only some fields can be modified
  1337.             if ($p_header['stored_filename'!= $v_local_header['stored_filename']{
  1338.                 $p_header['stored_filename'$this->_tool_PathReduction($v_local_header['stored_filename']);
  1339.             }
  1340.         }
  1341.  
  1342.         // ----- Look for empty stored filename
  1343.         if ($p_header['stored_filename'== ""{
  1344.             $p_header['status'"filtered";
  1345.         }
  1346.  
  1347.         // ----- Check the path length
  1348.         if (strlen($p_header['stored_filename']> 0xFF{
  1349.             $p_header['status''filename_too_long';
  1350.         }
  1351.  
  1352.         // ----- Look if no error, or file not skipped
  1353.         if ($p_header['status'== 'ok'{
  1354.  
  1355.             // ----- Look for a file
  1356.             if (is_file($p_filename)) {
  1357.                 // ----- Open the source file
  1358.                 if (($v_file @fopen($p_filename"rb")) == 0{
  1359.                     $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL"Unable to open file '$p_filename' in binary read mode");
  1360.                     return Archive_Zip::errorCode();
  1361.                 }
  1362.  
  1363.                 if ($p_params['no_compression']{
  1364.                     // ----- Read the file content
  1365.                     $v_content_compressed @fread($v_file$p_header['size']);
  1366.  
  1367.                     // ----- Calculate the CRC
  1368.                     $p_header['crc'crc32($v_content_compressed);
  1369.                 else {
  1370.                     // ----- Read the file content
  1371.                     $v_content @fread($v_file$p_header['size']);
  1372.  
  1373.                     // ----- Calculate the CRC
  1374.                     $p_header['crc'crc32($v_content);
  1375.  
  1376.                     // ----- Compress the file
  1377.                     $v_content_compressed gzdeflate($v_content);
  1378.                 }
  1379.  
  1380.                 // ----- Set header parameters
  1381.                 $p_header['compressed_size'strlen($v_content_compressed);
  1382.                 $p_header['compression']     = 8;
  1383.  
  1384.                 // ----- Call the header generation
  1385.                 if (($v_result $this->_writeFileHeader($p_header)) != 1{
  1386.                     @fclose($v_file);
  1387.                     return $v_result;
  1388.                 }
  1389.  
  1390.                 // ----- Write the compressed content
  1391.                 $v_binary_data pack('a'.$p_header['compressed_size']$v_content_compressed);
  1392.                 @fwrite($this->_zip_fd$v_binary_data$p_header['compressed_size']);
  1393.  
  1394.                 // ----- Close the file
  1395.                 @fclose($v_file);
  1396.             else {
  1397.                 // ----- Look for a directory
  1398.                 // ----- Set the file properties
  1399.                 $p_header['filename'.= '/';
  1400.                 $p_header['filename_len']++;
  1401.  
  1402.                 $p_header['size']     = 0;
  1403.                 $p_header['external'= 0x41FF0010;   // Value for a folder : to be checked
  1404.  
  1405.                 // ----- Call the header generation
  1406.                 if (($v_result $this->_writeFileHeader($p_header)) != 1{
  1407.                     return $v_result;
  1408.                 }
  1409.             }
  1410.         }
  1411.  
  1412.         // ----- Look for pre-add callback
  1413.         if ((isset($p_params[ARCHIVE_ZIP_PARAM_POST_ADD]))
  1414.             && ($p_params[ARCHIVE_ZIP_PARAM_POST_ADD!= '')) {
  1415.  
  1416.             // ----- Generate a local information
  1417.             $v_local_header = array();
  1418.             $this->_convertHeader2FileInfo($p_header$v_local_header);
  1419.  
  1420.             // ----- Call the callback
  1421.             // Here I do not use call_user_func() because I need to send a reference to the
  1422.             // header.
  1423.             eval('$v_result = '.$p_params[ARCHIVE_ZIP_PARAM_POST_ADD].'(ARCHIVE_ZIP_PARAM_POST_ADD, $v_local_header);');
  1424.  
  1425.             if ($v_result == 0{
  1426.                 // ----- Ignored
  1427.                 $v_result = 1;
  1428.             }
  1429.  
  1430.             // ----- Update the informations
  1431.             // Nothing can be modified
  1432.         }
  1433.  
  1434.         return $v_result;
  1435.     }
  1436.     // ---------------------------------------------------------------------------
  1437.  
  1438.     // ---------------------------------------------------------------------------
  1439.     // Function : _writeFileHeader()
  1440.     // Description :
  1441.     // Parameters :
  1442.     // Return Values :
  1443.     // ---------------------------------------------------------------------------
  1444.     /**
  1445.      * Archive_Zip::_writeFileHeader()
  1446.      *
  1447.      * { Description }
  1448.      *
  1449.      * @return int 
  1450.      */
  1451.     function _writeFileHeader(&$p_header)
  1452.     {
  1453.         $v_result = 1;
  1454.  
  1455.         // TBC
  1456.         //for(reset($p_header); $key = key($p_header); next($p_header)) {
  1457.         //}
  1458.  
  1459.         // ----- Store the offset position of the file
  1460.         $p_header['offset'ftell($this->_zip_fd);
  1461.  
  1462.         // ----- Transform UNIX mtime to DOS format mdate/mtime
  1463.         $v_date  getdate($p_header['mtime']);
  1464.         $v_mtime ($v_date['hours']<<11($v_date['minutes']<<5$v_date['seconds']/2;
  1465.         $v_mdate (($v_date['year']-1980)<<9($v_date['mon']<<5$v_date['mday'];
  1466.  
  1467.         // ----- Packed data
  1468.         $v_binary_data pack("VvvvvvVVVvv"0x04034b50$p_header['version']$p_header['flag'],
  1469.                           $p_header['compression']$v_mtime$v_mdate,
  1470.                           $p_header['crc']$p_header['compressed_size']$p_header['size'],
  1471.                           strlen($p_header['stored_filename'])$p_header['extra_len']);
  1472.  
  1473.         // ----- Write the first 148 bytes of the header in the archive
  1474.         fputs($this->_zip_fd$v_binary_data30);
  1475.  
  1476.         // ----- Write the variable fields
  1477.         if (strlen($p_header['stored_filename']!= 0{
  1478.             fputs($this->_zip_fd$p_header['stored_filename']strlen($p_header['stored_filename']));
  1479.         }
  1480.         if ($p_header['extra_len'!= 0{
  1481.             fputs($this->_zip_fd$p_header['extra']$p_header['extra_len']);
  1482.         }
  1483.  
  1484.  
  1485.         return $v_result;
  1486.     }
  1487.     // ---------------------------------------------------------------------------
  1488.  
  1489.     // ---------------------------------------------------------------------------
  1490.     // Function : _writeCentralFileHeader()
  1491.     // Description :
  1492.     // Parameters :
  1493.     // Return Values :
  1494.     // ---------------------------------------------------------------------------
  1495.     /**
  1496.      * Archive_Zip::_writeCentralFileHeader()
  1497.      *
  1498.      * { Description }
  1499.      *
  1500.      * @return int 
  1501.      */
  1502.     function _writeCentralFileHeader(&$p_header)
  1503.     {
  1504.         $v_result = 1;
  1505.  
  1506.         // TBC
  1507.         //for(reset($p_header); $key = key($p_header); next($p_header)) {
  1508.         //}
  1509.  
  1510.         // ----- Transform UNIX mtime to DOS format mdate/mtime
  1511.         $v_date  getdate($p_header['mtime']);
  1512.         $v_mtime ($v_date['hours']<<11($v_date['minutes']<<5$v_date['seconds']/2;
  1513.         $v_mdate (($v_date['year']-1980)<<9($v_date['mon']<<5$v_date['mday'];
  1514.  
  1515.         // ----- Packed data
  1516.         $v_binary_data pack("VvvvvvvVVVvvvvvVV"0x02014b50$p_header['version']$p_header['version_extracted'],
  1517.                           $p_header['flag']$p_header['compression']$v_mtime$v_mdate$p_header['crc'],
  1518.                           $p_header['compressed_size']$p_header['size'],
  1519.                           strlen($p_header['stored_filename'])$p_header['extra_len']$p_header['comment_len'],
  1520.                           $p_header['disk']$p_header['internal']$p_header['external']$p_header['offset']);
  1521.  
  1522.         // ----- Write the 42 bytes of the header in the zip file
  1523.         fputs($this->_zip_fd$v_binary_data46);
  1524.  
  1525.         // ----- Write the variable fields
  1526.         if (strlen($p_header['stored_filename']!= 0{
  1527.             fputs($this->_zip_fd$p_header['stored_filename']strlen($p_header['stored_filename']));
  1528.         }
  1529.         if ($p_header['extra_len'!= 0{
  1530.             fputs($this->_zip_fd$p_header['extra']$p_header['extra_len']);
  1531.         }
  1532.         if ($p_header['comment_len'!= 0{
  1533.             fputs($this->_zip_fd$p_header['comment']$p_header['comment_len']);
  1534.         }
  1535.  
  1536.  
  1537.         return $v_result;
  1538.     }
  1539.     // ---------------------------------------------------------------------------
  1540.  
  1541.     // ---------------------------------------------------------------------------
  1542.     // Function : _writeCentralHeader()
  1543.     // Description :
  1544.     // Parameters :
  1545.     // Return Values :
  1546.     // ---------------------------------------------------------------------------
  1547.     /**
  1548.      * Archive_Zip::_writeCentralHeader()
  1549.      *
  1550.      * { Description }
  1551.      *
  1552.      * @return int 
  1553.      */
  1554.     function _writeCentralHeader($p_nb_entries$p_size$p_offset$p_comment)
  1555.     {
  1556.         $v_result = 1;
  1557.  
  1558.         // ----- Packed data
  1559.         $v_binary_data pack("VvvvvVVv"0x06054b5000$p_nb_entries$p_nb_entries$p_size$p_offsetstrlen($p_comment));
  1560.  
  1561.         // ----- Write the 22 bytes of the header in the zip file
  1562.         fputs($this->_zip_fd$v_binary_data22);
  1563.  
  1564.         // ----- Write the variable fields
  1565.         if (strlen($p_comment!= 0{
  1566.             fputs($this->_zip_fd$p_commentstrlen($p_comment));
  1567.         }
  1568.  
  1569.  
  1570.         return $v_result;
  1571.     }
  1572.     // ---------------------------------------------------------------------------
  1573.  
  1574.     // ---------------------------------------------------------------------------
  1575.     // Function : _list()
  1576.     // Description :
  1577.     // Parameters :
  1578.     // Return Values :
  1579.     // ---------------------------------------------------------------------------
  1580.     /**
  1581.      * Archive_Zip::_list()
  1582.      *
  1583.      * { Description }
  1584.      *
  1585.      * @return int 
  1586.      */
  1587.     function _list(&$p_list)
  1588.     {
  1589.         $v_result = 1;
  1590.  
  1591.         // ----- Open the zip file
  1592.         if (($this->_zip_fd @fopen($this->_zipname'rb')) == 0{
  1593.             // ----- Error log
  1594.             $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL'Unable to open archive \''.$this->_zipname.'\' in binary read mode');
  1595.  
  1596.  
  1597.             return Archive_Zip::errorCode();
  1598.         }
  1599.  
  1600.         // ----- Read the central directory informations
  1601.         $v_central_dir = array();
  1602.         if (($v_result $this->_readEndCentralDir($v_central_dir)) != 1{
  1603.             return $v_result;
  1604.         }
  1605.  
  1606.         // ----- Go to beginning of Central Dir
  1607.         @rewind($this->_zip_fd);
  1608.         if (@fseek($this->_zip_fd$v_central_dir['offset'])) {
  1609.             // ----- Error log
  1610.             $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_ARCHIVE_ZIP'Invalid archive size');
  1611.  
  1612.             return Archive_Zip::errorCode();
  1613.         }
  1614.  
  1615.         // ----- Read each entry
  1616.         for ($i = 0; $i<$v_central_dir['entries']$i++{
  1617.             // ----- Read the file header
  1618.             if (($v_result $this->_readCentralFileHeader($v_header)) != 1{
  1619.                 return $v_result;
  1620.             }
  1621.             $v_header['index'$i;
  1622.  
  1623.             // ----- Get the only interesting attributes
  1624.             $this->_convertHeader2FileInfo($v_header$p_list[$i]);
  1625.             unset($v_header);
  1626.         }
  1627.  
  1628.         // ----- Close the zip file
  1629.         $this->_closeFd();
  1630.  
  1631.  
  1632.         return $v_result;
  1633.     }
  1634.     // ---------------------------------------------------------------------------
  1635.  
  1636.     // ---------------------------------------------------------------------------
  1637.     // Function : _convertHeader2FileInfo()
  1638.     // Description :
  1639.     //   This function takes the file informations from the central directory
  1640.     //   entries and extract the interesting parameters that will be given back.
  1641.     //   The resulting file infos are set in the array $p_info
  1642.     //     $p_info['filename'] : Filename with full path. Given by user (add),
  1643.     //                           extracted in the filesystem (extract).
  1644.     //     $p_info['stored_filename'] : Stored filename in the archive.
  1645.     //     $p_info['size'] = Size of the file.
  1646.     //     $p_info['compressed_size'] = Compressed size of the file.
  1647.     //     $p_info['mtime'] = Last modification date of the file.
  1648.     //     $p_info['comment'] = Comment associated with the file.
  1649.     //     $p_info['folder'] = true/false : indicates if the entry is a folder or not.
  1650.     //     $p_info['status'] = status of the action on the file.
  1651.     // Parameters :
  1652.     // Return Values :
  1653.     // ---------------------------------------------------------------------------
  1654.     /**
  1655.      * Archive_Zip::_convertHeader2FileInfo()
  1656.      *
  1657.      * { Description }
  1658.      *
  1659.      * @return int 
  1660.      */
  1661.     function _convertHeader2FileInfo($p_header&$p_info)
  1662.     {
  1663.         $v_result = 1;
  1664.  
  1665.         // ----- Get the interesting attributes
  1666.         $p_info['filename']        $p_header['filename'];
  1667.         $p_info['stored_filename'$p_header['stored_filename'];
  1668.         $p_info['size']            $p_header['size'];
  1669.         $p_info['compressed_size'$p_header['compressed_size'];
  1670.         $p_info['mtime']           $p_header['mtime'];
  1671.         $p_info['comment']         $p_header['comment'];
  1672.         $p_info['folder']          (($p_header['external']&0x00000010)==0x00000010);
  1673.         $p_info['index']           $p_header['index'];
  1674.         $p_info['status']          $p_header['status'];
  1675.  
  1676.  
  1677.         return $v_result;
  1678.     }
  1679.     // ---------------------------------------------------------------------------
  1680.  
  1681.     // ---------------------------------------------------------------------------
  1682.     // Function : _extractByRule()
  1683.     // Description :
  1684.     //   Extract a file or directory depending of rules (by index, by name, ...)
  1685.     // Parameters :
  1686.     //   $p_file_list : An array where will be placed the properties of each
  1687.     //                  extracted file
  1688.     //   $p_path : Path to add while writing the extracted files
  1689.     //   $p_remove_path : Path to remove (from the file memorized path) while writing the
  1690.     //                    extracted files. If the path does not match the file path,
  1691.     //                    the file is extracted with its memorized path.
  1692.     //                    $p_remove_path does not apply to 'list' mode.
  1693.     //                    $p_path and $p_remove_path are commulative.
  1694.     // Return Values :
  1695.     //   1 on success,0 or less on error (see error code list)
  1696.     // ---------------------------------------------------------------------------
  1697.     /**
  1698.      * Archive_Zip::_extractByRule()
  1699.      *
  1700.      * { Description }
  1701.      *
  1702.      * @return int 
  1703.      */
  1704.     function _extractByRule(&$p_file_list&$p_params)
  1705.     {
  1706.         $v_result = 1;
  1707.  
  1708.         $p_path            $p_params['add_path'];
  1709.         $p_remove_path     $p_params['remove_path'];
  1710.         $p_remove_all_path $p_params['remove_all_path'];
  1711.  
  1712.         // ----- Check the path
  1713.         if (($p_path == "")
  1714.             || ((substr($p_path01!= "/")
  1715.             && (substr($p_path03!= "../"&& (substr($p_path,1,2)!=":/"))) {
  1716.             $p_path "./".$p_path;
  1717.         }
  1718.  
  1719.         // ----- Reduce the path last (and duplicated) '/'
  1720.         if (($p_path != "./"&& ($p_path != "/")) {
  1721.             // ----- Look for the path end '/'
  1722.             while (substr($p_path-1== "/"{
  1723.                 $p_path substr($p_path0strlen($p_path)-1);
  1724.             }
  1725.         }
  1726.  
  1727.         // ----- Look for path to remove format (should end by /)
  1728.         if (($p_remove_path != ""&& (substr($p_remove_path-1!= '/')) {
  1729.             $p_remove_path .= '/';
  1730.         }
  1731.         $p_remove_path_size strlen($p_remove_path);
  1732.  
  1733.         // ----- Open the zip file
  1734.         if (($v_result $this->_openFd('rb')) != 1{
  1735.             return $v_result;
  1736.         }
  1737.  
  1738.         // ----- Read the central directory informations
  1739.         $v_central_dir = array();
  1740.         if (($v_result $this->_readEndCentralDir($v_central_dir)) != 1{
  1741.             // ----- Close the zip file
  1742.             $this->_closeFd();
  1743.  
  1744.             return $v_result;
  1745.         }
  1746.  
  1747.         // ----- Start at beginning of Central Dir
  1748.         $v_pos_entry $v_central_dir['offset'];
  1749.  
  1750.         // ----- Read each entry
  1751.         $j_start = 0;
  1752.  
  1753.         for ($i = 0$v_nb_extracted = 0; $i<$v_central_dir['entries']$i++{
  1754.             // ----- Read next Central dir entry
  1755.             @rewind($this->_zip_fd);
  1756.             if (@fseek($this->_zip_fd$v_pos_entry)) {
  1757.                 $this->_closeFd();
  1758.  
  1759.                 $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_ARCHIVE_ZIP,
  1760.                                  'Invalid archive size');
  1761.  
  1762.                 return Archive_Zip::errorCode();
  1763.             }
  1764.  
  1765.             // ----- Read the file header
  1766.             $v_header = array();
  1767.             if (($v_result $this->_readCentralFileHeader($v_header)) != 1{
  1768.                 $this->_closeFd();
  1769.  
  1770.                 return $v_result;
  1771.             }
  1772.  
  1773.             // ----- Store the index
  1774.             $v_header['index'$i;
  1775.  
  1776.             // ----- Store the file position
  1777.             $v_pos_entry ftell($this->_zip_fd);
  1778.  
  1779.             // ----- Look for the specific extract rules
  1780.             $v_extract = false;
  1781.  
  1782.             // ----- Look for extract by name rule
  1783.             if ((isset($p_params[ARCHIVE_ZIP_PARAM_BY_NAME]))
  1784.               && ($p_params[ARCHIVE_ZIP_PARAM_BY_NAME!= 0)) {
  1785.  
  1786.                 // ----- Look if the filename is in the list
  1787.                 for ($j = 0; ($j<sizeof($p_params[ARCHIVE_ZIP_PARAM_BY_NAME])) && (!$v_extract)$j++{
  1788.                     // ----- Look for a directory
  1789.                     if (substr($p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j]-1== "/"{
  1790.  
  1791.                         // ----- Look if the directory is in the filename path
  1792.                         if ((strlen($v_header['stored_filename']strlen($p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j]))
  1793.                           && (substr($v_header['stored_filename']0strlen($p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j])) == $p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j])) {
  1794.                             $v_extract = true;
  1795.                         }
  1796.                     elseif ($v_header['stored_filename'== $p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j]{
  1797.                         $v_extract = true;
  1798.                     }
  1799.                 }
  1800.             else if (   (isset($p_params[ARCHIVE_ZIP_PARAM_BY_PREG]))
  1801.                    && ($p_params[ARCHIVE_ZIP_PARAM_BY_PREG!= "")) {
  1802.                 // ----- Look for extract by preg rule
  1803.                 if (preg_match($p_params[ARCHIVE_ZIP_PARAM_BY_PREG]$v_header['stored_filename'])) {
  1804.                     $v_extract = true;
  1805.                 }
  1806.             else if ((isset($p_params[ARCHIVE_ZIP_PARAM_BY_INDEX]))
  1807.                && ($p_params[ARCHIVE_ZIP_PARAM_BY_INDEX!= 0)) {
  1808.  
  1809.                 // ----- Look for extract by index rule
  1810.                 // ----- Look if the index is in the list
  1811.                 for ($j $j_start($j<sizeof($p_params[ARCHIVE_ZIP_PARAM_BY_INDEX])) && (!$v_extract)$j++{
  1812.  
  1813.                     if (($i>=$p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['start']&& ($i<=$p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['end'])) {
  1814.                         $v_extract = true;
  1815.                     }
  1816.  
  1817.                     if ($i>=$p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['end']{
  1818.                         $j_start $j+1;
  1819.                     }
  1820.  
  1821.                     if ($p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['start']>$i{
  1822.                         break;
  1823.                     }
  1824.                 }
  1825.             else {
  1826.                 // ----- Look for no rule, which means extract all the archive
  1827.                 $v_extract = true;
  1828.             }
  1829.  
  1830.  
  1831.             // ----- Look for real extraction
  1832.             if ($v_extract{
  1833.  
  1834.                 // ----- Go to the file position
  1835.                 @rewind($this->_zip_fd);
  1836.                 if (@fseek($this->_zip_fd$v_header['offset'])) {
  1837.                     // ----- Close the zip file
  1838.                     $this->_closeFd();
  1839.  
  1840.                     // ----- Error log
  1841.                     $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_ARCHIVE_ZIP'Invalid archive size');
  1842.  
  1843.  
  1844.                     return Archive_Zip::errorCode();
  1845.                 }
  1846.  
  1847.                 // ----- Look for extraction as string
  1848.                 if ($p_params[ARCHIVE_ZIP_PARAM_EXTRACT_AS_STRING]{
  1849.  
  1850.                     // ----- Extracting the file
  1851.                     if (($v_result $this->_extractFileAsString($v_header$v_string)) != 1{
  1852.                         // ----- Close the zip file
  1853.                         $this->_closeFd();
  1854.  
  1855.                         return $v_result;
  1856.                     }
  1857.  
  1858.                     // ----- Get the only interesting attributes
  1859.                     if (($v_result $this->_convertHeader2FileInfo($v_header$p_file_list[$v_nb_extracted])) != 1{
  1860.                         // ----- Close the zip file
  1861.                         $this->_closeFd();
  1862.  
  1863.                         return $v_result;
  1864.                     }
  1865.  
  1866.                     // ----- Set the file content
  1867.                     $p_file_list[$v_nb_extracted]['content'$v_string;
  1868.  
  1869.                     // ----- Next extracted file
  1870.                     $v_nb_extracted++;
  1871.                 else {
  1872.                     // ----- Extracting the file
  1873.                     if (($v_result $this->_extractFile($v_header$p_path$p_remove_path$p_remove_all_path$p_params)) != 1{
  1874.                         // ----- Close the zip file
  1875.                         $this->_closeFd();
  1876.  
  1877.                         return $v_result;
  1878.                     }
  1879.  
  1880.                     // ----- Get the only interesting attributes
  1881.                     if (($v_result $this->_convertHeader2FileInfo($v_header$p_file_list[$v_nb_extracted++])) != 1{
  1882.                         // ----- Close the zip file
  1883.                         $this->_closeFd();
  1884.  
  1885.                         return $v_result;
  1886.                     }
  1887.                 }
  1888.             }
  1889.         }
  1890.  
  1891.         // ----- Close the zip file
  1892.         $this->_closeFd();
  1893.  
  1894.  
  1895.         return $v_result;
  1896.     }
  1897.     // ---------------------------------------------------------------------------
  1898.  
  1899.     // ---------------------------------------------------------------------------
  1900.     // Function : _extractFile()
  1901.     // Description :
  1902.     // Parameters :
  1903.     // Return Values :
  1904.     // ---------------------------------------------------------------------------
  1905.     /**
  1906.      * Archive_Zip::_extractFile()
  1907.      *
  1908.      * { Description }
  1909.      *
  1910.      * @return int 
  1911.      */
  1912.     function _extractFile(&$p_entry$p_path$p_remove_path$p_remove_all_path&$p_params)
  1913.     {
  1914.         $v_result = 1;
  1915.  
  1916.         // ----- Read the file header
  1917.         if (($v_result $this->_readFileHeader($v_header)) != 1{
  1918.             return $v_result;
  1919.         }
  1920.  
  1921.         // ----- Check that the file header is coherent with $p_entry info
  1922.         // TBC
  1923.  
  1924.         // ----- Look for all path to remove
  1925.         if ($p_remove_all_path == true{
  1926.             // ----- Get the basename of the path
  1927.             $p_entry['filename'basename($p_entry['filename']);
  1928.         else if ($p_remove_path != ""{
  1929.             if ($this->_tool_PathInclusion($p_remove_path$p_entry['filename']== 2{
  1930.                 // ----- Change the file status
  1931.                 $p_entry['status'"filtered";
  1932.  
  1933.  
  1934.                 return $v_result;
  1935.             }
  1936.  
  1937.             $p_remove_path_size strlen($p_remove_path);
  1938.             if (substr($p_entry['filename']0$p_remove_path_size== $p_remove_path{
  1939.  
  1940.                 // ----- Remove the path
  1941.                 $p_entry['filename'substr($p_entry['filename']$p_remove_path_size);
  1942.             }
  1943.         }
  1944.  
  1945.         // ----- Add the path
  1946.         if ($p_path != ''{
  1947.             $p_entry['filename'$p_path."/".$p_entry['filename'];
  1948.         }
  1949.  
  1950.         // ----- Look for pre-extract callback
  1951.         if ((isset($p_params[ARCHIVE_ZIP_PARAM_PRE_EXTRACT]))
  1952.             && ($p_params[ARCHIVE_ZIP_PARAM_PRE_EXTRACT!= '')) {
  1953.  
  1954.             // ----- Generate a local information
  1955.             $v_local_header = array();
  1956.             $this->_convertHeader2FileInfo($p_entry$v_local_header);
  1957.  
  1958.             // ----- Call the callback
  1959.             // Here I do not use call_user_func() because I need to send a reference to the
  1960.             // header.
  1961.             eval('$v_result = '.$p_params[ARCHIVE_ZIP_PARAM_PRE_EXTRACT].'(ARCHIVE_ZIP_PARAM_PRE_EXTRACT, $v_local_header);');
  1962.  
  1963.             if ($v_result == 0{
  1964.                 // ----- Change the file status
  1965.                 $p_entry['status'"skipped";
  1966.  
  1967.                 $v_result = 1;
  1968.             }
  1969.  
  1970.             // ----- Update the informations
  1971.             // Only some fields can be modified
  1972.             $p_entry['filename'$v_local_header['filename'];
  1973.         }
  1974.  
  1975.         // ----- Trace
  1976.  
  1977.         // ----- Look if extraction should be done
  1978.         if ($p_entry['status'== 'ok'{
  1979.  
  1980.             // ----- Look for specific actions while the file exist
  1981.             if (file_exists($p_entry['filename'])) {
  1982.                 // ----- Look if file is a directory
  1983.                 if (is_dir($p_entry['filename'])) {
  1984.                     // ----- Change the file status
  1985.                     $p_entry['status'"already_a_directory";
  1986.  
  1987.  
  1988.                     //return $v_result;
  1989.                 else if (!is_writeable($p_entry['filename'])) {
  1990.                     // ----- Look if file is write protected
  1991.                     // ----- Change the file status
  1992.                     $p_entry['status'"write_protected";
  1993.  
  1994.  
  1995.                     //return $v_result;
  1996.                 else if (filemtime($p_entry['filename']$p_entry['mtime']{
  1997.                     // ----- Look if the extracted file is older
  1998.                     // ----- Change the file status
  1999.                     $p_entry['status'"newer_exist";
  2000.  
  2001.  
  2002.                     //return $v_result;
  2003.                 }
  2004.             else {
  2005.  
  2006.                 // ----- Check the directory availability and create it if necessary
  2007.                 if ((($p_entry['external']&0x00000010)==0x00000010|| (substr($p_entry['filename']-1== '/')) {
  2008.                     $v_dir_to_check $p_entry['filename'];
  2009.                 else if (!strstr($p_entry['filename']"/")) {
  2010.                     $v_dir_to_check "";
  2011.                 else {
  2012.                     $v_dir_to_check dirname($p_entry['filename']);
  2013.                 }
  2014.  
  2015.                 if (($v_result $this->_dirCheck($v_dir_to_check(($p_entry['external']&0x00000010)==0x00000010))) != 1{
  2016.                     // ----- Change the file status
  2017.                     $p_entry['status'"path_creation_fail";
  2018.  
  2019.  
  2020.                     //return $v_result;
  2021.                     $v_result = 1;
  2022.                 }
  2023.             }
  2024.         }
  2025.  
  2026.         // ----- Look if extraction should be done
  2027.         if ($p_entry['status'== 'ok'{
  2028.  
  2029.             // ----- Do the extraction (if not a folder)
  2030.             if (!(($p_entry['external']&0x00000010)==0x00000010)) {
  2031.  
  2032.                 // ----- Look for not compressed file
  2033.                 if ($p_entry['compressed_size'== $p_entry['size']{
  2034.  
  2035.                     // ----- Opening destination file
  2036.                     if (($v_dest_file @fopen($p_entry['filename']'wb')) == 0{
  2037.  
  2038.                         // ----- Change the file status
  2039.                         $p_entry['status'"write_error";
  2040.  
  2041.  
  2042.                         return $v_result;
  2043.                     }
  2044.  
  2045.  
  2046.                     // ----- Read the file by ARCHIVE_ZIP_READ_BLOCK_SIZE octets blocks
  2047.                     $v_size $p_entry['compressed_size'];
  2048.                     while ($v_size != 0{
  2049.                         $v_read_size ($v_size ARCHIVE_ZIP_READ_BLOCK_SIZE ? $v_size ARCHIVE_ZIP_READ_BLOCK_SIZE);
  2050.  
  2051.                         $v_buffer fread($this->_zip_fd$v_read_size);
  2052.  
  2053.                         $v_binary_data pack('a'.$v_read_size$v_buffer);
  2054.  
  2055.                         @fwrite($v_dest_file$v_binary_data$v_read_size);
  2056.                         $v_size -= $v_read_size;
  2057.                     }
  2058.  
  2059.                     // ----- Closing the destination file
  2060.                     fclose($v_dest_file);
  2061.  
  2062.                     // ----- Change the file mtime
  2063.                     touch($p_entry['filename']$p_entry['mtime']);
  2064.                 else {
  2065.                     // ----- Trace
  2066.  
  2067.                     // ----- Opening destination file
  2068.                     if (($v_dest_file @fopen($p_entry['filename']'wb')) == 0{
  2069.  
  2070.                         // ----- Change the file status
  2071.                         $p_entry['status'"write_error";
  2072.  
  2073.                         return $v_result;
  2074.                     }
  2075.  
  2076.  
  2077.                     // ----- Read the compressed file in a buffer (one shot)
  2078.                     $v_buffer @fread($this->_zip_fd$p_entry['compressed_size']);
  2079.  
  2080.                     // ----- Decompress the file
  2081.                     $v_file_content gzinflate($v_buffer);
  2082.                     unset($v_buffer);
  2083.  
  2084.                     // ----- Write the uncompressed data
  2085.                     @fwrite($v_dest_file$v_file_content$p_entry['size']);
  2086.                     unset($v_file_content);
  2087.  
  2088.                     // ----- Closing the destination file
  2089.                     @fclose($v_dest_file);
  2090.  
  2091.                     // ----- Change the file mtime
  2092.                     touch($p_entry['filename']$p_entry['mtime']);
  2093.                 }
  2094.  
  2095.                 // ----- Look for chmod option
  2096.                 if ((isset($p_params[ARCHIVE_ZIP_PARAM_SET_CHMOD]))
  2097.                     && ($p_params[ARCHIVE_ZIP_PARAM_SET_CHMOD!= 0)) {
  2098.  
  2099.                     // ----- Change the mode of the file
  2100.                     chmod($p_entry['filename']$p_params[ARCHIVE_ZIP_PARAM_SET_CHMOD]);
  2101.                 }
  2102.             }
  2103.         }
  2104.  
  2105.         // ----- Look for post-extract callback
  2106.         if ((isset($p_params[ARCHIVE_ZIP_PARAM_POST_EXTRACT]))
  2107.         && ($p_params[ARCHIVE_ZIP_PARAM_POST_EXTRACT!= '')) {
  2108.  
  2109.             // ----- Generate a local information
  2110.             $v_local_header = array();
  2111.             $this->_convertHeader2FileInfo($p_entry$v_local_header);
  2112.  
  2113.             // ----- Call the callback
  2114.             // Here I do not use call_user_func() because I need to send a reference to the
  2115.             // header.
  2116.             eval('$v_result = '.$p_params[ARCHIVE_ZIP_PARAM_POST_EXTRACT].'(ARCHIVE_ZIP_PARAM_POST_EXTRACT, $v_local_header);');
  2117.         }
  2118.  
  2119.  
  2120.         return $v_result;
  2121.     }
  2122.     // ---------------------------------------------------------------------------
  2123.  
  2124.     // ---------------------------------------------------------------------------
  2125.     // Function : _extractFileAsString()
  2126.     // Description :
  2127.     // Parameters :
  2128.     // Return Values :
  2129.     // ---------------------------------------------------------------------------
  2130.     /**
  2131.      * Archive_Zip::_extractFileAsString()
  2132.      *
  2133.      * { Description }
  2134.      *
  2135.      * @return int 
  2136.      */
  2137.     function _extractFileAsString(&$p_entry&$p_string)
  2138.     {
  2139.         $v_result = 1;
  2140.  
  2141.         // ----- Read the file header
  2142.         $v_header = array();
  2143.         if (($v_result $this->_readFileHeader($v_header)) != 1{
  2144.             return $v_result;
  2145.         }
  2146.  
  2147.         // ----- Check that the file header is coherent with $p_entry info
  2148.         // TBC
  2149.  
  2150.         // ----- Trace
  2151.  
  2152.         // ----- Do the extraction (if not a folder)
  2153.         if (!(($p_entry['external']&0x00000010)==0x00000010)) {
  2154.             // ----- Look for not compressed file
  2155.             if ($p_entry['compressed_size'== $p_entry['size']{
  2156.                 // ----- Trace
  2157.  
  2158.                 // ----- Reading the file
  2159.                 $p_string fread($this->_zip_fd$p_entry['compressed_size']);
  2160.             else {
  2161.                 // ----- Trace
  2162.  
  2163.                 // ----- Reading the file
  2164.                 $v_data fread($this->_zip_fd$p_entry['compressed_size']);
  2165.  
  2166.                 // ----- Decompress the file
  2167.                 $p_string gzinflate($v_data);
  2168.             }
  2169.  
  2170.             // ----- Trace
  2171.         else {
  2172.             // TBC : error : can not extract a folder in a string
  2173.         }
  2174.  
  2175.  
  2176.         return $v_result;
  2177.     }
  2178.     // ---------------------------------------------------------------------------
  2179.  
  2180.     // ---------------------------------------------------------------------------
  2181.     // Function : _readFileHeader()
  2182.     // Description :
  2183.     // Parameters :
  2184.     // Return Values :
  2185.     // ---------------------------------------------------------------------------
  2186.     /**
  2187.      * Archive_Zip::_readFileHeader()
  2188.      *
  2189.      * { Description }
  2190.      *
  2191.      * @return int 
  2192.      */
  2193.     function _readFileHeader(&$p_header)
  2194.     {
  2195.         $v_result = 1;
  2196.  
  2197.         // ----- Read the 4 bytes signature
  2198.         $v_binary_data @fread($this->_zip_fd4);
  2199.  
  2200.         $v_data unpack('Vid'$v_binary_data);
  2201.  
  2202.         // ----- Check signature
  2203.         if ($v_data['id'!= 0x04034b50{
  2204.  
  2205.             // ----- Error log
  2206.             $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT'Invalid archive structure');
  2207.  
  2208.  
  2209.             return Archive_Zip::errorCode();
  2210.         }
  2211.  
  2212.         // ----- Read the first 42 bytes of the header
  2213.         $v_binary_data fread($this->_zip_fd26);
  2214.  
  2215.         // ----- Look for invalid block size
  2216.         if (strlen($v_binary_data!= 26{
  2217.             $p_header['filename'"";
  2218.             $p_header['status']   "invalid_header";
  2219.  
  2220.             // ----- Error log
  2221.             $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT"Invalid block size : ".strlen($v_binary_data));
  2222.  
  2223.  
  2224.             return Archive_Zip::errorCode();
  2225.         }
  2226.  
  2227.         // ----- Extract the values
  2228.         $v_data unpack('vversion/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len'$v_binary_data);
  2229.  
  2230.         // ----- Get filename
  2231.         $p_header['filename'fread($this->_zip_fd$v_data['filename_len']);
  2232.  
  2233.         // ----- Get extra_fields
  2234.         if ($v_data['extra_len'!= 0{
  2235.             $p_header['extra'fread($this->_zip_fd$v_data['extra_len']);
  2236.         else {
  2237.             $p_header['extra''';
  2238.         }
  2239.  
  2240.         // ----- Extract properties
  2241.         $p_header['compression']     $v_data['compression'];
  2242.         $p_header['size']            $v_data['size'];
  2243.         $p_header['compressed_size'$v_data['compressed_size'];
  2244.         $p_header['crc']             $v_data['crc'];
  2245.         $p_header['flag']            $v_data['flag'];
  2246.  
  2247.         // ----- Recuperate date in UNIX format
  2248.         $p_header['mdate'$v_data['mdate'];
  2249.         $p_header['mtime'$v_data['mtime'];
  2250.         if ($p_header['mdate'&& $p_header['mtime']{
  2251.             // ----- Extract time
  2252.             $v_hour    ($p_header['mtime'0xF800>> 11;
  2253.             $v_minute  ($p_header['mtime'0x07E0>> 5;
  2254.             $v_seconde ($p_header['mtime'0x001F)*2;
  2255.  
  2256.             // ----- Extract date
  2257.             $v_year  (($p_header['mdate'0xFE00>> 9+ 1980;
  2258.             $v_month ($p_header['mdate'0x01E0>> 5;
  2259.             $v_day   $p_header['mdate'0x001F;
  2260.  
  2261.             // ----- Get UNIX date format
  2262.             $p_header['mtime'mktime($v_hour$v_minute$v_seconde$v_month$v_day$v_year);
  2263.  
  2264.         else {
  2265.             $p_header['mtime'time();
  2266.         }
  2267.  
  2268.         // ----- Other informations
  2269.  
  2270.         // TBC
  2271.         //for(reset($v_data); $key = key($v_data); next($v_data)) {
  2272.         //}
  2273.  
  2274.         // ----- Set the stored filename
  2275.         $p_header['stored_filename'$p_header['filename'];
  2276.  
  2277.         // ----- Set the status field
  2278.         $p_header['status'"ok";
  2279.  
  2280.  
  2281.         return $v_result;
  2282.     }
  2283.     // ---------------------------------------------------------------------------
  2284.  
  2285.     // ---------------------------------------------------------------------------
  2286.     // Function : _readCentralFileHeader()
  2287.     // Description :
  2288.     // Parameters :
  2289.     // Return Values :
  2290.     // ---------------------------------------------------------------------------
  2291.     /**
  2292.      * Archive_Zip::_readCentralFileHeader()
  2293.      *
  2294.      * { Description }
  2295.      *
  2296.      * @return int 
  2297.      */
  2298.     function _readCentralFileHeader(&$p_header)
  2299.     {
  2300.         $v_result = 1;
  2301.  
  2302.         // ----- Read the 4 bytes signature
  2303.         $v_binary_data @fread($this->_zip_fd4);
  2304.  
  2305.         $v_data unpack('Vid'$v_binary_data);
  2306.  
  2307.         // ----- Check signature
  2308.         if ($v_data['id'!= 0x02014b50{
  2309.  
  2310.             // ----- Error log
  2311.             $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT'Invalid archive structure');
  2312.  
  2313.  
  2314.             return Archive_Zip::errorCode();
  2315.         }
  2316.  
  2317.         // ----- Read the first 42 bytes of the header
  2318.         $v_binary_data fread($this->_zip_fd42);
  2319.  
  2320.         // ----- Look for invalid block size
  2321.         if (strlen($v_binary_data!= 42{
  2322.             $p_header['filename'"";
  2323.             $p_header['status']   "invalid_header";
  2324.  
  2325.             // ----- Error log
  2326.             $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT"Invalid block size : ".strlen($v_binary_data));
  2327.  
  2328.  
  2329.             return Archive_Zip::errorCode();
  2330.         }
  2331.  
  2332.         // ----- Extract the values
  2333.         $p_header unpack('vversion/vversion_extracted/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len/vcomment_len/vdisk/vinternal/Vexternal/Voffset'$v_binary_data);
  2334.  
  2335.         // ----- Get filename
  2336.         if ($p_header['filename_len'!= 0{
  2337.             $p_header['filename'fread($this->_zip_fd$p_header['filename_len']);
  2338.         else {
  2339.             $p_header['filename''';
  2340.         }
  2341.  
  2342.         // ----- Get extra
  2343.         if ($p_header['extra_len'!= 0{
  2344.             $p_header['extra'fread($this->_zip_fd$p_header['extra_len']);
  2345.         else {
  2346.             $p_header['extra''';
  2347.         }
  2348.  
  2349.         // ----- Get comment
  2350.         if ($p_header['comment_len'!= 0{
  2351.             $p_header['comment'fread($this->_zip_fd$p_header['comment_len']);
  2352.         else {
  2353.             $p_header['comment''';
  2354.         }
  2355.  
  2356.         // ----- Extract properties
  2357.  
  2358.         // ----- Recuperate date in UNIX format
  2359.         if ($p_header['mdate'&& $p_header['mtime']{
  2360.             // ----- Extract time
  2361.             $v_hour    ($p_header['mtime'0xF800>> 11;
  2362.             $v_minute  ($p_header['mtime'0x07E0>> 5;
  2363.             $v_seconde ($p_header['mtime'0x001F)*2;
  2364.  
  2365.             // ----- Extract date
  2366.             $v_year  (($p_header['mdate'0xFE00>> 9+ 1980;
  2367.             $v_month ($p_header['mdate'0x01E0>> 5;
  2368.             $v_day   $p_header['mdate'0x001F;
  2369.  
  2370.             // ----- Get UNIX date format
  2371.             $p_header['mtime'mktime($v_hour$v_minute$v_seconde$v_month$v_day$v_year);
  2372.  
  2373.         else {
  2374.             $p_header['mtime'time();
  2375.         }
  2376.  
  2377.         // ----- Set the stored filename
  2378.         $p_header['stored_filename'$p_header['filename'];
  2379.  
  2380.         // ----- Set default status to ok
  2381.         $p_header['status''ok';
  2382.  
  2383.         // ----- Look if it is a directory
  2384.         if (substr($p_header['filename']-1== '/'{
  2385.             $p_header['external'= 0x41FF0010;
  2386.         }
  2387.  
  2388.         return $v_result;
  2389.     }
  2390.     // ---------------------------------------------------------------------------
  2391.  
  2392.     // ---------------------------------------------------------------------------
  2393.     // Function : _readEndCentralDir()
  2394.     // Description :
  2395.     // Parameters :
  2396.     // Return Values :
  2397.     // ---------------------------------------------------------------------------
  2398.     /**
  2399.      * Archive_Zip::_readEndCentralDir()
  2400.      *
  2401.      * { Description }
  2402.      *
  2403.      * @return int 
  2404.      */
  2405.     function _readEndCentralDir(&$p_central_dir)
  2406.     {
  2407.         $v_result = 1;
  2408.  
  2409.         // ----- Go to the end of the zip file
  2410.         $v_size filesize($this->_zipname);
  2411.         @fseek($this->_zip_fd$v_size);
  2412.  
  2413.         if (@ftell($this->_zip_fd!= $v_size{
  2414.             $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT,
  2415.                            'Unable to go to the end of the archive \''
  2416.                            .$this->_zipname.'\'');
  2417.             return Archive_Zip::errorCode();
  2418.         }
  2419.  
  2420.         // ----- First try : look if this is an archive with no commentaries
  2421.         // (most of the time)
  2422.         // in this case the end of central dir is at 22 bytes of the file end
  2423.         $v_found = 0;
  2424.         if ($v_size > 26{
  2425.             @fseek($this->_zip_fd$v_size-22);
  2426.  
  2427.             if (($v_pos @ftell($this->_zip_fd)) != ($v_size-22)) {
  2428.                 $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT,
  2429.                                  'Unable to seek back to the middle of the archive \''
  2430.                                  .$this->_zipname.'\'');
  2431.                 return Archive_Zip::errorCode();
  2432.             }
  2433.  
  2434.             // ----- Read for bytes
  2435.             $v_binary_data @fread($this->_zip_fd4);
  2436.  
  2437.             $v_data unpack('Vid'$v_binary_data);
  2438.  
  2439.             // ----- Check signature
  2440.             if ($v_data['id'== 0x06054b50{
  2441.                 $v_found = 1;
  2442.             }
  2443.  
  2444.             $v_pos ftell($this->_zip_fd);
  2445.         }
  2446.  
  2447.         // ----- Go back to the maximum possible size of the Central Dir End Record
  2448.         if (!$v_found{
  2449.             $v_maximum_size = 65557; // 0xFFFF + 22;
  2450.             if ($v_maximum_size $v_size{
  2451.                 $v_maximum_size $v_size;
  2452.             }
  2453.             @fseek($this->_zip_fd$v_size-$v_maximum_size);
  2454.             if (@ftell($this->_zip_fd!= ($v_size-$v_maximum_size)) {
  2455.                 $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT,
  2456.                                  'Unable to seek back to the middle of the archive \''
  2457.                                  .$this->_zipname.'\'');
  2458.                 return Archive_Zip::errorCode();
  2459.             }
  2460.  
  2461.             // ----- Read byte per byte in order to find the signature
  2462.             $v_pos   ftell($this->_zip_fd);
  2463.             $v_bytes = 0x00000000;
  2464.             while ($v_pos $v_size{
  2465.                 // ----- Read a byte
  2466.                 $v_byte @fread($this->_zip_fd1);
  2467.  
  2468.                 // -----  Add the byte
  2469.                 $v_bytes ($v_bytes << 8| Ord($v_byte);
  2470.  
  2471.                 // ----- Compare the bytes
  2472.                 if ($v_bytes == 0x504b0506{
  2473.                     $v_pos++;
  2474.                     break;
  2475.                 }
  2476.  
  2477.                 $v_pos++;
  2478.             }
  2479.  
  2480.             // ----- Look if not found end of central dir
  2481.             if ($v_pos == $v_size{
  2482.                 $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT,
  2483.                                  "Unable to find End of Central Dir Record signature");
  2484.                 return Archive_Zip::errorCode();
  2485.             }
  2486.         }
  2487.  
  2488.         // ----- Read the first 18 bytes of the header
  2489.         $v_binary_data fread($this->_zip_fd18);
  2490.  
  2491.         // ----- Look for invalid block size
  2492.         if (strlen($v_binary_data!= 18{
  2493.             $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT,
  2494.                            "Invalid End of Central Dir Record size : "
  2495.                            .strlen($v_binary_data));
  2496.             return Archive_Zip::errorCode();
  2497.         }
  2498.  
  2499.         // ----- Extract the values
  2500.         $v_data unpack('vdisk/vdisk_start/vdisk_entries/ventries/Vsize/Voffset/vcomment_size'$v_binary_data);
  2501.  
  2502.         // ----- Check the global size
  2503.         if (($v_pos $v_data['comment_size'+ 18!= $v_size{
  2504.             $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT,
  2505.                            "Fail to find the right signature");
  2506.             return Archive_Zip::errorCode();
  2507.         }
  2508.  
  2509.         // ----- Get comment
  2510.         if ($v_data['comment_size'!= 0{
  2511.             $p_central_dir['comment'fread($this->_zip_fd$v_data['comment_size']);
  2512.         else {
  2513.             $p_central_dir['comment''';
  2514.         }
  2515.  
  2516.         $p_central_dir['entries']      $v_data['entries'];
  2517.         $p_central_dir['disk_entries'$v_data['disk_entries'];
  2518.         $p_central_dir['offset']       $v_data['offset'];
  2519.         $p_central_dir['size']         $v_data['size'];
  2520.         $p_central_dir['disk']         $v_data['disk'];
  2521.         $p_central_dir['disk_start']   $v_data['disk_start'];
  2522.  
  2523.  
  2524.         return $v_result;
  2525.     }
  2526.     // ---------------------------------------------------------------------------
  2527.  
  2528.     // ---------------------------------------------------------------------------
  2529.     // Function : _deleteByRule()
  2530.     // Description :
  2531.     // Parameters :
  2532.     // Return Values :
  2533.     // ---------------------------------------------------------------------------
  2534.     /**
  2535.      * Archive_Zip::_deleteByRule()
  2536.      *
  2537.      * { Description }
  2538.      *
  2539.      * @return int 
  2540.      */
  2541.     function _deleteByRule(&$p_result_list&$p_params)
  2542.     {
  2543.         $v_result = 1;
  2544.  
  2545.         $v_list_detail = array();
  2546.  
  2547.         // ----- Open the zip file
  2548.         if (($v_result $this->_openFd('rb')) != 1{
  2549.  
  2550.             return $v_result;
  2551.         }
  2552.  
  2553.         // ----- Read the central directory informations
  2554.         $v_central_dir = array();
  2555.         if (($v_result $this->_readEndCentralDir($v_central_dir)) != 1{
  2556.             $this->_closeFd();
  2557.             return $v_result;
  2558.         }
  2559.  
  2560.         // ----- Go to beginning of File
  2561.         @rewind($this->_zip_fd);
  2562.  
  2563.         // ----- Scan all the files
  2564.         // ----- Start at beginning of Central Dir
  2565.         $v_pos_entry $v_central_dir['offset'];
  2566.         @rewind($this->_zip_fd);
  2567.         if (@fseek($this->_zip_fd$v_pos_entry)) {
  2568.             // ----- Clean
  2569.             $this->_closeFd();
  2570.  
  2571.             $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_ARCHIVE_ZIP,
  2572.                            'Invalid archive size');
  2573.             return Archive_Zip::errorCode();
  2574.         }
  2575.  
  2576.         // ----- Read each entry
  2577.         $v_header_list = array();
  2578.  
  2579.         $j_start = 0;
  2580.         for ($i = 0$v_nb_extracted = 0; $i<$v_central_dir['entries']$i++{
  2581.  
  2582.             // ----- Read the file header
  2583.             $v_header_list[$v_nb_extracted= array();
  2584.  
  2585.             $v_result $this->_readCentralFileHeader($v_header_list[$v_nb_extracted]);
  2586.             if ($v_result != 1{
  2587.                 // ----- Clean
  2588.                 $this->_closeFd();
  2589.  
  2590.                 return $v_result;
  2591.             }
  2592.  
  2593.             // ----- Store the index
  2594.             $v_header_list[$v_nb_extracted]['index'$i;
  2595.  
  2596.             // ----- Look for the specific extract rules
  2597.             $v_found = false;
  2598.  
  2599.             // ----- Look for extract by name rule
  2600.             if ((isset($p_params[ARCHIVE_ZIP_PARAM_BY_NAME]))
  2601.                 && ($p_params[ARCHIVE_ZIP_PARAM_BY_NAME!= 0)) {
  2602.  
  2603.                 // ----- Look if the filename is in the list
  2604.                 for ($j = 0; ($j<sizeof($p_params[ARCHIVE_ZIP_PARAM_BY_NAME])) && (!$v_found)$j++{
  2605.  
  2606.                     // ----- Look for a directory
  2607.                     if (substr($p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j]-1== "/"{
  2608.  
  2609.                         // ----- Look if the directory is in the filename path
  2610.                         if (   (strlen($v_header_list[$v_nb_extracted]['stored_filename']strlen($p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j]))
  2611.                             && (substr($v_header_list[$v_nb_extracted]['stored_filename']0strlen($p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j])) == $p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j])) {
  2612.                             $v_found = true;
  2613.                         elseif ((($v_header_list[$v_nb_extracted]['external']&0x00000010)==0x00000010/* Indicates a folder */
  2614.                               && ($v_header_list[$v_nb_extracted]['stored_filename'].'/' == $p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j])) {
  2615.                             $v_found = true;
  2616.                         }
  2617.                     elseif ($v_header_list[$v_nb_extracted]['stored_filename'== $p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j]{
  2618.                         // ----- Look for a filename
  2619.                         $v_found = true;
  2620.                     }
  2621.                 }
  2622.             else if ((isset($p_params[ARCHIVE_ZIP_PARAM_BY_PREG]))
  2623.                    && ($p_params[ARCHIVE_ZIP_PARAM_BY_PREG!= "")) {
  2624.                 // ----- Look for extract by preg rule
  2625.                 if (preg_match($p_params[ARCHIVE_ZIP_PARAM_BY_PREG],
  2626.                              $v_header_list[$v_nb_extracted]['stored_filename'])) {
  2627.                     $v_found = true;
  2628.                 }
  2629.             else if ((isset($p_params[ARCHIVE_ZIP_PARAM_BY_INDEX]))
  2630.                    && ($p_params[ARCHIVE_ZIP_PARAM_BY_INDEX!= 0)) {
  2631.                 // ----- Look for extract by index rule
  2632.  
  2633.                 // ----- Look if the index is in the list
  2634.                 for ($j $j_start($j<sizeof($p_params[ARCHIVE_ZIP_PARAM_BY_INDEX])) && (!$v_found)$j++{
  2635.  
  2636.                     if (($i>=$p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['start'])
  2637.                         && ($i<=$p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['end'])) {
  2638.                         $v_found = true;
  2639.                     }
  2640.                     if ($i>=$p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['end']{
  2641.                         $j_start $j+1;
  2642.                     }
  2643.  
  2644.                     if ($p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['start']>$i{
  2645.                         break;
  2646.                     }
  2647.                 }
  2648.             }
  2649.  
  2650.             // ----- Look for deletion
  2651.             if ($v_found{
  2652.                 unset($v_header_list[$v_nb_extracted]);
  2653.             else {
  2654.                 $v_nb_extracted++;
  2655.             }
  2656.         }
  2657.  
  2658.         // ----- Look if something need to be deleted
  2659.         if ($v_nb_extracted > 0{
  2660.  
  2661.             // ----- Creates a temporay file
  2662.             $v_zip_temp_name ARCHIVE_ZIP_TEMPORARY_DIR.uniqid('archive_zip-')
  2663.                                .'.tmp';
  2664.  
  2665.             // ----- Creates a temporary zip archive
  2666.             $v_temp_zip = new Archive_Zip($v_zip_temp_name);
  2667.  
  2668.             // ----- Open the temporary zip file in write mode
  2669.             if (($v_result $v_temp_zip->_openFd('wb')) != 1{
  2670.                 $this->_closeFd();
  2671.  
  2672.  
  2673.                 return $v_result;
  2674.             }
  2675.  
  2676.             // ----- Look which file need to be kept
  2677.             for ($i = 0; $i<sizeof($v_header_list)$i++{
  2678.  
  2679.                 // ----- Calculate the position of the header
  2680.                 @rewind($this->_zip_fd);
  2681.                 if (@fseek($this->_zip_fd,  $v_header_list[$i]['offset'])) {
  2682.                     // ----- Clean
  2683.                     $this->_closeFd();
  2684.                     $v_temp_zip->_closeFd();
  2685.                     @unlink($v_zip_temp_name);
  2686.  
  2687.                     $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_ARCHIVE_ZIP,
  2688.                                      'Invalid archive size');
  2689.                     return Archive_Zip::errorCode();
  2690.                 }
  2691.  
  2692.                 // ----- Read the file header
  2693.                 if (($v_result $this->_readFileHeader($v_header_list[$i])) != 1{
  2694.                     // ----- Clean
  2695.                     $this->_closeFd();
  2696.                     $v_temp_zip->_closeFd();
  2697.                     @unlink($v_zip_temp_name);
  2698.  
  2699.                     return $v_result;
  2700.                 }
  2701.  
  2702.                 // ----- Write the file header
  2703.                 $v_result $v_temp_zip->_writeFileHeader($v_header_list[$i]);
  2704.                 if ($v_result != 1{
  2705.                     // ----- Clean
  2706.                     $this->_closeFd();
  2707.                     $v_temp_zip->_closeFd();
  2708.                     @unlink($v_zip_temp_name);
  2709.  
  2710.                     return $v_result;
  2711.                 }
  2712.  
  2713.                 // ----- Read/write the data block
  2714.                 $v_result $this->_tool_CopyBlock($this->_zip_fd,
  2715.                                                    $v_temp_zip->_zip_fd,
  2716.                                            $v_header_list[$i]['compressed_size']);
  2717.                 if ($v_result != 1{
  2718.                     // ----- Clean
  2719.                     $this->_closeFd();
  2720.                     $v_temp_zip->_closeFd();
  2721.                     @unlink($v_zip_temp_name);
  2722.  
  2723.                     return $v_result;
  2724.                 }
  2725.             }
  2726.  
  2727.             // ----- Store the offset of the central dir
  2728.             $v_offset @ftell($v_temp_zip->_zip_fd);
  2729.  
  2730.             // ----- Re-Create the Central Dir files header
  2731.             for ($i = 0; $i<sizeof($v_header_list)$i++{
  2732.                 // ----- Create the file header
  2733.                 $v_result $v_temp_zip->_writeCentralFileHeader($v_header_list[$i]);
  2734.                 if ($v_result != 1{
  2735.                     // ----- Clean
  2736.                     $v_temp_zip->_closeFd();
  2737.                     $this->_closeFd();
  2738.                     @unlink($v_zip_temp_name);
  2739.  
  2740.                     return $v_result;
  2741.                 }
  2742.  
  2743.                 // ----- Transform the header to a 'usable' info
  2744.                 $v_temp_zip->_convertHeader2FileInfo($v_header_list[$i],
  2745.                                                      $p_result_list[$i]);
  2746.             }
  2747.  
  2748.  
  2749.             // ----- Zip file comment
  2750.             $v_comment '';
  2751.  
  2752.             // ----- Calculate the size of the central header
  2753.             $v_size @ftell($v_temp_zip->_zip_fd)-$v_offset;
  2754.  
  2755.             // ----- Create the central dir footer
  2756.             $v_result $v_temp_zip->_writeCentralHeader(sizeof($v_header_list),
  2757.                                                          $v_size$v_offset,
  2758.                                                          $v_comment);
  2759.             if ($v_result != 1{
  2760.                 // ----- Clean
  2761.                 unset($v_header_list);
  2762.                 $v_temp_zip->_closeFd();
  2763.                 $this->_closeFd();
  2764.                 @unlink($v_zip_temp_name);
  2765.  
  2766.                 return $v_result;
  2767.             }
  2768.  
  2769.             // ----- Close
  2770.             $v_temp_zip->_closeFd();
  2771.             $this->_closeFd();
  2772.  
  2773.             // ----- Delete the zip file
  2774.             // TBC : I should test the result ...
  2775.             @unlink($this->_zipname);
  2776.  
  2777.             // ----- Rename the temporary file
  2778.             // TBC : I should test the result ...
  2779.             //@rename($v_zip_temp_name, $this->_zipname);
  2780.             $this->_tool_Rename($v_zip_temp_name$this->_zipname);
  2781.  
  2782.             // ----- Destroy the temporary archive
  2783.             unset($v_temp_zip);
  2784.         }
  2785.  
  2786.  
  2787.         return $v_result;
  2788.     }
  2789.     // ---------------------------------------------------------------------------
  2790.  
  2791.     // ---------------------------------------------------------------------------
  2792.     // Function : _dirCheck()
  2793.     // Description :
  2794.     //   Check if a directory exists, if not it creates it and all the parents directory
  2795.     //   which may be useful.
  2796.     // Parameters :
  2797.     //   $p_dir : Directory path to check.
  2798.     // Return Values :
  2799.     //    1 : OK
  2800.     //   -1 : Unable to create directory
  2801.     // ---------------------------------------------------------------------------
  2802.     /**
  2803.      * Archive_Zip::_dirCheck()
  2804.      *
  2805.      * { Description }
  2806.      *
  2807.      * @param [type] $p_is_dir 
  2808.      * @return int 
  2809.      */
  2810.     function _dirCheck($p_dir$p_is_dir = false)
  2811.     {
  2812.         $v_result = 1;
  2813.  
  2814.         // ----- Remove the final '/'
  2815.         if (($p_is_dir&& (substr($p_dir-1)=='/')) {
  2816.             $p_dir substr($p_dir0strlen($p_dir)-1);
  2817.         }
  2818.  
  2819.         // ----- Check the directory availability
  2820.         if ((is_dir($p_dir)) || ($p_dir == "")) {
  2821.             return 1;
  2822.         }
  2823.  
  2824.         // ----- Extract parent directory
  2825.         $p_parent_dir dirname($p_dir);
  2826.  
  2827.         // ----- Just a check
  2828.         if ($p_parent_dir != $p_dir{
  2829.             // ----- Look for parent directory
  2830.             if ($p_parent_dir != ""{
  2831.                 if (($v_result $this->_dirCheck($p_parent_dir)) != 1{
  2832.                     return $v_result;
  2833.                 }
  2834.             }
  2835.         }
  2836.  
  2837.         // ----- Create the directory
  2838.         if (!@mkdir($p_dir0777)) {
  2839.             $this->_errorLog(ARCHIVE_ZIP_ERR_DIR_CREATE_FAIL,
  2840.                        "Unable to create directory '$p_dir'");
  2841.             return Archive_Zip::errorCode();
  2842.         }
  2843.  
  2844.  
  2845.         return $v_result;
  2846.     }
  2847.     // ---------------------------------------------------------------------------
  2848.  
  2849.     // ---------------------------------------------------------------------------
  2850.     // Function : _merge()
  2851.     // Description :
  2852.     //   If $p_archive_to_add does not exist, the function exit with a success result.
  2853.     // Parameters :
  2854.     // Return Values :
  2855.     // ---------------------------------------------------------------------------
  2856.     /**
  2857.      * Archive_Zip::_merge()
  2858.      *
  2859.      * { Description }
  2860.      *
  2861.      * @return int 
  2862.      */
  2863.     function _merge(&$p_archive_to_add)
  2864.     {
  2865.         $v_result = 1;
  2866.  
  2867.         // ----- Look if the archive_to_add exists
  2868.         if (!is_file($p_archive_to_add->_zipname)) {
  2869.             // ----- Nothing to merge, so merge is a success
  2870.             return 1;
  2871.         }
  2872.  
  2873.         // ----- Look if the archive exists
  2874.         if (!is_file($this->_zipname)) {
  2875.             // ----- Do a duplicate
  2876.             $v_result $this->_duplicate($p_archive_to_add->_zipname);
  2877.  
  2878.             return $v_result;
  2879.         }
  2880.  
  2881.         // ----- Open the zip file
  2882.         if (($v_result $this->_openFd('rb')) != 1{
  2883.             return $v_result;
  2884.         }
  2885.  
  2886.         // ----- Read the central directory informations
  2887.         $v_central_dir = array();
  2888.         if (($v_result $this->_readEndCentralDir($v_central_dir)) != 1{
  2889.             $this->_closeFd();
  2890.             return $v_result;
  2891.         }
  2892.  
  2893.         // ----- Go to beginning of File
  2894.         @rewind($this->_zip_fd);
  2895.  
  2896.         // ----- Open the archive_to_add file
  2897.         if (($v_result $p_archive_to_add->_openFd('rb')) != 1{
  2898.             $this->_closeFd();
  2899.             return $v_result;
  2900.         }
  2901.  
  2902.         // ----- Read the central directory informations
  2903.         $v_central_dir_to_add = array();
  2904.  
  2905.         $v_result $p_archive_to_add->_readEndCentralDir($v_central_dir_to_add);
  2906.         if ($v_result != 1{
  2907.             $this->_closeFd();
  2908.             $p_archive_to_add->_closeFd();
  2909.             return $v_result;
  2910.         }
  2911.  
  2912.         // ----- Go to beginning of File
  2913.         @rewind($p_archive_to_add->_zip_fd);
  2914.  
  2915.         // ----- Creates a temporay file
  2916.         $v_zip_temp_name ARCHIVE_ZIP_TEMPORARY_DIR.uniqid('archive_zip-').'.tmp';
  2917.  
  2918.         // ----- Open the temporary file in write mode
  2919.         if (($v_zip_temp_fd @fopen($v_zip_temp_name'wb')) == 0{
  2920.             $this->_closeFd();
  2921.             $p_archive_to_add->_closeFd();
  2922.             $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL,
  2923.                            'Unable to open temporary file \''
  2924.                            .$v_zip_temp_name.'\' in binary write mode');
  2925.             return Archive_Zip::errorCode();
  2926.         }
  2927.  
  2928.         // ----- Copy the files from the archive to the temporary file
  2929.         // TBC : Here I should better append the file and go back to erase the
  2930.         // central dir
  2931.         $v_size $v_central_dir['offset'];
  2932.         while ($v_size != 0{
  2933.             $v_read_size ($v_size ARCHIVE_ZIP_READ_BLOCK_SIZE
  2934.                           ? $v_size ARCHIVE_ZIP_READ_BLOCK_SIZE);
  2935.  
  2936.             $v_buffer fread($this->_zip_fd$v_read_size);
  2937.  
  2938.             @fwrite($v_zip_temp_fd$v_buffer$v_read_size);
  2939.             $v_size -= $v_read_size;
  2940.         }
  2941.  
  2942.         // ----- Copy the files from the archive_to_add into the temporary file
  2943.         $v_size $v_central_dir_to_add['offset'];
  2944.         while ($v_size != 0{
  2945.             $v_read_size ($v_size ARCHIVE_ZIP_READ_BLOCK_SIZE
  2946.                           ? $v_size ARCHIVE_ZIP_READ_BLOCK_SIZE);
  2947.  
  2948.             $v_buffer fread($p_archive_to_add->_zip_fd$v_read_size);
  2949.  
  2950.             @fwrite($v_zip_temp_fd$v_buffer$v_read_size);
  2951.             $v_size -= $v_read_size;
  2952.         }
  2953.  
  2954.         // ----- Store the offset of the central dir
  2955.         $v_offset @ftell($v_zip_temp_fd);
  2956.  
  2957.         // ----- Copy the block of file headers from the old archive
  2958.         $v_size $v_central_dir['size'];
  2959.         while ($v_size != 0{
  2960.             $v_read_size ($v_size ARCHIVE_ZIP_READ_BLOCK_SIZE
  2961.                           ? $v_size ARCHIVE_ZIP_READ_BLOCK_SIZE);
  2962.  
  2963.             $v_buffer @fread($this->_zip_fd$v_read_size);
  2964.  
  2965.             @fwrite($v_zip_temp_fd$v_buffer$v_read_size);
  2966.             $v_size -= $v_read_size;
  2967.         }
  2968.  
  2969.         // ----- Copy the block of file headers from the archive_to_add
  2970.         $v_size $v_central_dir_to_add['size'];
  2971.         while ($v_size != 0{
  2972.             $v_read_size ($v_size ARCHIVE_ZIP_READ_BLOCK_SIZE
  2973.                           ? $v_size ARCHIVE_ZIP_READ_BLOCK_SIZE);
  2974.  
  2975.             $v_buffer @fread($p_archive_to_add->_zip_fd$v_read_size);
  2976.  
  2977.             @fwrite($v_zip_temp_fd$v_buffer$v_read_size);
  2978.             $v_size -= $v_read_size;
  2979.         }
  2980.  
  2981.         // ----- Zip file comment
  2982.         // TBC : I should merge the two comments
  2983.         $v_comment '';
  2984.  
  2985.         // ----- Calculate the size of the (new) central header
  2986.         $v_size @ftell($v_zip_temp_fd)-$v_offset;
  2987.  
  2988.         // ----- Swap the file descriptor
  2989.         // Here is a trick : I swap the temporary fd with the zip fd, in order to use
  2990.         // the following methods on the temporary fil and not the real archive fd
  2991.         $v_swap $this->_zip_fd;
  2992.  
  2993.         $this->_zip_fd $v_zip_temp_fd;
  2994.         $v_zip_temp_fd $v_swap;
  2995.  
  2996.         // ----- Create the central dir footer
  2997.         if (($v_result $this->_writeCentralHeader($v_central_dir['entries']
  2998.                                               +$v_central_dir_to_add['entries'],
  2999.                                                 $v_size$v_offset,
  3000.                                                 $v_comment)) != 1{
  3001.             $this->_closeFd();
  3002.             $p_archive_to_add->_closeFd();
  3003.             @fclose($v_zip_temp_fd);
  3004.             $this->_zip_fd = null;
  3005.  
  3006.             // ----- Reset the file list
  3007.             unset($v_header_list);
  3008.  
  3009.  
  3010.             return $v_result;
  3011.         }
  3012.  
  3013.         // ----- Swap back the file descriptor
  3014.         $v_swap $this->_zip_fd;
  3015.  
  3016.         $this->_zip_fd $v_zip_temp_fd;
  3017.         $v_zip_temp_fd $v_swap;
  3018.  
  3019.         // ----- Close
  3020.         $this->_closeFd();
  3021.         $p_archive_to_add->_closeFd();
  3022.  
  3023.         // ----- Close the temporary file
  3024.         @fclose($v_zip_temp_fd);
  3025.  
  3026.         // ----- Delete the zip file
  3027.         // TBC : I should test the result ...
  3028.         @unlink($this->_zipname);
  3029.  
  3030.         // ----- Rename the temporary file
  3031.         // TBC : I should test the result ...
  3032.         //@rename($v_zip_temp_name, $this->_zipname);
  3033.         $this->_tool_Rename($v_zip_temp_name$this->_zipname);
  3034.  
  3035.  
  3036.         return $v_result;
  3037.     }
  3038.     // ---------------------------------------------------------------------------
  3039.  
  3040.     // ---------------------------------------------------------------------------
  3041.     // Function : _duplicate()
  3042.     // Description :
  3043.     // Parameters :
  3044.     // Return Values :
  3045.     // ---------------------------------------------------------------------------
  3046.     /**
  3047.      * Archive_Zip::_duplicate()
  3048.      *
  3049.      * { Description }
  3050.      * @return int 
  3051.      */
  3052.     function _duplicate($p_archive_filename)
  3053.     {
  3054.         $v_result = 1;
  3055.  
  3056.         // ----- Look if the $p_archive_filename exists
  3057.         if (!is_file($p_archive_filename)) {
  3058.  
  3059.             // ----- Nothing to duplicate, so duplicate is a success.
  3060.             $v_result = 1;
  3061.  
  3062.             return $v_result;
  3063.         }
  3064.  
  3065.         // ----- Open the zip file
  3066.         if (($v_result $this->_openFd('wb')) != 1{
  3067.  
  3068.             return $v_result;
  3069.         }
  3070.  
  3071.         // ----- Open the temporary file in write mode
  3072.         if (($v_zip_temp_fd @fopen($p_archive_filename'rb')) == 0{
  3073.             $this->_closeFd();
  3074.             $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL,
  3075.                        'Unable to open archive file \''
  3076.                        .$p_archive_filename.'\' in binary write mode');
  3077.             return Archive_Zip::errorCode();
  3078.         }
  3079.  
  3080.         // ----- Copy the files from the archive to the temporary file
  3081.         // TBC : Here I should better append the file and go back to erase the
  3082.         // central dir
  3083.         $v_size filesize($p_archive_filename);
  3084.         while ($v_size != 0{
  3085.             $v_read_size ($v_size ARCHIVE_ZIP_READ_BLOCK_SIZE
  3086.                           ? $v_size ARCHIVE_ZIP_READ_BLOCK_SIZE);
  3087.  
  3088.             $v_buffer fread($v_zip_temp_fd$v_read_size);
  3089.  
  3090.             @fwrite($this->_zip_fd$v_buffer$v_read_size);
  3091.             $v_size -= $v_read_size;
  3092.         }
  3093.  
  3094.         // ----- Close
  3095.         $this->_closeFd();
  3096.  
  3097.         // ----- Close the temporary file
  3098.         @fclose($v_zip_temp_fd);
  3099.  
  3100.         return $v_result;
  3101.     }
  3102.     // ---------------------------------------------------------------------------
  3103.  
  3104.     /**
  3105.      * Archive_Zip::_check_parameters()
  3106.      *
  3107.      * { Description }
  3108.      *
  3109.      * @param integer $p_error_code 
  3110.      * @param string $p_error_string 
  3111.      *
  3112.      * @return int 
  3113.      */
  3114.     function _check_parameters(&$p_params$p_default)
  3115.     {
  3116.  
  3117.         // ----- Check that param is an array
  3118.         if (!is_array($p_params)) {
  3119.             $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER,
  3120.                              'Unsupported parameter, waiting for an array');
  3121.             return Archive_Zip::errorCode();
  3122.         }
  3123.  
  3124.         // ----- Check that all the params are valid
  3125.         for (reset($p_params); list($v_key$v_valueeach($p_params){
  3126.             if (!isset($p_default[$v_key])) {
  3127.                 $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER,
  3128.                                  'Unsupported parameter with key \''.$v_key.'\'');
  3129.  
  3130.                 return Archive_Zip::errorCode();
  3131.             }
  3132.         }
  3133.  
  3134.         // ----- Set the default values
  3135.         for (reset($p_default); list($v_key$v_valueeach($p_default){
  3136.             if (!isset($p_params[$v_key])) {
  3137.                 $p_params[$v_key$p_default[$v_key];
  3138.             }
  3139.         }
  3140.  
  3141.         // ----- Check specific parameters
  3142.             $v_callback_list = array ('callback_pre_add','callback_post_add',
  3143.                                   'callback_pre_extract','callback_post_extract');
  3144.         for ($i = 0; $i<sizeof($v_callback_list)$i++{
  3145.             $v_key $v_callback_list[$i];
  3146.             if ((isset($p_params[$v_key])) && ($p_params[$v_key!= '')) {
  3147.                 if (!function_exists($p_params[$v_key])) {
  3148.                     $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAM_VALUE,
  3149.                                      "Callback '".$p_params[$v_key]
  3150.                                      ."()' is not an existing function for "
  3151.                                      ."parameter '".$v_key."'");
  3152.                     return Archive_Zip::errorCode();
  3153.                 }
  3154.             }
  3155.         }
  3156.  
  3157.         return(1);
  3158.     }
  3159.     // ---------------------------------------------------------------------------
  3160.  
  3161.     // ---------------------------------------------------------------------------
  3162.     // Function : _errorLog()
  3163.     // Description :
  3164.     // Parameters :
  3165.     // ---------------------------------------------------------------------------
  3166.     /**
  3167.      * Archive_Zip::_errorLog()
  3168.      *
  3169.      * { Description }
  3170.      *
  3171.      * @param integer $p_error_code   Error code
  3172.      * @param string  $p_error_string Error message
  3173.      *
  3174.      * @return void 
  3175.      */
  3176.     function _errorLog($p_error_code = 0$p_error_string '')
  3177.     {
  3178.         $this->_error_code   $p_error_code;
  3179.         $this->_error_string $p_error_string;
  3180.     }
  3181.     // ---------------------------------------------------------------------------
  3182.  
  3183.     // ---------------------------------------------------------------------------
  3184.     // Function : _errorReset()
  3185.     // Description :
  3186.     // Parameters :
  3187.     // ---------------------------------------------------------------------------
  3188.     /**
  3189.      * Archive_Zip::_errorReset()
  3190.      *
  3191.      * { Description }
  3192.      *
  3193.      * @return void 
  3194.      */
  3195.     function _errorReset()
  3196.     {
  3197.         $this->_error_code   = 1;
  3198.         $this->_error_string '';
  3199.     }
  3200.     // ---------------------------------------------------------------------------
  3201.  
  3202.     // ---------------------------------------------------------------------------
  3203.     // Function : $this->_tool_PathReduction()
  3204.     // Description :
  3205.     // Parameters :
  3206.     // Return Values :
  3207.     // ---------------------------------------------------------------------------
  3208.     /**
  3209.      * _tool_PathReduction()
  3210.      *
  3211.      * { Description }
  3212.      *
  3213.      * @return string 
  3214.      */
  3215.     function _tool_PathReduction($p_dir)
  3216.     {
  3217.         $v_result "";
  3218.  
  3219.         // ----- Look for not empty path
  3220.         if ($p_dir != ""{
  3221.             // ----- Explode path by directory names
  3222.             $v_list explode("/"$p_dir);
  3223.  
  3224.             // ----- Study directories from last to first
  3225.             for ($i sizeof($v_list)-1; $i>=0; $i--{
  3226.                 // ----- Look for current path
  3227.                 if ($v_list[$i== "."{
  3228.                     // ----- Ignore this directory
  3229.                     // Should be the first $i = 0, but no check is done
  3230.                 else if ($v_list[$i== ".."{
  3231.                     // ----- Ignore it and ignore the $i-1
  3232.                     $i--;
  3233.                 else if (($v_list[$i== ""&& ($i!=(sizeof($v_list)-1)) && ($i!=0)) {
  3234.                     // ----- Ignore only the double '//' in path,
  3235.                     // but not the first and last '/'
  3236.                 else {
  3237.                     $v_result $v_list[$i].($i!=(sizeof($v_list)-1)?"/".$v_result:"");
  3238.                 }
  3239.             }
  3240.         }
  3241.  
  3242.  
  3243.         return $v_result;
  3244.     }
  3245.     // ---------------------------------------------------------------------------
  3246.  
  3247.     // ---------------------------------------------------------------------------
  3248.     // Function : $this->_tool_PathInclusion()
  3249.     // Description :
  3250.     //   This function indicates if the path $p_path is under the $p_dir tree. Or,
  3251.     //   said in an other way, if the file or sub-dir $p_path is inside the dir
  3252.     //   $p_dir.
  3253.     //   The function indicates also if the path is exactly the same as the dir.
  3254.     //   This function supports path with duplicated '/' like '//', but does not
  3255.     //   support '.' or '..' statements.
  3256.     // Parameters :
  3257.     // Return Values :
  3258.     //   0 if $p_path is not inside directory $p_dir
  3259.     //   1 if $p_path is inside directory $p_dir
  3260.     //   2 if $p_path is exactly the same as $p_dir
  3261.     // ---------------------------------------------------------------------------
  3262.     /**
  3263.      * _tool_PathInclusion()
  3264.      *
  3265.      * { Description }
  3266.      *
  3267.      * @return int 
  3268.      */
  3269.     function _tool_PathInclusion($p_dir$p_path)
  3270.     {
  3271.         $v_result = 1;
  3272.  
  3273.         // ----- Explode dir and path by directory separator
  3274.         $v_list_dir  explode("/"$p_dir);
  3275.         $v_list_path explode("/"$p_path);
  3276.  
  3277.         $v_list_dir_size  sizeof($v_list_dir);
  3278.         $v_list_path_size sizeof($v_list_path);
  3279.  
  3280.         // ----- Study directories paths
  3281.         $i = 0;
  3282.         $j = 0;
  3283.  
  3284.         while (($i $v_list_dir_size&& ($j $v_list_path_size&& ($v_result)) {
  3285.             // ----- Look for empty dir (path reduction)
  3286.             if ($v_list_dir[$i== ''{
  3287.                 $i++;
  3288.                 continue;
  3289.             }
  3290.  
  3291.             if ($v_list_path[$j== ''{
  3292.                 $j++;
  3293.                 continue;
  3294.             }
  3295.  
  3296.             // ----- Compare the items
  3297.             if (($v_list_dir[$i!= $v_list_path[$j])
  3298.                 && ($v_list_dir[$i!= '')
  3299.                 && $v_list_path[$j!= '')) {
  3300.                 $v_result = 0;
  3301.             }
  3302.  
  3303.             // ----- Next items
  3304.             $i++;
  3305.             $j++;
  3306.         }
  3307.  
  3308.         // ----- Look if everything seems to be the same
  3309.         if ($v_result{
  3310.             // ----- Skip all the empty items
  3311.             while (($j $v_list_path_size&& ($v_list_path[$j== '')) {
  3312.                 $j++;
  3313.             }
  3314.  
  3315.             while (($i $v_list_dir_size&& ($v_list_dir[$i== '')) {
  3316.                   $i++;
  3317.             }
  3318.  
  3319.             if (($i >= $v_list_dir_size&& ($j >= $v_list_path_size)) {
  3320.                 // ----- There are exactly the same
  3321.                 $v_result = 2;
  3322.             else if ($i $v_list_dir_size{
  3323.                 // ----- The path is shorter than the dir
  3324.                 $v_result = 0;
  3325.             }
  3326.         }
  3327.  
  3328.  
  3329.         return $v_result;
  3330.     }
  3331.     // ---------------------------------------------------------------------------
  3332.  
  3333.     // ---------------------------------------------------------------------------
  3334.     // Function : $this->_tool_CopyBlock()
  3335.     // Description :
  3336.     // Parameters :
  3337.     //   $p_mode : read/write compression mode
  3338.     //             0 : src & dest normal
  3339.     //             1 : src gzip, dest normal
  3340.     //             2 : src normal, dest gzip
  3341.     //             3 : src & dest gzip
  3342.     // Return Values :
  3343.     // ---------------------------------------------------------------------------
  3344.     /**
  3345.      * _tool_CopyBlock()
  3346.      *
  3347.      * { Description }
  3348.      *
  3349.      * @param integer $p_mode 
  3350.      *
  3351.      * @return int 
  3352.      */
  3353.     function _tool_CopyBlock($p_src$p_dest$p_size$p_mode = 0)
  3354.     {
  3355.         $v_result = 1;
  3356.  
  3357.         if ($p_mode == 0{
  3358.             while ($p_size != 0{
  3359.                 $v_read_size ($p_size ARCHIVE_ZIP_READ_BLOCK_SIZE
  3360.                                 ? $p_size ARCHIVE_ZIP_READ_BLOCK_SIZE);
  3361.  
  3362.                 $v_buffer @fread($p_src$v_read_size);
  3363.  
  3364.                 @fwrite($p_dest$v_buffer$v_read_size);
  3365.                 $p_size -= $v_read_size;
  3366.             }
  3367.         else if ($p_mode == 1{
  3368.             while ($p_size != 0{
  3369.                     $v_read_size ($p_size ARCHIVE_ZIP_READ_BLOCK_SIZE
  3370.                                     ? $p_size ARCHIVE_ZIP_READ_BLOCK_SIZE);
  3371.  
  3372.                     $v_buffer @gzread($p_src$v_read_size);
  3373.  
  3374.                     @fwrite($p_dest$v_buffer$v_read_size);
  3375.                     $p_size -= $v_read_size;
  3376.             }
  3377.         else if ($p_mode == 2{
  3378.             while ($p_size != 0{
  3379.                 $v_read_size ($p_size ARCHIVE_ZIP_READ_BLOCK_SIZE
  3380.                                 ? $p_size ARCHIVE_ZIP_READ_BLOCK_SIZE);
  3381.  
  3382.                 $v_buffer @fread($p_src$v_read_size);
  3383.  
  3384.                 @gzwrite($p_dest$v_buffer$v_read_size);
  3385.                 $p_size -= $v_read_size;
  3386.             }
  3387.         else if ($p_mode == 3{
  3388.             while ($p_size != 0{
  3389.                 $v_read_size ($p_size ARCHIVE_ZIP_READ_BLOCK_SIZE
  3390.                                 ? $p_size ARCHIVE_ZIP_READ_BLOCK_SIZE);
  3391.  
  3392.                 $v_buffer @gzread($p_src$v_read_size);
  3393.  
  3394.                 @gzwrite($p_dest$v_buffer$v_read_size);
  3395.                 $p_size -= $v_read_size;
  3396.             }
  3397.         }
  3398.  
  3399.  
  3400.         return $v_result;
  3401.     }
  3402.     // ---------------------------------------------------------------------------
  3403.  
  3404.     // ---------------------------------------------------------------------------
  3405.     // Function : $this->_tool_Rename()
  3406.     // Description :
  3407.     //   This function tries to do a simple rename() function. If it fails, it
  3408.     //   tries to copy the $p_src file in a new $p_dest file and then unlink the
  3409.     //   first one.
  3410.     // Parameters :
  3411.     //   $p_src : Old filename
  3412.     //   $p_dest : New filename
  3413.     // Return Values :
  3414.     //   1 on success, 0 on failure.
  3415.     // ---------------------------------------------------------------------------
  3416.     /**
  3417.      * _tool_Rename()
  3418.      *
  3419.      * { Description }
  3420.      * @return int 
  3421.      */
  3422.     function _tool_Rename($p_src$p_dest)
  3423.     {
  3424.         $v_result = 1;
  3425.  
  3426.         // ----- Try to rename the files
  3427.         if (!@rename($p_src$p_dest)) {
  3428.  
  3429.             // ----- Try to copy & unlink the src
  3430.             if (!@copy($p_src$p_dest)) {
  3431.                 $v_result = 0;
  3432.             else if (!@unlink($p_src)) {
  3433.                 $v_result = 0;
  3434.             }
  3435.         }
  3436.  
  3437.  
  3438.         return $v_result;
  3439.     }
  3440.     // ---------------------------------------------------------------------------
  3441.  
  3442.     // ---------------------------------------------------------------------------
  3443.     // Function : $this->_tool_TranslateWinPath()
  3444.     // Description :
  3445.     //   Translate windows path by replacing '\' by '/' and optionally removing
  3446.     //   drive letter.
  3447.     // Parameters :
  3448.     //   $p_path : path to translate.
  3449.     //   $p_remove_disk_letter : true | false
  3450.     // Return Values :
  3451.     //   The path translated.
  3452.     // ---------------------------------------------------------------------------
  3453.     /**
  3454.      * _tool_TranslateWinPath()
  3455.      *
  3456.      * { Description }
  3457.      *
  3458.      * @param [type] $p_remove_disk_letter 
  3459.      *
  3460.      * @return string 
  3461.      */
  3462.     function _tool_TranslateWinPath($p_path$p_remove_disk_letter = true)
  3463.     {
  3464.         if (stristr(php_uname()'windows')) {
  3465.             // ----- Look for potential disk letter
  3466.             if (($p_remove_disk_letter)
  3467.                 && (($v_position strpos($p_path':')) != false)) {
  3468.                 $p_path substr($p_path$v_position+1);
  3469.             }
  3470.             // ----- Change potential windows directory separator
  3471.             if ((strpos($p_path'\\'> 0|| (substr($p_path01== '\\')) {
  3472.                 $p_path strtr($p_path'\\''/');
  3473.             }
  3474.         }
  3475.         return $p_path;
  3476.     }
  3477.     // ---------------------------------------------------------------------------
  3478.  
  3479. }

Documentation generated on Mon, 11 Mar 2019 15:44:26 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.