source: spip-zone/_outils_/spip_loader/trunk/pclzip.php @ 125323

Last change on this file since 125323 was 125323, checked in by Matthieu Marcillaud, 19 months ago

Notice PHP en moins en dehors de SPIP

File size: 176.2 KB
Line 
1<?php
2// --------------------------------------------------------------------------------
3// PhpConcept Library - Zip Module 2.8.2
4// --------------------------------------------------------------------------------
5// License GNU/LGPL - Vincent Blavet - August 2009
6// http://www.phpconcept.net
7// --------------------------------------------------------------------------------
8//
9// Presentation :
10//   PclZip is a PHP library that manage ZIP archives.
11//   So far tests show that archives generated by PclZip are readable by
12//   WinZip application and other tools.
13//
14// Description :
15//   See readme.txt and http://www.phpconcept.net
16//
17// Warning :
18//   This library and the associated files are non commercial, non professional
19//   work.
20//   It should not have unexpected results. However if any damage is caused by
21//   this software the author can not be responsible.
22//   The use of this software is at the risk of the user.
23//
24
25
26// personnalisations spip
27if (!defined('PCLZIP_TEMPORARY_DIR')) {
28        define('PCLZIP_TEMPORARY_DIR', _DIR_TMP);
29}
30if (!function_exists('gzopen') && function_exists('gzopen64')) {
31        function gzopen($filename, $mode, $use_include_path = 0) {
32                return gzopen64($filename, $mode, $use_include_path);
33        }
34}
35// fin personnalisations spip
36
37// ----- Constants
38if (!defined('PCLZIP_READ_BLOCK_SIZE')) {
39        define('PCLZIP_READ_BLOCK_SIZE', 2048);
40}
41
42// ----- File list separator
43// In version 1.x of PclZip, the separator for file list is a space
44// (which is not a very smart choice, specifically for windows paths !).
45// A better separator should be a comma (,). This constant gives you the
46// abilty to change that.
47// However notice that changing this value, may have impact on existing
48// scripts, using space separated filenames.
49// Recommanded values for compatibility with older versions :
50//define( 'PCLZIP_SEPARATOR', ' ' );
51// Recommanded values for smart separation of filenames.
52if (!defined('PCLZIP_SEPARATOR')) {
53        define('PCLZIP_SEPARATOR', ',');
54}
55
56// ----- Error configuration
57// 0 : PclZip Class integrated error handling
58// 1 : PclError external library error handling. By enabling this
59//     you must ensure that you have included PclError library.
60// [2,...] : reserved for futur use
61if (!defined('PCLZIP_ERROR_EXTERNAL')) {
62        define('PCLZIP_ERROR_EXTERNAL', 0);
63}
64
65// ----- Optional static temporary directory
66//       By default temporary files are generated in the script current
67//       path.
68//       If defined :
69//       - MUST BE terminated by a '/'.
70//       - MUST be a valid, already created directory
71//       Samples :
72// define( 'PCLZIP_TEMPORARY_DIR', '/temp/' );
73// define( 'PCLZIP_TEMPORARY_DIR', 'C:/Temp/' );
74if (!defined('PCLZIP_TEMPORARY_DIR')) {
75        define('PCLZIP_TEMPORARY_DIR', '');
76}
77
78// ----- Optional threshold ratio for use of temporary files
79//       Pclzip sense the size of the file to add/extract and decide to
80//       use or not temporary file. The algorythm is looking for
81//       memory_limit of PHP and apply a ratio.
82//       threshold = memory_limit * ratio.
83//       Recommended values are under 0.5. Default 0.47.
84//       Samples :
85// define( 'PCLZIP_TEMPORARY_FILE_RATIO', 0.5 );
86if (!defined('PCLZIP_TEMPORARY_FILE_RATIO')) {
87        define('PCLZIP_TEMPORARY_FILE_RATIO', 0.47);
88}
89
90// --------------------------------------------------------------------------------
91// ***** UNDER THIS LINE NOTHING NEEDS TO BE MODIFIED *****
92// --------------------------------------------------------------------------------
93
94// ----- Global variables
95$g_pclzip_version = "2.8.2";
96
97// ----- Error codes
98//   -1 : Unable to open file in binary write mode
99//   -2 : Unable to open file in binary read mode
100//   -3 : Invalid parameters
101//   -4 : File does not exist
102//   -5 : Filename is too long (max. 255)
103//   -6 : Not a valid zip file
104//   -7 : Invalid extracted file size
105//   -8 : Unable to create directory
106//   -9 : Invalid archive extension
107//  -10 : Invalid archive format
108//  -11 : Unable to delete file (unlink)
109//  -12 : Unable to rename file (rename)
110//  -13 : Invalid header checksum
111//  -14 : Invalid archive size
112define('PCLZIP_ERR_USER_ABORTED', 2);
113define('PCLZIP_ERR_NO_ERROR', 0);
114define('PCLZIP_ERR_WRITE_OPEN_FAIL', -1);
115define('PCLZIP_ERR_READ_OPEN_FAIL', -2);
116define('PCLZIP_ERR_INVALID_PARAMETER', -3);
117define('PCLZIP_ERR_MISSING_FILE', -4);
118define('PCLZIP_ERR_FILENAME_TOO_LONG', -5);
119define('PCLZIP_ERR_INVALID_ZIP', -6);
120define('PCLZIP_ERR_BAD_EXTRACTED_FILE', -7);
121define('PCLZIP_ERR_DIR_CREATE_FAIL', -8);
122define('PCLZIP_ERR_BAD_EXTENSION', -9);
123define('PCLZIP_ERR_BAD_FORMAT', -10);
124define('PCLZIP_ERR_DELETE_FILE_FAIL', -11);
125define('PCLZIP_ERR_RENAME_FILE_FAIL', -12);
126define('PCLZIP_ERR_BAD_CHECKSUM', -13);
127define('PCLZIP_ERR_INVALID_ARCHIVE_ZIP', -14);
128define('PCLZIP_ERR_MISSING_OPTION_VALUE', -15);
129define('PCLZIP_ERR_INVALID_OPTION_VALUE', -16);
130define('PCLZIP_ERR_ALREADY_A_DIRECTORY', -17);
131define('PCLZIP_ERR_UNSUPPORTED_COMPRESSION', -18);
132define('PCLZIP_ERR_UNSUPPORTED_ENCRYPTION', -19);
133define('PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE', -20);
134define('PCLZIP_ERR_DIRECTORY_RESTRICTION', -21);
135
136// ----- Options values
137define('PCLZIP_OPT_PATH', 77001);
138define('PCLZIP_OPT_ADD_PATH', 77002);
139define('PCLZIP_OPT_REMOVE_PATH', 77003);
140define('PCLZIP_OPT_REMOVE_ALL_PATH', 77004);
141define('PCLZIP_OPT_SET_CHMOD', 77005);
142define('PCLZIP_OPT_EXTRACT_AS_STRING', 77006);
143define('PCLZIP_OPT_NO_COMPRESSION', 77007);
144define('PCLZIP_OPT_BY_NAME', 77008);
145define('PCLZIP_OPT_BY_INDEX', 77009);
146define('PCLZIP_OPT_BY_EREG', 77010);
147define('PCLZIP_OPT_BY_PREG', 77011);
148define('PCLZIP_OPT_COMMENT', 77012);
149define('PCLZIP_OPT_ADD_COMMENT', 77013);
150define('PCLZIP_OPT_PREPEND_COMMENT', 77014);
151define('PCLZIP_OPT_EXTRACT_IN_OUTPUT', 77015);
152define('PCLZIP_OPT_REPLACE_NEWER', 77016);
153define('PCLZIP_OPT_STOP_ON_ERROR', 77017);
154// Having big trouble with crypt. Need to multiply 2 long int
155// which is not correctly supported by PHP ...
156//define( 'PCLZIP_OPT_CRYPT', 77018 );
157define('PCLZIP_OPT_EXTRACT_DIR_RESTRICTION', 77019);
158define('PCLZIP_OPT_TEMP_FILE_THRESHOLD', 77020);
159define('PCLZIP_OPT_ADD_TEMP_FILE_THRESHOLD', 77020); // alias
160define('PCLZIP_OPT_TEMP_FILE_ON', 77021);
161define('PCLZIP_OPT_ADD_TEMP_FILE_ON', 77021); // alias
162define('PCLZIP_OPT_TEMP_FILE_OFF', 77022);
163define('PCLZIP_OPT_ADD_TEMP_FILE_OFF', 77022); // alias
164
165// ----- File description attributes
166define('PCLZIP_ATT_FILE_NAME', 79001);
167define('PCLZIP_ATT_FILE_NEW_SHORT_NAME', 79002);
168define('PCLZIP_ATT_FILE_NEW_FULL_NAME', 79003);
169define('PCLZIP_ATT_FILE_MTIME', 79004);
170define('PCLZIP_ATT_FILE_CONTENT', 79005);
171define('PCLZIP_ATT_FILE_COMMENT', 79006);
172
173// ----- Call backs values
174define('PCLZIP_CB_PRE_EXTRACT', 78001);
175define('PCLZIP_CB_POST_EXTRACT', 78002);
176define('PCLZIP_CB_PRE_ADD', 78003);
177define('PCLZIP_CB_POST_ADD', 78004);
178/* For futur use
179  define( 'PCLZIP_CB_PRE_LIST', 78005 );
180  define( 'PCLZIP_CB_POST_LIST', 78006 );
181  define( 'PCLZIP_CB_PRE_DELETE', 78007 );
182  define( 'PCLZIP_CB_POST_DELETE', 78008 );
183  */
184
185// --------------------------------------------------------------------------------
186// Class : PclZip
187// Description :
188//   PclZip is the class that represent a Zip archive.
189//   The public methods allow the manipulation of the archive.
190// Attributes :
191//   Attributes must not be accessed directly.
192// Methods :
193//   PclZip() : Object creator
194//   create() : Creates the Zip archive
195//   listContent() : List the content of the Zip archive
196//   extract() : Extract the content of the archive
197//   properties() : List the properties of the archive
198// --------------------------------------------------------------------------------
199class PclZip {
200        // ----- Filename of the zip file
201        public $zipname = '';
202
203        // ----- File descriptor of the zip file
204        public $zip_fd = 0;
205
206        // ----- Internal error handling
207        public $error_code = 1;
208        public $error_string = '';
209
210        // ----- Current status of the magic_quotes_runtime
211        // This value store the php configuration for magic_quotes
212        // The class can then disable the magic_quotes and reset it after
213        public $magic_quotes_status;
214
215        // --------------------------------------------------------------------------------
216        // Function : PclZip()
217        // Description :
218        //   Creates a PclZip object and set the name of the associated Zip archive
219        //   filename.
220        //   Note that no real action is taken, if the archive does not exist it is not
221        //   created. Use create() for that.
222        // --------------------------------------------------------------------------------
223        public function __construct($p_zipname) {
224
225                // ----- Tests the zlib
226                if (!function_exists('gzopen')) {
227                        die('Abort ' . basename(__FILE__) . ' : Missing zlib extensions');
228                }
229
230                // ----- Set the attributes
231                $this->zipname = $p_zipname;
232                $this->zip_fd = 0;
233                $this->magic_quotes_status = -1;
234
235                // ----- Return
236                return;
237        }
238        // --------------------------------------------------------------------------------
239
240        // --------------------------------------------------------------------------------
241        // Function :
242        //   create($p_filelist, $p_add_dir="", $p_remove_dir="")
243        //   create($p_filelist, $p_option, $p_option_value, ...)
244        // Description :
245        //   This method supports two different synopsis. The first one is historical.
246        //   This method creates a Zip Archive. The Zip file is created in the
247        //   filesystem. The files and directories indicated in $p_filelist
248        //   are added in the archive. See the parameters description for the
249        //   supported format of $p_filelist.
250        //   When a directory is in the list, the directory and its content is added
251        //   in the archive.
252        //   In this synopsis, the function takes an optional variable list of
253        //   options. See bellow the supported options.
254        // Parameters :
255        //   $p_filelist : An array containing file or directory names, or
256        //                 a string containing one filename or one directory name, or
257        //                 a string containing a list of filenames and/or directory
258        //                 names separated by spaces.
259        //   $p_add_dir : A path to add before the real path of the archived file,
260        //                in order to have it memorized in the archive.
261        //   $p_remove_dir : A path to remove from the real path of the file to archive,
262        //                   in order to have a shorter path memorized in the archive.
263        //                   When $p_add_dir and $p_remove_dir are set, $p_remove_dir
264        //                   is removed first, before $p_add_dir is added.
265        // Options :
266        //   PCLZIP_OPT_ADD_PATH :
267        //   PCLZIP_OPT_REMOVE_PATH :
268        //   PCLZIP_OPT_REMOVE_ALL_PATH :
269        //   PCLZIP_OPT_COMMENT :
270        //   PCLZIP_CB_PRE_ADD :
271        //   PCLZIP_CB_POST_ADD :
272        // Return Values :
273        //   0 on failure,
274        //   The list of the added files, with a status of the add action.
275        //   (see PclZip::listContent() for list entry format)
276        // --------------------------------------------------------------------------------
277        public function create($p_filelist) {
278                $v_result = 1;
279
280                // ----- Reset the error handler
281                $this->privErrorReset();
282
283                // ----- Set default values
284                $v_options = array();
285                $v_options[PCLZIP_OPT_NO_COMPRESSION] = false;
286
287                // ----- Look for variable options arguments
288                $v_size = func_num_args();
289
290                // ----- Look for arguments
291                if ($v_size > 1) {
292                        // ----- Get the arguments
293                        $v_arg_list = func_get_args();
294
295                        // ----- Remove from the options list the first argument
296                        array_shift($v_arg_list);
297                        $v_size--;
298
299                        // ----- Look for first arg
300                        if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
301
302                                // ----- Parse the options
303                                $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
304                                        array(
305                                                PCLZIP_OPT_REMOVE_PATH => 'optional',
306                                                PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
307                                                PCLZIP_OPT_ADD_PATH => 'optional',
308                                                PCLZIP_CB_PRE_ADD => 'optional',
309                                                PCLZIP_CB_POST_ADD => 'optional',
310                                                PCLZIP_OPT_NO_COMPRESSION => 'optional',
311                                                PCLZIP_OPT_COMMENT => 'optional',
312                                                PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
313                                                PCLZIP_OPT_TEMP_FILE_ON => 'optional',
314                                                PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
315                                                //, PCLZIP_OPT_CRYPT => 'optional'
316                                        ));
317                                if ($v_result != 1) {
318                                        return 0;
319                                }
320                        }
321
322                        // ----- Look for 2 args
323                        // Here we need to support the first historic synopsis of the
324                        // method.
325                        else {
326
327                                // ----- Get the first argument
328                                $v_options[PCLZIP_OPT_ADD_PATH] = $v_arg_list[0];
329
330                                // ----- Look for the optional second argument
331                                if ($v_size == 2) {
332                                        $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1];
333                                } else {
334                                        if ($v_size > 2) {
335                                                PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER,
336                                                        "Invalid number / type of arguments");
337
338                                                return 0;
339                                        }
340                                }
341                        }
342                }
343
344                // ----- Look for default option values
345                $this->privOptionDefaultThreshold($v_options);
346
347                // ----- Init
348                $v_string_list = array();
349                $v_att_list = array();
350                $v_filedescr_list = array();
351                $p_result_list = array();
352
353                // ----- Look if the $p_filelist is really an array
354                if (is_array($p_filelist)) {
355
356                        // ----- Look if the first element is also an array
357                        //       This will mean that this is a file description entry
358                        if (isset($p_filelist[0]) && is_array($p_filelist[0])) {
359                                $v_att_list = $p_filelist;
360                        } // ----- The list is a list of string names
361                        else {
362                                $v_string_list = $p_filelist;
363                        }
364                } // ----- Look if the $p_filelist is a string
365                else {
366                        if (is_string($p_filelist)) {
367                                // ----- Create a list from the string
368                                $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist);
369                        } // ----- Invalid variable type for $p_filelist
370                        else {
371                                PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_filelist");
372
373                                return 0;
374                        }
375                }
376
377                // ----- Reformat the string list
378                if (sizeof($v_string_list) != 0) {
379                        foreach ($v_string_list as $v_string) {
380                                if ($v_string != '') {
381                                        $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string;
382                                } else {
383                                }
384                        }
385                }
386
387                // ----- For each file in the list check the attributes
388                $v_supported_attributes
389                        = array(
390                        PCLZIP_ATT_FILE_NAME => 'mandatory',
391                        PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional',
392                        PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional',
393                        PCLZIP_ATT_FILE_MTIME => 'optional',
394                        PCLZIP_ATT_FILE_CONTENT => 'optional',
395                        PCLZIP_ATT_FILE_COMMENT => 'optional'
396                );
397                foreach ($v_att_list as $v_entry) {
398                        $v_result = $this->privFileDescrParseAtt($v_entry,
399                                $v_filedescr_list[],
400                                $v_options,
401                                $v_supported_attributes);
402                        if ($v_result != 1) {
403                                return 0;
404                        }
405                }
406
407                // ----- Expand the filelist (expand directories)
408                $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options);
409                if ($v_result != 1) {
410                        return 0;
411                }
412
413                // ----- Call the create fct
414                $v_result = $this->privCreate($v_filedescr_list, $p_result_list, $v_options);
415                if ($v_result != 1) {
416                        return 0;
417                }
418
419                // ----- Return
420                return $p_result_list;
421        }
422        // --------------------------------------------------------------------------------
423
424        // --------------------------------------------------------------------------------
425        // Function :
426        //   add($p_filelist, $p_add_dir="", $p_remove_dir="")
427        //   add($p_filelist, $p_option, $p_option_value, ...)
428        // Description :
429        //   This method supports two synopsis. The first one is historical.
430        //   This methods add the list of files in an existing archive.
431        //   If a file with the same name already exists, it is added at the end of the
432        //   archive, the first one is still present.
433        //   If the archive does not exist, it is created.
434        // Parameters :
435        //   $p_filelist : An array containing file or directory names, or
436        //                 a string containing one filename or one directory name, or
437        //                 a string containing a list of filenames and/or directory
438        //                 names separated by spaces.
439        //   $p_add_dir : A path to add before the real path of the archived file,
440        //                in order to have it memorized in the archive.
441        //   $p_remove_dir : A path to remove from the real path of the file to archive,
442        //                   in order to have a shorter path memorized in the archive.
443        //                   When $p_add_dir and $p_remove_dir are set, $p_remove_dir
444        //                   is removed first, before $p_add_dir is added.
445        // Options :
446        //   PCLZIP_OPT_ADD_PATH :
447        //   PCLZIP_OPT_REMOVE_PATH :
448        //   PCLZIP_OPT_REMOVE_ALL_PATH :
449        //   PCLZIP_OPT_COMMENT :
450        //   PCLZIP_OPT_ADD_COMMENT :
451        //   PCLZIP_OPT_PREPEND_COMMENT :
452        //   PCLZIP_CB_PRE_ADD :
453        //   PCLZIP_CB_POST_ADD :
454        // Return Values :
455        //   0 on failure,
456        //   The list of the added files, with a status of the add action.
457        //   (see PclZip::listContent() for list entry format)
458        // --------------------------------------------------------------------------------
459        public function add($p_filelist) {
460                $v_result = 1;
461
462                // ----- Reset the error handler
463                $this->privErrorReset();
464
465                // ----- Set default values
466                $v_options = array();
467                $v_options[PCLZIP_OPT_NO_COMPRESSION] = false;
468
469                // ----- Look for variable options arguments
470                $v_size = func_num_args();
471
472                // ----- Look for arguments
473                if ($v_size > 1) {
474                        // ----- Get the arguments
475                        $v_arg_list = func_get_args();
476
477                        // ----- Remove form the options list the first argument
478                        array_shift($v_arg_list);
479                        $v_size--;
480
481                        // ----- Look for first arg
482                        if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
483
484                                // ----- Parse the options
485                                $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
486                                        array(
487                                                PCLZIP_OPT_REMOVE_PATH => 'optional',
488                                                PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
489                                                PCLZIP_OPT_ADD_PATH => 'optional',
490                                                PCLZIP_CB_PRE_ADD => 'optional',
491                                                PCLZIP_CB_POST_ADD => 'optional',
492                                                PCLZIP_OPT_NO_COMPRESSION => 'optional',
493                                                PCLZIP_OPT_COMMENT => 'optional',
494                                                PCLZIP_OPT_ADD_COMMENT => 'optional',
495                                                PCLZIP_OPT_PREPEND_COMMENT => 'optional',
496                                                PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
497                                                PCLZIP_OPT_TEMP_FILE_ON => 'optional',
498                                                PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
499                                                //, PCLZIP_OPT_CRYPT => 'optional'
500                                        ));
501                                if ($v_result != 1) {
502                                        return 0;
503                                }
504                        }
505
506                        // ----- Look for 2 args
507                        // Here we need to support the first historic synopsis of the
508                        // method.
509                        else {
510
511                                // ----- Get the first argument
512                                $v_options[PCLZIP_OPT_ADD_PATH] = $v_add_path = $v_arg_list[0];
513
514                                // ----- Look for the optional second argument
515                                if ($v_size == 2) {
516                                        $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1];
517                                } else {
518                                        if ($v_size > 2) {
519                                                // ----- Error log
520                                                PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments");
521
522                                                // ----- Return
523                                                return 0;
524                                        }
525                                }
526                        }
527                }
528
529                // ----- Look for default option values
530                $this->privOptionDefaultThreshold($v_options);
531
532                // ----- Init
533                $v_string_list = array();
534                $v_att_list = array();
535                $v_filedescr_list = array();
536                $p_result_list = array();
537
538                // ----- Look if the $p_filelist is really an array
539                if (is_array($p_filelist)) {
540
541                        // ----- Look if the first element is also an array
542                        //       This will mean that this is a file description entry
543                        if (isset($p_filelist[0]) && is_array($p_filelist[0])) {
544                                $v_att_list = $p_filelist;
545                        } // ----- The list is a list of string names
546                        else {
547                                $v_string_list = $p_filelist;
548                        }
549                } // ----- Look if the $p_filelist is a string
550                else {
551                        if (is_string($p_filelist)) {
552                                // ----- Create a list from the string
553                                $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist);
554                        } // ----- Invalid variable type for $p_filelist
555                        else {
556                                PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER,
557                                        "Invalid variable type '" . gettype($p_filelist) . "' for p_filelist");
558
559                                return 0;
560                        }
561                }
562
563                // ----- Reformat the string list
564                if (sizeof($v_string_list) != 0) {
565                        foreach ($v_string_list as $v_string) {
566                                $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string;
567                        }
568                }
569
570                // ----- For each file in the list check the attributes
571                $v_supported_attributes
572                        = array(
573                        PCLZIP_ATT_FILE_NAME => 'mandatory',
574                        PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional',
575                        PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional',
576                        PCLZIP_ATT_FILE_MTIME => 'optional',
577                        PCLZIP_ATT_FILE_CONTENT => 'optional',
578                        PCLZIP_ATT_FILE_COMMENT => 'optional'
579                );
580                foreach ($v_att_list as $v_entry) {
581                        $v_result = $this->privFileDescrParseAtt($v_entry,
582                                $v_filedescr_list[],
583                                $v_options,
584                                $v_supported_attributes);
585                        if ($v_result != 1) {
586                                return 0;
587                        }
588                }
589
590                // ----- Expand the filelist (expand directories)
591                $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options);
592                if ($v_result != 1) {
593                        return 0;
594                }
595
596                // ----- Call the create fct
597                $v_result = $this->privAdd($v_filedescr_list, $p_result_list, $v_options);
598                if ($v_result != 1) {
599                        return 0;
600                }
601
602                // ----- Return
603                return $p_result_list;
604        }
605        // --------------------------------------------------------------------------------
606
607        // --------------------------------------------------------------------------------
608        // Function : listContent()
609        // Description :
610        //   This public method, gives the list of the files and directories, with their
611        //   properties.
612        //   The properties of each entries in the list are (used also in other functions) :
613        //     filename : Name of the file. For a create or add action it is the filename
614        //                given by the user. For an extract function it is the filename
615        //                of the extracted file.
616        //     stored_filename : Name of the file / directory stored in the archive.
617        //     size : Size of the stored file.
618        //     compressed_size : Size of the file's data compressed in the archive
619        //                       (without the headers overhead)
620        //     mtime : Last known modification date of the file (UNIX timestamp)
621        //     comment : Comment associated with the file
622        //     folder : true | false
623        //     index : index of the file in the archive
624        //     status : status of the action (depending of the action) :
625        //              Values are :
626        //                ok : OK !
627        //                filtered : the file / dir is not extracted (filtered by user)
628        //                already_a_directory : the file can not be extracted because a
629        //                                      directory with the same name already exists
630        //                write_protected : the file can not be extracted because a file
631        //                                  with the same name already exists and is
632        //                                  write protected
633        //                newer_exist : the file was not extracted because a newer file exists
634        //                path_creation_fail : the file is not extracted because the folder
635        //                                     does not exist and can not be created
636        //                write_error : the file was not extracted because there was a
637        //                              error while writing the file
638        //                read_error : the file was not extracted because there was a error
639        //                             while reading the file
640        //                invalid_header : the file was not extracted because of an archive
641        //                                 format error (bad file header)
642        //   Note that each time a method can continue operating when there
643        //   is an action error on a file, the error is only logged in the file status.
644        // Return Values :
645        //   0 on an unrecoverable failure,
646        //   The list of the files in the archive.
647        // --------------------------------------------------------------------------------
648        public function listContent() {
649                $v_result = 1;
650
651                // ----- Reset the error handler
652                $this->privErrorReset();
653
654                // ----- Check archive
655                if (!$this->privCheckFormat()) {
656                        return (0);
657                }
658
659                // ----- Call the extracting fct
660                $p_list = array();
661                if (($v_result = $this->privList($p_list)) != 1) {
662                        unset($p_list);
663
664                        return (0);
665                }
666
667                // ----- Return
668                return $p_list;
669        }
670        // --------------------------------------------------------------------------------
671
672        // --------------------------------------------------------------------------------
673        // Function :
674        //   extract($p_path="./", $p_remove_path="")
675        //   extract([$p_option, $p_option_value, ...])
676        // Description :
677        //   This method supports two synopsis. The first one is historical.
678        //   This method extract all the files / directories from the archive to the
679        //   folder indicated in $p_path.
680        //   If you want to ignore the 'root' part of path of the memorized files
681        //   you can indicate this in the optional $p_remove_path parameter.
682        //   By default, if a newer file with the same name already exists, the
683        //   file is not extracted.
684        //
685        //   If both PCLZIP_OPT_PATH and PCLZIP_OPT_ADD_PATH aoptions
686        //   are used, the path indicated in PCLZIP_OPT_ADD_PATH is append
687        //   at the end of the path value of PCLZIP_OPT_PATH.
688        // Parameters :
689        //   $p_path : Path where the files and directories are to be extracted
690        //   $p_remove_path : First part ('root' part) of the memorized path
691        //                    (if any similar) to remove while extracting.
692        // Options :
693        //   PCLZIP_OPT_PATH :
694        //   PCLZIP_OPT_ADD_PATH :
695        //   PCLZIP_OPT_REMOVE_PATH :
696        //   PCLZIP_OPT_REMOVE_ALL_PATH :
697        //   PCLZIP_CB_PRE_EXTRACT :
698        //   PCLZIP_CB_POST_EXTRACT :
699        // Return Values :
700        //   0 or a negative value on failure,
701        //   The list of the extracted files, with a status of the action.
702        //   (see PclZip::listContent() for list entry format)
703        // --------------------------------------------------------------------------------
704        public function extract() {
705                $v_result = 1;
706
707                // ----- Reset the error handler
708                $this->privErrorReset();
709
710                // ----- Check archive
711                if (!$this->privCheckFormat()) {
712                        return (0);
713                }
714
715                // ----- Set default values
716                $v_options = array();
717//    $v_path = "./";
718                $v_path = '';
719                $v_remove_path = "";
720                $v_remove_all_path = false;
721
722                // ----- Look for variable options arguments
723                $v_size = func_num_args();
724
725                // ----- Default values for option
726                $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = false;
727
728                // ----- Look for arguments
729                if ($v_size > 0) {
730                        // ----- Get the arguments
731                        $v_arg_list = func_get_args();
732
733                        // ----- Look for first arg
734                        if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
735
736                                // ----- Parse the options
737                                $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
738                                        array(
739                                                PCLZIP_OPT_PATH => 'optional',
740                                                PCLZIP_OPT_REMOVE_PATH => 'optional',
741                                                PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
742                                                PCLZIP_OPT_ADD_PATH => 'optional',
743                                                PCLZIP_CB_PRE_EXTRACT => 'optional',
744                                                PCLZIP_CB_POST_EXTRACT => 'optional',
745                                                PCLZIP_OPT_SET_CHMOD => 'optional',
746                                                PCLZIP_OPT_BY_NAME => 'optional',
747                                                PCLZIP_OPT_BY_EREG => 'optional',
748                                                PCLZIP_OPT_BY_PREG => 'optional',
749                                                PCLZIP_OPT_BY_INDEX => 'optional',
750                                                PCLZIP_OPT_EXTRACT_AS_STRING => 'optional',
751                                                PCLZIP_OPT_EXTRACT_IN_OUTPUT => 'optional',
752                                                PCLZIP_OPT_REPLACE_NEWER => 'optional',
753                                                PCLZIP_OPT_STOP_ON_ERROR => 'optional',
754                                                PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional',
755                                                PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
756                                                PCLZIP_OPT_TEMP_FILE_ON => 'optional',
757                                                PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
758                                        ));
759                                if ($v_result != 1) {
760                                        return 0;
761                                }
762
763                                // ----- Set the arguments
764                                if (isset($v_options[PCLZIP_OPT_PATH])) {
765                                        $v_path = $v_options[PCLZIP_OPT_PATH];
766                                }
767                                if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) {
768                                        $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH];
769                                }
770                                if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) {
771                                        $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH];
772                                }
773                                if (isset($v_options[PCLZIP_OPT_ADD_PATH])) {
774                                        // ----- Check for '/' in last path char
775                                        if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) {
776                                                $v_path .= '/';
777                                        }
778                                        $v_path .= $v_options[PCLZIP_OPT_ADD_PATH];
779                                }
780                        }
781
782                        // ----- Look for 2 args
783                        // Here we need to support the first historic synopsis of the
784                        // method.
785                        else {
786
787                                // ----- Get the first argument
788                                $v_path = $v_arg_list[0];
789
790                                // ----- Look for the optional second argument
791                                if ($v_size == 2) {
792                                        $v_remove_path = $v_arg_list[1];
793                                } else {
794                                        if ($v_size > 2) {
795                                                // ----- Error log
796                                                PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments");
797
798                                                // ----- Return
799                                                return 0;
800                                        }
801                                }
802                        }
803                }
804
805                // ----- Look for default option values
806                $this->privOptionDefaultThreshold($v_options);
807
808                // ----- Trace
809
810                // ----- Call the extracting fct
811                $p_list = array();
812                $v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path,
813                        $v_remove_all_path, $v_options);
814                if ($v_result < 1) {
815                        unset($p_list);
816
817                        return (0);
818                }
819
820                // ----- Return
821                return $p_list;
822        }
823        // --------------------------------------------------------------------------------
824
825
826        // --------------------------------------------------------------------------------
827        // Function :
828        //   extractByIndex($p_index, $p_path="./", $p_remove_path="")
829        //   extractByIndex($p_index, [$p_option, $p_option_value, ...])
830        // Description :
831        //   This method supports two synopsis. The first one is historical.
832        //   This method is doing a partial extract of the archive.
833        //   The extracted files or folders are identified by their index in the
834        //   archive (from 0 to n).
835        //   Note that if the index identify a folder, only the folder entry is
836        //   extracted, not all the files included in the archive.
837        // Parameters :
838        //   $p_index : A single index (integer) or a string of indexes of files to
839        //              extract. The form of the string is "0,4-6,8-12" with only numbers
840        //              and '-' for range or ',' to separate ranges. No spaces or ';'
841        //              are allowed.
842        //   $p_path : Path where the files and directories are to be extracted
843        //   $p_remove_path : First part ('root' part) of the memorized path
844        //                    (if any similar) to remove while extracting.
845        // Options :
846        //   PCLZIP_OPT_PATH :
847        //   PCLZIP_OPT_ADD_PATH :
848        //   PCLZIP_OPT_REMOVE_PATH :
849        //   PCLZIP_OPT_REMOVE_ALL_PATH :
850        //   PCLZIP_OPT_EXTRACT_AS_STRING : The files are extracted as strings and
851        //     not as files.
852        //     The resulting content is in a new field 'content' in the file
853        //     structure.
854        //     This option must be used alone (any other options are ignored).
855        //   PCLZIP_CB_PRE_EXTRACT :
856        //   PCLZIP_CB_POST_EXTRACT :
857        // Return Values :
858        //   0 on failure,
859        //   The list of the extracted files, with a status of the action.
860        //   (see PclZip::listContent() for list entry format)
861        // --------------------------------------------------------------------------------
862        //function extractByIndex($p_index, options...)
863        public function extractByIndex($p_index) {
864                $v_result = 1;
865
866                // ----- Reset the error handler
867                $this->privErrorReset();
868
869                // ----- Check archive
870                if (!$this->privCheckFormat()) {
871                        return (0);
872                }
873
874                // ----- Set default values
875                $v_options = array();
876//    $v_path = "./";
877                $v_path = '';
878                $v_remove_path = "";
879                $v_remove_all_path = false;
880
881                // ----- Look for variable options arguments
882                $v_size = func_num_args();
883
884                // ----- Default values for option
885                $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = false;
886
887                // ----- Look for arguments
888                if ($v_size > 1) {
889                        // ----- Get the arguments
890                        $v_arg_list = func_get_args();
891
892                        // ----- Remove form the options list the first argument
893                        array_shift($v_arg_list);
894                        $v_size--;
895
896                        // ----- Look for first arg
897                        if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
898
899                                // ----- Parse the options
900                                $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
901                                        array(
902                                                PCLZIP_OPT_PATH => 'optional',
903                                                PCLZIP_OPT_REMOVE_PATH => 'optional',
904                                                PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
905                                                PCLZIP_OPT_EXTRACT_AS_STRING => 'optional',
906                                                PCLZIP_OPT_ADD_PATH => 'optional',
907                                                PCLZIP_CB_PRE_EXTRACT => 'optional',
908                                                PCLZIP_CB_POST_EXTRACT => 'optional',
909                                                PCLZIP_OPT_SET_CHMOD => 'optional',
910                                                PCLZIP_OPT_REPLACE_NEWER => 'optional',
911                                                PCLZIP_OPT_STOP_ON_ERROR => 'optional',
912                                                PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional',
913                                                PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
914                                                PCLZIP_OPT_TEMP_FILE_ON => 'optional',
915                                                PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
916                                        ));
917                                if ($v_result != 1) {
918                                        return 0;
919                                }
920
921                                // ----- Set the arguments
922                                if (isset($v_options[PCLZIP_OPT_PATH])) {
923                                        $v_path = $v_options[PCLZIP_OPT_PATH];
924                                }
925                                if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) {
926                                        $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH];
927                                }
928                                if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) {
929                                        $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH];
930                                }
931                                if (isset($v_options[PCLZIP_OPT_ADD_PATH])) {
932                                        // ----- Check for '/' in last path char
933                                        if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) {
934                                                $v_path .= '/';
935                                        }
936                                        $v_path .= $v_options[PCLZIP_OPT_ADD_PATH];
937                                }
938                                if (!isset($v_options[PCLZIP_OPT_EXTRACT_AS_STRING])) {
939                                        $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = false;
940                                } else {
941                                }
942                        }
943
944                        // ----- Look for 2 args
945                        // Here we need to support the first historic synopsis of the
946                        // method.
947                        else {
948
949                                // ----- Get the first argument
950                                $v_path = $v_arg_list[0];
951
952                                // ----- Look for the optional second argument
953                                if ($v_size == 2) {
954                                        $v_remove_path = $v_arg_list[1];
955                                } else {
956                                        if ($v_size > 2) {
957                                                // ----- Error log
958                                                PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments");
959
960                                                // ----- Return
961                                                return 0;
962                                        }
963                                }
964                        }
965                }
966
967                // ----- Trace
968
969                // ----- Trick
970                // Here I want to reuse extractByRule(), so I need to parse the $p_index
971                // with privParseOptions()
972                $v_arg_trick = array(PCLZIP_OPT_BY_INDEX, $p_index);
973                $v_options_trick = array();
974                $v_result = $this->privParseOptions($v_arg_trick, sizeof($v_arg_trick), $v_options_trick,
975                        array(PCLZIP_OPT_BY_INDEX => 'optional'));
976                if ($v_result != 1) {
977                        return 0;
978                }
979                $v_options[PCLZIP_OPT_BY_INDEX] = $v_options_trick[PCLZIP_OPT_BY_INDEX];
980
981                // ----- Look for default option values
982                $this->privOptionDefaultThreshold($v_options);
983
984                // ----- Call the extracting fct
985                if (($v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, $v_remove_all_path, $v_options)) < 1) {
986                        return (0);
987                }
988
989                // ----- Return
990                return $p_list;
991        }
992        // --------------------------------------------------------------------------------
993
994        // --------------------------------------------------------------------------------
995        // Function :
996        //   delete([$p_option, $p_option_value, ...])
997        // Description :
998        //   This method removes files from the archive.
999        //   If no parameters are given, then all the archive is emptied.
1000        // Parameters :
1001        //   None or optional arguments.
1002        // Options :
1003        //   PCLZIP_OPT_BY_INDEX :
1004        //   PCLZIP_OPT_BY_NAME :
1005        //   PCLZIP_OPT_BY_EREG :
1006        //   PCLZIP_OPT_BY_PREG :
1007        // Return Values :
1008        //   0 on failure,
1009        //   The list of the files which are still present in the archive.
1010        //   (see PclZip::listContent() for list entry format)
1011        // --------------------------------------------------------------------------------
1012        public function delete() {
1013                $v_result = 1;
1014
1015                // ----- Reset the error handler
1016                $this->privErrorReset();
1017
1018                // ----- Check archive
1019                if (!$this->privCheckFormat()) {
1020                        return (0);
1021                }
1022
1023                // ----- Set default values
1024                $v_options = array();
1025
1026                // ----- Look for variable options arguments
1027                $v_size = func_num_args();
1028
1029                // ----- Look for arguments
1030                if ($v_size > 0) {
1031                        // ----- Get the arguments
1032                        $v_arg_list = func_get_args();
1033
1034                        // ----- Parse the options
1035                        $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options,
1036                                array(
1037                                        PCLZIP_OPT_BY_NAME => 'optional',
1038                                        PCLZIP_OPT_BY_EREG => 'optional',
1039                                        PCLZIP_OPT_BY_PREG => 'optional',
1040                                        PCLZIP_OPT_BY_INDEX => 'optional'
1041                                ));
1042                        if ($v_result != 1) {
1043                                return 0;
1044                        }
1045                }
1046
1047                // ----- Magic quotes trick
1048                $this->privDisableMagicQuotes();
1049
1050                // ----- Call the delete fct
1051                $v_list = array();
1052                if (($v_result = $this->privDeleteByRule($v_list, $v_options)) != 1) {
1053                        $this->privSwapBackMagicQuotes();
1054                        unset($v_list);
1055
1056                        return (0);
1057                }
1058
1059                // ----- Magic quotes trick
1060                $this->privSwapBackMagicQuotes();
1061
1062                // ----- Return
1063                return $v_list;
1064        }
1065        // --------------------------------------------------------------------------------
1066
1067        // --------------------------------------------------------------------------------
1068        // Function : deleteByIndex()
1069        // Description :
1070        //   ***** Deprecated *****
1071        //   delete(PCLZIP_OPT_BY_INDEX, $p_index) should be prefered.
1072        // --------------------------------------------------------------------------------
1073        public function deleteByIndex($p_index) {
1074
1075                $p_list = $this->delete(PCLZIP_OPT_BY_INDEX, $p_index);
1076
1077                // ----- Return
1078                return $p_list;
1079        }
1080        // --------------------------------------------------------------------------------
1081
1082        // --------------------------------------------------------------------------------
1083        // Function : properties()
1084        // Description :
1085        //   This method gives the properties of the archive.
1086        //   The properties are :
1087        //     nb : Number of files in the archive
1088        //     comment : Comment associated with the archive file
1089        //     status : not_exist, ok
1090        // Parameters :
1091        //   None
1092        // Return Values :
1093        //   0 on failure,
1094        //   An array with the archive properties.
1095        // --------------------------------------------------------------------------------
1096        public function properties() {
1097
1098                // ----- Reset the error handler
1099                $this->privErrorReset();
1100
1101                // ----- Magic quotes trick
1102                $this->privDisableMagicQuotes();
1103
1104                // ----- Check archive
1105                if (!$this->privCheckFormat()) {
1106                        $this->privSwapBackMagicQuotes();
1107
1108                        return (0);
1109                }
1110
1111                // ----- Default properties
1112                $v_prop = array();
1113                $v_prop['comment'] = '';
1114                $v_prop['nb'] = 0;
1115                $v_prop['status'] = 'not_exist';
1116
1117                // ----- Look if file exists
1118                if (@is_file($this->zipname)) {
1119                        // ----- Open the zip file
1120                        if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0) {
1121                                $this->privSwapBackMagicQuotes();
1122
1123                                // ----- Error log
1124                                PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL,
1125                                        'Unable to open archive \'' . $this->zipname . '\' in binary read mode');
1126
1127                                // ----- Return
1128                                return 0;
1129                        }
1130
1131                        // ----- Read the central directory informations
1132                        $v_central_dir = array();
1133                        if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) {
1134                                $this->privSwapBackMagicQuotes();
1135
1136                                return 0;
1137                        }
1138
1139                        // ----- Close the zip file
1140                        $this->privCloseFd();
1141
1142                        // ----- Set the user attributes
1143                        $v_prop['comment'] = $v_central_dir['comment'];
1144                        $v_prop['nb'] = $v_central_dir['entries'];
1145                        $v_prop['status'] = 'ok';
1146                }
1147
1148                // ----- Magic quotes trick
1149                $this->privSwapBackMagicQuotes();
1150
1151                // ----- Return
1152                return $v_prop;
1153        }
1154        // --------------------------------------------------------------------------------
1155
1156        // --------------------------------------------------------------------------------
1157        // Function : duplicate()
1158        // Description :
1159        //   This method creates an archive by copying the content of an other one. If
1160        //   the archive already exist, it is replaced by the new one without any warning.
1161        // Parameters :
1162        //   $p_archive : The filename of a valid archive, or
1163        //                a valid PclZip object.
1164        // Return Values :
1165        //   1 on success.
1166        //   0 or a negative value on error (error code).
1167        // --------------------------------------------------------------------------------
1168        public function duplicate($p_archive) {
1169                $v_result = 1;
1170
1171                // ----- Reset the error handler
1172                $this->privErrorReset();
1173
1174                // ----- Look if the $p_archive is a PclZip object
1175                if ((is_object($p_archive)) && (get_class($p_archive) == 'pclzip')) {
1176
1177                        // ----- Duplicate the archive
1178                        $v_result = $this->privDuplicate($p_archive->zipname);
1179                } // ----- Look if the $p_archive is a string (so a filename)
1180                else {
1181                        if (is_string($p_archive)) {
1182
1183                                // ----- Check that $p_archive is a valid zip file
1184                                // TBC : Should also check the archive format
1185                                if (!is_file($p_archive)) {
1186                                        // ----- Error log
1187                                        PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "No file with filename '" . $p_archive . "'");
1188                                        $v_result = PCLZIP_ERR_MISSING_FILE;
1189                                } else {
1190                                        // ----- Duplicate the archive
1191                                        $v_result = $this->privDuplicate($p_archive);
1192                                }
1193                        } // ----- Invalid variable
1194                        else {
1195                                // ----- Error log
1196                                PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add");
1197                                $v_result = PCLZIP_ERR_INVALID_PARAMETER;
1198                        }
1199                }
1200
1201                // ----- Return
1202                return $v_result;
1203        }
1204        // --------------------------------------------------------------------------------
1205
1206        // --------------------------------------------------------------------------------
1207        // Function : merge()
1208        // Description :
1209        //   This method merge the $p_archive_to_add archive at the end of the current
1210        //   one ($this).
1211        //   If the archive ($this) does not exist, the merge becomes a duplicate.
1212        //   If the $p_archive_to_add archive does not exist, the merge is a success.
1213        // Parameters :
1214        //   $p_archive_to_add : It can be directly the filename of a valid zip archive,
1215        //                       or a PclZip object archive.
1216        // Return Values :
1217        //   1 on success,
1218        //   0 or negative values on error (see below).
1219        // --------------------------------------------------------------------------------
1220        public function merge($p_archive_to_add) {
1221                $v_result = 1;
1222
1223                // ----- Reset the error handler
1224                $this->privErrorReset();
1225
1226                // ----- Check archive
1227                if (!$this->privCheckFormat()) {
1228                        return (0);
1229                }
1230
1231                // ----- Look if the $p_archive_to_add is a PclZip object
1232                if ((is_object($p_archive_to_add)) && (get_class($p_archive_to_add) == 'pclzip')) {
1233
1234                        // ----- Merge the archive
1235                        $v_result = $this->privMerge($p_archive_to_add);
1236                } // ----- Look if the $p_archive_to_add is a string (so a filename)
1237                else {
1238                        if (is_string($p_archive_to_add)) {
1239
1240                                // ----- Create a temporary archive
1241                                $v_object_archive = new PclZip($p_archive_to_add);
1242
1243                                // ----- Merge the archive
1244                                $v_result = $this->privMerge($v_object_archive);
1245                        } // ----- Invalid variable
1246                        else {
1247                                // ----- Error log
1248                                PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add");
1249                                $v_result = PCLZIP_ERR_INVALID_PARAMETER;
1250                        }
1251                }
1252
1253                // ----- Return
1254                return $v_result;
1255        }
1256        // --------------------------------------------------------------------------------
1257
1258
1259        // --------------------------------------------------------------------------------
1260        // Function : errorCode()
1261        // Description :
1262        // Parameters :
1263        // --------------------------------------------------------------------------------
1264        public function errorCode() {
1265                if (PCLZIP_ERROR_EXTERNAL == 1) {
1266                        return (PclErrorCode());
1267                } else {
1268                        return ($this->error_code);
1269                }
1270        }
1271        // --------------------------------------------------------------------------------
1272
1273        // --------------------------------------------------------------------------------
1274        // Function : errorName()
1275        // Description :
1276        // Parameters :
1277        // --------------------------------------------------------------------------------
1278        public function errorName($p_with_code = false) {
1279                $v_name = array(
1280                        PCLZIP_ERR_NO_ERROR => 'PCLZIP_ERR_NO_ERROR',
1281                        PCLZIP_ERR_WRITE_OPEN_FAIL => 'PCLZIP_ERR_WRITE_OPEN_FAIL',
1282                        PCLZIP_ERR_READ_OPEN_FAIL => 'PCLZIP_ERR_READ_OPEN_FAIL',
1283                        PCLZIP_ERR_INVALID_PARAMETER => 'PCLZIP_ERR_INVALID_PARAMETER',
1284                        PCLZIP_ERR_MISSING_FILE => 'PCLZIP_ERR_MISSING_FILE',
1285                        PCLZIP_ERR_FILENAME_TOO_LONG => 'PCLZIP_ERR_FILENAME_TOO_LONG',
1286                        PCLZIP_ERR_INVALID_ZIP => 'PCLZIP_ERR_INVALID_ZIP',
1287                        PCLZIP_ERR_BAD_EXTRACTED_FILE => 'PCLZIP_ERR_BAD_EXTRACTED_FILE',
1288                        PCLZIP_ERR_DIR_CREATE_FAIL => 'PCLZIP_ERR_DIR_CREATE_FAIL',
1289                        PCLZIP_ERR_BAD_EXTENSION => 'PCLZIP_ERR_BAD_EXTENSION',
1290                        PCLZIP_ERR_BAD_FORMAT => 'PCLZIP_ERR_BAD_FORMAT',
1291                        PCLZIP_ERR_DELETE_FILE_FAIL => 'PCLZIP_ERR_DELETE_FILE_FAIL',
1292                        PCLZIP_ERR_RENAME_FILE_FAIL => 'PCLZIP_ERR_RENAME_FILE_FAIL',
1293                        PCLZIP_ERR_BAD_CHECKSUM => 'PCLZIP_ERR_BAD_CHECKSUM',
1294                        PCLZIP_ERR_INVALID_ARCHIVE_ZIP => 'PCLZIP_ERR_INVALID_ARCHIVE_ZIP',
1295                        PCLZIP_ERR_MISSING_OPTION_VALUE => 'PCLZIP_ERR_MISSING_OPTION_VALUE',
1296                        PCLZIP_ERR_INVALID_OPTION_VALUE => 'PCLZIP_ERR_INVALID_OPTION_VALUE',
1297                        PCLZIP_ERR_UNSUPPORTED_COMPRESSION => 'PCLZIP_ERR_UNSUPPORTED_COMPRESSION',
1298                        PCLZIP_ERR_UNSUPPORTED_ENCRYPTION => 'PCLZIP_ERR_UNSUPPORTED_ENCRYPTION',
1299                        PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE => 'PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE',
1300                        PCLZIP_ERR_DIRECTORY_RESTRICTION => 'PCLZIP_ERR_DIRECTORY_RESTRICTION'
1301                );
1302
1303                if (isset($v_name[$this->error_code])) {
1304                        $v_value = $v_name[$this->error_code];
1305                } else {
1306                        $v_value = 'NoName';
1307                }
1308
1309                if ($p_with_code) {
1310                        return ($v_value . ' (' . $this->error_code . ')');
1311                } else {
1312                        return ($v_value);
1313                }
1314        }
1315        // --------------------------------------------------------------------------------
1316
1317        // --------------------------------------------------------------------------------
1318        // Function : errorInfo()
1319        // Description :
1320        // Parameters :
1321        // --------------------------------------------------------------------------------
1322        public function errorInfo($p_full = false) {
1323                if (PCLZIP_ERROR_EXTERNAL == 1) {
1324                        return (PclErrorString());
1325                } else {
1326                        if ($p_full) {
1327                                return ($this->errorName(true) . " : " . $this->error_string);
1328                        } else {
1329                                return ($this->error_string . " [code " . $this->error_code . "]");
1330                        }
1331                }
1332        }
1333        // --------------------------------------------------------------------------------
1334
1335
1336// --------------------------------------------------------------------------------
1337// ***** UNDER THIS LINE ARE DEFINED PRIVATE INTERNAL FUNCTIONS *****
1338// *****                                                        *****
1339// *****       THESES FUNCTIONS MUST NOT BE USED DIRECTLY       *****
1340// --------------------------------------------------------------------------------
1341
1342
1343        // --------------------------------------------------------------------------------
1344        // Function : privCheckFormat()
1345        // Description :
1346        //   This method check that the archive exists and is a valid zip archive.
1347        //   Several level of check exists. (futur)
1348        // Parameters :
1349        //   $p_level : Level of check. Default 0.
1350        //              0 : Check the first bytes (magic codes) (default value))
1351        //              1 : 0 + Check the central directory (futur)
1352        //              2 : 1 + Check each file header (futur)
1353        // Return Values :
1354        //   true on success,
1355        //   false on error, the error code is set.
1356        // --------------------------------------------------------------------------------
1357        public function privCheckFormat($p_level = 0) {
1358                $v_result = true;
1359
1360                // ----- Reset the file system cache
1361                clearstatcache();
1362
1363                // ----- Reset the error handler
1364                $this->privErrorReset();
1365
1366                // ----- Look if the file exits
1367                if (!is_file($this->zipname)) {
1368                        // ----- Error log
1369                        PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "Missing archive file '" . $this->zipname . "'");
1370
1371                        return (false);
1372                }
1373
1374                // ----- Check that the file is readeable
1375                if (!is_readable($this->zipname)) {
1376                        // ----- Error log
1377                        PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to read archive '" . $this->zipname . "'");
1378
1379                        return (false);
1380                }
1381
1382                // ----- Check the magic code
1383                // TBC
1384
1385                // ----- Check the central header
1386                // TBC
1387
1388                // ----- Check each file header
1389                // TBC
1390
1391                // ----- Return
1392                return $v_result;
1393        }
1394        // --------------------------------------------------------------------------------
1395
1396        // --------------------------------------------------------------------------------
1397        // Function : privParseOptions()
1398        // Description :
1399        //   This internal methods reads the variable list of arguments ($p_options_list,
1400        //   $p_size) and generate an array with the options and values ($v_result_list).
1401        //   $v_requested_options contains the options that can be present and those that
1402        //   must be present.
1403        //   $v_requested_options is an array, with the option value as key, and 'optional',
1404        //   or 'mandatory' as value.
1405        // Parameters :
1406        //   See above.
1407        // Return Values :
1408        //   1 on success.
1409        //   0 on failure.
1410        // --------------------------------------------------------------------------------
1411        public function privParseOptions(&$p_options_list, $p_size, &$v_result_list, $v_requested_options = false) {
1412                $v_result = 1;
1413
1414                // ----- Read the options
1415                $i = 0;
1416                while ($i < $p_size) {
1417
1418                        // ----- Check if the option is supported
1419                        if (!isset($v_requested_options[$p_options_list[$i]])) {
1420                                // ----- Error log
1421                                PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER,
1422                                        "Invalid optional parameter '" . $p_options_list[$i] . "' for this method");
1423
1424                                // ----- Return
1425                                return PclZip::errorCode();
1426                        }
1427
1428                        // ----- Look for next option
1429                        switch ($p_options_list[$i]) {
1430                                // ----- Look for options that request a path value
1431                                case PCLZIP_OPT_PATH :
1432                                case PCLZIP_OPT_REMOVE_PATH :
1433                                case PCLZIP_OPT_ADD_PATH :
1434                                        // ----- Check the number of parameters
1435                                        if (($i + 1) >= $p_size) {
1436                                                // ----- Error log
1437                                                PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE,
1438                                                        "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'");
1439
1440                                                // ----- Return
1441                                                return PclZip::errorCode();
1442                                        }
1443
1444                                        // ----- Get the value
1445                                        $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i + 1], false);
1446                                        $i++;
1447                                        break;
1448
1449                                case PCLZIP_OPT_TEMP_FILE_THRESHOLD :
1450                                        // ----- Check the number of parameters
1451                                        if (($i + 1) >= $p_size) {
1452                                                PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE,
1453                                                        "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'");
1454
1455                                                return PclZip::errorCode();
1456                                        }
1457
1458                                        // ----- Check for incompatible options
1459                                        if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) {
1460                                                PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER,
1461                                                        "Option '" . PclZipUtilOptionText($p_options_list[$i]) . "' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'");
1462
1463                                                return PclZip::errorCode();
1464                                        }
1465
1466                                        // ----- Check the value
1467                                        $v_value = $p_options_list[$i + 1];
1468                                        if ((!is_integer($v_value)) || ($v_value < 0)) {
1469                                                PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE,
1470                                                        "Integer expected for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'");
1471
1472                                                return PclZip::errorCode();
1473                                        }
1474
1475                                        // ----- Get the value (and convert it in bytes)
1476                                        $v_result_list[$p_options_list[$i]] = $v_value * 1048576;
1477                                        $i++;
1478                                        break;
1479
1480                                case PCLZIP_OPT_TEMP_FILE_ON :
1481                                        // ----- Check for incompatible options
1482                                        if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) {
1483                                                PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER,
1484                                                        "Option '" . PclZipUtilOptionText($p_options_list[$i]) . "' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'");
1485
1486                                                return PclZip::errorCode();
1487                                        }
1488
1489                                        $v_result_list[$p_options_list[$i]] = true;
1490                                        break;
1491
1492                                case PCLZIP_OPT_TEMP_FILE_OFF :
1493                                        // ----- Check for incompatible options
1494                                        if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_ON])) {
1495                                                PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER,
1496                                                        "Option '" . PclZipUtilOptionText($p_options_list[$i]) . "' can not be used with option 'PCLZIP_OPT_TEMP_FILE_ON'");
1497
1498                                                return PclZip::errorCode();
1499                                        }
1500                                        // ----- Check for incompatible options
1501                                        if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) {
1502                                                PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER,
1503                                                        "Option '" . PclZipUtilOptionText($p_options_list[$i]) . "' can not be used with option 'PCLZIP_OPT_TEMP_FILE_THRESHOLD'");
1504
1505                                                return PclZip::errorCode();
1506                                        }
1507
1508                                        $v_result_list[$p_options_list[$i]] = true;
1509                                        break;
1510
1511                                case PCLZIP_OPT_EXTRACT_DIR_RESTRICTION :
1512                                        // ----- Check the number of parameters
1513                                        if (($i + 1) >= $p_size) {
1514                                                // ----- Error log
1515                                                PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE,
1516                                                        "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'");
1517
1518                                                // ----- Return
1519                                                return PclZip::errorCode();
1520                                        }
1521
1522                                        // ----- Get the value
1523                                        if (is_string($p_options_list[$i + 1])
1524                                                && ($p_options_list[$i + 1] != '')
1525                                        ) {
1526                                                $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i + 1], false);
1527                                                $i++;
1528                                        } else {
1529                                        }
1530                                        break;
1531
1532                                // ----- Look for options that request an array of string for value
1533                                case PCLZIP_OPT_BY_NAME :
1534                                        // ----- Check the number of parameters
1535                                        if (($i + 1) >= $p_size) {
1536                                                // ----- Error log
1537                                                PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE,
1538                                                        "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'");
1539
1540                                                // ----- Return
1541                                                return PclZip::errorCode();
1542                                        }
1543
1544                                        // ----- Get the value
1545                                        if (is_string($p_options_list[$i + 1])) {
1546                                                $v_result_list[$p_options_list[$i]][0] = $p_options_list[$i + 1];
1547                                        } else {
1548                                                if (is_array($p_options_list[$i + 1])) {
1549                                                        $v_result_list[$p_options_list[$i]] = $p_options_list[$i + 1];
1550                                                } else {
1551                                                        // ----- Error log
1552                                                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE,
1553                                                                "Wrong parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'");
1554
1555                                                        // ----- Return
1556                                                        return PclZip::errorCode();
1557                                                }
1558                                        }
1559                                        $i++;
1560                                        break;
1561
1562                                // ----- Look for options that request an EREG or PREG expression
1563                                case PCLZIP_OPT_BY_EREG :
1564                                        // ereg() is deprecated starting with PHP 5.3. Move PCLZIP_OPT_BY_EREG
1565                                        // to PCLZIP_OPT_BY_PREG
1566                                        $p_options_list[$i] = PCLZIP_OPT_BY_PREG;
1567                                case PCLZIP_OPT_BY_PREG :
1568                                        //case PCLZIP_OPT_CRYPT :
1569                                        // ----- Check the number of parameters
1570                                        if (($i + 1) >= $p_size) {
1571                                                // ----- Error log
1572                                                PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE,
1573                                                        "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'");
1574
1575                                                // ----- Return
1576                                                return PclZip::errorCode();
1577                                        }
1578
1579                                        // ----- Get the value
1580                                        if (is_string($p_options_list[$i + 1])) {
1581                                                $v_result_list[$p_options_list[$i]] = $p_options_list[$i + 1];
1582                                        } else {
1583                                                // ----- Error log
1584                                                PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE,
1585                                                        "Wrong parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'");
1586
1587                                                // ----- Return
1588                                                return PclZip::errorCode();
1589                                        }
1590                                        $i++;
1591                                        break;
1592
1593                                // ----- Look for options that takes a string
1594                                case PCLZIP_OPT_COMMENT :
1595                                case PCLZIP_OPT_ADD_COMMENT :
1596                                case PCLZIP_OPT_PREPEND_COMMENT :
1597                                        // ----- Check the number of parameters
1598                                        if (($i + 1) >= $p_size) {
1599                                                // ----- Error log
1600                                                PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE,
1601                                                        "Missing parameter value for option '"
1602                                                        . PclZipUtilOptionText($p_options_list[$i])
1603                                                        . "'");
1604
1605                                                // ----- Return
1606                                                return PclZip::errorCode();
1607                                        }
1608
1609                                        // ----- Get the value
1610                                        if (is_string($p_options_list[$i + 1])) {
1611                                                $v_result_list[$p_options_list[$i]] = $p_options_list[$i + 1];
1612                                        } else {
1613                                                // ----- Error log
1614                                                PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE,
1615                                                        "Wrong parameter value for option '"
1616                                                        . PclZipUtilOptionText($p_options_list[$i])
1617                                                        . "'");
1618
1619                                                // ----- Return
1620                                                return PclZip::errorCode();
1621                                        }
1622                                        $i++;
1623                                        break;
1624
1625                                // ----- Look for options that request an array of index
1626                                case PCLZIP_OPT_BY_INDEX :
1627                                        // ----- Check the number of parameters
1628                                        if (($i + 1) >= $p_size) {
1629                                                // ----- Error log
1630                                                PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE,
1631                                                        "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'");
1632
1633                                                // ----- Return
1634                                                return PclZip::errorCode();
1635                                        }
1636
1637                                        // ----- Get the value
1638                                        $v_work_list = array();
1639                                        if (is_string($p_options_list[$i + 1])) {
1640
1641                                                // ----- Remove spaces
1642                                                $p_options_list[$i + 1] = strtr($p_options_list[$i + 1], ' ', '');
1643
1644                                                // ----- Parse items
1645                                                $v_work_list = explode(",", $p_options_list[$i + 1]);
1646                                        } else {
1647                                                if (is_integer($p_options_list[$i + 1])) {
1648                                                        $v_work_list[0] = $p_options_list[$i + 1] . '-' . $p_options_list[$i + 1];
1649                                                } else {
1650                                                        if (is_array($p_options_list[$i + 1])) {
1651                                                                $v_work_list = $p_options_list[$i + 1];
1652                                                        } else {
1653                                                                // ----- Error log
1654                                                                PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE,
1655                                                                        "Value must be integer, string or array for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'");
1656
1657                                                                // ----- Return
1658                                                                return PclZip::errorCode();
1659                                                        }
1660                                                }
1661                                        }
1662
1663                                        // ----- Reduce the index list
1664                                        // each index item in the list must be a couple with a start and
1665                                        // an end value : [0,3], [5-5], [8-10], ...
1666                                        // ----- Check the format of each item
1667                                        $v_sort_flag = false;
1668                                        $v_sort_value = 0;
1669                                        for ($j = 0; $j < sizeof($v_work_list); $j++) {
1670                                                // ----- Explode the item
1671                                                $v_item_list = explode("-", $v_work_list[$j]);
1672                                                $v_size_item_list = sizeof($v_item_list);
1673
1674                                                // ----- TBC : Here we might check that each item is a
1675                                                // real integer ...
1676
1677                                                // ----- Look for single value
1678                                                if ($v_size_item_list == 1) {
1679                                                        // ----- Set the option value
1680                                                        $v_result_list[$p_options_list[$i]][$j]['start'] = $v_item_list[0];
1681                                                        $v_result_list[$p_options_list[$i]][$j]['end'] = $v_item_list[0];
1682                                                } elseif ($v_size_item_list == 2) {
1683                                                        // ----- Set the option value
1684                                                        $v_result_list[$p_options_list[$i]][$j]['start'] = $v_item_list[0];
1685                                                        $v_result_list[$p_options_list[$i]][$j]['end'] = $v_item_list[1];
1686                                                } else {
1687                                                        // ----- Error log
1688                                                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE,
1689                                                                "Too many values in index range for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'");
1690
1691                                                        // ----- Return
1692                                                        return PclZip::errorCode();
1693                                                }
1694
1695
1696                                                // ----- Look for list sort
1697                                                if ($v_result_list[$p_options_list[$i]][$j]['start'] < $v_sort_value) {
1698                                                        $v_sort_flag = true;
1699
1700                                                        // ----- TBC : An automatic sort should be writen ...
1701                                                        // ----- Error log
1702                                                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE,
1703                                                                "Invalid order of index range for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'");
1704
1705                                                        // ----- Return
1706                                                        return PclZip::errorCode();
1707                                                }
1708                                                $v_sort_value = $v_result_list[$p_options_list[$i]][$j]['start'];
1709                                        }
1710
1711                                        // ----- Sort the items
1712                                        if ($v_sort_flag) {
1713                                                // TBC : To Be Completed
1714                                        }
1715
1716                                        // ----- Next option
1717                                        $i++;
1718                                        break;
1719
1720                                // ----- Look for options that request no value
1721                                case PCLZIP_OPT_REMOVE_ALL_PATH :
1722                                case PCLZIP_OPT_EXTRACT_AS_STRING :
1723                                case PCLZIP_OPT_NO_COMPRESSION :
1724                                case PCLZIP_OPT_EXTRACT_IN_OUTPUT :
1725                                case PCLZIP_OPT_REPLACE_NEWER :
1726                                case PCLZIP_OPT_STOP_ON_ERROR :
1727                                        $v_result_list[$p_options_list[$i]] = true;
1728                                        break;
1729
1730                                // ----- Look for options that request an octal value
1731                                case PCLZIP_OPT_SET_CHMOD :
1732                                        // ----- Check the number of parameters
1733                                        if (($i + 1) >= $p_size) {
1734                                                // ----- Error log
1735                                                PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE,
1736                                                        "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'");
1737
1738                                                // ----- Return
1739                                                return PclZip::errorCode();
1740                                        }
1741
1742                                        // ----- Get the value
1743                                        $v_result_list[$p_options_list[$i]] = $p_options_list[$i + 1];
1744                                        $i++;
1745                                        break;
1746
1747                                // ----- Look for options that request a call-back
1748                                case PCLZIP_CB_PRE_EXTRACT :
1749                                case PCLZIP_CB_POST_EXTRACT :
1750                                case PCLZIP_CB_PRE_ADD :
1751                                case PCLZIP_CB_POST_ADD :
1752                                        /* for futur use
1753                                        case PCLZIP_CB_PRE_DELETE :
1754                                        case PCLZIP_CB_POST_DELETE :
1755                                        case PCLZIP_CB_PRE_LIST :
1756                                        case PCLZIP_CB_POST_LIST :
1757                                        */
1758                                        // ----- Check the number of parameters
1759                                        if (($i + 1) >= $p_size) {
1760                                                // ----- Error log
1761                                                PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE,
1762                                                        "Missing parameter value for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'");
1763
1764                                                // ----- Return
1765                                                return PclZip::errorCode();
1766                                        }
1767
1768                                        // ----- Get the value
1769                                        $v_function_name = $p_options_list[$i + 1];
1770
1771                                        // ----- Check that the value is a valid existing function
1772                                        if (!function_exists($v_function_name)) {
1773                                                // ----- Error log
1774                                                PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE,
1775                                                        "Function '" . $v_function_name . "()' is not an existing function for option '" . PclZipUtilOptionText($p_options_list[$i]) . "'");
1776
1777                                                // ----- Return
1778                                                return PclZip::errorCode();
1779                                        }
1780
1781                                        // ----- Set the attribute
1782                                        $v_result_list[$p_options_list[$i]] = $v_function_name;
1783                                        $i++;
1784                                        break;
1785
1786                                default :
1787                                        // ----- Error log
1788                                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER,
1789                                                "Unknown parameter '"
1790                                                . $p_options_list[$i] . "'");
1791
1792                                        // ----- Return
1793                                        return PclZip::errorCode();
1794                        }
1795
1796                        // ----- Next options
1797                        $i++;
1798                }
1799
1800                // ----- Look for mandatory options
1801                if ($v_requested_options !== false) {
1802                        for ($key = reset($v_requested_options); $key = key($v_requested_options); $key = next($v_requested_options)) {
1803                                // ----- Look for mandatory option
1804                                if ($v_requested_options[$key] == 'mandatory') {
1805                                        // ----- Look if present
1806                                        if (!isset($v_result_list[$key])) {
1807                                                // ----- Error log
1808                                                PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER,
1809                                                        "Missing mandatory parameter " . PclZipUtilOptionText($key) . "(" . $key . ")");
1810
1811                                                // ----- Return
1812                                                return PclZip::errorCode();
1813                                        }
1814                                }
1815                        }
1816                }
1817
1818                // ----- Look for default values
1819                if (!isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) {
1820
1821                }
1822
1823                // ----- Return
1824                return $v_result;
1825        }
1826        // --------------------------------------------------------------------------------
1827
1828        // --------------------------------------------------------------------------------
1829        // Function : privOptionDefaultThreshold()
1830        // Description :
1831        // Parameters :
1832        // Return Values :
1833        // --------------------------------------------------------------------------------
1834        public function privOptionDefaultThreshold(&$p_options) {
1835                $v_result = 1;
1836
1837                if (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD])
1838                        || isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])
1839                ) {
1840                        return $v_result;
1841                }
1842
1843                // ----- Get 'memory_limit' configuration value
1844                $v_memory_limit = ini_get('memory_limit');
1845                $v_memory_limit = trim($v_memory_limit);
1846                $last = strtolower(substr($v_memory_limit, -1));
1847                $v_memory_limit = strtolower(substr($v_memory_limit, 0, -1));
1848
1849                if ($last == 'g') //$v_memory_limit = $v_memory_limit*1024*1024*1024;
1850                {
1851                        $v_memory_limit = $v_memory_limit * 1073741824;
1852                }
1853                if ($last == 'm') //$v_memory_limit = $v_memory_limit*1024*1024;
1854                {
1855                        $v_memory_limit = $v_memory_limit * 1048576;
1856                }
1857                if ($last == 'k') {
1858                        $v_memory_limit = $v_memory_limit * 1024;
1859                }
1860
1861                $p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] = floor($v_memory_limit * PCLZIP_TEMPORARY_FILE_RATIO);
1862
1863
1864                // ----- Sanity check : No threshold if value lower than 1M
1865                if ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] < 1048576) {
1866                        unset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]);
1867                }
1868
1869                // ----- Return
1870                return $v_result;
1871        }
1872        // --------------------------------------------------------------------------------
1873
1874        // --------------------------------------------------------------------------------
1875        // Function : privFileDescrParseAtt()
1876        // Description :
1877        // Parameters :
1878        // Return Values :
1879        //   1 on success.
1880        //   0 on failure.
1881        // --------------------------------------------------------------------------------
1882        public function privFileDescrParseAtt(&$p_file_list, &$p_filedescr, $v_options, $v_requested_options = false) {
1883                $v_result = 1;
1884
1885                // ----- For each file in the list check the attributes
1886                foreach ($p_file_list as $v_key => $v_value) {
1887
1888                        // ----- Check if the option is supported
1889                        if (!isset($v_requested_options[$v_key])) {
1890                                // ----- Error log
1891                                PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file attribute '" . $v_key . "' for this file");
1892
1893                                // ----- Return
1894                                return PclZip::errorCode();
1895                        }
1896
1897                        // ----- Look for attribute
1898                        switch ($v_key) {
1899                                case PCLZIP_ATT_FILE_NAME :
1900                                        if (!is_string($v_value)) {
1901                                                PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE,
1902                                                        "Invalid type " . gettype($v_value) . ". String expected for attribute '" . PclZipUtilOptionText($v_key) . "'");
1903
1904                                                return PclZip::errorCode();
1905                                        }
1906
1907                                        $p_filedescr['filename'] = PclZipUtilPathReduction($v_value);
1908
1909                                        if ($p_filedescr['filename'] == '') {
1910                                                PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE,
1911                                                        "Invalid empty filename for attribute '" . PclZipUtilOptionText($v_key) . "'");
1912
1913                                                return PclZip::errorCode();
1914                                        }
1915
1916                                        break;
1917
1918                                case PCLZIP_ATT_FILE_NEW_SHORT_NAME :
1919                                        if (!is_string($v_value)) {
1920                                                PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE,
1921                                                        "Invalid type " . gettype($v_value) . ". String expected for attribute '" . PclZipUtilOptionText($v_key) . "'");
1922
1923                                                return PclZip::errorCode();
1924                                        }
1925
1926                                        $p_filedescr['new_short_name'] = PclZipUtilPathReduction($v_value);
1927
1928                                        if ($p_filedescr['new_short_name'] == '') {
1929                                                PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE,
1930                                                        "Invalid empty short filename for attribute '" . PclZipUtilOptionText($v_key) . "'");
1931
1932                                                return PclZip::errorCode();
1933                                        }
1934                                        break;
1935
1936                                case PCLZIP_ATT_FILE_NEW_FULL_NAME :
1937                                        if (!is_string($v_value)) {
1938                                                PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE,
1939                                                        "Invalid type " . gettype($v_value) . ". String expected for attribute '" . PclZipUtilOptionText($v_key) . "'");
1940
1941                                                return PclZip::errorCode();
1942                                        }
1943
1944                                        $p_filedescr['new_full_name'] = PclZipUtilPathReduction($v_value);
1945
1946                                        if ($p_filedescr['new_full_name'] == '') {
1947                                                PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE,
1948                                                        "Invalid empty full filename for attribute '" . PclZipUtilOptionText($v_key) . "'");
1949
1950                                                return PclZip::errorCode();
1951                                        }
1952                                        break;
1953
1954                                // ----- Look for options that takes a string
1955                                case PCLZIP_ATT_FILE_COMMENT :
1956                                        if (!is_string($v_value)) {
1957                                                PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE,
1958                                                        "Invalid type " . gettype($v_value) . ". String expected for attribute '" . PclZipUtilOptionText($v_key) . "'");
1959
1960                                                return PclZip::errorCode();
1961                                        }
1962
1963                                        $p_filedescr['comment'] = $v_value;
1964                                        break;
1965
1966                                case PCLZIP_ATT_FILE_MTIME :
1967                                        if (!is_integer($v_value)) {
1968                                                PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE,
1969                                                        "Invalid type " . gettype($v_value) . ". Integer expected for attribute '" . PclZipUtilOptionText($v_key) . "'");
1970
1971                                                return PclZip::errorCode();
1972                                        }
1973
1974                                        $p_filedescr['mtime'] = $v_value;
1975                                        break;
1976
1977                                case PCLZIP_ATT_FILE_CONTENT :
1978                                        $p_filedescr['content'] = $v_value;
1979                                        break;
1980
1981                                default :
1982                                        // ----- Error log
1983                                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER,
1984                                                "Unknown parameter '" . $v_key . "'");
1985
1986                                        // ----- Return
1987                                        return PclZip::errorCode();
1988                        }
1989
1990                        // ----- Look for mandatory options
1991                        if ($v_requested_options !== false) {
1992                                for ($key = reset($v_requested_options); $key = key($v_requested_options); $key = next($v_requested_options)) {
1993                                        // ----- Look for mandatory option
1994                                        if ($v_requested_options[$key] == 'mandatory') {
1995                                                // ----- Look if present
1996                                                if (!isset($p_file_list[$key])) {
1997                                                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER,
1998                                                                "Missing mandatory parameter " . PclZipUtilOptionText($key) . "(" . $key . ")");
1999
2000                                                        return PclZip::errorCode();
2001                                                }
2002                                        }
2003                                }
2004                        }
2005
2006                        // end foreach
2007                }
2008
2009                // ----- Return
2010                return $v_result;
2011        }
2012        // --------------------------------------------------------------------------------
2013
2014        // --------------------------------------------------------------------------------
2015        // Function : privFileDescrExpand()
2016        // Description :
2017        //   This method look for each item of the list to see if its a file, a folder
2018        //   or a string to be added as file. For any other type of files (link, other)
2019        //   just ignore the item.
2020        //   Then prepare the information that will be stored for that file.
2021        //   When its a folder, expand the folder with all the files that are in that
2022        //   folder (recursively).
2023        // Parameters :
2024        // Return Values :
2025        //   1 on success.
2026        //   0 on failure.
2027        // --------------------------------------------------------------------------------
2028        public function privFileDescrExpand(&$p_filedescr_list, &$p_options) {
2029                $v_result = 1;
2030
2031                // ----- Create a result list
2032                $v_result_list = array();
2033
2034                // ----- Look each entry
2035                for ($i = 0; $i < sizeof($p_filedescr_list); $i++) {
2036
2037                        // ----- Get filedescr
2038                        $v_descr = $p_filedescr_list[$i];
2039
2040                        // ----- Reduce the filename
2041                        $v_descr['filename'] = PclZipUtilTranslateWinPath($v_descr['filename'], false);
2042                        $v_descr['filename'] = PclZipUtilPathReduction($v_descr['filename']);
2043
2044                        // ----- Look for real file or folder
2045                        if (file_exists($v_descr['filename'])) {
2046                                if (@is_file($v_descr['filename'])) {
2047                                        $v_descr['type'] = 'file';
2048                                } else {
2049                                        if (@is_dir($v_descr['filename'])) {
2050                                                $v_descr['type'] = 'folder';
2051                                        } else {
2052                                                if (@is_link($v_descr['filename'])) {
2053                                                        // skip
2054                                                        continue;
2055                                                } else {
2056                                                        // skip
2057                                                        continue;
2058                                                }
2059                                        }
2060                                }
2061                        } // ----- Look for string added as file
2062                        else {
2063                                if (isset($v_descr['content'])) {
2064                                        $v_descr['type'] = 'virtual_file';
2065                                } // ----- Missing file
2066                                else {
2067                                        // ----- Error log
2068                                        PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "File '" . $v_descr['filename'] . "' does not exist");
2069
2070                                        // ----- Return
2071                                        return PclZip::errorCode();
2072                                }
2073                        }
2074
2075                        // ----- Calculate the stored filename
2076                        $this->privCalculateStoredFilename($v_descr, $p_options);
2077
2078                        // ----- Add the descriptor in result list
2079                        $v_result_list[sizeof($v_result_list)] = $v_descr;
2080
2081                        // ----- Look for folder
2082                        if ($v_descr['type'] == 'folder') {
2083                                // ----- List of items in folder
2084                                $v_dirlist_descr = array();
2085                                $v_dirlist_nb = 0;
2086                                if ($v_folder_handler = opendir($v_descr['filename'])) {
2087                                        while (($v_item_handler = @readdir($v_folder_handler)) !== false) {
2088
2089                                                // ----- Skip '.' and '..'
2090                                                if (($v_item_handler == '.') || ($v_item_handler == '..')) {
2091                                                        continue;
2092                                                }
2093
2094                                                // ----- Compose the full filename
2095                                                $v_dirlist_descr[$v_dirlist_nb]['filename'] = $v_descr['filename'] . '/' . $v_item_handler;
2096
2097                                                // ----- Look for different stored filename
2098                                                // Because the name of the folder was changed, the name of the
2099                                                // files/sub-folders also change
2100                                                if (($v_descr['stored_filename'] != $v_descr['filename'])
2101                                                        && (!isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH]))
2102                                                ) {
2103                                                        if ($v_descr['stored_filename'] != '') {
2104                                                                $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_descr['stored_filename'] . '/' . $v_item_handler;
2105                                                        } else {
2106                                                                $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_item_handler;
2107                                                        }
2108                                                }
2109
2110                                                $v_dirlist_nb++;
2111                                        }
2112
2113                                        @closedir($v_folder_handler);
2114                                } else {
2115                                        // TBC : unable to open folder in read mode
2116                                }
2117
2118                                // ----- Expand each element of the list
2119                                if ($v_dirlist_nb != 0) {
2120                                        // ----- Expand
2121                                        if (($v_result = $this->privFileDescrExpand($v_dirlist_descr, $p_options)) != 1) {
2122                                                return $v_result;
2123                                        }
2124
2125                                        // ----- Concat the resulting list
2126                                        $v_result_list = array_merge($v_result_list, $v_dirlist_descr);
2127                                } else {
2128                                }
2129
2130                                // ----- Free local array
2131                                unset($v_dirlist_descr);
2132                        }
2133                }
2134
2135                // ----- Get the result list
2136                $p_filedescr_list = $v_result_list;
2137
2138                // ----- Return
2139                return $v_result;
2140        }
2141        // --------------------------------------------------------------------------------
2142
2143        // --------------------------------------------------------------------------------
2144        // Function : privCreate()
2145        // Description :
2146        // Parameters :
2147        // Return Values :
2148        // --------------------------------------------------------------------------------
2149        public function privCreate($p_filedescr_list, &$p_result_list, &$p_options) {
2150                $v_result = 1;
2151                $v_list_detail = array();
2152
2153                // ----- Magic quotes trick
2154                $this->privDisableMagicQuotes();
2155
2156                // ----- Open the file in write mode
2157                if (($v_result = $this->privOpenFd('wb')) != 1) {
2158                        // ----- Return
2159                        return $v_result;
2160                }
2161
2162                // ----- Add the list of files
2163                $v_result = $this->privAddList($p_filedescr_list, $p_result_list, $p_options);
2164
2165                // ----- Close
2166                $this->privCloseFd();
2167
2168                // ----- Magic quotes trick
2169                $this->privSwapBackMagicQuotes();
2170
2171                // ----- Return
2172                return $v_result;
2173        }
2174        // --------------------------------------------------------------------------------
2175
2176        // --------------------------------------------------------------------------------
2177        // Function : privAdd()
2178        // Description :
2179        // Parameters :
2180        // Return Values :
2181        // --------------------------------------------------------------------------------
2182        public function privAdd($p_filedescr_list, &$p_result_list, &$p_options) {
2183                $v_result = 1;
2184                $v_list_detail = array();
2185
2186                // ----- Look if the archive exists or is empty
2187                if ((!is_file($this->zipname)) || (filesize($this->zipname) == 0)) {
2188
2189                        // ----- Do a create
2190                        $v_result = $this->privCreate($p_filedescr_list, $p_result_list, $p_options);
2191
2192                        // ----- Return
2193                        return $v_result;
2194                }
2195                // ----- Magic quotes trick
2196                $this->privDisableMagicQuotes();
2197
2198                // ----- Open the zip file
2199                if (($v_result = $this->privOpenFd('rb')) != 1) {
2200                        // ----- Magic quotes trick
2201                        $this->privSwapBackMagicQuotes();
2202
2203                        // ----- Return
2204                        return $v_result;
2205                }
2206
2207                // ----- Read the central directory informations
2208                $v_central_dir = array();
2209                if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) {
2210                        $this->privCloseFd();
2211                        $this->privSwapBackMagicQuotes();
2212
2213                        return $v_result;
2214                }
2215
2216                // ----- Go to beginning of File
2217                @rewind($this->zip_fd);
2218
2219                // ----- Creates a temporay file
2220                $v_zip_temp_name = PCLZIP_TEMPORARY_DIR . uniqid('pclzip-') . '.tmp';
2221
2222                // ----- Open the temporary file in write mode
2223                if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) {
2224                        $this->privCloseFd();
2225                        $this->privSwapBackMagicQuotes();
2226
2227                        PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL,
2228                                'Unable to open temporary file \'' . $v_zip_temp_name . '\' in binary write mode');
2229
2230                        // ----- Return
2231                        return PclZip::errorCode();
2232                }
2233
2234                // ----- Copy the files from the archive to the temporary file
2235                // TBC : Here I should better append the file and go back to erase the central dir
2236                $v_size = $v_central_dir['offset'];
2237                while ($v_size != 0) {
2238                        $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
2239                        $v_buffer = fread($this->zip_fd, $v_read_size);
2240                        @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
2241                        $v_size -= $v_read_size;
2242                }
2243
2244                // ----- Swap the file descriptor
2245                // Here is a trick : I swap the temporary fd with the zip fd, in order to use
2246                // the following methods on the temporary fil and not the real archive
2247                $v_swap = $this->zip_fd;
2248                $this->zip_fd = $v_zip_temp_fd;
2249                $v_zip_temp_fd = $v_swap;
2250
2251                // ----- Add the files
2252                $v_header_list = array();
2253                if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1) {
2254                        fclose($v_zip_temp_fd);
2255                        $this->privCloseFd();
2256                        @unlink($v_zip_temp_name);
2257                        $this->privSwapBackMagicQuotes();
2258
2259                        // ----- Return
2260                        return $v_result;
2261                }
2262
2263                // ----- Store the offset of the central dir
2264                $v_offset = @ftell($this->zip_fd);
2265
2266                // ----- Copy the block of file headers from the old archive
2267                $v_size = $v_central_dir['size'];
2268                while ($v_size != 0) {
2269                        $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
2270                        $v_buffer = @fread($v_zip_temp_fd, $v_read_size);
2271                        @fwrite($this->zip_fd, $v_buffer, $v_read_size);
2272                        $v_size -= $v_read_size;
2273                }
2274
2275                // ----- Create the Central Dir files header
2276                for ($i = 0, $v_count = 0; $i < sizeof($v_header_list); $i++) {
2277                        // ----- Create the file header
2278                        if ($v_header_list[$i]['status'] == 'ok') {
2279                                if (($v_result = $this->privWriteCentralFileHeader($v_header_list[$i])) != 1) {
2280                                        fclose($v_zip_temp_fd);
2281                                        $this->privCloseFd();
2282                                        @unlink($v_zip_temp_name);
2283                                        $this->privSwapBackMagicQuotes();
2284
2285                                        // ----- Return
2286                                        return $v_result;
2287                                }
2288                                $v_count++;
2289                        }
2290
2291                        // ----- Transform the header to a 'usable' info
2292                        $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);
2293                }
2294
2295                // ----- Zip file comment
2296                $v_comment = $v_central_dir['comment'];
2297                if (isset($p_options[PCLZIP_OPT_COMMENT])) {
2298                        $v_comment = $p_options[PCLZIP_OPT_COMMENT];
2299                }
2300                if (isset($p_options[PCLZIP_OPT_ADD_COMMENT])) {
2301                        $v_comment = $v_comment . $p_options[PCLZIP_OPT_ADD_COMMENT];
2302                }
2303                if (isset($p_options[PCLZIP_OPT_PREPEND_COMMENT])) {
2304                        $v_comment = $p_options[PCLZIP_OPT_PREPEND_COMMENT] . $v_comment;
2305                }
2306
2307                // ----- Calculate the size of the central header
2308                $v_size = @ftell($this->zip_fd) - $v_offset;
2309
2310                // ----- Create the central dir footer
2311                if (($v_result = $this->privWriteCentralHeader($v_count + $v_central_dir['entries'], $v_size, $v_offset,
2312                                $v_comment)) != 1
2313                ) {
2314                        // ----- Reset the file list
2315                        unset($v_header_list);
2316                        $this->privSwapBackMagicQuotes();
2317
2318                        // ----- Return
2319                        return $v_result;
2320                }
2321
2322                // ----- Swap back the file descriptor
2323                $v_swap = $this->zip_fd;
2324                $this->zip_fd = $v_zip_temp_fd;
2325                $v_zip_temp_fd = $v_swap;
2326
2327                // ----- Close
2328                $this->privCloseFd();
2329
2330                // ----- Close the temporary file
2331                @fclose($v_zip_temp_fd);
2332
2333                // ----- Magic quotes trick
2334                $this->privSwapBackMagicQuotes();
2335
2336                // ----- Delete the zip file
2337                // TBC : I should test the result ...
2338                @unlink($this->zipname);
2339
2340                // ----- Rename the temporary file
2341                // TBC : I should test the result ...
2342                //@rename($v_zip_temp_name, $this->zipname);
2343                PclZipUtilRename($v_zip_temp_name, $this->zipname);
2344
2345                // ----- Return
2346                return $v_result;
2347        }
2348        // --------------------------------------------------------------------------------
2349
2350        // --------------------------------------------------------------------------------
2351        // Function : privOpenFd()
2352        // Description :
2353        // Parameters :
2354        // --------------------------------------------------------------------------------
2355        public function privOpenFd($p_mode) {
2356                $v_result = 1;
2357
2358                // ----- Look if already open
2359                if ($this->zip_fd != 0) {
2360                        // ----- Error log
2361                        PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Zip file \'' . $this->zipname . '\' already open');
2362
2363                        // ----- Return
2364                        return PclZip::errorCode();
2365                }
2366
2367                // ----- Open the zip file
2368                if (($this->zip_fd = @fopen($this->zipname, $p_mode)) == 0) {
2369                        // ----- Error log
2370                        PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL,
2371                                'Unable to open archive \'' . $this->zipname . '\' in ' . $p_mode . ' mode');
2372
2373                        // ----- Return
2374                        return PclZip::errorCode();
2375                }
2376
2377                // ----- Return
2378                return $v_result;
2379        }
2380        // --------------------------------------------------------------------------------
2381
2382        // --------------------------------------------------------------------------------
2383        // Function : privCloseFd()
2384        // Description :
2385        // Parameters :
2386        // --------------------------------------------------------------------------------
2387        public function privCloseFd() {
2388                $v_result = 1;
2389
2390                if ($this->zip_fd != 0) {
2391                        @fclose($this->zip_fd);
2392                }
2393                $this->zip_fd = 0;
2394
2395                // ----- Return
2396                return $v_result;
2397        }
2398        // --------------------------------------------------------------------------------
2399
2400        // --------------------------------------------------------------------------------
2401        // Function : privAddList()
2402        // Description :
2403        //   $p_add_dir and $p_remove_dir will give the ability to memorize a path which is
2404        //   different from the real path of the file. This is usefull if you want to have PclTar
2405        //   running in any directory, and memorize relative path from an other directory.
2406        // Parameters :
2407        //   $p_list : An array containing the file or directory names to add in the tar
2408        //   $p_result_list : list of added files with their properties (specially the status field)
2409        //   $p_add_dir : Path to add in the filename path archived
2410        //   $p_remove_dir : Path to remove in the filename path archived
2411        // Return Values :
2412        // --------------------------------------------------------------------------------
2413//  function privAddList($p_list, &$p_result_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, &$p_options)
2414        public function privAddList($p_filedescr_list, &$p_result_list, &$p_options) {
2415                $v_result = 1;
2416
2417                // ----- Add the files
2418                $v_header_list = array();
2419                if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1) {
2420                        // ----- Return
2421                        return $v_result;
2422                }
2423
2424                // ----- Store the offset of the central dir
2425                $v_offset = @ftell($this->zip_fd);
2426
2427                // ----- Create the Central Dir files header
2428                for ($i = 0, $v_count = 0; $i < sizeof($v_header_list); $i++) {
2429                        // ----- Create the file header
2430                        if ($v_header_list[$i]['status'] == 'ok') {
2431                                if (($v_result = $this->privWriteCentralFileHeader($v_header_list[$i])) != 1) {
2432                                        // ----- Return
2433                                        return $v_result;
2434                                }
2435                                $v_count++;
2436                        }
2437
2438                        // ----- Transform the header to a 'usable' info
2439                        $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);
2440                }
2441
2442                // ----- Zip file comment
2443                $v_comment = '';
2444                if (isset($p_options[PCLZIP_OPT_COMMENT])) {
2445                        $v_comment = $p_options[PCLZIP_OPT_COMMENT];
2446                }
2447
2448                // ----- Calculate the size of the central header
2449                $v_size = @ftell($this->zip_fd) - $v_offset;
2450
2451                // ----- Create the central dir footer
2452                if (($v_result = $this->privWriteCentralHeader($v_count, $v_size, $v_offset, $v_comment)) != 1) {
2453                        // ----- Reset the file list
2454                        unset($v_header_list);
2455
2456                        // ----- Return
2457                        return $v_result;
2458                }
2459
2460                // ----- Return
2461                return $v_result;
2462        }
2463        // --------------------------------------------------------------------------------
2464
2465        // --------------------------------------------------------------------------------
2466        // Function : privAddFileList()
2467        // Description :
2468        // Parameters :
2469        //   $p_filedescr_list : An array containing the file description
2470        //                      or directory names to add in the zip
2471        //   $p_result_list : list of added files with their properties (specially the status field)
2472        // Return Values :
2473        // --------------------------------------------------------------------------------
2474        public function privAddFileList($p_filedescr_list, &$p_result_list, &$p_options) {
2475                $v_result = 1;
2476                $v_header = array();
2477
2478                // ----- Recuperate the current number of elt in list
2479                $v_nb = sizeof($p_result_list);
2480
2481                // ----- Loop on the files
2482                for ($j = 0; ($j < sizeof($p_filedescr_list)) && ($v_result == 1); $j++) {
2483                        // ----- Format the filename
2484                        $p_filedescr_list[$j]['filename']
2485                                = PclZipUtilTranslateWinPath($p_filedescr_list[$j]['filename'], false);
2486
2487
2488                        // ----- Skip empty file names
2489                        // TBC : Can this be possible ? not checked in DescrParseAtt ?
2490                        if ($p_filedescr_list[$j]['filename'] == "") {
2491                                continue;
2492                        }
2493
2494                        // ----- Check the filename
2495                        if (($p_filedescr_list[$j]['type'] != 'virtual_file')
2496                                && (!file_exists($p_filedescr_list[$j]['filename']))
2497                        ) {
2498                                PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE,
2499                                        "File '" . $p_filedescr_list[$j]['filename'] . "' does not exist");
2500
2501                                return PclZip::errorCode();
2502                        }
2503
2504                        // ----- Look if it is a file or a dir with no all path remove option
2505                        // or a dir with all its path removed
2506//      if (   (is_file($p_filedescr_list[$j]['filename']))
2507//          || (   is_dir($p_filedescr_list[$j]['filename'])
2508                        if (($p_filedescr_list[$j]['type'] == 'file')
2509                                || ($p_filedescr_list[$j]['type'] == 'virtual_file')
2510                                || (($p_filedescr_list[$j]['type'] == 'folder')
2511                                        && (!isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH])
2512                                                || !$p_options[PCLZIP_OPT_REMOVE_ALL_PATH]))
2513                        ) {
2514
2515                                // ----- Add the file
2516                                $v_result = $this->privAddFile($p_filedescr_list[$j], $v_header,
2517                                        $p_options);
2518                                if ($v_result != 1) {
2519                                        return $v_result;
2520                                }
2521
2522                                // ----- Store the file infos
2523                                $p_result_list[$v_nb++] = $v_header;
2524                        }
2525                }
2526
2527                // ----- Return
2528                return $v_result;
2529        }
2530        // --------------------------------------------------------------------------------
2531
2532        // --------------------------------------------------------------------------------
2533        // Function : privAddFile()
2534        // Description :
2535        // Parameters :
2536        // Return Values :
2537        // --------------------------------------------------------------------------------
2538        public function privAddFile($p_filedescr, &$p_header, &$p_options) {
2539                $v_result = 1;
2540
2541                // ----- Working variable
2542                $p_filename = $p_filedescr['filename'];
2543
2544                // TBC : Already done in the fileAtt check ... ?
2545                if ($p_filename == "") {
2546                        // ----- Error log
2547                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file list parameter (invalid or empty list)");
2548
2549                        // ----- Return
2550                        return PclZip::errorCode();
2551                }
2552
2553                // ----- Look for a stored different filename
2554                /* TBC : Removed
2555    if (isset($p_filedescr['stored_filename'])) {
2556      $v_stored_filename = $p_filedescr['stored_filename'];
2557    }
2558    else {
2559      $v_stored_filename = $p_filedescr['stored_filename'];
2560    }
2561    */
2562
2563                // ----- Set the file properties
2564                clearstatcache();
2565                $p_header['version'] = 20;
2566                $p_header['version_extracted'] = 10;
2567                $p_header['flag'] = 0;
2568                $p_header['compression'] = 0;
2569                $p_header['crc'] = 0;
2570                $p_header['compressed_size'] = 0;
2571                $p_header['filename_len'] = strlen($p_filename);
2572                $p_header['extra_len'] = 0;
2573                $p_header['disk'] = 0;
2574                $p_header['internal'] = 0;
2575                $p_header['offset'] = 0;
2576                $p_header['filename'] = $p_filename;
2577// TBC : Removed    $p_header['stored_filename'] = $v_stored_filename;
2578                $p_header['stored_filename'] = $p_filedescr['stored_filename'];
2579                $p_header['extra'] = '';
2580                $p_header['status'] = 'ok';
2581                $p_header['index'] = -1;
2582
2583                // ----- Look for regular file
2584                if ($p_filedescr['type'] == 'file') {
2585                        $p_header['external'] = 0x00000000;
2586                        $p_header['size'] = filesize($p_filename);
2587                } // ----- Look for regular folder
2588                else {
2589                        if ($p_filedescr['type'] == 'folder') {
2590                                $p_header['external'] = 0x00000010;
2591                                $p_header['mtime'] = filemtime($p_filename);
2592                                $p_header['size'] = filesize($p_filename);
2593                        } // ----- Look for virtual file
2594                        else {
2595                                if ($p_filedescr['type'] == 'virtual_file') {
2596                                        $p_header['external'] = 0x00000000;
2597                                        $p_header['size'] = strlen($p_filedescr['content']);
2598                                }
2599                        }
2600                }
2601
2602
2603                // ----- Look for filetime
2604                if (isset($p_filedescr['mtime'])) {
2605                        $p_header['mtime'] = $p_filedescr['mtime'];
2606                } else {
2607                        if ($p_filedescr['type'] == 'virtual_file') {
2608                                $p_header['mtime'] = time();
2609                        } else {
2610                                $p_header['mtime'] = filemtime($p_filename);
2611                        }
2612                }
2613
2614                // ------ Look for file comment
2615                if (isset($p_filedescr['comment'])) {
2616                        $p_header['comment_len'] = strlen($p_filedescr['comment']);
2617                        $p_header['comment'] = $p_filedescr['comment'];
2618                } else {
2619                        $p_header['comment_len'] = 0;
2620                        $p_header['comment'] = '';
2621                }
2622
2623                // ----- Look for pre-add callback
2624                if (isset($p_options[PCLZIP_CB_PRE_ADD])) {
2625
2626                        // ----- Generate a local information
2627                        $v_local_header = array();
2628                        $this->privConvertHeader2FileInfo($p_header, $v_local_header);
2629
2630                        // ----- Call the callback
2631                        // Here I do not use call_user_func() because I need to send a reference to the
2632                        // header.
2633//      eval('$v_result = '.$p_options[PCLZIP_CB_PRE_ADD].'(PCLZIP_CB_PRE_ADD, $v_local_header);');
2634                        $v_result = $p_options[PCLZIP_CB_PRE_ADD](PCLZIP_CB_PRE_ADD, $v_local_header);
2635                        if ($v_result == 0) {
2636                                // ----- Change the file status
2637                                $p_header['status'] = "skipped";
2638                                $v_result = 1;
2639                        }
2640
2641                        // ----- Update the informations
2642                        // Only some fields can be modified
2643                        if ($p_header['stored_filename'] != $v_local_header['stored_filename']) {
2644                                $p_header['stored_filename'] = PclZipUtilPathReduction($v_local_header['stored_filename']);
2645                        }
2646                }
2647
2648                // ----- Look for empty stored filename
2649                if ($p_header['stored_filename'] == "") {
2650                        $p_header['status'] = "filtered";
2651                }
2652
2653                // ----- Check the path length
2654                if (strlen($p_header['stored_filename']) > 0xFF) {
2655                        $p_header['status'] = 'filename_too_long';
2656                }
2657
2658                // ----- Look if no error, or file not skipped
2659                if ($p_header['status'] == 'ok') {
2660
2661                        // ----- Look for a file
2662                        if ($p_filedescr['type'] == 'file') {
2663                                // ----- Look for using temporary file to zip
2664                                if ((!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF]))
2665                                        && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON])
2666                                                || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD])
2667                                                        && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_header['size'])))
2668                                ) {
2669                                        $v_result = $this->privAddFileUsingTempFile($p_filedescr, $p_header, $p_options);
2670                                        if ($v_result < PCLZIP_ERR_NO_ERROR) {
2671                                                return $v_result;
2672                                        }
2673                                } // ----- Use "in memory" zip algo
2674                                else {
2675
2676                                        // ----- Open the source file
2677                                        if (($v_file = @fopen($p_filename, "rb")) == 0) {
2678                                                PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode");
2679
2680                                                return PclZip::errorCode();
2681                                        }
2682
2683                                        // ----- Read the file content
2684                                        $v_content = @fread($v_file, $p_header['size']);
2685
2686                                        // ----- Close the file
2687                                        @fclose($v_file);
2688
2689                                        // ----- Calculate the CRC
2690                                        $p_header['crc'] = @crc32($v_content);
2691
2692                                        // ----- Look for no compression
2693                                        if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) {
2694                                                // ----- Set header parameters
2695                                                $p_header['compressed_size'] = $p_header['size'];
2696                                                $p_header['compression'] = 0;
2697                                        } // ----- Look for normal compression
2698                                        else {
2699                                                // ----- Compress the content
2700                                                $v_content = @gzdeflate($v_content);
2701
2702                                                // ----- Set header parameters
2703                                                $p_header['compressed_size'] = strlen($v_content);
2704                                                $p_header['compression'] = 8;
2705                                        }
2706
2707                                        // ----- Call the header generation
2708                                        if (($v_result = $this->privWriteFileHeader($p_header)) != 1) {
2709                                                @fclose($v_file);
2710
2711                                                return $v_result;
2712                                        }
2713
2714                                        // ----- Write the compressed (or not) content
2715                                        @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']);
2716
2717                                }
2718
2719                        } // ----- Look for a virtual file (a file from string)
2720                        else {
2721                                if ($p_filedescr['type'] == 'virtual_file') {
2722
2723                                        $v_content = $p_filedescr['content'];
2724
2725                                        // ----- Calculate the CRC
2726                                        $p_header['crc'] = @crc32($v_content);
2727
2728                                        // ----- Look for no compression
2729                                        if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) {
2730                                                // ----- Set header parameters
2731                                                $p_header['compressed_size'] = $p_header['size'];
2732                                                $p_header['compression'] = 0;
2733                                        } // ----- Look for normal compression
2734                                        else {
2735                                                // ----- Compress the content
2736                                                $v_content = @gzdeflate($v_content);
2737
2738                                                // ----- Set header parameters
2739                                                $p_header['compressed_size'] = strlen($v_content);
2740                                                $p_header['compression'] = 8;
2741                                        }
2742
2743                                        // ----- Call the header generation
2744                                        if (($v_result = $this->privWriteFileHeader($p_header)) != 1) {
2745                                                @fclose($v_file);
2746
2747                                                return $v_result;
2748                                        }
2749
2750                                        // ----- Write the compressed (or not) content
2751                                        @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']);
2752                                } // ----- Look for a directory
2753                                else {
2754                                        if ($p_filedescr['type'] == 'folder') {
2755                                                // ----- Look for directory last '/'
2756                                                if (@substr($p_header['stored_filename'], -1) != '/') {
2757                                                        $p_header['stored_filename'] .= '/';
2758                                                }
2759
2760                                                // ----- Set the file properties
2761                                                $p_header['size'] = 0;
2762                                                //$p_header['external'] = 0x41FF0010;   // Value for a folder : to be checked
2763                                                $p_header['external'] = 0x00000010;   // Value for a folder : to be checked
2764
2765                                                // ----- Call the header generation
2766                                                if (($v_result = $this->privWriteFileHeader($p_header)) != 1) {
2767                                                        return $v_result;
2768                                                }
2769                                        }
2770                                }
2771                        }
2772                }
2773
2774                // ----- Look for post-add callback
2775                if (isset($p_options[PCLZIP_CB_POST_ADD])) {
2776
2777                        // ----- Generate a local information
2778                        $v_local_header = array();
2779                        $this->privConvertHeader2FileInfo($p_header, $v_local_header);
2780
2781                        // ----- Call the callback
2782                        // Here I do not use call_user_func() because I need to send a reference to the
2783                        // header.
2784//      eval('$v_result = '.$p_options[PCLZIP_CB_POST_ADD].'(PCLZIP_CB_POST_ADD, $v_local_header);');
2785                        $v_result = $p_options[PCLZIP_CB_POST_ADD](PCLZIP_CB_POST_ADD, $v_local_header);
2786                        if ($v_result == 0) {
2787                                // ----- Ignored
2788                                $v_result = 1;
2789                        }
2790
2791                        // ----- Update the informations
2792                        // Nothing can be modified
2793                }
2794
2795                // ----- Return
2796                return $v_result;
2797        }
2798        // --------------------------------------------------------------------------------
2799
2800        // --------------------------------------------------------------------------------
2801        // Function : privAddFileUsingTempFile()
2802        // Description :
2803        // Parameters :
2804        // Return Values :
2805        // --------------------------------------------------------------------------------
2806        public function privAddFileUsingTempFile($p_filedescr, &$p_header, &$p_options) {
2807                $v_result = PCLZIP_ERR_NO_ERROR;
2808
2809                // ----- Working variable
2810                $p_filename = $p_filedescr['filename'];
2811
2812
2813                // ----- Open the source file
2814                if (($v_file = @fopen($p_filename, "rb")) == 0) {
2815                        PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode");
2816
2817                        return PclZip::errorCode();
2818                }
2819
2820                // ----- Creates a compressed temporary file
2821                $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR . uniqid('pclzip-') . '.gz';
2822                if (($v_file_compressed = @gzopen($v_gzip_temp_name, "wb")) == 0) {
2823                        fclose($v_file);
2824                        PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL,
2825                                'Unable to open temporary file \'' . $v_gzip_temp_name . '\' in binary write mode');
2826
2827                        return PclZip::errorCode();
2828                }
2829
2830                // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
2831                $v_size = filesize($p_filename);
2832                while ($v_size != 0) {
2833                        $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
2834                        $v_buffer = @fread($v_file, $v_read_size);
2835                        //$v_binary_data = pack('a'.$v_read_size, $v_buffer);
2836                        @gzputs($v_file_compressed, $v_buffer, $v_read_size);
2837                        $v_size -= $v_read_size;
2838                }
2839
2840                // ----- Close the file
2841                @fclose($v_file);
2842                @gzclose($v_file_compressed);
2843
2844                // ----- Check the minimum file size
2845                if (filesize($v_gzip_temp_name) < 18) {
2846                        PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT,
2847                                'gzip temporary file \'' . $v_gzip_temp_name . '\' has invalid filesize - should be minimum 18 bytes');
2848
2849                        return PclZip::errorCode();
2850                }
2851
2852                // ----- Extract the compressed attributes
2853                if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0) {
2854                        PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL,
2855                                'Unable to open temporary file \'' . $v_gzip_temp_name . '\' in binary read mode');
2856
2857                        return PclZip::errorCode();
2858                }
2859
2860                // ----- Read the gzip file header
2861                $v_binary_data = @fread($v_file_compressed, 10);
2862                $v_data_header = unpack('a1id1/a1id2/a1cm/a1flag/Vmtime/a1xfl/a1os', $v_binary_data);
2863
2864                // ----- Check some parameters
2865                $v_data_header['os'] = bin2hex($v_data_header['os']);
2866
2867                // ----- Read the gzip file footer
2868                @fseek($v_file_compressed, filesize($v_gzip_temp_name) - 8);
2869                $v_binary_data = @fread($v_file_compressed, 8);
2870                $v_data_footer = unpack('Vcrc/Vcompressed_size', $v_binary_data);
2871
2872                // ----- Set the attributes
2873                $p_header['compression'] = ord($v_data_header['cm']);
2874                //$p_header['mtime'] = $v_data_header['mtime'];
2875                $p_header['crc'] = $v_data_footer['crc'];
2876                $p_header['compressed_size'] = filesize($v_gzip_temp_name) - 18;
2877
2878                // ----- Close the file
2879                @fclose($v_file_compressed);
2880
2881                // ----- Call the header generation
2882                if (($v_result = $this->privWriteFileHeader($p_header)) != 1) {
2883                        return $v_result;
2884                }
2885
2886                // ----- Add the compressed data
2887                if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0) {
2888                        PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL,
2889                                'Unable to open temporary file \'' . $v_gzip_temp_name . '\' in binary read mode');
2890
2891                        return PclZip::errorCode();
2892                }
2893
2894                // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
2895                fseek($v_file_compressed, 10);
2896                $v_size = $p_header['compressed_size'];
2897                while ($v_size != 0) {
2898                        $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
2899                        $v_buffer = @fread($v_file_compressed, $v_read_size);
2900                        //$v_binary_data = pack('a'.$v_read_size, $v_buffer);
2901                        @fwrite($this->zip_fd, $v_buffer, $v_read_size);
2902                        $v_size -= $v_read_size;
2903                }
2904
2905                // ----- Close the file
2906                @fclose($v_file_compressed);
2907
2908                // ----- Unlink the temporary file
2909                @unlink($v_gzip_temp_name);
2910
2911                // ----- Return
2912                return $v_result;
2913        }
2914        // --------------------------------------------------------------------------------
2915
2916        // --------------------------------------------------------------------------------
2917        // Function : privCalculateStoredFilename()
2918        // Description :
2919        //   Based on file descriptor properties and global options, this method
2920        //   calculate the filename that will be stored in the archive.
2921        // Parameters :
2922        // Return Values :
2923        // --------------------------------------------------------------------------------
2924        public function privCalculateStoredFilename(&$p_filedescr, &$p_options) {
2925                $v_result = 1;
2926
2927                // ----- Working variables
2928                $p_filename = $p_filedescr['filename'];
2929                if (isset($p_options[PCLZIP_OPT_ADD_PATH])) {
2930                        $p_add_dir = $p_options[PCLZIP_OPT_ADD_PATH];
2931                } else {
2932                        $p_add_dir = '';
2933                }
2934                if (isset($p_options[PCLZIP_OPT_REMOVE_PATH])) {
2935                        $p_remove_dir = $p_options[PCLZIP_OPT_REMOVE_PATH];
2936                } else {
2937                        $p_remove_dir = '';
2938                }
2939                if (isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH])) {
2940                        $p_remove_all_dir = $p_options[PCLZIP_OPT_REMOVE_ALL_PATH];
2941                } else {
2942                        $p_remove_all_dir = 0;
2943                }
2944
2945
2946                // ----- Look for full name change
2947                if (isset($p_filedescr['new_full_name'])) {
2948                        // ----- Remove drive letter if any
2949                        $v_stored_filename = PclZipUtilTranslateWinPath($p_filedescr['new_full_name']);
2950                } // ----- Look for path and/or short name change
2951                else {
2952
2953                        // ----- Look for short name change
2954                        // Its when we cahnge just the filename but not the path
2955                        if (isset($p_filedescr['new_short_name'])) {
2956                                $v_path_info = pathinfo($p_filename);
2957                                $v_dir = '';
2958                                if ($v_path_info['dirname'] != '') {
2959                                        $v_dir = $v_path_info['dirname'] . '/';
2960                                }
2961                                $v_stored_filename = $v_dir . $p_filedescr['new_short_name'];
2962                        } else {
2963                                // ----- Calculate the stored filename
2964                                $v_stored_filename = $p_filename;
2965                        }
2966
2967                        // ----- Look for all path to remove
2968                        if ($p_remove_all_dir) {
2969                                $v_stored_filename = basename($p_filename);
2970                        } // ----- Look for partial path remove
2971                        else {
2972                                if ($p_remove_dir != "") {
2973                                        if (substr($p_remove_dir, -1) != '/') {
2974                                                $p_remove_dir .= "/";
2975                                        }
2976
2977                                        if ((substr($p_filename, 0, 2) == "./")
2978                                                || (substr($p_remove_dir, 0, 2) == "./")
2979                                        ) {
2980
2981                                                if ((substr($p_filename, 0, 2) == "./")
2982                                                        && (substr($p_remove_dir, 0, 2) != "./")
2983                                                ) {
2984                                                        $p_remove_dir = "./" . $p_remove_dir;
2985                                                }
2986                                                if ((substr($p_filename, 0, 2) != "./")
2987                                                        && (substr($p_remove_dir, 0, 2) == "./")
2988                                                ) {
2989                                                        $p_remove_dir = substr($p_remove_dir, 2);
2990                                                }
2991                                        }
2992
2993                                        $v_compare = PclZipUtilPathInclusion($p_remove_dir,
2994                                                $v_stored_filename);
2995                                        if ($v_compare > 0) {
2996                                                if ($v_compare == 2) {
2997                                                        $v_stored_filename = "";
2998                                                } else {
2999                                                        $v_stored_filename = substr($v_stored_filename,
3000                                                                strlen($p_remove_dir));
3001                                                }
3002                                        }
3003                                }
3004                        }
3005
3006                        // ----- Remove drive letter if any
3007                        $v_stored_filename = PclZipUtilTranslateWinPath($v_stored_filename);
3008
3009                        // ----- Look for path to add
3010                        if ($p_add_dir != "") {
3011                                if (substr($p_add_dir, -1) == "/") {
3012                                        $v_stored_filename = $p_add_dir . $v_stored_filename;
3013                                } else {
3014                                        $v_stored_filename = $p_add_dir . "/" . $v_stored_filename;
3015                                }
3016                        }
3017                }
3018
3019                // ----- Filename (reduce the path of stored name)
3020                $v_stored_filename = PclZipUtilPathReduction($v_stored_filename);
3021                $p_filedescr['stored_filename'] = $v_stored_filename;
3022
3023                // ----- Return
3024                return $v_result;
3025        }
3026        // --------------------------------------------------------------------------------
3027
3028        // --------------------------------------------------------------------------------
3029        // Function : privWriteFileHeader()
3030        // Description :
3031        // Parameters :
3032        // Return Values :
3033        // --------------------------------------------------------------------------------
3034        public function privWriteFileHeader(&$p_header) {
3035                $v_result = 1;
3036
3037                // ----- Store the offset position of the file
3038                $p_header['offset'] = ftell($this->zip_fd);
3039
3040                // ----- Transform UNIX mtime to DOS format mdate/mtime
3041                $v_date = getdate($p_header['mtime']);
3042                $v_mtime = ($v_date['hours'] << 11) + ($v_date['minutes'] << 5) + $v_date['seconds'] / 2;
3043                $v_mdate = (($v_date['year'] - 1980) << 9) + ($v_date['mon'] << 5) + $v_date['mday'];
3044
3045                // ----- Packed data
3046                $v_binary_data = pack("VvvvvvVVVvv", 0x04034b50,
3047                        $p_header['version_extracted'], $p_header['flag'],
3048                        $p_header['compression'], $v_mtime, $v_mdate,
3049                        $p_header['crc'], $p_header['compressed_size'],
3050                        $p_header['size'],
3051                        strlen($p_header['stored_filename']),
3052                        $p_header['extra_len']);
3053
3054                // ----- Write the first 148 bytes of the header in the archive
3055                fputs($this->zip_fd, $v_binary_data, 30);
3056
3057                // ----- Write the variable fields
3058                if (strlen($p_header['stored_filename']) != 0) {
3059                        fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename']));
3060                }
3061                if ($p_header['extra_len'] != 0) {
3062                        fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']);
3063                }
3064
3065                // ----- Return
3066                return $v_result;
3067        }
3068        // --------------------------------------------------------------------------------
3069
3070        // --------------------------------------------------------------------------------
3071        // Function : privWriteCentralFileHeader()
3072        // Description :
3073        // Parameters :
3074        // Return Values :
3075        // --------------------------------------------------------------------------------
3076        public function privWriteCentralFileHeader(&$p_header) {
3077                $v_result = 1;
3078
3079                // TBC
3080                //for(reset($p_header); $key = key($p_header); next($p_header)) {
3081                //}
3082
3083                // ----- Transform UNIX mtime to DOS format mdate/mtime
3084                $v_date = getdate($p_header['mtime']);
3085                $v_mtime = ($v_date['hours'] << 11) + ($v_date['minutes'] << 5) + $v_date['seconds'] / 2;
3086                $v_mdate = (($v_date['year'] - 1980) << 9) + ($v_date['mon'] << 5) + $v_date['mday'];
3087
3088
3089                // ----- Packed data
3090                $v_binary_data = pack("VvvvvvvVVVvvvvvVV", 0x02014b50,
3091                        $p_header['version'], $p_header['version_extracted'],
3092                        $p_header['flag'], $p_header['compression'],
3093                        $v_mtime, $v_mdate, $p_header['crc'],
3094                        $p_header['compressed_size'], $p_header['size'],
3095                        strlen($p_header['stored_filename']),
3096                        $p_header['extra_len'], $p_header['comment_len'],
3097                        $p_header['disk'], $p_header['internal'],
3098                        $p_header['external'], $p_header['offset']);
3099
3100                // ----- Write the 42 bytes of the header in the zip file
3101                fputs($this->zip_fd, $v_binary_data, 46);
3102
3103                // ----- Write the variable fields
3104                if (strlen($p_header['stored_filename']) != 0) {
3105                        fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename']));
3106                }
3107                if ($p_header['extra_len'] != 0) {
3108                        fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']);
3109                }
3110                if ($p_header['comment_len'] != 0) {
3111                        fputs($this->zip_fd, $p_header['comment'], $p_header['comment_len']);
3112                }
3113
3114                // ----- Return
3115                return $v_result;
3116        }
3117        // --------------------------------------------------------------------------------
3118
3119        // --------------------------------------------------------------------------------
3120        // Function : privWriteCentralHeader()
3121        // Description :
3122        // Parameters :
3123        // Return Values :
3124        // --------------------------------------------------------------------------------
3125        public function privWriteCentralHeader($p_nb_entries, $p_size, $p_offset, $p_comment) {
3126                $v_result = 1;
3127
3128                // ----- Packed data
3129                $v_binary_data = pack("VvvvvVVv", 0x06054b50, 0, 0, $p_nb_entries,
3130                        $p_nb_entries, $p_size,
3131                        $p_offset, strlen($p_comment));
3132
3133                // ----- Write the 22 bytes of the header in the zip file
3134                fputs($this->zip_fd, $v_binary_data, 22);
3135
3136                // ----- Write the variable fields
3137                if (strlen($p_comment) != 0) {
3138                        fputs($this->zip_fd, $p_comment, strlen($p_comment));
3139                }
3140
3141                // ----- Return
3142                return $v_result;
3143        }
3144        // --------------------------------------------------------------------------------
3145
3146        // --------------------------------------------------------------------------------
3147        // Function : privList()
3148        // Description :
3149        // Parameters :
3150        // Return Values :
3151        // --------------------------------------------------------------------------------
3152        public function privList(&$p_list) {
3153                $v_result = 1;
3154
3155                // ----- Magic quotes trick
3156                $this->privDisableMagicQuotes();
3157
3158                // ----- Open the zip file
3159                if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0) {
3160                        // ----- Magic quotes trick
3161                        $this->privSwapBackMagicQuotes();
3162
3163                        // ----- Error log
3164                        PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL,
3165                                'Unable to open archive \'' . $this->zipname . '\' in binary read mode');
3166
3167                        // ----- Return
3168                        return PclZip::errorCode();
3169                }
3170
3171                // ----- Read the central directory informations
3172                $v_central_dir = array();
3173                if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) {
3174                        $this->privSwapBackMagicQuotes();
3175
3176                        return $v_result;
3177                }
3178
3179                // ----- Go to beginning of Central Dir
3180                @rewind($this->zip_fd);
3181                if (@fseek($this->zip_fd, $v_central_dir['offset'])) {
3182                        $this->privSwapBackMagicQuotes();
3183
3184                        // ----- Error log
3185                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
3186
3187                        // ----- Return
3188                        return PclZip::errorCode();
3189                }
3190
3191                // ----- Read each entry
3192                for ($i = 0; $i < $v_central_dir['entries']; $i++) {
3193                        // ----- Read the file header
3194                        if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1) {
3195                                $this->privSwapBackMagicQuotes();
3196
3197                                return $v_result;
3198                        }
3199                        $v_header['index'] = $i;
3200
3201                        // ----- Get the only interesting attributes
3202                        $this->privConvertHeader2FileInfo($v_header, $p_list[$i]);
3203                        unset($v_header);
3204                }
3205
3206                // ----- Close the zip file
3207                $this->privCloseFd();
3208
3209                // ----- Magic quotes trick
3210                $this->privSwapBackMagicQuotes();
3211
3212                // ----- Return
3213                return $v_result;
3214        }
3215        // --------------------------------------------------------------------------------
3216
3217        // --------------------------------------------------------------------------------
3218        // Function : privConvertHeader2FileInfo()
3219        // Description :
3220        //   This function takes the file informations from the central directory
3221        //   entries and extract the interesting parameters that will be given back.
3222        //   The resulting file infos are set in the array $p_info
3223        //     $p_info['filename'] : Filename with full path. Given by user (add),
3224        //                           extracted in the filesystem (extract).
3225        //     $p_info['stored_filename'] : Stored filename in the archive.
3226        //     $p_info['size'] = Size of the file.
3227        //     $p_info['compressed_size'] = Compressed size of the file.
3228        //     $p_info['mtime'] = Last modification date of the file.
3229        //     $p_info['comment'] = Comment associated with the file.
3230        //     $p_info['folder'] = true/false : indicates if the entry is a folder or not.
3231        //     $p_info['status'] = status of the action on the file.
3232        //     $p_info['crc'] = CRC of the file content.
3233        // Parameters :
3234        // Return Values :
3235        // --------------------------------------------------------------------------------
3236        public function privConvertHeader2FileInfo($p_header, &$p_info) {
3237                $v_result = 1;
3238
3239                // ----- Get the interesting attributes
3240                $v_temp_path = PclZipUtilPathReduction($p_header['filename']);
3241                $p_info['filename'] = $v_temp_path;
3242                $v_temp_path = PclZipUtilPathReduction($p_header['stored_filename']);
3243                $p_info['stored_filename'] = $v_temp_path;
3244                $p_info['size'] = $p_header['size'];
3245                $p_info['compressed_size'] = $p_header['compressed_size'];
3246                $p_info['mtime'] = $p_header['mtime'];
3247                $p_info['comment'] = $p_header['comment'];
3248                $p_info['folder'] = (($p_header['external'] & 0x00000010) == 0x00000010);
3249                $p_info['index'] = $p_header['index'];
3250                $p_info['status'] = $p_header['status'];
3251                $p_info['crc'] = $p_header['crc'];
3252
3253                // ----- Return
3254                return $v_result;
3255        }
3256        // --------------------------------------------------------------------------------
3257
3258        // --------------------------------------------------------------------------------
3259        // Function : privExtractByRule()
3260        // Description :
3261        //   Extract a file or directory depending of rules (by index, by name, ...)
3262        // Parameters :
3263        //   $p_file_list : An array where will be placed the properties of each
3264        //                  extracted file
3265        //   $p_path : Path to add while writing the extracted files
3266        //   $p_remove_path : Path to remove (from the file memorized path) while writing the
3267        //                    extracted files. If the path does not match the file path,
3268        //                    the file is extracted with its memorized path.
3269        //                    $p_remove_path does not apply to 'list' mode.
3270        //                    $p_path and $p_remove_path are commulative.
3271        // Return Values :
3272        //   1 on success,0 or less on error (see error code list)
3273        // --------------------------------------------------------------------------------
3274        public function privExtractByRule(&$p_file_list, $p_path, $p_remove_path, $p_remove_all_path, &$p_options) {
3275                $v_result = 1;
3276
3277                // ----- Magic quotes trick
3278                $this->privDisableMagicQuotes();
3279
3280                // ----- Check the path
3281                if (($p_path == "")
3282                        || ((substr($p_path, 0, 1) != "/")
3283                                && (substr($p_path, 0, 3) != "../")
3284                                && (substr($p_path, 1, 2) != ":/"))
3285                ) {
3286                        $p_path = "./" . $p_path;
3287                }
3288
3289                // ----- Reduce the path last (and duplicated) '/'
3290                if (($p_path != "./") && ($p_path != "/")) {
3291                        // ----- Look for the path end '/'
3292                        while (substr($p_path, -1) == "/") {
3293                                $p_path = substr($p_path, 0, strlen($p_path) - 1);
3294                        }
3295                }
3296
3297                // ----- Look for path to remove format (should end by /)
3298                if (($p_remove_path != "") && (substr($p_remove_path, -1) != '/')) {
3299                        $p_remove_path .= '/';
3300                }
3301                $p_remove_path_size = strlen($p_remove_path);
3302
3303                // ----- Open the zip file
3304                if (($v_result = $this->privOpenFd('rb')) != 1) {
3305                        $this->privSwapBackMagicQuotes();
3306
3307                        return $v_result;
3308                }
3309
3310                // ----- Read the central directory informations
3311                $v_central_dir = array();
3312                if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) {
3313                        // ----- Close the zip file
3314                        $this->privCloseFd();
3315                        $this->privSwapBackMagicQuotes();
3316
3317                        return $v_result;
3318                }
3319
3320                // ----- Start at beginning of Central Dir
3321                $v_pos_entry = $v_central_dir['offset'];
3322
3323                // ----- Read each entry
3324                $j_start = 0;
3325                for ($i = 0, $v_nb_extracted = 0; $i < $v_central_dir['entries']; $i++) {
3326
3327                        // ----- Read next Central dir entry
3328                        @rewind($this->zip_fd);
3329                        if (@fseek($this->zip_fd, $v_pos_entry)) {
3330                                // ----- Close the zip file
3331                                $this->privCloseFd();
3332                                $this->privSwapBackMagicQuotes();
3333
3334                                // ----- Error log
3335                                PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
3336
3337                                // ----- Return
3338                                return PclZip::errorCode();
3339                        }
3340
3341                        // ----- Read the file header
3342                        $v_header = array();
3343                        if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1) {
3344                                // ----- Close the zip file
3345                                $this->privCloseFd();
3346                                $this->privSwapBackMagicQuotes();
3347
3348                                return $v_result;
3349                        }
3350
3351                        // ----- Store the index
3352                        $v_header['index'] = $i;
3353
3354                        // ----- Store the file position
3355                        $v_pos_entry = ftell($this->zip_fd);
3356
3357                        // ----- Look for the specific extract rules
3358                        $v_extract = false;
3359
3360                        // ----- Look for extract by name rule
3361                        if ((isset($p_options[PCLZIP_OPT_BY_NAME]))
3362                                && ($p_options[PCLZIP_OPT_BY_NAME] != 0)
3363                        ) {
3364
3365                                // ----- Look if the filename is in the list
3366                                for ($j = 0; ($j < sizeof($p_options[PCLZIP_OPT_BY_NAME])) && (!$v_extract); $j++) {
3367
3368                                        // ----- Look for a directory
3369                                        if (substr($p_options[PCLZIP_OPT_BY_NAME][$j], -1) == "/") {
3370
3371                                                // ----- Look if the directory is in the filename path
3372                                                if ((strlen($v_header['stored_filename']) > strlen($p_options[PCLZIP_OPT_BY_NAME][$j]))
3373                                                        && (substr($v_header['stored_filename'], 0,
3374                                                                        strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])
3375                                                ) {
3376                                                        $v_extract = true;
3377                                                }
3378                                        } // ----- Look for a filename
3379                                        elseif ($v_header['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) {
3380                                                $v_extract = true;
3381                                        }
3382                                }
3383                        }
3384
3385                        // ----- Look for extract by ereg rule
3386                        // ereg() is deprecated with PHP 5.3
3387                        /*
3388      else if (   (isset($p_options[PCLZIP_OPT_BY_EREG]))
3389               && ($p_options[PCLZIP_OPT_BY_EREG] != "")) {
3390
3391          if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header['stored_filename'])) {
3392              $v_extract = true;
3393          }
3394      }
3395      */
3396
3397                        // ----- Look for extract by preg rule
3398                        else {
3399                                if ((isset($p_options[PCLZIP_OPT_BY_PREG]))
3400                                        && ($p_options[PCLZIP_OPT_BY_PREG] != "")
3401                                ) {
3402
3403                                        if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header['stored_filename'])) {
3404                                                $v_extract = true;
3405                                        }
3406                                } // ----- Look for extract by index rule
3407                                else {
3408                                        if ((isset($p_options[PCLZIP_OPT_BY_INDEX]))
3409                                                && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)
3410                                        ) {
3411
3412                                                // ----- Look if the index is in the list
3413                                                for ($j = $j_start; ($j < sizeof($p_options[PCLZIP_OPT_BY_INDEX])) && (!$v_extract); $j++) {
3414
3415                                                        if (($i >= $p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i <= $p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) {
3416                                                                $v_extract = true;
3417                                                        }
3418                                                        if ($i >= $p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) {
3419                                                                $j_start = $j + 1;
3420                                                        }
3421
3422                                                        if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start'] > $i) {
3423                                                                break;
3424                                                        }
3425                                                }
3426                                        } // ----- Look for no rule, which means extract all the archive
3427                                        else {
3428                                                $v_extract = true;
3429                                        }
3430                                }
3431                        }
3432
3433                        // ----- Check compression method
3434                        if (($v_extract)
3435                                && (($v_header['compression'] != 8)
3436                                        && ($v_header['compression'] != 0))
3437                        ) {
3438                                $v_header['status'] = 'unsupported_compression';
3439
3440                                // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
3441                                if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
3442                                        && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)
3443                                ) {
3444
3445                                        $this->privSwapBackMagicQuotes();
3446
3447                                        PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_COMPRESSION,
3448                                                "Filename '" . $v_header['stored_filename'] . "' is "
3449                                                . "compressed by an unsupported compression "
3450                                                . "method (" . $v_header['compression'] . ") ");
3451
3452                                        return PclZip::errorCode();
3453                                }
3454                        }
3455
3456                        // ----- Check encrypted files
3457                        if (($v_extract) && (($v_header['flag'] & 1) == 1)) {
3458                                $v_header['status'] = 'unsupported_encryption';
3459
3460                                // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
3461                                if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
3462                                        && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)
3463                                ) {
3464
3465                                        $this->privSwapBackMagicQuotes();
3466
3467                                        PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION,
3468                                                "Unsupported encryption for "
3469                                                . " filename '" . $v_header['stored_filename']
3470                                                . "'");
3471
3472                                        return PclZip::errorCode();
3473                                }
3474                        }
3475
3476                        // ----- Look for real extraction
3477                        if (($v_extract) && ($v_header['status'] != 'ok')) {
3478                                $v_result = $this->privConvertHeader2FileInfo($v_header,
3479                                        $p_file_list[$v_nb_extracted++]);
3480                                if ($v_result != 1) {
3481                                        $this->privCloseFd();
3482                                        $this->privSwapBackMagicQuotes();
3483
3484                                        return $v_result;
3485                                }
3486
3487                                $v_extract = false;
3488                        }
3489
3490                        // ----- Look for real extraction
3491                        if ($v_extract) {
3492
3493                                // ----- Go to the file position
3494                                @rewind($this->zip_fd);
3495                                if (@fseek($this->zip_fd, $v_header['offset'])) {
3496                                        // ----- Close the zip file
3497                                        $this->privCloseFd();
3498
3499                                        $this->privSwapBackMagicQuotes();
3500
3501                                        // ----- Error log
3502                                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
3503
3504                                        // ----- Return
3505                                        return PclZip::errorCode();
3506                                }
3507
3508                                // ----- Look for extraction as string
3509                                if ($p_options[PCLZIP_OPT_EXTRACT_AS_STRING]) {
3510
3511                                        $v_string = '';
3512
3513                                        // ----- Extracting the file
3514                                        $v_result1 = $this->privExtractFileAsString($v_header, $v_string, $p_options);
3515                                        if ($v_result1 < 1) {
3516                                                $this->privCloseFd();
3517                                                $this->privSwapBackMagicQuotes();
3518
3519                                                return $v_result1;
3520                                        }
3521
3522                                        // ----- Get the only interesting attributes
3523                                        if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted])) != 1) {
3524                                                // ----- Close the zip file
3525                                                $this->privCloseFd();
3526                                                $this->privSwapBackMagicQuotes();
3527
3528                                                return $v_result;
3529                                        }
3530
3531                                        // ----- Set the file content
3532                                        $p_file_list[$v_nb_extracted]['content'] = $v_string;
3533
3534                                        // ----- Next extracted file
3535                                        $v_nb_extracted++;
3536
3537                                        // ----- Look for user callback abort
3538                                        if ($v_result1 == 2) {
3539                                                break;
3540                                        }
3541                                } // ----- Look for extraction in standard output
3542                                elseif ((isset($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT]))
3543                                        && ($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])
3544                                ) {
3545                                        // ----- Extracting the file in standard output
3546                                        $v_result1 = $this->privExtractFileInOutput($v_header, $p_options);
3547                                        if ($v_result1 < 1) {
3548                                                $this->privCloseFd();
3549                                                $this->privSwapBackMagicQuotes();
3550
3551                                                return $v_result1;
3552                                        }
3553
3554                                        // ----- Get the only interesting attributes
3555                                        if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) {
3556                                                $this->privCloseFd();
3557                                                $this->privSwapBackMagicQuotes();
3558
3559                                                return $v_result;
3560                                        }
3561
3562                                        // ----- Look for user callback abort
3563                                        if ($v_result1 == 2) {
3564                                                break;
3565                                        }
3566                                } // ----- Look for normal extraction
3567                                else {
3568                                        // ----- Extracting the file
3569                                        $v_result1 = $this->privExtractFile($v_header,
3570                                                $p_path, $p_remove_path,
3571                                                $p_remove_all_path,
3572                                                $p_options);
3573                                        if ($v_result1 < 1) {
3574                                                $this->privCloseFd();
3575                                                $this->privSwapBackMagicQuotes();
3576
3577                                                return $v_result1;
3578                                        }
3579
3580                                        // ----- Get the only interesting attributes
3581                                        if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) {
3582                                                // ----- Close the zip file
3583                                                $this->privCloseFd();
3584                                                $this->privSwapBackMagicQuotes();
3585
3586                                                return $v_result;
3587                                        }
3588
3589                                        // ----- Look for user callback abort
3590                                        if ($v_result1 == 2) {
3591                                                break;
3592                                        }
3593                                }
3594                        }
3595                }
3596
3597                // ----- Close the zip file
3598                $this->privCloseFd();
3599                $this->privSwapBackMagicQuotes();
3600
3601                // ----- Return
3602                return $v_result;
3603        }
3604        // --------------------------------------------------------------------------------
3605
3606        // --------------------------------------------------------------------------------
3607        // Function : privExtractFile()
3608        // Description :
3609        // Parameters :
3610        // Return Values :
3611        //
3612        // 1 : ... ?
3613        // PCLZIP_ERR_USER_ABORTED(2) : User ask for extraction stop in callback
3614        // --------------------------------------------------------------------------------
3615        public function privExtractFile(&$p_entry, $p_path, $p_remove_path, $p_remove_all_path, &$p_options) {
3616                $v_result = 1;
3617
3618                // ----- Read the file header
3619                if (($v_result = $this->privReadFileHeader($v_header)) != 1) {
3620                        // ----- Return
3621                        return $v_result;
3622                }
3623
3624
3625                // ----- Check that the file header is coherent with $p_entry info
3626                if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) {
3627                        // TBC
3628                }
3629
3630                // ----- Look for all path to remove
3631                if ($p_remove_all_path == true) {
3632                        // ----- Look for folder entry that not need to be extracted
3633                        if (($p_entry['external'] & 0x00000010) == 0x00000010) {
3634
3635                                $p_entry['status'] = "filtered";
3636
3637                                return $v_result;
3638                        }
3639
3640                        // ----- Get the basename of the path
3641                        $p_entry['filename'] = basename($p_entry['filename']);
3642                } // ----- Look for path to remove
3643                else {
3644                        if ($p_remove_path != "") {
3645                                if (PclZipUtilPathInclusion($p_remove_path, $p_entry['filename']) == 2) {
3646
3647                                        // ----- Change the file status
3648                                        $p_entry['status'] = "filtered";
3649
3650                                        // ----- Return
3651                                        return $v_result;
3652                                }
3653
3654                                $p_remove_path_size = strlen($p_remove_path);
3655                                if (substr($p_entry['filename'], 0, $p_remove_path_size) == $p_remove_path) {
3656
3657                                        // ----- Remove the path
3658                                        $p_entry['filename'] = substr($p_entry['filename'], $p_remove_path_size);
3659
3660                                }
3661                        }
3662                }
3663
3664                // ----- Add the path
3665                if ($p_path != '') {
3666                        $p_entry['filename'] = $p_path . "/" . $p_entry['filename'];
3667                }
3668
3669                // ----- Check a base_dir_restriction
3670                if (isset($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION])) {
3671                        $v_inclusion
3672                                = PclZipUtilPathInclusion($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION],
3673                                $p_entry['filename']);
3674                        if ($v_inclusion == 0) {
3675
3676                                PclZip::privErrorLog(PCLZIP_ERR_DIRECTORY_RESTRICTION,
3677                                        "Filename '" . $p_entry['filename'] . "' is "
3678                                        . "outside PCLZIP_OPT_EXTRACT_DIR_RESTRICTION");
3679
3680                                return PclZip::errorCode();
3681                        }
3682                }
3683
3684                // ----- Look for pre-extract callback
3685                if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) {
3686
3687                        // ----- Generate a local information
3688                        $v_local_header = array();
3689                        $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
3690
3691                        // ----- Call the callback
3692                        // Here I do not use call_user_func() because I need to send a reference to the
3693                        // header.
3694//      eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);');
3695                        $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header);
3696                        if ($v_result == 0) {
3697                                // ----- Change the file status
3698                                $p_entry['status'] = "skipped";
3699                                $v_result = 1;
3700                        }
3701
3702                        // ----- Look for abort result
3703                        if ($v_result == 2) {
3704                                // ----- This status is internal and will be changed in 'skipped'
3705                                $p_entry['status'] = "aborted";
3706                                $v_result = PCLZIP_ERR_USER_ABORTED;
3707                        }
3708
3709                        // ----- Update the informations
3710                        // Only some fields can be modified
3711                        $p_entry['filename'] = $v_local_header['filename'];
3712                }
3713
3714
3715                // ----- Look if extraction should be done
3716                if ($p_entry['status'] == 'ok') {
3717
3718                        // ----- Look for specific actions while the file exist
3719                        if (file_exists($p_entry['filename'])) {
3720
3721                                // ----- Look if file is a directory
3722                                if (is_dir($p_entry['filename'])) {
3723
3724                                        // ----- Change the file status
3725                                        $p_entry['status'] = "already_a_directory";
3726
3727                                        // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
3728                                        // For historical reason first PclZip implementation does not stop
3729                                        // when this kind of error occurs.
3730                                        if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
3731                                                && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)
3732                                        ) {
3733
3734                                                PclZip::privErrorLog(PCLZIP_ERR_ALREADY_A_DIRECTORY,
3735                                                        "Filename '" . $p_entry['filename'] . "' is "
3736                                                        . "already used by an existing directory");
3737
3738                                                return PclZip::errorCode();
3739                                        }
3740                                } // ----- Look if file is write protected
3741                                else {
3742                                        if (!is_writeable($p_entry['filename'])) {
3743
3744                                                // ----- Change the file status
3745                                                $p_entry['status'] = "write_protected";
3746
3747                                                // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
3748                                                // For historical reason first PclZip implementation does not stop
3749                                                // when this kind of error occurs.
3750                                                if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
3751                                                        && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)
3752                                                ) {
3753
3754                                                        PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL,
3755                                                                "Filename '" . $p_entry['filename'] . "' exists "
3756                                                                . "and is write protected");
3757
3758                                                        return PclZip::errorCode();
3759                                                }
3760                                        } // ----- Look if the extracted file is older
3761                                        else {
3762                                                if (filemtime($p_entry['filename']) > $p_entry['mtime']) {
3763                                                        // ----- Change the file status
3764                                                        if ((isset($p_options[PCLZIP_OPT_REPLACE_NEWER]))
3765                                                                && ($p_options[PCLZIP_OPT_REPLACE_NEWER] === true)
3766                                                        ) {
3767                                                        } else {
3768                                                                $p_entry['status'] = "newer_exist";
3769
3770                                                                // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
3771                                                                // For historical reason first PclZip implementation does not stop
3772                                                                // when this kind of error occurs.
3773                                                                if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
3774                                                                        && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)
3775                                                                ) {
3776
3777                                                                        PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL,
3778                                                                                "Newer version of '" . $p_entry['filename'] . "' exists "
3779                                                                                . "and option PCLZIP_OPT_REPLACE_NEWER is not selected");
3780
3781                                                                        return PclZip::errorCode();
3782                                                                }
3783                                                        }
3784                                                } else {
3785                                                }
3786                                        }
3787                                }
3788                        } // ----- Check the directory availability and create it if necessary
3789                        else {
3790                                if ((($p_entry['external'] & 0x00000010) == 0x00000010) || (substr($p_entry['filename'], -1) == '/')) {
3791                                        $v_dir_to_check = $p_entry['filename'];
3792                                } else {
3793                                        if (!strstr($p_entry['filename'], "/")) {
3794                                                $v_dir_to_check = "";
3795                                        } else {
3796                                                $v_dir_to_check = dirname($p_entry['filename']);
3797                                        }
3798                                }
3799
3800                                if (($v_result = $this->privDirCheck($v_dir_to_check,
3801                                                (($p_entry['external'] & 0x00000010) == 0x00000010))) != 1
3802                                ) {
3803
3804                                        // ----- Change the file status
3805                                        $p_entry['status'] = "path_creation_fail";
3806
3807                                        // ----- Return
3808                                        //return $v_result;
3809                                        $v_result = 1;
3810                                }
3811                        }
3812                }
3813
3814                // ----- Look if extraction should be done
3815                if ($p_entry['status'] == 'ok') {
3816
3817                        // ----- Do the extraction (if not a folder)
3818                        if (!(($p_entry['external'] & 0x00000010) == 0x00000010)) {
3819                                // ----- Look for not compressed file
3820                                if ($p_entry['compression'] == 0) {
3821
3822                                        // ----- Opening destination file
3823                                        if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) {
3824
3825                                                // ----- Change the file status
3826                                                $p_entry['status'] = "write_error";
3827
3828                                                // ----- Return
3829                                                return $v_result;
3830                                        }
3831
3832
3833                                        // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
3834                                        $v_size = $p_entry['compressed_size'];
3835                                        while ($v_size != 0) {
3836                                                $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
3837                                                $v_buffer = @fread($this->zip_fd, $v_read_size);
3838                                                /* Try to speed up the code
3839            $v_binary_data = pack('a'.$v_read_size, $v_buffer);
3840            @fwrite($v_dest_file, $v_binary_data, $v_read_size);
3841            */
3842                                                @fwrite($v_dest_file, $v_buffer, $v_read_size);
3843                                                $v_size -= $v_read_size;
3844                                        }
3845
3846                                        // ----- Closing the destination file
3847                                        fclose($v_dest_file);
3848
3849                                        // ----- Change the file mtime
3850                                        touch($p_entry['filename'], $p_entry['mtime']);
3851
3852
3853                                } else {
3854                                        // ----- TBC
3855                                        // Need to be finished
3856                                        if (($p_entry['flag'] & 1) == 1) {
3857                                                PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION,
3858                                                        'File \'' . $p_entry['filename'] . '\' is encrypted. Encrypted files are not supported.');
3859
3860                                                return PclZip::errorCode();
3861                                        }
3862
3863
3864                                        // ----- Look for using temporary file to unzip
3865                                        if ((!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF]))
3866                                                && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON])
3867                                                        || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD])
3868                                                                && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_entry['size'])))
3869                                        ) {
3870                                                $v_result = $this->privExtractFileUsingTempFile($p_entry, $p_options);
3871                                                if ($v_result < PCLZIP_ERR_NO_ERROR) {
3872                                                        return $v_result;
3873                                                }
3874                                        } // ----- Look for extract in memory
3875                                        else {
3876
3877
3878                                                // ----- Read the compressed file in a buffer (one shot)
3879                                                $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']);
3880
3881                                                // ----- Decompress the file
3882                                                $v_file_content = @gzinflate($v_buffer);
3883                                                unset($v_buffer);
3884                                                if ($v_file_content === false) {
3885
3886                                                        // ----- Change the file status
3887                                                        // TBC
3888                                                        $p_entry['status'] = "error";
3889
3890                                                        return $v_result;
3891                                                }
3892
3893                                                // ----- Opening destination file
3894                                                if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) {
3895
3896                                                        // ----- Change the file status
3897                                                        $p_entry['status'] = "write_error";
3898
3899                                                        return $v_result;
3900                                                }
3901
3902                                                // ----- Write the uncompressed data
3903                                                @fwrite($v_dest_file, $v_file_content, $p_entry['size']);
3904                                                unset($v_file_content);
3905
3906                                                // ----- Closing the destination file
3907                                                @fclose($v_dest_file);
3908
3909                                        }
3910
3911                                        // ----- Change the file mtime
3912                                        @touch($p_entry['filename'], $p_entry['mtime']);
3913                                }
3914
3915                                // ----- Look for chmod option
3916                                if (isset($p_options[PCLZIP_OPT_SET_CHMOD])) {
3917
3918                                        // ----- Change the mode of the file
3919                                        @chmod($p_entry['filename'], $p_options[PCLZIP_OPT_SET_CHMOD]);
3920                                }
3921
3922                        }
3923                }
3924
3925                // ----- Change abort status
3926                if ($p_entry['status'] == "aborted") {
3927                        $p_entry['status'] = "skipped";
3928                } // ----- Look for post-extract callback
3929                elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) {
3930
3931                        // ----- Generate a local information
3932                        $v_local_header = array();
3933                        $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
3934
3935                        // ----- Call the callback
3936                        // Here I do not use call_user_func() because I need to send a reference to the
3937                        // header.
3938//      eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);');
3939                        $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header);
3940
3941                        // ----- Look for abort result
3942                        if ($v_result == 2) {
3943                                $v_result = PCLZIP_ERR_USER_ABORTED;
3944                        }
3945                }
3946
3947                // ----- Return
3948                return $v_result;
3949        }
3950        // --------------------------------------------------------------------------------
3951
3952        // --------------------------------------------------------------------------------
3953        // Function : privExtractFileUsingTempFile()
3954        // Description :
3955        // Parameters :
3956        // Return Values :
3957        // --------------------------------------------------------------------------------
3958        public function privExtractFileUsingTempFile(&$p_entry, &$p_options) {
3959                $v_result = 1;
3960
3961                // ----- Creates a temporary file
3962                $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR . uniqid('pclzip-') . '.gz';
3963                if (($v_dest_file = @fopen($v_gzip_temp_name, "wb")) == 0) {
3964                        fclose($v_file);
3965                        PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL,
3966                                'Unable to open temporary file \'' . $v_gzip_temp_name . '\' in binary write mode');
3967
3968                        return PclZip::errorCode();
3969                }
3970
3971
3972                // ----- Write gz file format header
3973                $v_binary_data = pack('va1a1Va1a1', 0x8b1f, Chr($p_entry['compression']), Chr(0x00), time(), Chr(0x00), Chr(3));
3974                @fwrite($v_dest_file, $v_binary_data, 10);
3975
3976                // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
3977                $v_size = $p_entry['compressed_size'];
3978                while ($v_size != 0) {
3979                        $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
3980                        $v_buffer = @fread($this->zip_fd, $v_read_size);
3981                        //$v_binary_data = pack('a'.$v_read_size, $v_buffer);
3982                        @fwrite($v_dest_file, $v_buffer, $v_read_size);
3983                        $v_size -= $v_read_size;
3984                }
3985
3986                // ----- Write gz file format footer
3987                $v_binary_data = pack('VV', $p_entry['crc'], $p_entry['size']);
3988                @fwrite($v_dest_file, $v_binary_data, 8);
3989
3990                // ----- Close the temporary file
3991                @fclose($v_dest_file);
3992
3993                // ----- Opening destination file
3994                if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) {
3995                        $p_entry['status'] = "write_error";
3996
3997                        return $v_result;
3998                }
3999
4000                // ----- Open the temporary gz file
4001                if (($v_src_file = @gzopen($v_gzip_temp_name, 'rb')) == 0) {
4002                        @fclose($v_dest_file);
4003                        $p_entry['status'] = "read_error";
4004                        PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL,
4005                                'Unable to open temporary file \'' . $v_gzip_temp_name . '\' in binary read mode');
4006
4007                        return PclZip::errorCode();
4008                }
4009
4010
4011                // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
4012                $v_size = $p_entry['size'];
4013                while ($v_size != 0) {
4014                        $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
4015                        $v_buffer = @gzread($v_src_file, $v_read_size);
4016                        //$v_binary_data = pack('a'.$v_read_size, $v_buffer);
4017                        @fwrite($v_dest_file, $v_buffer, $v_read_size);
4018                        $v_size -= $v_read_size;
4019                }
4020                @fclose($v_dest_file);
4021                @gzclose($v_src_file);
4022
4023                // ----- Delete the temporary file
4024                @unlink($v_gzip_temp_name);
4025
4026                // ----- Return
4027                return $v_result;
4028        }
4029        // --------------------------------------------------------------------------------
4030
4031        // --------------------------------------------------------------------------------
4032        // Function : privExtractFileInOutput()
4033        // Description :
4034        // Parameters :
4035        // Return Values :
4036        // --------------------------------------------------------------------------------
4037        public function privExtractFileInOutput(&$p_entry, &$p_options) {
4038                $v_result = 1;
4039
4040                // ----- Read the file header
4041                if (($v_result = $this->privReadFileHeader($v_header)) != 1) {
4042                        return $v_result;
4043                }
4044
4045
4046                // ----- Check that the file header is coherent with $p_entry info
4047                if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) {
4048                        // TBC
4049                }
4050
4051                // ----- Look for pre-extract callback
4052                if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) {
4053
4054                        // ----- Generate a local information
4055                        $v_local_header = array();
4056                        $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
4057
4058                        // ----- Call the callback
4059                        // Here I do not use call_user_func() because I need to send a reference to the
4060                        // header.
4061//      eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);');
4062                        $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header);
4063                        if ($v_result == 0) {
4064                                // ----- Change the file status
4065                                $p_entry['status'] = "skipped";
4066                                $v_result = 1;
4067                        }
4068
4069                        // ----- Look for abort result
4070                        if ($v_result == 2) {
4071                                // ----- This status is internal and will be changed in 'skipped'
4072                                $p_entry['status'] = "aborted";
4073                                $v_result = PCLZIP_ERR_USER_ABORTED;
4074                        }
4075
4076                        // ----- Update the informations
4077                        // Only some fields can be modified
4078                        $p_entry['filename'] = $v_local_header['filename'];
4079                }
4080
4081                // ----- Trace
4082
4083                // ----- Look if extraction should be done
4084                if ($p_entry['status'] == 'ok') {
4085
4086                        // ----- Do the extraction (if not a folder)
4087                        if (!(($p_entry['external'] & 0x00000010) == 0x00000010)) {
4088                                // ----- Look for not compressed file
4089                                if ($p_entry['compressed_size'] == $p_entry['size']) {
4090
4091                                        // ----- Read the file in a buffer (one shot)
4092                                        $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']);
4093
4094                                        // ----- Send the file to the output
4095                                        echo $v_buffer;
4096                                        unset($v_buffer);
4097                                } else {
4098
4099                                        // ----- Read the compressed file in a buffer (one shot)
4100                                        $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']);
4101
4102                                        // ----- Decompress the file
4103                                        $v_file_content = gzinflate($v_buffer);
4104                                        unset($v_buffer);
4105
4106                                        // ----- Send the file to the output
4107                                        echo $v_file_content;
4108                                        unset($v_file_content);
4109                                }
4110                        }
4111                }
4112
4113                // ----- Change abort status
4114                if ($p_entry['status'] == "aborted") {
4115                        $p_entry['status'] = "skipped";
4116                } // ----- Look for post-extract callback
4117                elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) {
4118
4119                        // ----- Generate a local information
4120                        $v_local_header = array();
4121                        $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
4122
4123                        // ----- Call the callback
4124                        // Here I do not use call_user_func() because I need to send a reference to the
4125                        // header.
4126//      eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);');
4127                        $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header);
4128
4129                        // ----- Look for abort result
4130                        if ($v_result == 2) {
4131                                $v_result = PCLZIP_ERR_USER_ABORTED;
4132                        }
4133                }
4134
4135                return $v_result;
4136        }
4137        // --------------------------------------------------------------------------------
4138
4139        // --------------------------------------------------------------------------------
4140        // Function : privExtractFileAsString()
4141        // Description :
4142        // Parameters :
4143        // Return Values :
4144        // --------------------------------------------------------------------------------
4145        public function privExtractFileAsString(&$p_entry, &$p_string, &$p_options) {
4146                $v_result = 1;
4147
4148                // ----- Read the file header
4149                $v_header = array();
4150                if (($v_result = $this->privReadFileHeader($v_header)) != 1) {
4151                        // ----- Return
4152                        return $v_result;
4153                }
4154
4155
4156                // ----- Check that the file header is coherent with $p_entry info
4157                if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) {
4158                        // TBC
4159                }
4160
4161                // ----- Look for pre-extract callback
4162                if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) {
4163
4164                        // ----- Generate a local information
4165                        $v_local_header = array();
4166                        $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
4167
4168                        // ----- Call the callback
4169                        // Here I do not use call_user_func() because I need to send a reference to the
4170                        // header.
4171//      eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);');
4172                        $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header);
4173                        if ($v_result == 0) {
4174                                // ----- Change the file status
4175                                $p_entry['status'] = "skipped";
4176                                $v_result = 1;
4177                        }
4178
4179                        // ----- Look for abort result
4180                        if ($v_result == 2) {
4181                                // ----- This status is internal and will be changed in 'skipped'
4182                                $p_entry['status'] = "aborted";
4183                                $v_result = PCLZIP_ERR_USER_ABORTED;
4184                        }
4185
4186                        // ----- Update the informations
4187                        // Only some fields can be modified
4188                        $p_entry['filename'] = $v_local_header['filename'];
4189                }
4190
4191
4192                // ----- Look if extraction should be done
4193                if ($p_entry['status'] == 'ok') {
4194
4195                        // ----- Do the extraction (if not a folder)
4196                        if (!(($p_entry['external'] & 0x00000010) == 0x00000010)) {
4197                                // ----- Look for not compressed file
4198                                //      if ($p_entry['compressed_size'] == $p_entry['size'])
4199                                if ($p_entry['compression'] == 0) {
4200
4201                                        // ----- Reading the file
4202                                        $p_string = @fread($this->zip_fd, $p_entry['compressed_size']);
4203                                } else {
4204
4205                                        // ----- Reading the file
4206                                        $v_data = @fread($this->zip_fd, $p_entry['compressed_size']);
4207
4208                                        // ----- Decompress the file
4209                                        if (($p_string = @gzinflate($v_data)) === false) {
4210                                                // TBC
4211                                        }
4212                                }
4213
4214                                // ----- Trace
4215                        } else {
4216                                // TBC : error : can not extract a folder in a string
4217                        }
4218
4219                }
4220
4221                // ----- Change abort status
4222                if ($p_entry['status'] == "aborted") {
4223                        $p_entry['status'] = "skipped";
4224                } // ----- Look for post-extract callback
4225                elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) {
4226
4227                        // ----- Generate a local information
4228                        $v_local_header = array();
4229                        $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
4230
4231                        // ----- Swap the content to header
4232                        $v_local_header['content'] = $p_string;
4233                        $p_string = '';
4234
4235                        // ----- Call the callback
4236                        // Here I do not use call_user_func() because I need to send a reference to the
4237                        // header.
4238//      eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);');
4239                        $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header);
4240
4241                        // ----- Swap back the content to header
4242                        $p_string = $v_local_header['content'];
4243                        unset($v_local_header['content']);
4244
4245                        // ----- Look for abort result
4246                        if ($v_result == 2) {
4247                                $v_result = PCLZIP_ERR_USER_ABORTED;
4248                        }
4249                }
4250
4251                // ----- Return
4252                return $v_result;
4253        }
4254        // --------------------------------------------------------------------------------
4255
4256        // --------------------------------------------------------------------------------
4257        // Function : privReadFileHeader()
4258        // Description :
4259        // Parameters :
4260        // Return Values :
4261        // --------------------------------------------------------------------------------
4262        public function privReadFileHeader(&$p_header) {
4263                $v_result = 1;
4264
4265                // ----- Read the 4 bytes signature
4266                $v_binary_data = @fread($this->zip_fd, 4);
4267                $v_data = unpack('Vid', $v_binary_data);
4268
4269                // ----- Check signature
4270                if ($v_data['id'] != 0x04034b50) {
4271
4272                        // ----- Error log
4273                        PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure');
4274
4275                        // ----- Return
4276                        return PclZip::errorCode();
4277                }
4278
4279                // ----- Read the first 42 bytes of the header
4280                $v_binary_data = fread($this->zip_fd, 26);
4281
4282                // ----- Look for invalid block size
4283                if (strlen($v_binary_data) != 26) {
4284                        $p_header['filename'] = "";
4285                        $p_header['status'] = "invalid_header";
4286
4287                        // ----- Error log
4288                        PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : " . strlen($v_binary_data));
4289
4290                        // ----- Return
4291                        return PclZip::errorCode();
4292                }
4293
4294                // ----- Extract the values
4295                $v_data = unpack('vversion/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len',
4296                        $v_binary_data);
4297
4298                // ----- Get filename
4299                $p_header['filename'] = fread($this->zip_fd, $v_data['filename_len']);
4300
4301                // ----- Get extra_fields
4302                if ($v_data['extra_len'] != 0) {
4303                        $p_header['extra'] = fread($this->zip_fd, $v_data['extra_len']);
4304                } else {
4305                        $p_header['extra'] = '';
4306                }
4307
4308                // ----- Extract properties
4309                $p_header['version_extracted'] = $v_data['version'];
4310                $p_header['compression'] = $v_data['compression'];
4311                $p_header['size'] = $v_data['size'];
4312                $p_header['compressed_size'] = $v_data['compressed_size'];
4313                $p_header['crc'] = $v_data['crc'];
4314                $p_header['flag'] = $v_data['flag'];
4315                $p_header['filename_len'] = $v_data['filename_len'];
4316
4317                // ----- Recuperate date in UNIX format
4318                $p_header['mdate'] = $v_data['mdate'];
4319                $p_header['mtime'] = $v_data['mtime'];
4320                if ($p_header['mdate'] && $p_header['mtime']) {
4321                        // ----- Extract time
4322                        $v_hour = ($p_header['mtime'] & 0xF800) >> 11;
4323                        $v_minute = ($p_header['mtime'] & 0x07E0) >> 5;
4324                        $v_seconde = ($p_header['mtime'] & 0x001F) * 2;
4325
4326                        // ----- Extract date
4327                        $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980;
4328                        $v_month = ($p_header['mdate'] & 0x01E0) >> 5;
4329                        $v_day = $p_header['mdate'] & 0x001F;
4330
4331                        // ----- Get UNIX date format
4332                        $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year);
4333
4334                } else {
4335                        $p_header['mtime'] = time();
4336                }
4337
4338                // TBC
4339                //for(reset($v_data); $key = key($v_data); next($v_data)) {
4340                //}
4341
4342                // ----- Set the stored filename
4343                $p_header['stored_filename'] = $p_header['filename'];
4344
4345                // ----- Set the status field
4346                $p_header['status'] = "ok";
4347
4348                // ----- Return
4349                return $v_result;
4350        }
4351        // --------------------------------------------------------------------------------
4352
4353        // --------------------------------------------------------------------------------
4354        // Function : privReadCentralFileHeader()
4355        // Description :
4356        // Parameters :
4357        // Return Values :
4358        // --------------------------------------------------------------------------------
4359        public function privReadCentralFileHeader(&$p_header) {
4360                $v_result = 1;
4361
4362                // ----- Read the 4 bytes signature
4363                $v_binary_data = @fread($this->zip_fd, 4);
4364                $v_data = unpack('Vid', $v_binary_data);
4365
4366                // ----- Check signature
4367                if ($v_data['id'] != 0x02014b50) {
4368
4369                        // ----- Error log
4370                        PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure');
4371
4372                        // ----- Return
4373                        return PclZip::errorCode();
4374                }
4375
4376                // ----- Read the first 42 bytes of the header
4377                $v_binary_data = fread($this->zip_fd, 42);
4378
4379                // ----- Look for invalid block size
4380                if (strlen($v_binary_data) != 42) {
4381                        $p_header['filename'] = "";
4382                        $p_header['status'] = "invalid_header";
4383
4384                        // ----- Error log
4385                        PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : " . strlen($v_binary_data));
4386
4387                        // ----- Return
4388                        return PclZip::errorCode();
4389                }
4390
4391                // ----- Extract the values
4392                $p_header = unpack('vversion/vversion_extracted/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len/vcomment_len/vdisk/vinternal/Vexternal/Voffset',
4393                        $v_binary_data);
4394
4395                // ----- Get filename
4396                if ($p_header['filename_len'] != 0) {
4397                        $p_header['filename'] = fread($this->zip_fd, $p_header['filename_len']);
4398                } else {
4399                        $p_header['filename'] = '';
4400                }
4401
4402                // ----- Get extra
4403                if ($p_header['extra_len'] != 0) {
4404                        $p_header['extra'] = fread($this->zip_fd, $p_header['extra_len']);
4405                } else {
4406                        $p_header['extra'] = '';
4407                }
4408
4409                // ----- Get comment
4410                if ($p_header['comment_len'] != 0) {
4411                        $p_header['comment'] = fread($this->zip_fd, $p_header['comment_len']);
4412                } else {
4413                        $p_header['comment'] = '';
4414                }
4415
4416                // ----- Extract properties
4417
4418                // ----- Recuperate date in UNIX format
4419                //if ($p_header['mdate'] && $p_header['mtime'])
4420                // TBC : bug : this was ignoring time with 0/0/0
4421                if (1) {
4422                        // ----- Extract time
4423                        $v_hour = ($p_header['mtime'] & 0xF800) >> 11;
4424                        $v_minute = ($p_header['mtime'] & 0x07E0) >> 5;
4425                        $v_seconde = ($p_header['mtime'] & 0x001F) * 2;
4426
4427                        // ----- Extract date
4428                        $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980;
4429                        $v_month = ($p_header['mdate'] & 0x01E0) >> 5;
4430                        $v_day = $p_header['mdate'] & 0x001F;
4431
4432                        // ----- Get UNIX date format
4433                        $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year);
4434
4435                } else {
4436                        $p_header['mtime'] = time();
4437                }
4438
4439                // ----- Set the stored filename
4440                $p_header['stored_filename'] = $p_header['filename'];
4441
4442                // ----- Set default status to ok
4443                $p_header['status'] = 'ok';
4444
4445                // ----- Look if it is a directory
4446                if (substr($p_header['filename'], -1) == '/') {
4447                        //$p_header['external'] = 0x41FF0010;
4448                        $p_header['external'] = 0x00000010;
4449                }
4450
4451
4452                // ----- Return
4453                return $v_result;
4454        }
4455        // --------------------------------------------------------------------------------
4456
4457        // --------------------------------------------------------------------------------
4458        // Function : privCheckFileHeaders()
4459        // Description :
4460        // Parameters :
4461        // Return Values :
4462        //   1 on success,
4463        //   0 on error;
4464        // --------------------------------------------------------------------------------
4465        public function privCheckFileHeaders(&$p_local_header, &$p_central_header) {
4466                $v_result = 1;
4467
4468                // ----- Check the static values
4469                // TBC
4470                if ($p_local_header['filename'] != $p_central_header['filename']) {
4471                }
4472                if ($p_local_header['version_extracted'] != $p_central_header['version_extracted']) {
4473                }
4474                if ($p_local_header['flag'] != $p_central_header['flag']) {
4475                }
4476                if ($p_local_header['compression'] != $p_central_header['compression']) {
4477                }
4478                if ($p_local_header['mtime'] != $p_central_header['mtime']) {
4479                }
4480                if ($p_local_header['filename_len'] != $p_central_header['filename_len']) {
4481                }
4482
4483                // ----- Look for flag bit 3
4484                if (($p_local_header['flag'] & 8) == 8) {
4485                        $p_local_header['size'] = $p_central_header['size'];
4486                        $p_local_header['compressed_size'] = $p_central_header['compressed_size'];
4487                        $p_local_header['crc'] = $p_central_header['crc'];
4488                }
4489
4490                // ----- Return
4491                return $v_result;
4492        }
4493        // --------------------------------------------------------------------------------
4494
4495        // --------------------------------------------------------------------------------
4496        // Function : privReadEndCentralDir()
4497        // Description :
4498        // Parameters :
4499        // Return Values :
4500        // --------------------------------------------------------------------------------
4501        public function privReadEndCentralDir(&$p_central_dir) {
4502                $v_result = 1;
4503
4504                // ----- Go to the end of the zip file
4505                $v_size = filesize($this->zipname);
4506                @fseek($this->zip_fd, $v_size);
4507                if (@ftell($this->zip_fd) != $v_size) {
4508                        // ----- Error log
4509                        PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to go to the end of the archive \'' . $this->zipname . '\'');
4510
4511                        // ----- Return
4512                        return PclZip::errorCode();
4513                }
4514
4515                // ----- First try : look if this is an archive with no commentaries (most of the time)
4516                // in this case the end of central dir is at 22 bytes of the file end
4517                $v_found = 0;
4518                if ($v_size > 26) {
4519                        @fseek($this->zip_fd, $v_size - 22);
4520                        if (($v_pos = @ftell($this->zip_fd)) != ($v_size - 22)) {
4521                                // ----- Error log
4522                                PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT,
4523                                        'Unable to seek back to the middle of the archive \'' . $this->zipname . '\'');
4524
4525                                // ----- Return
4526                                return PclZip::errorCode();
4527                        }
4528
4529                        // ----- Read for bytes
4530                        $v_binary_data = @fread($this->zip_fd, 4);
4531                        $v_data = @unpack('Vid', $v_binary_data);
4532
4533                        // ----- Check signature
4534                        if ($v_data['id'] == 0x06054b50) {
4535                                $v_found = 1;
4536                        }
4537
4538                        $v_pos = ftell($this->zip_fd);
4539                }
4540
4541                // ----- Go back to the maximum possible size of the Central Dir End Record
4542                if (!$v_found) {
4543                        $v_maximum_size = 65557; // 0xFFFF + 22;
4544                        if ($v_maximum_size > $v_size) {
4545                                $v_maximum_size = $v_size;
4546                        }
4547                        @fseek($this->zip_fd, $v_size - $v_maximum_size);
4548                        if (@ftell($this->zip_fd) != ($v_size - $v_maximum_size)) {
4549                                // ----- Error log
4550                                PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT,
4551                                        'Unable to seek back to the middle of the archive \'' . $this->zipname . '\'');
4552
4553                                // ----- Return
4554                                return PclZip::errorCode();
4555                        }
4556
4557                        // ----- Read byte per byte in order to find the signature
4558                        $v_pos = ftell($this->zip_fd);
4559                        $v_bytes = 0x00000000;
4560                        while ($v_pos < $v_size) {
4561                                // ----- Read a byte
4562                                $v_byte = @fread($this->zip_fd, 1);
4563
4564                                // -----  Add the byte
4565                                //$v_bytes = ($v_bytes << 8) | Ord($v_byte);
4566                                // Note we mask the old value down such that once shifted we can never end up with more than a 32bit number
4567                                // Otherwise on systems where we have 64bit integers the check below for the magic number will fail.
4568                                $v_bytes = (($v_bytes & 0xFFFFFF) << 8) | Ord($v_byte);
4569
4570                                // ----- Compare the bytes
4571                                if ($v_bytes == 0x504b0506) {
4572                                        $v_pos++;
4573                                        break;
4574                                }
4575
4576                                $v_pos++;
4577                        }
4578
4579                        // ----- Look if not found end of central dir
4580                        if ($v_pos == $v_size) {
4581
4582                                // ----- Error log
4583                                PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Unable to find End of Central Dir Record signature");
4584
4585                                // ----- Return
4586                                return PclZip::errorCode();
4587                        }
4588                }
4589
4590                // ----- Read the first 18 bytes of the header
4591                $v_binary_data = fread($this->zip_fd, 18);
4592
4593                // ----- Look for invalid block size
4594                if (strlen($v_binary_data) != 18) {
4595
4596                        // ----- Error log
4597                        PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid End of Central Dir Record size : " . strlen($v_binary_data));
4598
4599                        // ----- Return
4600                        return PclZip::errorCode();
4601                }
4602
4603                // ----- Extract the values
4604                $v_data = unpack('vdisk/vdisk_start/vdisk_entries/ventries/Vsize/Voffset/vcomment_size', $v_binary_data);
4605
4606                // ----- Check the global size
4607                if (($v_pos + $v_data['comment_size'] + 18) != $v_size) {
4608
4609                        // ----- Removed in release 2.2 see readme file
4610                        // The check of the file size is a little too strict.
4611                        // Some bugs where found when a zip is encrypted/decrypted with 'crypt'.
4612                        // While decrypted, zip has training 0 bytes
4613                        if (0) {
4614                                // ----- Error log
4615                                PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT,
4616                                        'The central dir is not at the end of the archive.'
4617                                        . ' Some trailing bytes exists after the archive.');
4618
4619                                // ----- Return
4620                                return PclZip::errorCode();
4621                        }
4622                }
4623
4624                // ----- Get comment
4625                if ($v_data['comment_size'] != 0) {
4626                        $p_central_dir['comment'] = fread($this->zip_fd, $v_data['comment_size']);
4627                } else {
4628                        $p_central_dir['comment'] = '';
4629                }
4630
4631                $p_central_dir['entries'] = $v_data['entries'];
4632                $p_central_dir['disk_entries'] = $v_data['disk_entries'];
4633                $p_central_dir['offset'] = $v_data['offset'];
4634                $p_central_dir['size'] = $v_data['size'];
4635                $p_central_dir['disk'] = $v_data['disk'];
4636                $p_central_dir['disk_start'] = $v_data['disk_start'];
4637
4638                // TBC
4639                //for(reset($p_central_dir); $key = key($p_central_dir); next($p_central_dir)) {
4640                //}
4641
4642                // ----- Return
4643                return $v_result;
4644        }
4645        // --------------------------------------------------------------------------------
4646
4647        // --------------------------------------------------------------------------------
4648        // Function : privDeleteByRule()
4649        // Description :
4650        // Parameters :
4651        // Return Values :
4652        // --------------------------------------------------------------------------------
4653        public function privDeleteByRule(&$p_result_list, &$p_options) {
4654                $v_result = 1;
4655                $v_list_detail = array();
4656
4657                // ----- Open the zip file
4658                if (($v_result = $this->privOpenFd('rb')) != 1) {
4659                        // ----- Return
4660                        return $v_result;
4661                }
4662
4663                // ----- Read the central directory informations
4664                $v_central_dir = array();
4665                if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) {
4666                        $this->privCloseFd();
4667
4668                        return $v_result;
4669                }
4670
4671                // ----- Go to beginning of File
4672                @rewind($this->zip_fd);
4673
4674                // ----- Scan all the files
4675                // ----- Start at beginning of Central Dir
4676                $v_pos_entry = $v_central_dir['offset'];
4677                @rewind($this->zip_fd);
4678                if (@fseek($this->zip_fd, $v_pos_entry)) {
4679                        // ----- Close the zip file
4680                        $this->privCloseFd();
4681
4682                        // ----- Error log
4683                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
4684
4685                        // ----- Return
4686                        return PclZip::errorCode();
4687                }
4688
4689                // ----- Read each entry
4690                $v_header_list = array();
4691                $j_start = 0;
4692                for ($i = 0, $v_nb_extracted = 0; $i < $v_central_dir['entries']; $i++) {
4693
4694                        // ----- Read the file header
4695                        $v_header_list[$v_nb_extracted] = array();
4696                        if (($v_result = $this->privReadCentralFileHeader($v_header_list[$v_nb_extracted])) != 1) {
4697                                // ----- Close the zip file
4698                                $this->privCloseFd();
4699
4700                                return $v_result;
4701                        }
4702
4703
4704                        // ----- Store the index
4705                        $v_header_list[$v_nb_extracted]['index'] = $i;
4706
4707                        // ----- Look for the specific extract rules
4708                        $v_found = false;
4709
4710                        // ----- Look for extract by name rule
4711                        if ((isset($p_options[PCLZIP_OPT_BY_NAME]))
4712                                && ($p_options[PCLZIP_OPT_BY_NAME] != 0)
4713                        ) {
4714
4715                                // ----- Look if the filename is in the list
4716                                for ($j = 0; ($j < sizeof($p_options[PCLZIP_OPT_BY_NAME])) && (!$v_found); $j++) {
4717
4718                                        // ----- Look for a directory
4719                                        if (substr($p_options[PCLZIP_OPT_BY_NAME][$j], -1) == "/") {
4720
4721                                                // ----- Look if the directory is in the filename path
4722                                                if ((strlen($v_header_list[$v_nb_extracted]['stored_filename']) > strlen($p_options[PCLZIP_OPT_BY_NAME][$j]))
4723                                                        && (substr($v_header_list[$v_nb_extracted]['stored_filename'], 0,
4724                                                                        strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])
4725                                                ) {
4726                                                        $v_found = true;
4727                                                } elseif ((($v_header_list[$v_nb_extracted]['external'] & 0x00000010) == 0x00000010) /* Indicates a folder */
4728                                                        && ($v_header_list[$v_nb_extracted]['stored_filename'] . '/' == $p_options[PCLZIP_OPT_BY_NAME][$j])
4729                                                ) {
4730                                                        $v_found = true;
4731                                                }
4732                                        } // ----- Look for a filename
4733                                        elseif ($v_header_list[$v_nb_extracted]['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) {
4734                                                $v_found = true;
4735                                        }
4736                                }
4737                        }
4738
4739                        // ----- Look for extract by ereg rule
4740                        // ereg() is deprecated with PHP 5.3
4741                        /*
4742      else if (   (isset($p_options[PCLZIP_OPT_BY_EREG]))
4743               && ($p_options[PCLZIP_OPT_BY_EREG] != "")) {
4744
4745          if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header_list[$v_nb_extracted]['stored_filename'])) {
4746              $v_found = true;
4747          }
4748      }
4749      */
4750
4751                        // ----- Look for extract by preg rule
4752                        else {
4753                                if ((isset($p_options[PCLZIP_OPT_BY_PREG]))
4754                                        && ($p_options[PCLZIP_OPT_BY_PREG] != "")
4755                                ) {
4756
4757                                        if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header_list[$v_nb_extracted]['stored_filename'])) {
4758                                                $v_found = true;
4759                                        }
4760                                } // ----- Look for extract by index rule
4761                                else {
4762                                        if ((isset($p_options[PCLZIP_OPT_BY_INDEX]))
4763                                                && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)
4764                                        ) {
4765
4766                                                // ----- Look if the index is in the list
4767                                                for ($j = $j_start; ($j < sizeof($p_options[PCLZIP_OPT_BY_INDEX])) && (!$v_found); $j++) {
4768
4769                                                        if (($i >= $p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i <= $p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) {
4770                                                                $v_found = true;
4771                                                        }
4772                                                        if ($i >= $p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) {
4773                                                                $j_start = $j + 1;
4774                                                        }
4775
4776                                                        if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start'] > $i) {
4777                                                                break;
4778                                                        }
4779                                                }
4780                                        } else {
4781                                                $v_found = true;
4782                                        }
4783                                }
4784                        }
4785
4786                        // ----- Look for deletion
4787                        if ($v_found) {
4788                                unset($v_header_list[$v_nb_extracted]);
4789                        } else {
4790                                $v_nb_extracted++;
4791                        }
4792                }
4793
4794                // ----- Look if something need to be deleted
4795                if ($v_nb_extracted > 0) {
4796
4797                        // ----- Creates a temporay file
4798                        $v_zip_temp_name = PCLZIP_TEMPORARY_DIR . uniqid('pclzip-') . '.tmp';
4799
4800                        // ----- Creates a temporary zip archive
4801                        $v_temp_zip = new PclZip($v_zip_temp_name);
4802
4803                        // ----- Open the temporary zip file in write mode
4804                        if (($v_result = $v_temp_zip->privOpenFd('wb')) != 1) {
4805                                $this->privCloseFd();
4806
4807                                // ----- Return
4808                                return $v_result;
4809                        }
4810
4811                        // ----- Look which file need to be kept
4812                        for ($i = 0; $i < sizeof($v_header_list); $i++) {
4813
4814                                // ----- Calculate the position of the header
4815                                @rewind($this->zip_fd);
4816                                if (@fseek($this->zip_fd, $v_header_list[$i]['offset'])) {
4817                                        // ----- Close the zip file
4818                                        $this->privCloseFd();
4819                                        $v_temp_zip->privCloseFd();
4820                                        @unlink($v_zip_temp_name);
4821
4822                                        // ----- Error log
4823                                        PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
4824
4825                                        // ----- Return
4826                                        return PclZip::errorCode();
4827                                }
4828
4829                                // ----- Read the file header
4830                                $v_local_header = array();
4831                                if (($v_result = $this->privReadFileHeader($v_local_header)) != 1) {
4832                                        // ----- Close the zip file
4833                                        $this->privCloseFd();
4834                                        $v_temp_zip->privCloseFd();
4835                                        @unlink($v_zip_temp_name);
4836
4837                                        // ----- Return
4838                                        return $v_result;
4839                                }
4840
4841                                // ----- Check that local file header is same as central file header
4842                                if ($this->privCheckFileHeaders($v_local_header,
4843                                                $v_header_list[$i]) != 1
4844                                ) {
4845                                        // TBC
4846                                }
4847                                unset($v_local_header);
4848
4849                                // ----- Write the file header
4850                                if (($v_result = $v_temp_zip->privWriteFileHeader($v_header_list[$i])) != 1) {
4851                                        // ----- Close the zip file
4852                                        $this->privCloseFd();
4853                                        $v_temp_zip->privCloseFd();
4854                                        @unlink($v_zip_temp_name);
4855
4856                                        // ----- Return
4857                                        return $v_result;
4858                                }
4859
4860                                // ----- Read/write the data block
4861                                if (($v_result = PclZipUtilCopyBlock($this->zip_fd, $v_temp_zip->zip_fd,
4862                                                $v_header_list[$i]['compressed_size'])) != 1
4863                                ) {
4864                                        // ----- Close the zip file
4865                                        $this->privCloseFd();
4866                                        $v_temp_zip->privCloseFd();
4867                                        @unlink($v_zip_temp_name);
4868
4869                                        // ----- Return
4870                                        return $v_result;
4871                                }
4872                        }
4873
4874                        // ----- Store the offset of the central dir
4875                        $v_offset = @ftell($v_temp_zip->zip_fd);
4876
4877                        // ----- Re-Create the Central Dir files header
4878                        for ($i = 0; $i < sizeof($v_header_list); $i++) {
4879                                // ----- Create the file header
4880                                if (($v_result = $v_temp_zip->privWriteCentralFileHeader($v_header_list[$i])) != 1) {
4881                                        $v_temp_zip->privCloseFd();
4882                                        $this->privCloseFd();
4883                                        @unlink($v_zip_temp_name);
4884
4885                                        // ----- Return
4886                                        return $v_result;
4887                                }
4888
4889                                // ----- Transform the header to a 'usable' info
4890                                $v_temp_zip->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);
4891                        }
4892
4893
4894                        // ----- Zip file comment
4895                        $v_comment = '';
4896                        if (isset($p_options[PCLZIP_OPT_COMMENT])) {
4897                                $v_comment = $p_options[PCLZIP_OPT_COMMENT];
4898                        }
4899
4900                        // ----- Calculate the size of the central header
4901                        $v_size = @ftell($v_temp_zip->zip_fd) - $v_offset;
4902
4903                        // ----- Create the central dir footer
4904                        if (($v_result = $v_temp_zip->privWriteCentralHeader(sizeof($v_header_list), $v_size, $v_offset,
4905                                        $v_comment)) != 1
4906                        ) {
4907                                // ----- Reset the file list
4908                                unset($v_header_list);
4909                                $v_temp_zip->privCloseFd();
4910                                $this->privCloseFd();
4911                                @unlink($v_zip_temp_name);
4912
4913                                // ----- Return
4914                                return $v_result;
4915                        }
4916
4917                        // ----- Close
4918                        $v_temp_zip->privCloseFd();
4919                        $this->privCloseFd();
4920
4921                        // ----- Delete the zip file
4922                        // TBC : I should test the result ...
4923                        @unlink($this->zipname);
4924
4925                        // ----- Rename the temporary file
4926                        // TBC : I should test the result ...
4927                        //@rename($v_zip_temp_name, $this->zipname);
4928                        PclZipUtilRename($v_zip_temp_name, $this->zipname);
4929
4930                        // ----- Destroy the temporary archive