Completed
Push — master ( 3a6ebc...3a5a05 )
by Michael
04:13
created

libs/altsys/include/Archive_Zip.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
3385
              $p_size -= $v_read_size;
3386
          }
3387 View Code Duplication
      } elseif ($p_mode==1) {
3388
          while ($p_size != 0) {
3389
              $v_read_size = ($p_size < ARCHIVE_ZIP_READ_BLOCK_SIZE
3390
                        ? $p_size : ARCHIVE_ZIP_READ_BLOCK_SIZE);
3391
              $v_buffer = @gzread($p_src, $v_read_size);
3392
              @fwrite($p_dest, $v_buffer, $v_read_size);
3393
              $p_size -= $v_read_size;
3394
          }
3395
      } elseif ($p_mode==2) {
3396
          while ($p_size != 0) {
3397
              $v_read_size = ($p_size < ARCHIVE_ZIP_READ_BLOCK_SIZE
3398
                        ? $p_size : ARCHIVE_ZIP_READ_BLOCK_SIZE);
3399
              $v_buffer = @fread($p_src, $v_read_size);
3400
              @gzwrite($p_dest, $v_buffer, $v_read_size);
3401
              $p_size -= $v_read_size;
3402
          }
3403 View Code Duplication
      } elseif ($p_mode==3) {
3404
          while ($p_size != 0) {
3405
              $v_read_size = ($p_size < ARCHIVE_ZIP_READ_BLOCK_SIZE
3406
                        ? $p_size : ARCHIVE_ZIP_READ_BLOCK_SIZE);
3407
              $v_buffer = @gzread($p_src, $v_read_size);
3408
              @gzwrite($p_dest, $v_buffer, $v_read_size);
3409
              $p_size -= $v_read_size;
3410
          }
3411
      }
3412
3413
    // ----- Return
3414
    return $v_result;
3415
  }
3416
  // ---------------------------------------------------------------------------
3417
3418
  // ---------------------------------------------------------------------------
3419
  // Function : $this->_tool_Rename()
3420
  // Description :
3421
  //   This function tries to do a simple rename() function. If it fails, it
3422
  //   tries to copy the $p_src file in a new $p_dest file and then unlink the
3423
  //   first one.
3424
  // Parameters :
3425
  //   $p_src : Old filename
3426
  //   $p_dest : New filename
3427
  // Return Values :
3428
  //   1 on success, 0 on failure.
3429
  // ---------------------------------------------------------------------------
3430
  /**
3431
  * _tool_Rename()
3432
  *
3433
  * { Description }
3434
  *
3435
  */
3436
  public function _tool_Rename($p_src, $p_dest)
3437
  {
3438
      $v_result = 1;
3439
3440
    // ----- Try to rename the files
3441
    if (!@rename($p_src, $p_dest)) {
3442
3443
      // ----- Try to copy & unlink the src
3444
      if (!@copy($p_src, $p_dest)) {
3445
          $v_result = 0;
3446
      } elseif (!@unlink($p_src)) {
3447
          $v_result = 0;
3448
      }
3449
    }
3450
3451
    // ----- Return
3452
    return $v_result;
3453
  }
3454
  // ---------------------------------------------------------------------------
3455
3456
  // ---------------------------------------------------------------------------
3457
  // Function : $this->_tool_TranslateWinPath()
3458
  // Description :
3459
  //   Translate windows path by replacing '\' by '/' and optionally removing
3460
  //   drive letter.
3461
  // Parameters :
3462
  //   $p_path : path to translate.
3463
  //   $p_remove_disk_letter : true | false
3464
  // Return Values :
3465
  //   The path translated.
3466
  // ---------------------------------------------------------------------------
3467
  /**
3468
  * _tool_TranslateWinPath()
3469
  *
3470
  * { Description }
3471
  *
3472
  * @param [type] $p_remove_disk_letter
3473
  */
3474
  public function _tool_TranslateWinPath($p_path, $p_remove_disk_letter=true)
3475
  {
3476
      if (stristr(php_uname(), 'windows')) {
3477
          // ----- Look for potential disk letter
3478
      if ($p_remove_disk_letter
3479
          && (($v_position = strpos($p_path, ':')) != false)) {
3480
          $p_path = substr($p_path, $v_position+1);
3481
      }
3482
      // ----- Change potential windows directory separator
3483
      if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0, 1) == '\\')) {
3484
          $p_path = strtr($p_path, '\\', '/');
3485
      }
3486
      }
3487
      return $p_path;
3488
  }
3489
  // ---------------------------------------------------------------------------
3490
}
3491
  // End of class
3492
3493