Completed
Pull Request — master (#2)
by Stephen
09:27
created

PclZip::privAddFile()   F

Complexity

Conditions 31
Paths 16801

Size

Total Lines 263
Code Lines 113

Duplication

Lines 34
Ratio 12.93 %

Importance

Changes 0
Metric Value
cc 31
eloc 113
nc 16801
nop 3
dl 34
loc 263
rs 2
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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