Test Failed
Push — main ( c8394f...8477f1 )
by Rafael
66:21
created

PclZip   F

Complexity

Total Complexity 602

Size/Duplication

Total Lines 4840
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 1849
dl 0
loc 4840
rs 0.8
c 0
b 0
f 0
wmc 602

How to fix   Complexity   

Complex Class

Complex classes like PclZip often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use PclZip, and based on these observations, apply Extract Interface, too.

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