source: spip-zone/_core_/plugins/archiviste/inc/pclzip.php

Last change on this file was 101851, checked in by marcimat@…, 2 years ago

Compatibilité PHP 7.1 : notice --

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