Archive_Zip   F
last analyzed

Complexity

Total Complexity 386

Size/Duplication

Total Lines 3352
Duplicated Lines 9.1 %

Coupling/Cohesion

Components 1
Dependencies 0

Importance

Changes 0
Metric Value
dl 305
loc 3352
rs 0.8
c 0
b 0
f 0
wmc 386
lcom 1
cbo 0

43 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 15 2
B create() 13 40 6
B add() 15 45 6
A listContent() 0 18 3
B extract() 0 40 5
B delete() 0 37 8
B properties() 0 40 5
A duplicate() 0 25 5
A merge() 0 28 5
A errorCode() 0 4 1
A errorName() 0 24 5
A errorInfo() 0 8 2
A _checkFormat() 0 35 3
A _create() 0 24 2
D _add() 13 142 15
A _openFd() 5 21 3
A _closeFd() 0 12 2
B _addList() 0 45 6
C _addFileList() 0 82 14
F _addFile() 11 210 31
A _writeFileHeader() 6 33 3
A _writeCentralFileHeader() 6 35 4
A _writeCentralHeader() 0 18 2
B _list() 14 48 6
A _convertHeader2FileInfo() 0 18 1
F _extractByRule() 38 191 44
F _extractFile() 15 208 30
A _extractFileAsString() 0 42 4
B _readFileHeader() 26 88 6
C _readCentralFileHeader() 41 91 9
C _readEndCentralDir() 15 114 14
F _deleteByRule() 46 240 41
B _dirCheck() 0 37 9
F _merge() 19 159 17
B _duplicate() 6 47 6
B _check_parameters() 0 46 10
A _errorLog() 0 5 1
A _errorReset() 0 5 1
B _tool_PathReduction() 0 30 9
C _tool_PathInclusion() 0 57 17
C _tool_CopyBlock() 16 37 13
A _tool_Rename() 0 18 4
A _tool_TranslateWinPath() 0 15 6

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Archive_Zip often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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

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

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
 * Class for manipulating zip archive files
90
 *
91
 * A class which provided common methods to manipulate ZIP formatted
92
 * archive files.
93
 * It provides creation, extraction, deletion and add features.
94
 *
95
 * @author   Vincent Blavet <[email protected]>
96
 * @version  $Revision: 1.2 $
97
 * @package  Archive_Zip
98
 * @category Archive
99
 */
100
class Archive_Zip
101
{
102
    /**
103
     * The filename of the zip archive.
104
     *
105
     * @var string Name of the Zip file
106
     */
107
    public $_zipname = '';
108
109
    /**
110
     * File descriptor of the opened Zip file.
111
     *
112
     * @var int Internal zip file descriptor
113
     */
114
    public $_zip_fd = 0;
115
116
    /**
117
     * @var int last error code
118
     */
119
    public $_error_code = 1;
120
121
    /**
122
     * @var string Last error description
123
     */
124
    public $_error_string = '';
125
126
    // {{{ constructor
127
    /**
128
     * Archive_Zip Class constructor. This flavour of the constructor only
129
     * declare a new Archive_Zip object, identifying it by the name of the
130
     * zip file.
131
     *
132
     * @param string $p_zipname The name of the zip archive to create
133
     * @access public
134
     */
135
    public function __construct($p_zipname)
136
    {
137
138
        // ----- Check the zlib
139
        /*      if (!extension_loaded('zlib')) {
140
                  PEAR::loadExtension('zlib');
141
              }*/ // GIJ
142
        if (!extension_loaded('zlib')) {
143
            die("The extension 'zlib' couldn't be found.\n" . 'Please make sure your version of PHP was built ' . "with 'zlib' support.\n");
144
        }
145
146
        // ----- Set the attributes
147
        $this->_zipname = $p_zipname;
148
        $this->_zip_fd  = 0;
149
    }
150
    // }}}
151
152
    // {{{ create()
153
    /**
154
     * This method creates a Zip Archive with the filename set with
155
     * the constructor.
156
     * The files and directories indicated in $p_filelist
157
     * are added in the archive.
158
     * When a directory is in the list, the directory and its content is added
159
     * in the archive.
160
     * The methods takes a variable list of parameters in $p_params.
161
     * The supported parameters for this method are :
162
     *   'add_path' : Add a path to the archived files.
163
     *   'remove_path' : Remove the specified 'root' path of the archived files.
164
     *   'remove_all_path' : Remove all the path of the archived files.
165
     *   'no_compression' : The archived files will not be compressed.
166
     *
167
     * @access public
168
     * @param  mixed $p_filelist The list of the files or folders to add.
169
     *                           It can be a string with filenames separated
170
     *                           by a comma, or an array of filenames.
171
     * @param  mixed $p_params   An array of variable parameters and values.
172
     * @return mixed An array of file description on success,
173
     *                           an error code on error
174
     */
175
    public function create($p_filelist, $p_params = 0)
176
    {
177
        $this->_errorReset();
178
179
        // ----- Set default values
180
        if ($p_params === 0) {
181
            $p_params = array();
182
        }
183
        if ($this->_check_parameters($p_params, array(
184
                'no_compression'  => false,
185
                'add_path'        => '',
186
                'remove_path'     => '',
187
                'remove_all_path' => false
188
            )) != 1
189
        ) {
190
            return 0;
191
        }
192
193
        // ----- Look if the $p_filelist is really an array
194
        $p_result_list = array();
195 View Code Duplication
        if (is_array($p_filelist)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
196
            $v_result = $this->_create($p_filelist, $p_result_list, $p_params);
197
        } // ----- Look if the $p_filelist is a string
198
        elseif (is_string($p_filelist)) {
199
            // ----- Create a list with the elements from the string
200
            $v_list = explode(ARCHIVE_ZIP_SEPARATOR, $p_filelist);
201
202
            $v_result = $this->_create($v_list, $p_result_list, $p_params);
203
        } // ----- Invalid variable
204
        else {
205
            $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER, 'Invalid variable type p_filelist');
206
            $v_result = ARCHIVE_ZIP_ERR_INVALID_PARAMETER;
207
        }
208
209
        if ($v_result != 1) {
210
            return 0;
211
        }
212
213
        return $p_result_list;
214
    }
215
    // }}}
216
217
    // {{{ add()
218
    /**
219
     * This method add files or directory in an existing Zip Archive.
220
     * If the Zip Archive does not exist it is created.
221
     * The files and directories to add are indicated in $p_filelist.
222
     * When a directory is in the list, the directory and its content is added
223
     * in the archive.
224
     * The methods takes a variable list of parameters in $p_params.
225
     * The supported parameters for this method are :
226
     *   'add_path' : Add a path to the archived files.
227
     *   'remove_path' : Remove the specified 'root' path of the archived files.
228
     *   'remove_all_path' : Remove all the path of the archived files.
229
     *   'no_compression' : The archived files will not be compressed.
230
     *   'callback_pre_add' : A callback function that will be called before
231
     *                        each entry archiving.
232
     *   'callback_post_add' : A callback function that will be called after
233
     *                         each entry archiving.
234
     *
235
     * @access public
236
     * @param  mixed $p_filelist The list of the files or folders to add.
237
     *                           It can be a string with filenames separated
238
     *                           by a comma, or an array of filenames.
239
     * @param  mixed $p_params   An array of variable parameters and values.
240
     * @return mixed An array of file description on success,
241
     *                           0 on an unrecoverable failure, an error code is logged.
242
     */
243
    public function add($p_filelist, $p_params = 0)
244
    {
245
        $this->_errorReset();
246
247
        // ----- Set default values
248
        if ($p_params === 0) {
249
            $p_params = array();
250
        }
251
        if ($this->_check_parameters($p_params, array(
252
                'no_compression'    => false,
253
                'add_path'          => '',
254
                'remove_path'       => '',
255
                'remove_all_path'   => false,
256
                'callback_pre_add'  => '',
257
                'callback_post_add' => ''
258
            )) != 1
259
        ) {
260
            return 0;
261
        }
262
263
        // ----- Look if the $p_filelist is really an array
264
        $p_result_list = array();
265 View Code Duplication
        if (is_array($p_filelist)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
266
            // ----- Call the create fct
267
            $v_result = $this->_add($p_filelist, $p_result_list, $p_params);
268
        } // ----- Look if the $p_filelist is a string
269
        elseif (is_string($p_filelist)) {
270
            // ----- Create a list with the elements from the string
271
            $v_list = explode(ARCHIVE_ZIP_SEPARATOR, $p_filelist);
272
273
            // ----- Call the create fct
274
            $v_result = $this->_add($v_list, $p_result_list, $p_params);
275
        } // ----- Invalid variable
276
        else {
277
            $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER, 'add() : Invalid variable type p_filelist');
278
            $v_result = ARCHIVE_ZIP_ERR_INVALID_PARAMETER;
279
        }
280
281
        if ($v_result != 1) {
282
            return 0;
283
        }
284
285
        // ----- Return the result list
286
        return $p_result_list;
287
    }
288
    // }}}
289
290
    // {{{ listContent()
291
    /**
292
     * This method gives the names and properties of the files and directories
293
     * which are present in the zip archive.
294
     * The properties of each entries in the list are :
295
     *   filename : Name of the file.
296
     *              For create() or add() it's the filename given by the user.
297
     *              For an extract() it's the filename of the extracted file.
298
     *   stored_filename : Name of the file / directory stored in the archive.
299
     *   size : Size of the stored file.
300
     *   compressed_size : Size of the file's data compressed in the archive
301
     *                     (without the zip headers overhead)
302
     *   mtime : Last known modification date of the file (UNIX timestamp)
303
     *   comment : Comment associated with the file
304
     *   folder : true | false (indicates if the entry is a folder)
305
     *   index : index of the file in the archive (-1 when not available)
306
     *   status : status of the action on the entry (depending of the action) :
307
     *            Values are :
308
     *              ok : OK !
309
     *              filtered : the file/dir was not extracted (filtered by user)
310
     *              already_a_directory : the file can't be extracted because a
311
     *                                    directory with the same name already
312
     *                                    exists
313
     *              write_protected : the file can't be extracted because a file
314
     *                                with the same name already exists and is
315
     *                                write protected
316
     *              newer_exist : the file was not extracted because a newer
317
     *                            file already exists
318
     *              path_creation_fail : the file is not extracted because the
319
     *                                   folder does not exists and can't be
320
     *                                   created
321
     *              write_error : the file was not extracted because there was a
322
     *                            error while writing the file
323
     *              read_error : the file was not extracted because there was a
324
     *                           error while reading the file
325
     *              invalid_header : the file was not extracted because of an
326
     *                               archive format error (bad file header)
327
     * Note that each time a method can continue operating when there
328
     * is an error on a single file, the error is only logged in the file status.
329
     *
330
     * @access public
331
     * @return mixed An array of file description on success,
332
     *               0 on an unrecoverable failure, an error code is logged.
333
     */
334
    public function listContent()
335
    {
336
        $this->_errorReset();
337
338
        // ----- Check archive
339
        if (!$this->_checkFormat()) {
340
            return 0;
341
        }
342
343
        $v_list = array();
344
        if ($this->_list($v_list) != 1) {
345
            unset($v_list);
346
347
            return 0;
348
        }
349
350
        return $v_list;
351
    }
352
    // }}}
353
354
    // {{{ extract()
355
    /**
356
     * This method extract the files and folders which are in the zip archive.
357
     * It can extract all the archive or a part of the archive by using filter
358
     * feature (extract by name, by index, by ereg, by preg). The extraction
359
     * can occur in the current path or an other path.
360
     * All the advanced features are activated by the use of variable
361
     * parameters.
362
     * The return value is an array of entry descriptions which gives
363
     * information on extracted files (See listContent()).
364
     * The method may return a success value (an array) even if some files
365
     * are not correctly extracted (see the file status in listContent()).
366
     * The supported variable parameters for this method are :
367
     *   'add_path' : Path where the files and directories are to be extracted
368
     *   'remove_path' : First part ('root' part) of the memorized path
369
     *                   (if similar) to remove while extracting.
370
     *   'remove_all_path' : Remove all the memorized path while extracting.
371
     *   'extract_as_string' :
372
     *   'set_chmod' : After the extraction of the file the indicated mode
373
     *                 will be set.
374
     *   'by_name' : It can be a string with file/dir names separated by ',',
375
     *               or an array of file/dir names to extract from the archive.
376
     *   'by_index' : A string with range of indexes separated by ',',
377
     *                (sample "1,3-5,12").
378
     *   'by_ereg' : A regular expression (ereg) that must match the extracted
379
     *               filename.
380
     *   'by_preg' : A regular expression (preg) that must match the extracted
381
     *               filename.
382
     *   'callback_pre_extract' : A callback function that will be called before
383
     *                            each entry extraction.
384
     *   'callback_post_extract' : A callback function that will be called after
385
     *                            each entry extraction.
386
     *
387
     * @access public
388
     * @param  mixed $p_params An array of variable parameters and values.
389
     * @return mixed An array of file description on success,
390
     *                         0 on an unrecoverable failure, an error code is logged.
391
     */
392
    public function extract($p_params = 0)
393
    {
394
        $this->_errorReset();
395
396
        // ----- Check archive
397
        if (!$this->_checkFormat()) {
398
            return 0;
399
        }
400
401
        // ----- Set default values
402
        if ($p_params === 0) {
403
            $p_params = array();
404
        }
405
        if ($this->_check_parameters($p_params, array(
406
                'extract_as_string'     => false,
407
                'add_path'              => '',
408
                'remove_path'           => '',
409
                'remove_all_path'       => false,
410
                'callback_pre_extract'  => '',
411
                'callback_post_extract' => '',
412
                'set_chmod'             => 0,
413
                'by_name'               => '',
414
                'by_index'              => '',
415
                'by_ereg'               => '',
416
                'by_preg'               => ''
417
            )) != 1
418
        ) {
419
            return 0;
420
        }
421
422
        // ----- Call the extracting fct
423
        $v_list = array();
424
        if ($this->_extractByRule($v_list, $p_params) != 1) {
425
            unset($v_list);
426
427
            return 0;
428
        }
429
430
        return $v_list;
431
    }
432
    // }}}
433
434
    // {{{ delete()
435
    /**
436
     * This methods delete archive entries in the zip archive.
437
     * Notice that at least one filtering rule (set by the variable parameter
438
     * list) must be set.
439
     * Also notice that if you delete a folder entry, only the folder entry
440
     * is deleted, not all the files bellonging to this folder.
441
     * The supported variable parameters for this method are :
442
     *   'by_name' : It can be a string with file/dir names separated by ',',
443
     *               or an array of file/dir names to delete from the archive.
444
     *   'by_index' : A string with range of indexes separated by ',',
445
     *                (sample "1,3-5,12").
446
     *   'by_ereg' : A regular expression (ereg) that must match the extracted
447
     *               filename.
448
     *   'by_preg' : A regular expression (preg) that must match the extracted
449
     *               filename.
450
     *
451
     * @access public
452
     * @param  mixed $p_params An array of variable parameters and values.
453
     * @return mixed An array of file description on success,
454
     *                         0 on an unrecoverable failure, an error code is logged.
455
     */
456
    public function delete($p_params)
457
    {
458
        $this->_errorReset();
459
460
        // ----- Check archive
461
        if (!$this->_checkFormat()) {
462
            return 0;
463
        }
464
465
        // ----- Set default values
466
        if ($this->_check_parameters($p_params, array(
467
                'by_name'  => '',
468
                'by_index' => '',
469
                'by_ereg'  => '',
470
                'by_preg'  => ''
471
            )) != 1
472
        ) {
473
            return 0;
474
        }
475
476
        // ----- Check that at least one rule is set
477
        if (($p_params['by_name'] == '') && ($p_params['by_index'] == '') && ($p_params['by_ereg'] == '') && ($p_params['by_preg'] == '')) {
478
            $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER, 'At least one filtering rule must' . ' be set as parameter');
479
480
            return 0;
481
        }
482
483
        // ----- Call the delete fct
484
        $v_list = array();
485
        if ($this->_deleteByRule($v_list, $p_params) != 1) {
486
            unset($v_list);
487
488
            return 0;
489
        }
490
491
        return $v_list;
492
    }
493
    // }}}
494
495
    // {{{ properties()
496
    /**
497
     * This method gives the global properties of the archive.
498
     *  The properties are :
499
     *    nb : Number of files in the archive
500
     *    comment : Comment associated with the archive file
501
     *    status : not_exist, ok
502
     *
503
     * @access   public
504
     * @return mixed An array with the global properties or 0 on error.
505
     * @internal param mixed $p_params {Description}
506
     */
507
    public function properties()
508
    {
509
        $this->_errorReset();
510
511
        // ----- Check archive
512
        if (!$this->_checkFormat()) {
513
            return 0;
514
        }
515
516
        // ----- Default properties
517
        $v_prop            = array();
518
        $v_prop['comment'] = '';
519
        $v_prop['nb']      = 0;
520
        $v_prop['status']  = 'not_exist';
521
522
        // ----- Look if file exists
523
        if (@is_file($this->_zipname)) {
524
            // ----- Open the zip file
525
            if (($this->_zip_fd = @fopen($this->_zipname, 'rb')) == 0) {
526
                $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \'' . $this->_zipname . '\' in binary read mode');
527
528
                return 0;
529
            }
530
531
            // ----- Read the central directory informations
532
            $v_central_dir = array();
533
            if (($v_result = $this->_readEndCentralDir($v_central_dir)) != 1) {
534
                return 0;
535
            }
536
537
            $this->_closeFd();
538
539
            // ----- Set the user attributes
540
            $v_prop['comment'] = $v_central_dir['comment'];
541
            $v_prop['nb']      = $v_central_dir['entries'];
542
            $v_prop['status']  = 'ok';
543
        }
544
545
        return $v_prop;
546
    }
547
    // }}}
548
549
    // {{{ duplicate()
550
    /**
551
     * This method creates an archive by copying the content of an other one.
552
     * If the archive already exist, it is replaced by the new one without
553
     * any warning.
554
     *
555
     * @access public
556
     * @param  mixed $p_archive   It can be a valid Archive_Zip object or
557
     *                            the filename of a valid zip archive.
558
     * @return integer 1 on success, 0 on failure.
559
     */
560
    public function duplicate($p_archive)
561
    {
562
        $this->_errorReset();
563
564
        // ----- Look if the $p_archive is a Archive_Zip object
565
        if (is_object($p_archive) && (strtolower(get_class($p_archive)) === 'archive_zip')) {
566
            $v_result = $this->_duplicate($p_archive->_zipname);
567
        } // ----- Look if the $p_archive is a string (so a filename)
568
        elseif (is_string($p_archive)) {
569
            // ----- Check that $p_archive is a valid zip file
570
            // TBC : Should also check the archive format
571
            if (!is_file($p_archive)) {
572
                $this->_errorLog(ARCHIVE_ZIP_ERR_MISSING_FILE, "No file with filename '" . $p_archive . "'");
573
                $v_result = ARCHIVE_ZIP_ERR_MISSING_FILE;
574
            } else {
575
                $v_result = $this->_duplicate($p_archive);
576
            }
577
        } // ----- Invalid variable
578
        else {
579
            $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER, 'Invalid variable type p_archive_to_add');
580
            $v_result = ARCHIVE_ZIP_ERR_INVALID_PARAMETER;
581
        }
582
583
        return $v_result;
584
    }
585
    // }}}
586
587
    // {{{ merge()
588
    /**
589
     *  This method merge a valid zip archive at the end of the
590
     *  archive identified by the Archive_Zip object.
591
     *  If the archive ($this) does not exist, the merge becomes a duplicate.
592
     *  If the archive to add does not exist, the merge is a success.
593
     *
594
     * @access public
595
     * @param  mixed $p_archive_to_add   It can be a valid Archive_Zip object or
596
     *                                   the filename of a valid zip archive.
597
     * @return integer 1 on success, 0 on failure.
598
     */
599
    public function merge($p_archive_to_add)
600
    {
601
        $v_result = 1;
0 ignored issues
show
Unused Code introduced by
$v_result is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
602
        $this->_errorReset();
603
604
        // ----- Check archive
605
        if (!$this->_checkFormat()) {
606
            return 0;
607
        }
608
609
        // ----- Look if the $p_archive_to_add is a Archive_Zip object
610
        if (is_object($p_archive_to_add) && (strtolower(get_class($p_archive_to_add)) === 'archive_zip')) {
611
            $v_result = $this->_merge($p_archive_to_add);
612
        } // ----- Look if the $p_archive_to_add is a string (so a filename)
613
        elseif (is_string($p_archive_to_add)) {
614
            // ----- Create a temporary archive
615
            $v_object_archive = new Archive_Zip($p_archive_to_add);
616
617
            // ----- Merge the archive
618
            $v_result = $this->_merge($v_object_archive);
619
        } // ----- Invalid variable
620
        else {
621
            $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER, 'Invalid variable type p_archive_to_add');
622
            $v_result = ARCHIVE_ZIP_ERR_INVALID_PARAMETER;
623
        }
624
625
        return $v_result;
626
    }
627
    // }}}
628
629
    // {{{ errorCode()
630
    /**
631
     * Method that gives the lastest error code.
632
     *
633
     * @access public
634
     * @return integer The error code value.
635
     */
636
    public function errorCode()
637
    {
638
        return $this->_error_code;
639
    }
640
    // }}}
641
642
    // {{{ errorName()
643
    /**
644
     * This method gives the latest error code name.
645
     *
646
     * @access public
647
     * @param  boolean $p_with_code If true, gives the name and the int value.
648
     * @return string  The error name.
649
     */
650
    public function errorName($p_with_code = false)
651
    {
652
        $v_const_list = get_defined_constants();
653
654
        // ----- Extract error constants from all const.
655
        for (reset($v_const_list); list($v_key, $v_value) = each($v_const_list);) {
656
            if (0 === strpos($v_key, 'ARCHIVE_ZIP_ERR_')) {
657
                $v_error_list[$v_key] = $v_value;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$v_error_list was never initialized. Although not strictly required by PHP, it is generally a good practice to add $v_error_list = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
658
            }
659
        }
660
661
        // ----- Search the name form the code value
662
        $v_key   = array_search($this->_error_code, $v_error_list, true);
0 ignored issues
show
Bug introduced by
The variable $v_error_list does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
663
        $v_value = 'NoName';
664
        if ($v_key != false) {
665
            $v_value = $v_key;
666
        }
667
668
        if ($p_with_code) {
669
            return ($v_value . ' (' . $this->_error_code . ')');
670
        } else {
671
            return $v_value;
672
        }
673
    }
674
    // }}}
675
676
    // {{{ errorInfo()
677
    /**
678
     * This method returns the description associated with the latest error.
679
     *
680
     * @access public
681
     * @param  boolean $p_full If set to true gives the description with the
682
     *                         error code, the name and the description.
683
     *                         If set to false gives only the description
684
     *                         and the error code.
685
     * @return string  The error description.
686
     */
687
    public function errorInfo($p_full = false)
688
    {
689
        if ($p_full) {
690
            return ($this->errorName(true) . ' : ' . $this->_error_string);
691
        } else {
692
            return ($this->_error_string . ' [code ' . $this->_error_code . ']');
693
        }
694
    }
695
    // }}}
696
697
    // -----------------------------------------------------------------------------
698
    // ***** UNDER THIS LINE ARE DEFINED PRIVATE INTERNAL FUNCTIONS *****
699
    // *****                                                        *****
700
    // *****       THESES FUNCTIONS MUST NOT BE USED DIRECTLY       *****
701
    // -----------------------------------------------------------------------------
702
703
    // ---------------------------------------------------------------------------
704
    // Function : _checkFormat()
705
    // Description :
706
    //   This method check that the archive exists and is a valid zip archive.
707
    //   Several level of check exists. (futur)
708
    // Parameters :
709
    //   $p_level : Level of check. Default 0.
710
    //              0 : Check the first bytes (magic codes) (default value))
711
    //              1 : 0 + Check the central directory (futur)
712
    //              2 : 1 + Check each file header (futur)
713
    // Return Values :
714
    //   true on success,
715
    //   false on error, the error code is set.
716
    // ---------------------------------------------------------------------------
717
    /**
718
     * Archive_Zip::_checkFormat()
719
     *
720
     * { Description }
721
     *
722
     * @param  integer $p_level
723
     * @return bool
724
     */
725
    public function _checkFormat($p_level = 0)
0 ignored issues
show
Unused Code introduced by
The parameter $p_level is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
726
    {
727
        $v_result = true;
728
729
        // ----- Reset the error handler
730
        $this->_errorReset();
731
732
        // ----- Look if the file exits
733
        if (!is_file($this->_zipname)) {
734
            // ----- Error log
735
            $this->_errorLog(ARCHIVE_ZIP_ERR_MISSING_FILE, "Missing archive file '" . $this->_zipname . "'");
736
737
            return false;
738
        }
739
740
        // ----- Check that the file is readeable
741
        if (!is_readable($this->_zipname)) {
742
            // ----- Error log
743
            $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, "Unable to read archive '" . $this->_zipname . "'");
744
745
            return false;
746
        }
747
748
        // ----- Check the magic code
749
        // TBC
750
751
        // ----- Check the central header
752
        // TBC
753
754
        // ----- Check each file header
755
        // TBC
756
757
        // ----- Return
758
        return $v_result;
759
    }
760
    // ---------------------------------------------------------------------------
761
762
    // ---------------------------------------------------------------------------
763
    // Function : _create()
764
    // Description :
765
    // Parameters :
766
    // Return Values :
767
    // ---------------------------------------------------------------------------
768
    /**
769
     * Archive_Zip::_create()
770
     *
771
     * { Description }
772
     * @param $p_list
773
     * @param $p_result_list
774
     * @param $p_params
775
     * @return int
776
     */
777
    public function _create($p_list, &$p_result_list, &$p_params)
778
    {
779
        $v_result      = 1;
0 ignored issues
show
Unused Code introduced by
$v_result is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
780
        $v_list_detail = array();
0 ignored issues
show
Unused Code introduced by
$v_list_detail is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
781
782
        $p_add_dir        = $p_params['add_path'];
783
        $p_remove_dir     = $p_params['remove_path'];
784
        $p_remove_all_dir = $p_params['remove_all_path'];
785
786
        // ----- Open the file in write mode
787
        if (($v_result = $this->_openFd('wb')) != 1) {
788
            // ----- Return
789
            return $v_result;
790
        }
791
792
        // ----- Add the list of files
793
        $v_result = $this->_addList($p_list, $p_result_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, $p_params);
794
795
        // ----- Close
796
        $this->_closeFd();
797
798
        // ----- Return
799
        return $v_result;
800
    }
801
    // ---------------------------------------------------------------------------
802
803
    // ---------------------------------------------------------------------------
804
    // Function : _add()
805
    // Description :
806
    // Parameters :
807
    // Return Values :
808
    // ---------------------------------------------------------------------------
809
    /**
810
     * Archive_Zip::_add()
811
     *
812
     * { Description }
813
     * @param $p_list
814
     * @param $p_result_list
815
     * @param $p_params
816
     * @return int
817
     */
818
    public function _add($p_list, &$p_result_list, &$p_params)
819
    {
820
        $v_result      = 1;
0 ignored issues
show
Unused Code introduced by
$v_result is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
821
        $v_list_detail = array();
0 ignored issues
show
Unused Code introduced by
$v_list_detail is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
822
823
        $p_add_dir        = $p_params['add_path'];
824
        $p_remove_dir     = $p_params['remove_path'];
825
        $p_remove_all_dir = $p_params['remove_all_path'];
826
827
        // ----- Look if the archive exists or is empty and need to be created
828
        if ((!is_file($this->_zipname)) || (filesize($this->_zipname) == 0)) {
829
            $v_result = $this->_create($p_list, $p_result_list, $p_params);
830
831
            return $v_result;
832
        }
833
834
        // ----- Open the zip file
835
        if (($v_result = $this->_openFd('rb')) != 1) {
836
            return $v_result;
837
        }
838
839
        // ----- Read the central directory informations
840
        $v_central_dir = array();
841
        if (($v_result = $this->_readEndCentralDir($v_central_dir)) != 1) {
842
            $this->_closeFd();
843
844
            return $v_result;
845
        }
846
847
        // ----- Go to beginning of File
848
        @rewind($this->_zip_fd);
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...
849
850
        // ----- Creates a temporay file
851
        $v_zip_temp_name = ARCHIVE_ZIP_TEMPORARY_DIR . uniqid('archive_zip-') . '.tmp';
852
853
        // ----- Open the temporary file in write mode
854 View Code Duplication
        if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
855
            $this->_closeFd();
856
857
            $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \'' . $v_zip_temp_name . '\' in binary write mode');
858
859
            return Archive_Zip::errorCode();
860
        }
861
862
        // ----- Copy the files from the archive to the temporary file
863
        // TBC : Here I should better append the file and go back to erase the
864
        // central dir
865
        $v_size = $v_central_dir['offset'];
866
        while ($v_size != 0) {
867
            $v_read_size = ($v_size < ARCHIVE_ZIP_READ_BLOCK_SIZE ? $v_size : ARCHIVE_ZIP_READ_BLOCK_SIZE);
868
            $v_buffer    = fread($this->_zip_fd, $v_read_size);
869
            @fwrite($v_zip_temp_fd, $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...
870
            $v_size -= $v_read_size;
871
        }
872
873
        // ----- Swap the file descriptor
874
        // Here is a trick : I swap the temporary fd with the zip fd, in order to
875
        // use the following methods on the temporary fil and not the real archive
876
        $v_swap        = $this->_zip_fd;
877
        $this->_zip_fd = $v_zip_temp_fd;
878
        $v_zip_temp_fd = $v_swap;
879
880
        // ----- Add the files
881
        $v_header_list = array();
882
        if (($v_result = $this->_addFileList($p_list, $v_header_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, $p_params)) != 1) {
883
            fclose($v_zip_temp_fd);
884
            $this->_closeFd();
885
            @unlink($v_zip_temp_name);
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...
886
887
            // ----- Return
888
            return $v_result;
889
        }
890
891
        // ----- Store the offset of the central dir
892
        $v_offset = @ftell($this->_zip_fd);
893
894
        // ----- Copy the block of file headers from the old archive
895
        $v_size = $v_central_dir['size'];
896 View Code Duplication
        while ($v_size != 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
897
            $v_read_size = ($v_size < ARCHIVE_ZIP_READ_BLOCK_SIZE ? $v_size : ARCHIVE_ZIP_READ_BLOCK_SIZE);
898
            $v_buffer    = @fread($v_zip_temp_fd, $v_read_size);
899
            @fwrite($this->_zip_fd, $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...
900
            $v_size -= $v_read_size;
901
        }
902
903
        // ----- Create the Central Dir files header
904
        for ($i = 0, $iMax = count($v_header_list); $i < $iMax; ++$i) {
905
            // ----- Create the file header
906
            if ($v_header_list[$i]['status'] === 'ok') {
907
                if (($v_result = $this->_writeCentralFileHeader($v_header_list[$i])) != 1) {
908
                    fclose($v_zip_temp_fd);
909
                    $this->_closeFd();
910
                    @unlink($v_zip_temp_name);
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...
911
912
                    // ----- Return
913
                    return $v_result;
914
                }
915
                ++$v_count;
0 ignored issues
show
Bug introduced by
The variable $v_count does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
916
            }
917
918
            // ----- Transform the header to a 'usable' info
919
            $this->_convertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);
920
        }
921
922
        // ----- Zip file comment
923
        $v_comment = '';
924
925
        // ----- Calculate the size of the central header
926
        $v_size = @ftell($this->_zip_fd) - $v_offset;
927
928
        // ----- Create the central dir footer
929
        if (($v_result = $this->_writeCentralHeader($v_count + $v_central_dir['entries'], $v_size, $v_offset, $v_comment)) != 1) {
930
            // ----- Reset the file list
931
            unset($v_header_list);
932
933
            // ----- Return
934
            return $v_result;
935
        }
936
937
        // ----- Swap back the file descriptor
938
        $v_swap        = $this->_zip_fd;
939
        $this->_zip_fd = $v_zip_temp_fd;
940
        $v_zip_temp_fd = $v_swap;
941
942
        // ----- Close
943
        $this->_closeFd();
944
945
        // ----- Close the temporary file
946
        @fclose($v_zip_temp_fd);
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...
947
948
        // ----- Delete the zip file
949
        // TBC : I should test the result ...
950
        @unlink($this->_zipname);
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...
951
952
        // ----- Rename the temporary file
953
        // TBC : I should test the result ...
954
        //@rename($v_zip_temp_name, $this->_zipname);
955
        $this->_tool_Rename($v_zip_temp_name, $this->_zipname);
956
957
        // ----- Return
958
        return $v_result;
959
    }
960
    // ---------------------------------------------------------------------------
961
962
    // ---------------------------------------------------------------------------
963
    // Function : _openFd()
964
    // Description :
965
    // Parameters :
966
    // ---------------------------------------------------------------------------
967
    /**
968
     * Archive_Zip::_openFd()
969
     *
970
     * { Description }
971
     * @param $p_mode
972
     * @return int
973
     */
974
    public function _openFd($p_mode)
975
    {
976
        $v_result = 1;
977
978
        // ----- Look if already open
979
        if ($this->_zip_fd != 0) {
980
            $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, 'Zip file \'' . $this->_zipname . '\' already open');
981
982
            return Archive_Zip::errorCode();
983
        }
984
985
        // ----- Open the zip file
986 View Code Duplication
        if (($this->_zip_fd = @fopen($this->_zipname, $p_mode)) == 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
987
            $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \'' . $this->_zipname . '\' in ' . $p_mode . ' mode');
988
989
            return Archive_Zip::errorCode();
990
        }
991
992
        // ----- Return
993
        return $v_result;
994
    }
995
    // ---------------------------------------------------------------------------
996
997
    // ---------------------------------------------------------------------------
998
    // Function : _closeFd()
999
    // Description :
1000
    // Parameters :
1001
    // ---------------------------------------------------------------------------
1002
    /**
1003
     * Archive_Zip::_closeFd()
1004
     *
1005
     * { Description }
1006
     *
1007
     */
1008
    public function _closeFd()
1009
    {
1010
        $v_result = 1;
1011
1012
        if ($this->_zip_fd != 0) {
1013
            @fclose($this->_zip_fd);
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...
1014
        }
1015
        $this->_zip_fd = 0;
1016
1017
        // ----- Return
1018
        return $v_result;
1019
    }
1020
    // ---------------------------------------------------------------------------
1021
1022
    // ---------------------------------------------------------------------------
1023
    // Function : _addList()
1024
    // Description :
1025
    //   $p_add_dir and $p_remove_dir will give the ability to memorize a path which is
1026
    //   different from the real path of the file. This is usefull if you want to have PclTar
1027
    //   running in any directory, and memorize relative path from an other directory.
1028
    // Parameters :
1029
    //   $p_list : An array containing the file or directory names to add in the tar
1030
    //   $p_result_list : list of added files with their properties (specially the status field)
1031
    //   $p_add_dir : Path to add in the filename path archived
1032
    //   $p_remove_dir : Path to remove in the filename path archived
1033
    // Return Values :
1034
    // ---------------------------------------------------------------------------
1035
    /**
1036
     * Archive_Zip::_addList()
1037
     *
1038
     * { Description }
1039
     * @param $p_list
1040
     * @param $p_result_list
1041
     * @param $p_add_dir
1042
     * @param $p_remove_dir
1043
     * @param $p_remove_all_dir
1044
     * @param $p_params
1045
     * @return int
1046
     */
1047
    public function _addList($p_list, &$p_result_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, &$p_params)
1048
    {
1049
        $v_result = 1;
0 ignored issues
show
Unused Code introduced by
$v_result is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1050
1051
        // ----- Add the files
1052
        $v_header_list = array();
1053
        if (($v_result = $this->_addFileList($p_list, $v_header_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, $p_params)) != 1) {
1054
            return $v_result;
1055
        }
1056
1057
        // ----- Store the offset of the central dir
1058
        $v_offset = @ftell($this->_zip_fd);
1059
1060
        // ----- Create the Central Dir files header
1061
        for ($i = 0, $iMax = count($v_header_list); $i < $iMax; ++$i) {
1062
            // ----- Create the file header
1063
            if ($v_header_list[$i]['status'] === 'ok') {
1064
                if (($v_result = $this->_writeCentralFileHeader($v_header_list[$i])) != 1) {
1065
                    return $v_result;
1066
                }
1067
                ++$v_count;
0 ignored issues
show
Bug introduced by
The variable $v_count does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1068
            }
1069
1070
            // ----- Transform the header to a 'usable' info
1071
            $this->_convertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);
1072
        }
1073
1074
        // ----- Zip file comment
1075
        $v_comment = '';
1076
1077
        // ----- Calculate the size of the central header
1078
        $v_size = @ftell($this->_zip_fd) - $v_offset;
1079
1080
        // ----- Create the central dir footer
1081
        if (($v_result = $this->_writeCentralHeader($v_count, $v_size, $v_offset, $v_comment)) != 1) {
1082
            // ----- Reset the file list
1083
            unset($v_header_list);
1084
1085
            // ----- Return
1086
            return $v_result;
1087
        }
1088
1089
        // ----- Return
1090
        return $v_result;
1091
    }
1092
    // ---------------------------------------------------------------------------
1093
1094
    // ---------------------------------------------------------------------------
1095
    // Function : _addFileList()
1096
    // Description :
1097
    //   $p_add_dir and $p_remove_dir will give the ability to memorize a path which is
1098
    //   different from the real path of the file. This is usefull if you want to
1099
    //   run the lib in any directory, and memorize relative path from an other directory.
1100
    // Parameters :
1101
    //   $p_list : An array containing the file or directory names to add in the tar
1102
    //   $p_result_list : list of added files with their properties (specially the status field)
1103
    //   $p_add_dir : Path to add in the filename path archived
1104
    //   $p_remove_dir : Path to remove in the filename path archived
1105
    // Return Values :
1106
    // ---------------------------------------------------------------------------
1107
    /**
1108
     * Archive_Zip::_addFileList()
1109
     *
1110
     * { Description }
1111
     * @param $p_list
1112
     * @param $p_result_list
1113
     * @param $p_add_dir
1114
     * @param $p_remove_dir
1115
     * @param $p_remove_all_dir
1116
     * @param $p_params
1117
     * @return int
1118
     */
1119
    public function _addFileList($p_list, &$p_result_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, &$p_params)
1120
    {
1121
        $v_result = 1;
1122
        $v_header = array();
1123
1124
        // ----- Recuperate the current number of elt in list
1125
        $v_nb = count($p_result_list);
1126
1127
        // ----- Loop on the files
1128
        for ($j = 0; ($j < count($p_list)) && ($v_result == 1); ++$j) {
1129
            // ----- Recuperate the filename
1130
            $p_filename = $this->_tool_TranslateWinPath($p_list[$j], false);
1131
1132
            // ----- Skip empty file names
1133
            if ($p_filename == '') {
1134
                continue;
1135
            }
1136
1137
            // ----- Check the filename
1138
            if (!file_exists($p_filename)) {
1139
                $this->_errorLog(ARCHIVE_ZIP_ERR_MISSING_FILE, "File '$p_filename' does not exists");
1140
1141
                return Archive_Zip::errorCode();
1142
            }
1143
1144
            // ----- Look if it is a file or a dir with no all pathnre move
1145
            if (is_file($p_filename) || (is_dir($p_filename) && !$p_remove_all_dir)) {
1146
                // ----- Add the file
1147
                if (($v_result = $this->_addFile($p_filename, $v_header, $p_add_dir, $p_remove_dir, $p_remove_all_dir, $p_params)) != 1) {
1148
                    // ----- Return status
1149
                    return $v_result;
1150
                }
1151
1152
                // ----- Store the file infos
1153
                $p_result_list[$v_nb++] = $v_header;
1154
            }
1155
1156
            // ----- Look for directory
1157
            if (is_dir($p_filename)) {
1158
1159
                // ----- Look for path
1160
                $v_path = '';
1161
                if ($p_filename !== '.') {
1162
                    $v_path = $p_filename . '/';
1163
                }
1164
1165
                // ----- Read the directory for files and sub-directories
1166
                $p_hdir  = opendir($p_filename);
1167
                $p_hitem = readdir($p_hdir); // '.' directory
0 ignored issues
show
Unused Code introduced by
$p_hitem is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1168
                $p_hitem = readdir($p_hdir); // '..' directory
0 ignored issues
show
Unused Code introduced by
$p_hitem is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1169
                while ($p_hitem = readdir($p_hdir)) {
1170
1171
                    // ----- Look for a file
1172
                    if (is_file($v_path . $p_hitem)) {
1173
1174
                        // ----- Add the file
1175
                        if (($v_result = $this->_addFile($v_path . $p_hitem, $v_header, $p_add_dir, $p_remove_dir, $p_remove_all_dir, $p_params)) != 1) {
1176
                            // ----- Return status
1177
                            return $v_result;
1178
                        }
1179
1180
                        // ----- Store the file infos
1181
                        $p_result_list[$v_nb++] = $v_header;
1182
                    } // ----- Recursive call to _addFileList()
1183
                    else {
1184
1185
                        // ----- Need an array as parameter
1186
                        $p_temp_list[0] = $v_path . $p_hitem;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$p_temp_list was never initialized. Although not strictly required by PHP, it is generally a good practice to add $p_temp_list = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
1187
                        $v_result       = $this->_addFileList($p_temp_list, $p_result_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, $p_params);
0 ignored issues
show
Bug introduced by
The variable $p_temp_list does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1188
1189
                        // ----- Update the number of elements of the list
1190
                        $v_nb = count($p_result_list);
1191
                    }
1192
                }
1193
1194
                // ----- Free memory for the recursive loop
1195
                unset($p_temp_list, $p_hdir, $p_hitem);
1196
            }
1197
        }
1198
1199
        return $v_result;
1200
    }
1201
    // ---------------------------------------------------------------------------
1202
1203
    // ---------------------------------------------------------------------------
1204
    // Function : _addFile()
1205
    // Description :
1206
    // Parameters :
1207
    // Return Values :
1208
    // ---------------------------------------------------------------------------
1209
    /**
1210
     * Archive_Zip::_addFile()
1211
     *
1212
     * { Description }
1213
     * @param $p_filename
1214
     * @param $p_header
1215
     * @param $p_add_dir
1216
     * @param $p_remove_dir
1217
     * @param $p_remove_all_dir
1218
     * @param $p_params
1219
     * @return int
1220
     */
1221
    public function _addFile($p_filename, &$p_header, $p_add_dir, $p_remove_dir, $p_remove_all_dir, &$p_params)
1222
    {
1223
        $v_result = 1;
1224
1225
        if ($p_filename == '') {
1226
            // ----- Error log
1227
            $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER, 'Invalid file list parameter (invalid or empty list)');
1228
1229
            // ----- Return
1230
            return Archive_Zip::errorCode();
1231
        }
1232
1233
        // ----- Calculate the stored filename
1234
        $v_stored_filename = $p_filename;
1235
1236
        // ----- Look for all path to remove
1237
        if ($p_remove_all_dir) {
1238
            $v_stored_filename = basename($p_filename);
1239
        } // ----- Look for partial path remove
1240
        elseif ($p_remove_dir != '') {
1241
            if (substr($p_remove_dir, -1) !== '/') {
1242
                $p_remove_dir .= '/';
1243
            }
1244
1245
            if ((substr($p_filename, 0, 2) === './') || (substr($p_remove_dir, 0, 2) === './')) {
1246 View Code Duplication
                if ((substr($p_filename, 0, 2) === './') && (substr($p_remove_dir, 0, 2) !== './')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1247
                    $p_remove_dir = './' . $p_remove_dir;
1248
                }
1249 View Code Duplication
                if ((substr($p_filename, 0, 2) !== './') && (substr($p_remove_dir, 0, 2) === './')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1250
                    $p_remove_dir = substr($p_remove_dir, 2);
1251
                }
1252
            }
1253
1254
            $v_compare = $this->_tool_PathInclusion($p_remove_dir, $p_filename);
1255
            if ($v_compare > 0) {
1256
                //      if (substr($p_filename, 0, strlen($p_remove_dir)) == $p_remove_dir) {
1257
1258
                if ($v_compare == 2) {
1259
                    $v_stored_filename = '';
1260
                } else {
1261
                    $v_stored_filename = substr($p_filename, strlen($p_remove_dir));
1262
                }
1263
            }
1264
        }
1265
1266
        // ----- Look for path to add
1267
        if ($p_add_dir != '') {
1268
            if (substr($p_add_dir, -1) === '/') {
1269
                $v_stored_filename = $p_add_dir . $v_stored_filename;
1270
            } else {
1271
                $v_stored_filename = $p_add_dir . '/' . $v_stored_filename;
1272
            }
1273
        }
1274
1275
        // ----- Filename (reduce the path of stored name)
1276
        $v_stored_filename = $this->_tool_PathReduction($v_stored_filename);
1277
1278
        /* filename length moved after call-back in release 1.3
1279
        // ----- Check the path length
1280
        if (strlen($v_stored_filename) > 0xFF) {
1281
          // ----- Error log
1282
          $this->_errorLog(-5, "Stored file name is too long (max. 255) : '$v_stored_filename'");
1283
1284
          // ----- Return
1285
          return Archive_Zip::errorCode();
1286
        }
1287
        */
1288
1289
        // ----- Set the file properties
1290
        clearstatcache();
1291
        $p_header['version']           = 20;
1292
        $p_header['version_extracted'] = 10;
1293
        $p_header['flag']              = 0;
1294
        $p_header['compression']       = 0;
1295
        $p_header['mtime']             = filemtime($p_filename);
1296
        $p_header['crc']               = 0;
1297
        $p_header['compressed_size']   = 0;
1298
        $p_header['size']              = filesize($p_filename);
1299
        $p_header['filename_len']      = strlen($p_filename);
1300
        $p_header['extra_len']         = 0;
1301
        $p_header['comment_len']       = 0;
1302
        $p_header['disk']              = 0;
1303
        $p_header['internal']          = 0;
1304
        $p_header['external']          = (is_file($p_filename) ? 0xFE49FFE0 : 0x41FF0010);
1305
        $p_header['offset']            = 0;
1306
        $p_header['filename']          = $p_filename;
1307
        $p_header['stored_filename']   = $v_stored_filename;
1308
        $p_header['extra']             = '';
1309
        $p_header['comment']           = '';
1310
        $p_header['status']            = 'ok';
1311
        $p_header['index']             = -1;
1312
1313
        // ----- Look for pre-add callback
1314
        if (isset($p_params[ARCHIVE_ZIP_PARAM_PRE_ADD]) && ($p_params[ARCHIVE_ZIP_PARAM_PRE_ADD] != '')) {
1315
1316
            // ----- Generate a local information
1317
            $v_local_header = array();
1318
            $this->_convertHeader2FileInfo($p_header, $v_local_header);
1319
1320
            // ----- Call the callback
1321
            // Here I do not use call_user_func() because I need to send a reference to the
1322
            // header.
1323
            eval('$v_result = ' . $p_params[ARCHIVE_ZIP_PARAM_PRE_ADD] . '(ARCHIVE_ZIP_PARAM_PRE_ADD, $v_local_header);');
1324
            if ($v_result == 0) {
1325
                // ----- Change the file status
1326
                $p_header['status'] = 'skipped';
1327
                $v_result           = 1;
1328
            }
1329
1330
            // ----- Update the informations
1331
            // Only some fields can be modified
1332
            if ($p_header['stored_filename'] != $v_local_header['stored_filename']) {
1333
                $p_header['stored_filename'] = $this->_tool_PathReduction($v_local_header['stored_filename']);
1334
            }
1335
        }
1336
1337
        // ----- Look for empty stored filename
1338
        if ($p_header['stored_filename'] == '') {
1339
            $p_header['status'] = 'filtered';
1340
        }
1341
1342
        // ----- Check the path length
1343
        if (strlen($p_header['stored_filename']) > 0xFF) {
1344
            $p_header['status'] = 'filename_too_long';
1345
        }
1346
1347
        // ----- Look if no error, or file not skipped
1348
        if ($p_header['status'] === 'ok') {
1349
1350
            // ----- Look for a file
1351
            if (is_file($p_filename)) {
1352
                // ----- Open the source file
1353 View Code Duplication
                if (($v_file = @fopen($p_filename, 'rb')) == 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1354
                    $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode");
1355
1356
                    return Archive_Zip::errorCode();
1357
                }
1358
1359
                if ($p_params['no_compression']) {
1360
                    // ----- Read the file content
1361
                    $v_content_compressed = @fread($v_file, $p_header['size']);
1362
1363
                    // ----- Calculate the CRC
1364
                    $p_header['crc'] = crc32($v_content_compressed);
1365
                } else {
1366
                    // ----- Read the file content
1367
                    $v_content = @fread($v_file, $p_header['size']);
1368
1369
                    // ----- Calculate the CRC
1370
                    $p_header['crc'] = crc32($v_content);
1371
1372
                    // ----- Compress the file
1373
                    $v_content_compressed = gzdeflate($v_content);
1374
                }
1375
1376
                // ----- Set header parameters
1377
                $p_header['compressed_size'] = strlen($v_content_compressed);
1378
                $p_header['compression']     = 8;
1379
1380
                // ----- Call the header generation
1381
                if (($v_result = $this->_writeFileHeader($p_header)) != 1) {
1382
                    @fclose($v_file);
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...
1383
1384
                    return $v_result;
1385
                }
1386
1387
                // ----- Write the compressed content
1388
                $v_binary_data = pack('a' . $p_header['compressed_size'], $v_content_compressed);
1389
                @fwrite($this->_zip_fd, $v_binary_data, $p_header['compressed_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...
1390
1391
                // ----- Close the file
1392
                @fclose($v_file);
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...
1393
            } // ----- Look for a directory
1394
            else {
1395
                // ----- Set the file properties
1396
                $p_header['filename'] .= '/';
1397
                $p_header['filename_len']++;
1398
                $p_header['size']     = 0;
1399
                $p_header['external'] = 0x41FF0010;   // Value for a folder : to be checked
1400
1401
                // ----- Call the header generation
1402
                if (($v_result = $this->_writeFileHeader($p_header)) != 1) {
1403
                    return $v_result;
1404
                }
1405
            }
1406
        }
1407
1408
        // ----- Look for pre-add callback
1409
        if (isset($p_params[ARCHIVE_ZIP_PARAM_POST_ADD]) && ($p_params[ARCHIVE_ZIP_PARAM_POST_ADD] != '')) {
1410
1411
            // ----- Generate a local information
1412
            $v_local_header = array();
1413
            $this->_convertHeader2FileInfo($p_header, $v_local_header);
1414
1415
            // ----- Call the callback
1416
            // Here I do not use call_user_func() because I need to send a reference to the
1417
            // header.
1418
            eval('$v_result = ' . $p_params[ARCHIVE_ZIP_PARAM_POST_ADD] . '(ARCHIVE_ZIP_PARAM_POST_ADD, $v_local_header);');
1419
            if ($v_result == 0) {
1420
                // ----- Ignored
1421
                $v_result = 1;
1422
            }
1423
1424
            // ----- Update the informations
1425
            // Nothing can be modified
1426
        }
1427
1428
        // ----- Return
1429
        return $v_result;
1430
    }
1431
    // ---------------------------------------------------------------------------
1432
1433
    // ---------------------------------------------------------------------------
1434
    // Function : _writeFileHeader()
1435
    // Description :
1436
    // Parameters :
1437
    // Return Values :
1438
    // ---------------------------------------------------------------------------
1439
    /**
1440
     * Archive_Zip::_writeFileHeader()
1441
     *
1442
     * { Description }
1443
     * @param $p_header
1444
     * @return int
1445
     */
1446
    public function _writeFileHeader(&$p_header)
1447
    {
1448
        $v_result = 1;
1449
1450
        // TBC
1451
        //for (reset($p_header); $key = key($p_header); next($p_header)) {
1452
        //}
1453
1454
        // ----- Store the offset position of the file
1455
        $p_header['offset'] = ftell($this->_zip_fd);
1456
1457
        // ----- Transform UNIX mtime to DOS format mdate/mtime
1458
        $v_date  = getdate($p_header['mtime']);
1459
        $v_mtime = ($v_date['hours'] << 11) + ($v_date['minutes'] << 5) + $v_date['seconds'] / 2;
1460
        $v_mdate = (($v_date['year'] - 1980) << 9) + ($v_date['mon'] << 5) + $v_date['mday'];
1461
1462
        // ----- Packed data
1463
        $v_binary_data = pack('VvvvvvVVVvv', 0x04034b50, $p_header['version'], $p_header['flag'], $p_header['compression'], $v_mtime, $v_mdate, $p_header['crc'], $p_header['compressed_size'], $p_header['size'], strlen($p_header['stored_filename']), $p_header['extra_len']);
1464
1465
        // ----- Write the first 148 bytes of the header in the archive
1466
        fwrite($this->_zip_fd, $v_binary_data, 30);
1467
1468
        // ----- Write the variable fields
1469 View Code Duplication
        if ($p_header['stored_filename'] != 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1470
            fwrite($this->_zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename']));
1471
        }
1472 View Code Duplication
        if ($p_header['extra_len'] != 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1473
            fwrite($this->_zip_fd, $p_header['extra'], $p_header['extra_len']);
1474
        }
1475
1476
        // ----- Return
1477
        return $v_result;
1478
    }
1479
1480
    // ---------------------------------------------------------------------------
1481
1482
    // ---------------------------------------------------------------------------
1483
    // Function : _writeCentralFileHeader()
1484
    // Description :
1485
    // Parameters :
1486
    // Return Values :
1487
    // ---------------------------------------------------------------------------
1488
    /**
1489
     * Archive_Zip::_writeCentralFileHeader()
1490
     *
1491
     * { Description }
1492
     * @param $p_header
1493
     * @return int
1494
     */
1495
    public function _writeCentralFileHeader(&$p_header)
1496
    {
1497
        $v_result = 1;
1498
1499
        // TBC
1500
        //for (reset($p_header); $key = key($p_header); next($p_header)) {
1501
        //}
1502
1503
        // ----- Transform UNIX mtime to DOS format mdate/mtime
1504
        $v_date  = getdate($p_header['mtime']);
1505
        $v_mtime = ($v_date['hours'] << 11) + ($v_date['minutes'] << 5) + $v_date['seconds'] / 2;
1506
        $v_mdate = (($v_date['year'] - 1980) << 9) + ($v_date['mon'] << 5) + $v_date['mday'];
1507
1508
        // ----- Packed data
1509
        $v_binary_data =
1510
            pack('VvvvvvvVVVvvvvvVV', 0x02014b50, $p_header['version'], $p_header['version_extracted'], $p_header['flag'], $p_header['compression'], $v_mtime, $v_mdate, $p_header['crc'], $p_header['compressed_size'], $p_header['size'], strlen($p_header['stored_filename']), $p_header['extra_len'],
1511
                 $p_header['comment_len'], $p_header['disk'], $p_header['internal'], $p_header['external'], $p_header['offset']);
1512
1513
        // ----- Write the 42 bytes of the header in the zip file
1514
        fwrite($this->_zip_fd, $v_binary_data, 46);
1515
1516
        // ----- Write the variable fields
1517 View Code Duplication
        if ('' !== $p_header['stored_filename']) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1518
            fwrite($this->_zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename']));
1519
        }
1520 View Code Duplication
        if ($p_header['extra_len'] != 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1521
            fwrite($this->_zip_fd, $p_header['extra'], $p_header['extra_len']);
1522
        }
1523
        if ($p_header['comment_len'] != 0) {
1524
            fwrite($this->_zip_fd, $p_header['comment'], $p_header['comment_len']);
1525
        }
1526
1527
        // ----- Return
1528
        return $v_result;
1529
    }
1530
1531
    // ---------------------------------------------------------------------------
1532
1533
    // ---------------------------------------------------------------------------
1534
    // Function : _writeCentralHeader()
1535
    // Description :
1536
    // Parameters :
1537
    // Return Values :
1538
    // ---------------------------------------------------------------------------
1539
    /**
1540
     * Archive_Zip::_writeCentralHeader()
1541
     *
1542
     * { Description }
1543
     * @param $p_nb_entries
1544
     * @param $p_size
1545
     * @param $p_offset
1546
     * @param $p_comment
1547
     * @return int
1548
     */
1549
    public function _writeCentralHeader($p_nb_entries, $p_size, $p_offset, $p_comment)
1550
    {
1551
        $v_result = 1;
1552
1553
        // ----- Packed data
1554
        $v_binary_data = pack('VvvvvVVv', 0x06054b50, 0, 0, $p_nb_entries, $p_nb_entries, $p_size, $p_offset, strlen($p_comment));
1555
1556
        // ----- Write the 22 bytes of the header in the zip file
1557
        fwrite($this->_zip_fd, $v_binary_data, 22);
1558
1559
        // ----- Write the variable fields
1560
        if ('' !== $p_comment) {
1561
            fwrite($this->_zip_fd, $p_comment, strlen($p_comment));
1562
        }
1563
1564
        // ----- Return
1565
        return $v_result;
1566
    }
1567
1568
    // ---------------------------------------------------------------------------
1569
1570
    // ---------------------------------------------------------------------------
1571
    // Function : _list()
1572
    // Description :
1573
    // Parameters :
1574
    // Return Values :
1575
    // ---------------------------------------------------------------------------
1576
    /**
1577
     * Archive_Zip::_list()
1578
     *
1579
     * { Description }
1580
     * @param $p_list
1581
     * @return int
1582
     */
1583
    public function _list(&$p_list)
1584
    {
1585
        $v_result = 1;
0 ignored issues
show
Unused Code introduced by
$v_result is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1586
1587
        // ----- Open the zip file
1588 View Code Duplication
        if (($this->_zip_fd = @fopen($this->_zipname, 'rb')) == 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1589
            // ----- Error log
1590
            $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \'' . $this->_zipname . '\' in binary read mode');
1591
1592
            // ----- Return
1593
            return Archive_Zip::errorCode();
1594
        }
1595
1596
        // ----- Read the central directory informations
1597
        $v_central_dir = array();
1598
        if (($v_result = $this->_readEndCentralDir($v_central_dir)) != 1) {
1599
            return $v_result;
1600
        }
1601
1602
        // ----- Go to beginning of Central Dir
1603
        @rewind($this->_zip_fd);
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...
1604 View Code Duplication
        if (@fseek($this->_zip_fd, $v_central_dir['offset'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1605
            // ----- Error log
1606
            $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
1607
1608
            // ----- Return
1609
            return Archive_Zip::errorCode();
1610
        }
1611
1612
        // ----- Read each entry
1613
        for ($i = 0; $i < $v_central_dir['entries']; ++$i) {
1614
            // ----- Read the file header
1615
            if (($v_result = $this->_readCentralFileHeader($v_header)) != 1) {
1616
                return $v_result;
1617
            }
1618
            $v_header['index'] = $i;
1619
1620
            // ----- Get the only interesting attributes
1621
            $this->_convertHeader2FileInfo($v_header, $p_list[$i]);
1622
            unset($v_header);
1623
        }
1624
1625
        // ----- Close the zip file
1626
        $this->_closeFd();
1627
1628
        // ----- Return
1629
        return $v_result;
1630
    }
1631
1632
    // ---------------------------------------------------------------------------
1633
1634
    // ---------------------------------------------------------------------------
1635
    // Function : _convertHeader2FileInfo()
1636
    // Description :
1637
    //   This function takes the file informations from the central directory
1638
    //   entries and extract the interesting parameters that will be given back.
1639
    //   The resulting file infos are set in the array $p_info
1640
    //     $p_info['filename'] : Filename with full path. Given by user (add),
1641
    //                           extracted in the filesystem (extract).
1642
    //     $p_info['stored_filename'] : Stored filename in the archive.
1643
    //     $p_info['size'] = Size of the file.
1644
    //     $p_info['compressed_size'] = Compressed size of the file.
1645
    //     $p_info['mtime'] = Last modification date of the file.
1646
    //     $p_info['comment'] = Comment associated with the file.
1647
    //     $p_info['folder'] = true/false : indicates if the entry is a folder or not.
1648
    //     $p_info['status'] = status of the action on the file.
1649
    // Parameters :
1650
    // Return Values :
1651
    // ---------------------------------------------------------------------------
1652
    /**
1653
     * Archive_Zip::_convertHeader2FileInfo()
1654
     *
1655
     * { Description }
1656
     * @param $p_header
1657
     * @param $p_info
1658
     * @return int
1659
     */
1660
    public function _convertHeader2FileInfo($p_header, &$p_info)
1661
    {
1662
        $v_result = 1;
1663
1664
        // ----- Get the interesting attributes
1665
        $p_info['filename']        = $p_header['filename'];
1666
        $p_info['stored_filename'] = $p_header['stored_filename'];
1667
        $p_info['size']            = $p_header['size'];
1668
        $p_info['compressed_size'] = $p_header['compressed_size'];
1669
        $p_info['mtime']           = $p_header['mtime'];
1670
        $p_info['comment']         = $p_header['comment'];
1671
        $p_info['folder']          = (($p_header['external'] & 0x00000010) == 0x00000010);
1672
        $p_info['index']           = $p_header['index'];
1673
        $p_info['status']          = $p_header['status'];
1674
1675
        // ----- Return
1676
        return $v_result;
1677
    }
1678
1679
    // ---------------------------------------------------------------------------
1680
1681
    // ---------------------------------------------------------------------------
1682
    // Function : _extractByRule()
1683
    // Description :
1684
    //   Extract a file or directory depending of rules (by index, by name, ...)
1685
    // Parameters :
1686
    //   $p_file_list : An array where will be placed the properties of each
1687
    //                  extracted file
1688
    //   $p_path : Path to add while writing the extracted files
1689
    //   $p_remove_path : Path to remove (from the file memorized path) while writing the
1690
    //                    extracted files. If the path does not match the file path,
1691
    //                    the file is extracted with its memorized path.
1692
    //                    $p_remove_path does not apply to 'list' mode.
1693
    //                    $p_path and $p_remove_path are commulative.
1694
    // Return Values :
1695
    //   1 on success,0 or less on error (see error code list)
1696
    // ---------------------------------------------------------------------------
1697
    /**
1698
     * Archive_Zip::_extractByRule()
1699
     *
1700
     * { Description }
1701
     * @param $p_file_list
1702
     * @param $p_params
1703
     * @return int
1704
     */
1705
    public function _extractByRule(&$p_file_list, &$p_params)
1706
    {
1707
        $v_result = 1;
0 ignored issues
show
Unused Code introduced by
$v_result is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1708
1709
        $p_path            = $p_params['add_path'];
1710
        $p_remove_path     = $p_params['remove_path'];
1711
        $p_remove_all_path = $p_params['remove_all_path'];
1712
1713
        // ----- Check the path
1714
        if (($p_path == '') || ((substr($p_path, 0, 1) !== '/') && (substr($p_path, 0, 3) !== '../') && (substr($p_path, 1, 2) !== ':/'))) {
1715
            $p_path = './' . $p_path;
1716
        }
1717
1718
        // ----- Reduce the path last (and duplicated) '/'
1719
        if (($p_path !== './') && ($p_path !== '/')) {
1720
            // ----- Look for the path end '/'
1721
            while (substr($p_path, -1) === '/') {
1722
                $p_path = substr($p_path, 0, -1);
1723
            }
1724
        }
1725
1726
        // ----- Look for path to remove format (should end by /)
1727
        if (($p_remove_path != '') && (substr($p_remove_path, -1) !== '/')) {
1728
            $p_remove_path .= '/';
1729
        }
1730
        $p_remove_path_size = strlen($p_remove_path);
0 ignored issues
show
Unused Code introduced by
$p_remove_path_size is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1731
1732
        // ----- Open the zip file
1733
        if (($v_result = $this->_openFd('rb')) != 1) {
1734
            return $v_result;
1735
        }
1736
1737
        // ----- Read the central directory informations
1738
        $v_central_dir = array();
1739
        if (($v_result = $this->_readEndCentralDir($v_central_dir)) != 1) {
1740
            // ----- Close the zip file
1741
            $this->_closeFd();
1742
1743
            return $v_result;
1744
        }
1745
1746
        // ----- Start at beginning of Central Dir
1747
        $v_pos_entry = $v_central_dir['offset'];
1748
1749
        // ----- Read each entry
1750
        $j_start = 0;
1751
        for ($i = 0, $v_nb_extracted = 0; $i < $v_central_dir['entries']; ++$i) {
1752
            // ----- Read next Central dir entry
1753
            @rewind($this->_zip_fd);
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...
1754 View Code Duplication
            if (@fseek($this->_zip_fd, $v_pos_entry)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1755
                $this->_closeFd();
1756
1757
                $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
1758
1759
                return Archive_Zip::errorCode();
1760
            }
1761
1762
            // ----- Read the file header
1763
            $v_header = array();
1764
            if (($v_result = $this->_readCentralFileHeader($v_header)) != 1) {
1765
                $this->_closeFd();
1766
1767
                return $v_result;
1768
            }
1769
1770
            // ----- Store the index
1771
            $v_header['index'] = $i;
1772
1773
            // ----- Store the file position
1774
            $v_pos_entry = ftell($this->_zip_fd);
1775
1776
            // ----- Look for the specific extract rules
1777
            $v_extract = false;
1778
1779
            // ----- Look for extract by name rule
1780
            if (isset($p_params[ARCHIVE_ZIP_PARAM_BY_NAME]) && ($p_params[ARCHIVE_ZIP_PARAM_BY_NAME] != 0)) {
1781
1782
                // ----- Look if the filename is in the list
1783
                for ($j = 0; ($j < count($p_params[ARCHIVE_ZIP_PARAM_BY_NAME])) && (!$v_extract); ++$j) {
1784
1785
                    // ----- Look for a directory
1786
                    if (substr($p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j], -1) === '/') {
1787
1788
                        // ----- Look if the directory is in the filename path
1789
                        if ((strlen($v_header['stored_filename']) > strlen($p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j]))
1790
                            && (substr($v_header['stored_filename'], 0, strlen($p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j])) == $p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j])
1791
                        ) {
1792
                            $v_extract = true;
1793
                        }
1794
                    } // ----- Look for a filename
1795
                    elseif ($v_header['stored_filename'] == $p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j]) {
1796
                        $v_extract = true;
1797
                    }
1798
                }
1799
            } // ----- Look for extract by ereg rule
1800 View Code Duplication
            elseif (isset($p_params[ARCHIVE_ZIP_PARAM_BY_EREG]) && ($p_params[ARCHIVE_ZIP_PARAM_BY_EREG] != '')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1801
                if (preg_match('/' . $p_params[ARCHIVE_ZIP_PARAM_BY_EREG] . '/', $v_header['stored_filename'])) {
1802
                    $v_extract = true;
1803
                }
1804
            } // ----- Look for extract by preg rule
1805
            elseif (isset($p_params[ARCHIVE_ZIP_PARAM_BY_PREG]) && ($p_params[ARCHIVE_ZIP_PARAM_BY_PREG] != '')) {
1806
                if (preg_match($p_params[ARCHIVE_ZIP_PARAM_BY_PREG], $v_header['stored_filename'])) {
1807
                    $v_extract = true;
1808
                }
1809
            } // ----- Look for extract by index rule
1810 View Code Duplication
            elseif (isset($p_params[ARCHIVE_ZIP_PARAM_BY_INDEX]) && ($p_params[ARCHIVE_ZIP_PARAM_BY_INDEX] != 0)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1811
1812
                // ----- Look if the index is in the list
1813
                for ($j = $j_start; ($j < count($p_params[ARCHIVE_ZIP_PARAM_BY_INDEX])) && (!$v_extract); ++$j) {
1814
                    if (($i >= $p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['start']) && ($i <= $p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['end'])) {
1815
                        $v_extract = true;
1816
                    }
1817
                    if ($i >= $p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['end']) {
1818
                        $j_start = $j + 1;
1819
                    }
1820
1821
                    if ($p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['start'] > $i) {
1822
                        break;
1823
                    }
1824
                }
1825
            } // ----- Look for no rule, which means extract all the archive
1826
            else {
1827
                $v_extract = true;
1828
            }
1829
1830
            // ----- Look for real extraction
1831
            if ($v_extract) {
1832
1833
                // ----- Go to the file position
1834
                @rewind($this->_zip_fd);
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...
1835 View Code Duplication
                if (@fseek($this->_zip_fd, $v_header['offset'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1836
                    // ----- Close the zip file
1837
                    $this->_closeFd();
1838
1839
                    // ----- Error log
1840
                    $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
1841
1842
                    // ----- Return
1843
                    return Archive_Zip::errorCode();
1844
                }
1845
1846
                // ----- Look for extraction as string
1847
                if ($p_params[ARCHIVE_ZIP_PARAM_EXTRACT_AS_STRING]) {
1848
1849
                    // ----- Extracting the file
1850
                    if (($v_result = $this->_extractFileAsString($v_header, $v_string)) != 1) {
1851
                        // ----- Close the zip file
1852
                        $this->_closeFd();
1853
1854
                        return $v_result;
1855
                    }
1856
1857
                    // ----- Get the only interesting attributes
1858
                    if (($v_result = $this->_convertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted])) != 1) {
1859
                        // ----- Close the zip file
1860
                        $this->_closeFd();
1861
1862
                        return $v_result;
1863
                    }
1864
1865
                    // ----- Set the file content
1866
                    $p_file_list[$v_nb_extracted]['content'] = $v_string;
1867
1868
                    // ----- Next extracted file
1869
                    ++$v_nb_extracted;
1870
                } else {
1871
                    // ----- Extracting the file
1872
                    if (($v_result = $this->_extractFile($v_header, $p_path, $p_remove_path, $p_remove_all_path, $p_params)) != 1) {
1873
                        // ----- Close the zip file
1874
                        $this->_closeFd();
1875
1876
                        return $v_result;
1877
                    }
1878
1879
                    // ----- Get the only interesting attributes
1880
                    if (($v_result = $this->_convertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) {
1881
                        // ----- Close the zip file
1882
                        $this->_closeFd();
1883
1884
                        return $v_result;
1885
                    }
1886
                }
1887
            }
1888
        }
1889
1890
        // ----- Close the zip file
1891
        $this->_closeFd();
1892
1893
        // ----- Return
1894
        return $v_result;
1895
    }
1896
1897
    // ---------------------------------------------------------------------------
1898
1899
    // ---------------------------------------------------------------------------
1900
    // Function : _extractFile()
1901
    // Description :
1902
    // Parameters :
1903
    // Return Values :
1904
    // ---------------------------------------------------------------------------
1905
    /**
1906
     * Archive_Zip::_extractFile()
1907
     *
1908
     * { Description }
1909
     * @param $p_entry
1910
     * @param $p_path
1911
     * @param $p_remove_path
1912
     * @param $p_remove_all_path
1913
     * @param $p_params
1914
     * @return int
1915
     */
1916
    public function _extractFile(&$p_entry, $p_path, $p_remove_path, $p_remove_all_path, &$p_params)
1917
    {
1918
        $v_result = 1;
0 ignored issues
show
Unused Code introduced by
$v_result is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1919
1920
        // ----- Read the file header
1921
        if (($v_result = $this->_readFileHeader($v_header)) != 1) {
1922
            // ----- Return
1923
            return $v_result;
1924
        }
1925
1926
        // ----- Check that the file header is coherent with $p_entry info
1927
        // TBC
1928
1929
        // ----- Look for all path to remove
1930
        if ($p_remove_all_path == true) {
1931
            // ----- Get the basename of the path
1932
            $p_entry['filename'] = basename($p_entry['filename']);
1933
        } // ----- Look for path to remove
1934
        elseif ($p_remove_path != '') {
1935
            //if (strcmp($p_remove_path, $p_entry['filename'])==0)
1936
            if ($this->_tool_PathInclusion($p_remove_path, $p_entry['filename']) == 2) {
1937
1938
                // ----- Change the file status
1939
                $p_entry['status'] = 'filtered';
1940
1941
                // ----- Return
1942
                return $v_result;
1943
            }
1944
1945
            $p_remove_path_size = strlen($p_remove_path);
1946
            if (substr($p_entry['filename'], 0, $p_remove_path_size) == $p_remove_path) {
1947
1948
                // ----- Remove the path
1949
                $p_entry['filename'] = substr($p_entry['filename'], $p_remove_path_size);
1950
            }
1951
        }
1952
1953
        // ----- Add the path
1954
        if ($p_path != '') {
1955
            $p_entry['filename'] = $p_path . '/' . $p_entry['filename'];
1956
        }
1957
1958
        // ----- Look for pre-extract callback
1959
        if (isset($p_params[ARCHIVE_ZIP_PARAM_PRE_EXTRACT]) && ($p_params[ARCHIVE_ZIP_PARAM_PRE_EXTRACT] != '')) {
1960
1961
            // ----- Generate a local information
1962
            $v_local_header = array();
1963
            $this->_convertHeader2FileInfo($p_entry, $v_local_header);
1964
1965
            // ----- Call the callback
1966
            // Here I do not use call_user_func() because I need to send a reference to the
1967
            // header.
1968
            eval('$v_result = ' . $p_params[ARCHIVE_ZIP_PARAM_PRE_EXTRACT] . '(ARCHIVE_ZIP_PARAM_PRE_EXTRACT, $v_local_header);');
1969
            if ($v_result == 0) {
1970
                // ----- Change the file status
1971
                $p_entry['status'] = 'skipped';
1972
                $v_result          = 1;
1973
            }
1974
1975
            // ----- Update the informations
1976
            // Only some fields can be modified
1977
            $p_entry['filename'] = $v_local_header['filename'];
1978
        }
1979
1980
        // ----- Trace
1981
1982
        // ----- Look if extraction should be done
1983
        if ($p_entry['status'] === 'ok') {
1984
1985
            // ----- Look for specific actions while the file exist
1986
            if (file_exists($p_entry['filename'])) {
1987
1988
                // ----- Look if file is a directory
1989
                if (is_dir($p_entry['filename'])) {
1990
1991
                    // ----- Change the file status
1992
                    $p_entry['status'] = 'already_a_directory';
1993
1994
                    // ----- Return
1995
                    //return $v_result;
1996
                } // ----- Look if file is write protected
1997
                elseif (!is_writable($p_entry['filename'])) {
1998
1999
                    // ----- Change the file status
2000
                    $p_entry['status'] = 'write_protected';
2001
2002
                    // ----- Return
2003
                    //return $v_result;
2004
                } // ----- Look if the extracted file is older
2005
                elseif (filemtime($p_entry['filename']) > $p_entry['mtime']) {
2006
2007
                    // ----- Change the file status
2008
                    $p_entry['status'] = 'newer_exist';
2009
2010
                    // ----- Return
2011
                    //return $v_result;
2012
                }
2013
            } // ----- Check the directory availability and create it if necessary
2014
            else {
2015
                if ((($p_entry['external'] & 0x00000010) == 0x00000010) || (substr($p_entry['filename'], -1) === '/')) {
2016
                    $v_dir_to_check = $p_entry['filename'];
2017
                } elseif (false === strpos($p_entry['filename'], '/')) {
2018
                    $v_dir_to_check = '';
2019
                } else {
2020
                    $v_dir_to_check = dirname($p_entry['filename']);
2021
                }
2022
2023
                if (($v_result = $this->_dirCheck($v_dir_to_check, ($p_entry['external'] & 0x00000010) == 0x00000010)) != 1) {
2024
2025
                    // ----- Change the file status
2026
                    $p_entry['status'] = 'path_creation_fail';
2027
2028
                    // ----- Return
2029
                    //return $v_result;
2030
                    $v_result = 1;
2031
                }
2032
            }
2033
        }
2034
2035
        // ----- Look if extraction should be done
2036
        if ($p_entry['status'] === 'ok') {
2037
2038
            // ----- Do the extraction (if not a folder)
2039
            if (!(($p_entry['external'] & 0x00000010) == 0x00000010)) {
2040
2041
                // ----- Look for not compressed file
2042
                if ($p_entry['compressed_size'] == $p_entry['size']) {
2043
2044
                    // ----- Opening destination file
2045 View Code Duplication
                    if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2046
2047
                        // ----- Change the file status
2048
                        $p_entry['status'] = 'write_error';
2049
2050
                        // ----- Return
2051
                        return $v_result;
2052
                    }
2053
2054
                    // ----- Read the file by ARCHIVE_ZIP_READ_BLOCK_SIZE octets blocks
2055
                    $v_size = $p_entry['compressed_size'];
2056
                    while ($v_size != 0) {
2057
                        $v_read_size   = ($v_size < ARCHIVE_ZIP_READ_BLOCK_SIZE ? $v_size : ARCHIVE_ZIP_READ_BLOCK_SIZE);
2058
                        $v_buffer      = fread($this->_zip_fd, $v_read_size);
2059
                        $v_binary_data = pack('a' . $v_read_size, $v_buffer);
2060
                        @fwrite($v_dest_file, $v_binary_data, $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...
2061
                        $v_size -= $v_read_size;
2062
                    }
2063
2064
                    // ----- Closing the destination file
2065
                    fclose($v_dest_file);
2066
2067
                    // ----- Change the file mtime
2068
                    touch($p_entry['filename'], $p_entry['mtime']);
2069
                } else {
2070
                    // ----- Trace
2071
2072
                    // ----- Opening destination file
2073 View Code Duplication
                    if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2074
2075
                        // ----- Change the file status
2076
                        $p_entry['status'] = 'write_error';
2077
2078
                        return $v_result;
2079
                    }
2080
2081
                    // ----- Read the compressed file in a buffer (one shot)
2082
                    $v_buffer = @fread($this->_zip_fd, $p_entry['compressed_size']);
2083
2084
                    // ----- Decompress the file
2085
                    $v_file_content = gzinflate($v_buffer);
2086
                    unset($v_buffer);
2087
2088
                    // ----- Write the uncompressed data
2089
                    @fwrite($v_dest_file, $v_file_content, $p_entry['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...
2090
                    unset($v_file_content);
2091
2092
                    // ----- Closing the destination file
2093
                    @fclose($v_dest_file);
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...
2094
2095
                    // ----- Change the file mtime
2096
                    touch($p_entry['filename'], $p_entry['mtime']);
2097
                }
2098
2099
                // ----- Look for chmod option
2100
                if (isset($p_params[ARCHIVE_ZIP_PARAM_SET_CHMOD]) && ($p_params[ARCHIVE_ZIP_PARAM_SET_CHMOD] != 0)) {
2101
2102
                    // ----- Change the mode of the file
2103
                    chmod($p_entry['filename'], $p_params[ARCHIVE_ZIP_PARAM_SET_CHMOD]);
2104
                }
2105
            }
2106
        }
2107
2108
        // ----- Look for post-extract callback
2109
        if (isset($p_params[ARCHIVE_ZIP_PARAM_POST_EXTRACT]) && ($p_params[ARCHIVE_ZIP_PARAM_POST_EXTRACT] != '')) {
2110
2111
            // ----- Generate a local information
2112
            $v_local_header = array();
2113
            $this->_convertHeader2FileInfo($p_entry, $v_local_header);
2114
2115
            // ----- Call the callback
2116
            // Here I do not use call_user_func() because I need to send a reference to the
2117
            // header.
2118
            eval('$v_result = ' . $p_params[ARCHIVE_ZIP_PARAM_POST_EXTRACT] . '(ARCHIVE_ZIP_PARAM_POST_EXTRACT, $v_local_header);');
2119
        }
2120
2121
        // ----- Return
2122
        return $v_result;
2123
    }
2124
2125
    // ---------------------------------------------------------------------------
2126
2127
    // ---------------------------------------------------------------------------
2128
    // Function : _extractFileAsString()
2129
    // Description :
2130
    // Parameters :
2131
    // Return Values :
2132
    // ---------------------------------------------------------------------------
2133
    /**
2134
     * Archive_Zip::_extractFileAsString()
2135
     *
2136
     * { Description }
2137
     * @param $p_entry
2138
     * @param $p_string
2139
     * @return int
2140
     */
2141
    public function _extractFileAsString(&$p_entry, &$p_string)
2142
    {
2143
        $v_result = 1;
0 ignored issues
show
Unused Code introduced by
$v_result is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2144
2145
        // ----- Read the file header
2146
        $v_header = array();
2147
        if (($v_result = $this->_readFileHeader($v_header)) != 1) {
2148
            // ----- Return
2149
            return $v_result;
2150
        }
2151
2152
        // ----- Check that the file header is coherent with $p_entry info
2153
        // TBC
2154
2155
        // ----- Trace
2156
2157
        // ----- Do the extraction (if not a folder)
2158
        if (!(($p_entry['external'] & 0x00000010) == 0x00000010)) {
2159
            // ----- Look for not compressed file
2160
            if ($p_entry['compressed_size'] == $p_entry['size']) {
2161
                // ----- Trace
2162
2163
                // ----- Reading the file
2164
                $p_string = fread($this->_zip_fd, $p_entry['compressed_size']);
2165
            } else {
2166
                // ----- Trace
2167
2168
                // ----- Reading the file
2169
                $v_data = fread($this->_zip_fd, $p_entry['compressed_size']);
2170
2171
                // ----- Decompress the file
2172
                $p_string = gzinflate($v_data);
2173
            }
2174
2175
            // ----- Trace
2176
        } else {
2177
            // TBC : error : can not extract a folder in a string
2178
        }
2179
2180
        // ----- Return
2181
        return $v_result;
2182
    }
2183
2184
    // ---------------------------------------------------------------------------
2185
2186
    // ---------------------------------------------------------------------------
2187
    // Function : _readFileHeader()
2188
    // Description :
2189
    // Parameters :
2190
    // Return Values :
2191
    // ---------------------------------------------------------------------------
2192
    /**
2193
     * Archive_Zip::_readFileHeader()
2194
     *
2195
     * { Description }
2196
     * @param $p_header
2197
     * @return int
2198
     */
2199
    public function _readFileHeader(&$p_header)
2200
    {
2201
        $v_result = 1;
2202
2203
        // ----- Read the 4 bytes signature
2204
        $v_binary_data = @fread($this->_zip_fd, 4);
2205
        $v_data        = unpack('Vid', $v_binary_data);
2206
2207
        // ----- Check signature
2208
        if ($v_data['id'] != 0x04034b50) {
2209
2210
            // ----- Error log
2211
            $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, 'Invalid archive structure');
2212
2213
            // ----- Return
2214
            return Archive_Zip::errorCode();
2215
        }
2216
2217
        // ----- Read the first 42 bytes of the header
2218
        $v_binary_data = fread($this->_zip_fd, 26);
2219
2220
        // ----- Look for invalid block size
2221 View Code Duplication
        if (strlen($v_binary_data) != 26) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2222
            $p_header['filename'] = '';
2223
            $p_header['status']   = 'invalid_header';
2224
2225
            // ----- Error log
2226
            $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, 'Invalid block size : ' . strlen($v_binary_data));
2227
2228
            // ----- Return
2229
            return Archive_Zip::errorCode();
2230
        }
2231
2232
        // ----- Extract the values
2233
        $v_data = unpack('vversion/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len', $v_binary_data);
2234
2235
        // ----- Get filename
2236
        $p_header['filename'] = fread($this->_zip_fd, $v_data['filename_len']);
2237
2238
        // ----- Get extra_fields
2239
        if ($v_data['extra_len'] != 0) {
2240
            $p_header['extra'] = fread($this->_zip_fd, $v_data['extra_len']);
2241
        } else {
2242
            $p_header['extra'] = '';
2243
        }
2244
2245
        // ----- Extract properties
2246
        $p_header['compression']     = $v_data['compression'];
2247
        $p_header['size']            = $v_data['size'];
2248
        $p_header['compressed_size'] = $v_data['compressed_size'];
2249
        $p_header['crc']             = $v_data['crc'];
2250
        $p_header['flag']            = $v_data['flag'];
2251
2252
        // ----- Recuperate date in UNIX format
2253
        $p_header['mdate'] = $v_data['mdate'];
2254
        $p_header['mtime'] = $v_data['mtime'];
2255 View Code Duplication
        if ($p_header['mdate'] && $p_header['mtime']) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2256
            // ----- Extract time
2257
            $v_hour    = ($p_header['mtime'] & 0xF800) >> 11;
2258
            $v_minute  = ($p_header['mtime'] & 0x07E0) >> 5;
2259
            $v_seconde = ($p_header['mtime'] & 0x001F) * 2;
2260
2261
            // ----- Extract date
2262
            $v_year  = (($p_header['mdate'] & 0xFE00) >> 9) + 1980;
2263
            $v_month = ($p_header['mdate'] & 0x01E0) >> 5;
2264
            $v_day   = $p_header['mdate'] & 0x001F;
2265
2266
            // ----- Get UNIX date format
2267
            $p_header['mtime'] = mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year);
2268
        } else {
2269
            $p_header['mtime'] = time();
2270
        }
2271
2272
        // ----- Other informations
2273
2274
        // TBC
2275
        //for (reset($v_data); $key = key($v_data); next($v_data)) {
2276
        //}
2277
2278
        // ----- Set the stored filename
2279
        $p_header['stored_filename'] = $p_header['filename'];
2280
2281
        // ----- Set the status field
2282
        $p_header['status'] = 'ok';
2283
2284
        // ----- Return
2285
        return $v_result;
2286
    }
2287
2288
    // ---------------------------------------------------------------------------
2289
2290
    // ---------------------------------------------------------------------------
2291
    // Function : _readCentralFileHeader()
2292
    // Description :
2293
    // Parameters :
2294
    // Return Values :
2295
    // ---------------------------------------------------------------------------
2296
    /**
2297
     * Archive_Zip::_readCentralFileHeader()
2298
     *
2299
     * { Description }
2300
     * @param $p_header
2301
     * @return int
2302
     */
2303
    public function _readCentralFileHeader(&$p_header)
2304
    {
2305
        $v_result = 1;
2306
2307
        // ----- Read the 4 bytes signature
2308
        $v_binary_data = @fread($this->_zip_fd, 4);
2309
        $v_data        = unpack('Vid', $v_binary_data);
2310
2311
        // ----- Check signature
2312
        if ($v_data['id'] != 0x02014b50) {
2313
2314
            // ----- Error log
2315
            $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, 'Invalid archive structure');
2316
2317
            // ----- Return
2318
            return Archive_Zip::errorCode();
2319
        }
2320
2321
        // ----- Read the first 42 bytes of the header
2322
        $v_binary_data = fread($this->_zip_fd, 42);
2323
2324
        // ----- Look for invalid block size
2325 View Code Duplication
        if (strlen($v_binary_data) != 42) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2326
            $p_header['filename'] = '';
2327
            $p_header['status']   = 'invalid_header';
2328
2329
            // ----- Error log
2330
            $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, 'Invalid block size : ' . strlen($v_binary_data));
2331
2332
            // ----- Return
2333
            return Archive_Zip::errorCode();
2334
        }
2335
2336
        // ----- Extract the values
2337
        $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);
2338
2339
        // ----- Get filename
2340 View Code Duplication
        if ($p_header['filename_len'] != 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2341
            $p_header['filename'] = fread($this->_zip_fd, $p_header['filename_len']);
2342
        } else {
2343
            $p_header['filename'] = '';
2344
        }
2345
2346
        // ----- Get extra
2347 View Code Duplication
        if ($p_header['extra_len'] != 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2348
            $p_header['extra'] = fread($this->_zip_fd, $p_header['extra_len']);
2349
        } else {
2350
            $p_header['extra'] = '';
2351
        }
2352
2353
        // ----- Get comment
2354 View Code Duplication
        if ($p_header['comment_len'] != 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2355
            $p_header['comment'] = fread($this->_zip_fd, $p_header['comment_len']);
2356
        } else {
2357
            $p_header['comment'] = '';
2358
        }
2359
2360
        // ----- Extract properties
2361
2362
        // ----- Recuperate date in UNIX format
2363 View Code Duplication
        if ($p_header['mdate'] && $p_header['mtime']) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2364
            // ----- Extract time
2365
            $v_hour    = ($p_header['mtime'] & 0xF800) >> 11;
2366
            $v_minute  = ($p_header['mtime'] & 0x07E0) >> 5;
2367
            $v_seconde = ($p_header['mtime'] & 0x001F) * 2;
2368
2369
            // ----- Extract date
2370
            $v_year  = (($p_header['mdate'] & 0xFE00) >> 9) + 1980;
2371
            $v_month = ($p_header['mdate'] & 0x01E0) >> 5;
2372
            $v_day   = $p_header['mdate'] & 0x001F;
2373
2374
            // ----- Get UNIX date format
2375
            $p_header['mtime'] = mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year);
2376
        } else {
2377
            $p_header['mtime'] = time();
2378
        }
2379
2380
        // ----- Set the stored filename
2381
        $p_header['stored_filename'] = $p_header['filename'];
2382
2383
        // ----- Set default status to ok
2384
        $p_header['status'] = 'ok';
2385
2386
        // ----- Look if it is a directory
2387
        if (substr($p_header['filename'], -1) === '/') {
2388
            $p_header['external'] = 0x41FF0010;
2389
        }
2390
2391
        // ----- Return
2392
        return $v_result;
2393
    }
2394
2395
    // ---------------------------------------------------------------------------
2396
2397
    // ---------------------------------------------------------------------------
2398
    // Function : _readEndCentralDir()
2399
    // Description :
2400
    // Parameters :
2401
    // Return Values :
2402
    // ---------------------------------------------------------------------------
2403
    /**
2404
     * Archive_Zip::_readEndCentralDir()
2405
     *
2406
     * { Description }
2407
     * @param $p_central_dir
2408
     * @return int
2409
     */
2410
    public function _readEndCentralDir(&$p_central_dir)
2411
    {
2412
        $v_result = 1;
2413
2414
        // ----- Go to the end of the zip file
2415
        $v_size = filesize($this->_zipname);
2416
        @fseek($this->_zip_fd, $v_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...
2417 View Code Duplication
        if (@ftell($this->_zip_fd) != $v_size) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2418
            $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, 'Unable to go to the end of the archive \'' . $this->_zipname . '\'');
2419
2420
            return Archive_Zip::errorCode();
2421
        }
2422
2423
        // ----- First try : look if this is an archive with no commentaries
2424
        // (most of the time)
2425
        // in this case the end of central dir is at 22 bytes of the file end
2426
        $v_found = 0;
2427
        if ($v_size > 26) {
2428
            @fseek($this->_zip_fd, $v_size - 22);
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...
2429 View Code Duplication
            if (($v_pos = @ftell($this->_zip_fd)) != ($v_size - 22)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2430
                $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \'' . $this->_zipname . '\'');
2431
2432
                return Archive_Zip::errorCode();
2433
            }
2434
2435
            // ----- Read for bytes
2436
            $v_binary_data = @fread($this->_zip_fd, 4);
2437
            $v_data        = unpack('Vid', $v_binary_data);
2438
2439
            // ----- Check signature
2440
            if ($v_data['id'] == 0x06054b50) {
2441
                $v_found = 1;
2442
            }
2443
2444
            $v_pos = ftell($this->_zip_fd);
2445
        }
2446
2447
        // ----- Go back to the maximum possible size of the Central Dir End Record
2448
        if (!$v_found) {
2449
            $v_maximum_size = 65557; // 0xFFFF + 22;
2450
            if ($v_maximum_size > $v_size) {
2451
                $v_maximum_size = $v_size;
2452
            }
2453
            @fseek($this->_zip_fd, $v_size - $v_maximum_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...
2454 View Code Duplication
            if (@ftell($this->_zip_fd) != ($v_size - $v_maximum_size)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2455
                $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \'' . $this->_zipname . '\'');
2456
2457
                return Archive_Zip::errorCode();
2458
            }
2459
2460
            // ----- Read byte per byte in order to find the signature
2461
            $v_pos   = ftell($this->_zip_fd);
2462
            $v_bytes = 0x00000000;
2463
            while ($v_pos < $v_size) {
2464
                // ----- Read a byte
2465
                $v_byte = @fread($this->_zip_fd, 1);
2466
2467
                // -----  Add the byte
2468
                $v_bytes = ($v_bytes << 8) | ord($v_byte);
2469
2470
                // ----- Compare the bytes
2471
                if ($v_bytes == 0x504b0506) {
2472
                    ++$v_pos;
2473
                    break;
2474
                }
2475
2476
                ++$v_pos;
2477
            }
2478
2479
            // ----- Look if not found end of central dir
2480
            if ($v_pos == $v_size) {
2481
                $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, 'Unable to find End of Central Dir Record signature');
2482
2483
                return Archive_Zip::errorCode();
2484
            }
2485
        }
2486
2487
        // ----- Read the first 18 bytes of the header
2488
        $v_binary_data = fread($this->_zip_fd, 18);
2489
2490
        // ----- Look for invalid block size
2491
        if (strlen($v_binary_data) != 18) {
2492
            $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, 'Invalid End of Central Dir Record size : ' . strlen($v_binary_data));
2493
2494
            return Archive_Zip::errorCode();
2495
        }
2496
2497
        // ----- Extract the values
2498
        $v_data = unpack('vdisk/vdisk_start/vdisk_entries/ventries/Vsize/Voffset/vcomment_size', $v_binary_data);
2499
2500
        // ----- Check the global size
2501
        if (($v_pos + $v_data['comment_size'] + 18) != $v_size) {
0 ignored issues
show
Bug introduced by
The variable $v_pos does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
2502
            $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, 'Fail to find the right signature');
2503
2504
            return Archive_Zip::errorCode();
2505
        }
2506
2507
        // ----- Get comment
2508
        if ($v_data['comment_size'] != 0) {
2509
            $p_central_dir['comment'] = fread($this->_zip_fd, $v_data['comment_size']);
2510
        } else {
2511
            $p_central_dir['comment'] = '';
2512
        }
2513
2514
        $p_central_dir['entries']      = $v_data['entries'];
2515
        $p_central_dir['disk_entries'] = $v_data['disk_entries'];
2516
        $p_central_dir['offset']       = $v_data['offset'];
2517
        $p_central_dir['size']         = $v_data['size'];
2518
        $p_central_dir['disk']         = $v_data['disk'];
2519
        $p_central_dir['disk_start']   = $v_data['disk_start'];
2520
2521
        // ----- Return
2522
        return $v_result;
2523
    }
2524
2525
    // ---------------------------------------------------------------------------
2526
2527
    // ---------------------------------------------------------------------------
2528
    // Function : _deleteByRule()
2529
    // Description :
2530
    // Parameters :
2531
    // Return Values :
2532
    // ---------------------------------------------------------------------------
2533
    /**
2534
     * Archive_Zip::_deleteByRule()
2535
     *
2536
     * { Description }
2537
     * @param $p_result_list
2538
     * @param $p_params
2539
     * @return int
2540
     */
2541
    public function _deleteByRule(&$p_result_list, &$p_params)
2542
    {
2543
        $v_result      = 1;
0 ignored issues
show
Unused Code introduced by
$v_result is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2544
        $v_list_detail = array();
0 ignored issues
show
Unused Code introduced by
$v_list_detail is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2545
2546
        // ----- Open the zip file
2547
        if (($v_result = $this->_openFd('rb')) != 1) {
2548
            // ----- Return
2549
            return $v_result;
2550
        }
2551
2552
        // ----- Read the central directory informations
2553
        $v_central_dir = array();
2554
        if (($v_result = $this->_readEndCentralDir($v_central_dir)) != 1) {
2555
            $this->_closeFd();
2556
2557
            return $v_result;
2558
        }
2559
2560
        // ----- Go to beginning of File
2561
        @rewind($this->_zip_fd);
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...
2562
2563
        // ----- Scan all the files
2564
        // ----- Start at beginning of Central Dir
2565
        $v_pos_entry = $v_central_dir['offset'];
2566
        @rewind($this->_zip_fd);
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...
2567 View Code Duplication
        if (@fseek($this->_zip_fd, $v_pos_entry)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2568
            // ----- Clean
2569
            $this->_closeFd();
2570
2571
            $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
2572
2573
            return Archive_Zip::errorCode();
2574
        }
2575
2576
        // ----- Read each entry
2577
        $v_header_list = array();
2578
        $j_start       = 0;
2579
        for ($i = 0, $v_nb_extracted = 0; $i < $v_central_dir['entries']; ++$i) {
2580
2581
            // ----- Read the file header
2582
            $v_header_list[$v_nb_extracted] = array();
2583
            $v_result                       = $this->_readCentralFileHeader($v_header_list[$v_nb_extracted]);
2584
            if ($v_result != 1) {
2585
                // ----- Clean
2586
                $this->_closeFd();
2587
2588
                return $v_result;
2589
            }
2590
2591
            // ----- Store the index
2592
            $v_header_list[$v_nb_extracted]['index'] = $i;
2593
2594
            // ----- Look for the specific extract rules
2595
            $v_found = false;
2596
2597
            // ----- Look for extract by name rule
2598
            if (isset($p_params[ARCHIVE_ZIP_PARAM_BY_NAME]) && ($p_params[ARCHIVE_ZIP_PARAM_BY_NAME] != 0)) {
2599
2600
                // ----- Look if the filename is in the list
2601
                for ($j = 0; ($j < count($p_params[ARCHIVE_ZIP_PARAM_BY_NAME])) && (!$v_found); ++$j) {
2602
2603
                    // ----- Look for a directory
2604
                    if (substr($p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j], -1) === '/') {
2605
2606
                        // ----- Look if the directory is in the filename path
2607
                        if ((strlen($v_header_list[$v_nb_extracted]['stored_filename']) > strlen($p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j]))
2608
                            && (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])
2609
                        ) {
2610
                            $v_found = true;
2611
                        } elseif ((($v_header_list[$v_nb_extracted]['external'] & 0x00000010) == 0x00000010) /* Indicates a folder */
2612
                                  && ($v_header_list[$v_nb_extracted]['stored_filename'] . '/' == $p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j])
2613
                        ) {
2614
                            $v_found = true;
2615
                        }
2616
                    } // ----- Look for a filename
2617
                    elseif ($v_header_list[$v_nb_extracted]['stored_filename'] == $p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j]) {
2618
                        $v_found = true;
2619
                    }
2620
                }
2621
            } // ----- Look for extract by ereg rule
2622 View Code Duplication
            elseif (isset($p_params[ARCHIVE_ZIP_PARAM_BY_EREG]) && ($p_params[ARCHIVE_ZIP_PARAM_BY_EREG] != '')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2623
                if (preg_match('/' . $p_params[ARCHIVE_ZIP_PARAM_BY_EREG] . '/', $v_header_list[$v_nb_extracted]['stored_filename'])) {
2624
                    $v_found = true;
2625
                }
2626
            } // ----- Look for extract by preg rule
2627
            elseif (isset($p_params[ARCHIVE_ZIP_PARAM_BY_PREG]) && ($p_params[ARCHIVE_ZIP_PARAM_BY_PREG] != '')) {
2628
                if (preg_match($p_params[ARCHIVE_ZIP_PARAM_BY_PREG], $v_header_list[$v_nb_extracted]['stored_filename'])) {
2629
                    $v_found = true;
2630
                }
2631
            } // ----- Look for extract by index rule
2632 View Code Duplication
            elseif (isset($p_params[ARCHIVE_ZIP_PARAM_BY_INDEX]) && ($p_params[ARCHIVE_ZIP_PARAM_BY_INDEX] != 0)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2633
2634
                // ----- Look if the index is in the list
2635
                for ($j = $j_start; ($j < count($p_params[ARCHIVE_ZIP_PARAM_BY_INDEX])) && (!$v_found); ++$j) {
2636
                    if (($i >= $p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['start']) && ($i <= $p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['end'])) {
2637
                        $v_found = true;
2638
                    }
2639
                    if ($i >= $p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['end']) {
2640
                        $j_start = $j + 1;
2641
                    }
2642
2643
                    if ($p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['start'] > $i) {
2644
                        break;
2645
                    }
2646
                }
2647
            }
2648
2649
            // ----- Look for deletion
2650
            if ($v_found) {
2651
                unset($v_header_list[$v_nb_extracted]);
2652
            } else {
2653
                ++$v_nb_extracted;
2654
            }
2655
        }
2656
2657
        // ----- Look if something need to be deleted
2658
        if ($v_nb_extracted > 0) {
2659
2660
            // ----- Creates a temporay file
2661
            $v_zip_temp_name = ARCHIVE_ZIP_TEMPORARY_DIR . uniqid('archive_zip-') . '.tmp';
2662
2663
            // ----- Creates a temporary zip archive
2664
            $v_temp_zip = new Archive_Zip($v_zip_temp_name);
2665
2666
            // ----- Open the temporary zip file in write mode
2667
            if (($v_result = $v_temp_zip->_openFd('wb')) != 1) {
2668
                $this->_closeFd();
2669
2670
                // ----- Return
2671
                return $v_result;
2672
            }
2673
2674
            // ----- Look which file need to be kept
2675
            for ($i = 0, $iMax = count($v_header_list); $i < $iMax; ++$i) {
2676
2677
                // ----- Calculate the position of the header
2678
                @rewind($this->_zip_fd);
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...
2679
                if (@fseek($this->_zip_fd, $v_header_list[$i]['offset'])) {
2680
                    // ----- Clean
2681
                    $this->_closeFd();
2682
                    $v_temp_zip->_closeFd();
2683
                    @unlink($v_zip_temp_name);
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...
2684
2685
                    $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
2686
2687
                    return Archive_Zip::errorCode();
2688
                }
2689
2690
                // ----- Read the file header
2691 View Code Duplication
                if (($v_result = $this->_readFileHeader($v_header_list[$i])) != 1) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2692
                    // ----- Clean
2693
                    $this->_closeFd();
2694
                    $v_temp_zip->_closeFd();
2695
                    @unlink($v_zip_temp_name);
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...
2696
2697
                    return $v_result;
2698
                }
2699
2700
                // ----- Write the file header
2701
                $v_result = $v_temp_zip->_writeFileHeader($v_header_list[$i]);
2702
                if ($v_result != 1) {
2703
                    // ----- Clean
2704
                    $this->_closeFd();
2705
                    $v_temp_zip->_closeFd();
2706
                    @unlink($v_zip_temp_name);
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...
2707
2708
                    return $v_result;
2709
                }
2710
2711
                // ----- Read/write the data block
2712
                $v_result = $this->_tool_CopyBlock($this->_zip_fd, $v_temp_zip->_zip_fd, $v_header_list[$i]['compressed_size']);
2713
                if ($v_result != 1) {
2714
                    // ----- Clean
2715
                    $this->_closeFd();
2716
                    $v_temp_zip->_closeFd();
2717
                    @unlink($v_zip_temp_name);
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...
2718
2719
                    return $v_result;
2720
                }
2721
            }
2722
2723
            // ----- Store the offset of the central dir
2724
            $v_offset = @ftell($v_temp_zip->_zip_fd);
2725
2726
            // ----- Re-Create the Central Dir files header
2727
            for ($i = 0, $iMax = count($v_header_list); $i < $iMax; ++$i) {
2728
                // ----- Create the file header
2729
                $v_result = $v_temp_zip->_writeCentralFileHeader($v_header_list[$i]);
2730
                if ($v_result != 1) {
2731
                    // ----- Clean
2732
                    $v_temp_zip->_closeFd();
2733
                    $this->_closeFd();
2734
                    @unlink($v_zip_temp_name);
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...
2735
2736
                    return $v_result;
2737
                }
2738
2739
                // ----- Transform the header to a 'usable' info
2740
                $v_temp_zip->_convertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);
2741
            }
2742
2743
            // ----- Zip file comment
2744
            $v_comment = '';
2745
2746
            // ----- Calculate the size of the central header
2747
            $v_size = @ftell($v_temp_zip->_zip_fd) - $v_offset;
2748
2749
            // ----- Create the central dir footer
2750
            $v_result = $v_temp_zip->_writeCentralHeader(count($v_header_list), $v_size, $v_offset, $v_comment);
2751 View Code Duplication
            if ($v_result != 1) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2752
                // ----- Clean
2753
                unset($v_header_list);
2754
                $v_temp_zip->_closeFd();
2755
                $this->_closeFd();
2756
                @unlink($v_zip_temp_name);
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...
2757
2758
                return $v_result;
2759
            }
2760
2761
            // ----- Close
2762
            $v_temp_zip->_closeFd();
2763
            $this->_closeFd();
2764
2765
            // ----- Delete the zip file
2766
            // TBC : I should test the result ...
2767
            @unlink($this->_zipname);
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...
2768
2769
            // ----- Rename the temporary file
2770
            // TBC : I should test the result ...
2771
            //@rename($v_zip_temp_name, $this->_zipname);
2772
            $this->_tool_Rename($v_zip_temp_name, $this->_zipname);
2773
2774
            // ----- Destroy the temporary archive
2775
            unset($v_temp_zip);
2776
        }
2777
2778
        // ----- Return
2779
        return $v_result;
2780
    }
2781
2782
    // ---------------------------------------------------------------------------
2783
2784
    // ---------------------------------------------------------------------------
2785
    // Function : _dirCheck()
2786
    // Description :
2787
    //   Check if a directory exists, if not it creates it and all the parents directory
2788
    //   which may be useful.
2789
    // Parameters :
2790
    //   $p_dir : Directory path to check.
2791
    // Return Values :
2792
    //    1 : OK
2793
    //   -1 : Unable to create directory
2794
    // ---------------------------------------------------------------------------
2795
    /**
2796
     * Archive_Zip::_dirCheck()
2797
     *
2798
     * { Description }
2799
     *
2800
     * @param  [type] $p_is_dir
0 ignored issues
show
Documentation introduced by
The doc-type [type] could not be parsed: Unknown type name "" at position 0. [(view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
2801
     * @param  bool $p_is_dir
2802
     * @return int
2803
     */
2804
    public function _dirCheck($p_dir, $p_is_dir = false)
2805
    {
2806
        $v_result = 1;
2807
2808
        // ----- Remove the final '/'
2809
        if ($p_is_dir && (substr($p_dir, -1) === '/')) {
2810
            $p_dir = substr($p_dir, 0, -1);
2811
        }
2812
2813
        // ----- Check the directory availability
2814
        if (is_dir($p_dir) || ($p_dir == '')) {
2815
            return 1;
2816
        }
2817
2818
        // ----- Extract parent directory
2819
        $p_parent_dir = dirname($p_dir);
2820
2821
        // ----- Just a check
2822
        if ($p_parent_dir != $p_dir) {
2823
            // ----- Look for parent directory
2824
            if ($p_parent_dir != '') {
2825
                if (($v_result = $this->_dirCheck($p_parent_dir)) != 1) {
2826
                    return $v_result;
2827
                }
2828
            }
2829
        }
2830
2831
        // ----- Create the directory
2832
        if (!@mkdir($p_dir, 0777)) {
2833
            $this->_errorLog(ARCHIVE_ZIP_ERR_DIR_CREATE_FAIL, "Unable to create directory '$p_dir'");
2834
2835
            return Archive_Zip::errorCode();
2836
        }
2837
2838
        // ----- Return
2839
        return $v_result;
2840
    }
2841
2842
    // ---------------------------------------------------------------------------
2843
2844
    // ---------------------------------------------------------------------------
2845
    // Function : _merge()
2846
    // Description :
2847
    //   If $p_archive_to_add does not exist, the function exit with a success result.
2848
    // Parameters :
2849
    // Return Values :
2850
    // ---------------------------------------------------------------------------
2851
    /**
2852
     * Archive_Zip::_merge()
2853
     *
2854
     * { Description }
2855
     * @param $p_archive_to_add
2856
     * @return int
2857
     */
2858
    public function _merge(&$p_archive_to_add)
2859
    {
2860
        $v_result = 1;
0 ignored issues
show
Unused Code introduced by
$v_result is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2861
2862
        // ----- Look if the archive_to_add exists
2863
        if (!is_file($p_archive_to_add->_zipname)) {
2864
            // ----- Nothing to merge, so merge is a success
2865
            return 1;
2866
        }
2867
2868
        // ----- Look if the archive exists
2869
        if (!is_file($this->_zipname)) {
2870
            // ----- Do a duplicate
2871
            $v_result = $this->_duplicate($p_archive_to_add->_zipname);
2872
2873
            return $v_result;
2874
        }
2875
2876
        // ----- Open the zip file
2877
        if (($v_result = $this->_openFd('rb')) != 1) {
2878
            return $v_result;
2879
        }
2880
2881
        // ----- Read the central directory informations
2882
        $v_central_dir = array();
2883
        if (($v_result = $this->_readEndCentralDir($v_central_dir)) != 1) {
2884
            $this->_closeFd();
2885
2886
            return $v_result;
2887
        }
2888
2889
        // ----- Go to beginning of File
2890
        @rewind($this->_zip_fd);
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...
2891
2892
        // ----- Open the archive_to_add file
2893
        if (($v_result = $p_archive_to_add->_openFd('rb')) != 1) {
2894
            $this->_closeFd();
2895
2896
            return $v_result;
2897
        }
2898
2899
        // ----- Read the central directory informations
2900
        $v_central_dir_to_add = array();
2901
        $v_result             = $p_archive_to_add->_readEndCentralDir($v_central_dir_to_add);
2902
        if ($v_result != 1) {
2903
            $this->_closeFd();
2904
            $p_archive_to_add->_closeFd();
2905
2906
            return $v_result;
2907
        }
2908
2909
        // ----- Go to beginning of File
2910
        @rewind($p_archive_to_add->_zip_fd);
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...
2911
2912
        // ----- Creates a temporay file
2913
        $v_zip_temp_name = ARCHIVE_ZIP_TEMPORARY_DIR . uniqid('archive_zip-') . '.tmp';
2914
2915
        // ----- Open the temporary file in write mode
2916 View Code Duplication
        if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2917
            $this->_closeFd();
2918
            $p_archive_to_add->_closeFd();
2919
            $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \'' . $v_zip_temp_name . '\' in binary write mode');
2920
2921
            return Archive_Zip::errorCode();
2922
        }
2923
2924
        // ----- Copy the files from the archive to the temporary file
2925
        // TBC : Here I should better append the file and go back to erase the
2926
        // central dir
2927
        $v_size = $v_central_dir['offset'];
2928
        while ($v_size != 0) {
2929
            $v_read_size = ($v_size < ARCHIVE_ZIP_READ_BLOCK_SIZE ? $v_size : ARCHIVE_ZIP_READ_BLOCK_SIZE);
2930
            $v_buffer    = fread($this->_zip_fd, $v_read_size);
2931
            @fwrite($v_zip_temp_fd, $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...
2932
            $v_size -= $v_read_size;
2933
        }
2934
2935
        // ----- Copy the files from the archive_to_add into the temporary file
2936
        $v_size = $v_central_dir_to_add['offset'];
2937
        while ($v_size != 0) {
2938
            $v_read_size = ($v_size < ARCHIVE_ZIP_READ_BLOCK_SIZE ? $v_size : ARCHIVE_ZIP_READ_BLOCK_SIZE);
2939
            $v_buffer    = fread($p_archive_to_add->_zip_fd, $v_read_size);
2940
            @fwrite($v_zip_temp_fd, $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...
2941
            $v_size -= $v_read_size;
2942
        }
2943
2944
        // ----- Store the offset of the central dir
2945
        $v_offset = @ftell($v_zip_temp_fd);
2946
2947
        // ----- Copy the block of file headers from the old archive
2948
        $v_size = $v_central_dir['size'];
2949 View Code Duplication
        while ($v_size != 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2950
            $v_read_size = ($v_size < ARCHIVE_ZIP_READ_BLOCK_SIZE ? $v_size : ARCHIVE_ZIP_READ_BLOCK_SIZE);
2951
            $v_buffer    = @fread($this->_zip_fd, $v_read_size);
2952
            @fwrite($v_zip_temp_fd, $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...
2953
            $v_size -= $v_read_size;
2954
        }
2955
2956
        // ----- Copy the block of file headers from the archive_to_add
2957
        $v_size = $v_central_dir_to_add['size'];
2958 View Code Duplication
        while ($v_size != 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2959
            $v_read_size = ($v_size < ARCHIVE_ZIP_READ_BLOCK_SIZE ? $v_size : ARCHIVE_ZIP_READ_BLOCK_SIZE);
2960
            $v_buffer    = @fread($p_archive_to_add->_zip_fd, $v_read_size);
2961
            @fwrite($v_zip_temp_fd, $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...
2962
            $v_size -= $v_read_size;
2963
        }
2964
2965
        // ----- Zip file comment
2966
        // TBC : I should merge the two comments
2967
        $v_comment = '';
2968
2969
        // ----- Calculate the size of the (new) central header
2970
        $v_size = @ftell($v_zip_temp_fd) - $v_offset;
2971
2972
        // ----- Swap the file descriptor
2973
        // Here is a trick : I swap the temporary fd with the zip fd, in order to use
2974
        // the following methods on the temporary fil and not the real archive fd
2975
        $v_swap        = $this->_zip_fd;
2976
        $this->_zip_fd = $v_zip_temp_fd;
2977
        $v_zip_temp_fd = $v_swap;
2978
2979
        // ----- Create the central dir footer
2980
        if (($v_result = $this->_writeCentralHeader($v_central_dir['entries'] + $v_central_dir_to_add['entries'], $v_size, $v_offset, $v_comment)) != 1) {
2981
            $this->_closeFd();
2982
            $p_archive_to_add->_closeFd();
2983
            @fclose($v_zip_temp_fd);
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...
2984
            $this->_zip_fd = null;
2985
2986
            // ----- Reset the file list
2987
            unset($v_header_list);
2988
2989
            // ----- Return
2990
            return $v_result;
2991
        }
2992
2993
        // ----- Swap back the file descriptor
2994
        $v_swap        = $this->_zip_fd;
2995
        $this->_zip_fd = $v_zip_temp_fd;
2996
        $v_zip_temp_fd = $v_swap;
2997
2998
        // ----- Close
2999
        $this->_closeFd();
3000
        $p_archive_to_add->_closeFd();
3001
3002
        // ----- Close the temporary file
3003
        @fclose($v_zip_temp_fd);
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...
3004
3005
        // ----- Delete the zip file
3006
        // TBC : I should test the result ...
3007
        @unlink($this->_zipname);
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...
3008
3009
        // ----- Rename the temporary file
3010
        // TBC : I should test the result ...
3011
        //@rename($v_zip_temp_name, $this->_zipname);
3012
        $this->_tool_Rename($v_zip_temp_name, $this->_zipname);
3013
3014
        // ----- Return
3015
        return $v_result;
3016
    }
3017
3018
    // ---------------------------------------------------------------------------
3019
3020
    // ---------------------------------------------------------------------------
3021
    // Function : _duplicate()
3022
    // Description :
3023
    // Parameters :
3024
    // Return Values :
3025
    // ---------------------------------------------------------------------------
3026
    /**
3027
     * Archive_Zip::_duplicate()
3028
     *
3029
     * { Description }
3030
     * @param $p_archive_filename
3031
     * @return int
3032
     */
3033
    public function _duplicate($p_archive_filename)
3034
    {
3035
        $v_result = 1;
0 ignored issues
show
Unused Code introduced by
$v_result is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
3036
3037
        // ----- Look if the $p_archive_filename exists
3038
        if (!is_file($p_archive_filename)) {
3039
3040
            // ----- Nothing to duplicate, so duplicate is a success.
3041
            $v_result = 1;
3042
3043
            // ----- Return
3044
            return $v_result;
3045
        }
3046
3047
        // ----- Open the zip file
3048
        if (($v_result = $this->_openFd('wb')) != 1) {
3049
            // ----- Return
3050
            return $v_result;
3051
        }
3052
3053
        // ----- Open the temporary file in write mode
3054 View Code Duplication
        if (($v_zip_temp_fd = @fopen($p_archive_filename, 'rb')) == 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
3055
            $this->_closeFd();
3056
            $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive file \'' . $p_archive_filename . '\' in binary write mode');
3057
3058
            return Archive_Zip::errorCode();
3059
        }
3060
3061
        // ----- Copy the files from the archive to the temporary file
3062
        // TBC : Here I should better append the file and go back to erase the
3063
        // central dir
3064
        $v_size = filesize($p_archive_filename);
3065
        while ($v_size != 0) {
3066
            $v_read_size = ($v_size < ARCHIVE_ZIP_READ_BLOCK_SIZE ? $v_size : ARCHIVE_ZIP_READ_BLOCK_SIZE);
3067
            $v_buffer    = fread($v_zip_temp_fd, $v_read_size);
3068
            @fwrite($this->_zip_fd, $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...
3069
            $v_size -= $v_read_size;
3070
        }
3071
3072
        // ----- Close
3073
        $this->_closeFd();
3074
3075
        // ----- Close the temporary file
3076
        @fclose($v_zip_temp_fd);
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...
3077
3078
        return $v_result;
3079
    }
3080
3081
    // ---------------------------------------------------------------------------
3082
3083
    /**
3084
     * Archive_Zip::_check_parameters()
3085
     *
3086
     * { Description }
3087
     *
3088
     * @param $p_params
3089
     * @param $p_default
3090
     * @return int
3091
     * @internal param int $p_error_code
3092
     * @internal param string $p_error_string
3093
     */
3094
    public function _check_parameters(&$p_params, $p_default)
3095
    {
3096
3097
        // ----- Check that param is an array
3098
        if (!is_array($p_params)) {
3099
            $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER, 'Unsupported parameter, waiting for an array');
3100
3101
            return Archive_Zip::errorCode();
3102
        }
3103
3104
        // ----- Check that all the params are valid
3105
        for (reset($p_params); list($v_key, $v_value) = each($p_params);) {
0 ignored issues
show
Unused Code introduced by
The assignment to $v_value is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
3106
            if (!isset($p_default[$v_key])) {
3107
                $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER, 'Unsupported parameter with key \'' . $v_key . '\'');
3108
3109
                return Archive_Zip::errorCode();
3110
            }
3111
        }
3112
3113
        // ----- Set the default values
3114
        for (reset($p_default); list($v_key, $v_value) = each($p_default);) {
0 ignored issues
show
Unused Code introduced by
The assignment to $v_value is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
3115
            if (!isset($p_params[$v_key])) {
3116
                $p_params[$v_key] = $p_default[$v_key];
3117
            }
3118
        }
3119
3120
        // ----- Check specific parameters
3121
        $v_callback_list = array(
3122
            'callback_pre_add',
3123
            'callback_post_add',
3124
            'callback_pre_extract',
3125
            'callback_post_extract'
3126
        );
3127
        for ($i = 0, $iMax = count($v_callback_list); $i < $iMax; ++$i) {
3128
            $v_key = $v_callback_list[$i];
3129
            if (isset($p_params[$v_key]) && ($p_params[$v_key] != '')) {
3130
                if (!function_exists($p_params[$v_key])) {
3131
                    $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAM_VALUE, "Callback '" . $p_params[$v_key] . "()' is not an existing function for " . "parameter '" . $v_key . "'");
3132
3133
                    return Archive_Zip::errorCode();
3134
                }
3135
            }
3136
        }
3137
3138
        return 1;
3139
    }
3140
3141
    // ---------------------------------------------------------------------------
3142
3143
    // ---------------------------------------------------------------------------
3144
    // Function : _errorLog()
3145
    // Description :
3146
    // Parameters :
3147
    // ---------------------------------------------------------------------------
3148
    /**
3149
     * Archive_Zip::_errorLog()
3150
     *
3151
     * { Description }
3152
     *
3153
     * @param integer $p_error_code
3154
     * @param string  $p_error_string
3155
     */
3156
    public function _errorLog($p_error_code = 0, $p_error_string = '')
3157
    {
3158
        $this->_error_code   = $p_error_code;
3159
        $this->_error_string = $p_error_string;
3160
    }
3161
3162
    // ---------------------------------------------------------------------------
3163
3164
    // ---------------------------------------------------------------------------
3165
    // Function : _errorReset()
3166
    // Description :
3167
    // Parameters :
3168
    // ---------------------------------------------------------------------------
3169
    /**
3170
     * Archive_Zip::_errorReset()
3171
     *
3172
     * { Description }
3173
     *
3174
     */
3175
    public function _errorReset()
3176
    {
3177
        $this->_error_code   = 1;
3178
        $this->_error_string = '';
3179
    }
3180
3181
    // ---------------------------------------------------------------------------
3182
3183
    // ---------------------------------------------------------------------------
3184
    // Function : $this->_tool_PathReduction()
3185
    // Description :
3186
    // Parameters :
3187
    // Return Values :
3188
    // ---------------------------------------------------------------------------
3189
    /**
3190
     * _tool_PathReduction()
3191
     *
3192
     * { Description }
3193
     * @param $p_dir
3194
     * @return string
3195
     */
3196
    public function _tool_PathReduction($p_dir)
3197
    {
3198
        $v_result = '';
3199
3200
        // ----- Look for not empty path
3201
        if ($p_dir != '') {
3202
            // ----- Explode path by directory names
3203
            $v_list = explode('/', $p_dir);
3204
3205
            // ----- Study directories from last to first
3206
            for ($i = count($v_list) - 1; $i >= 0; $i--) {
3207
                // ----- Look for current path
3208
                if ($v_list[$i] === '.') {
3209
                    // ----- Ignore this directory
3210
                    // Should be the first $i=0, but no check is done
3211
                } elseif ($v_list[$i] === '..') {
3212
                    // ----- Ignore it and ignore the $i-1
3213
                    $i--;
3214
                } elseif (($v_list[$i] == '') && ($i != (count($v_list) - 1)) && ($i != 0)) {
3215
                    // ----- Ignore only the double '//' in path,
3216
                    // but not the first and last '/'
3217
                } else {
3218
                    $v_result = $v_list[$i] . ($i != (count($v_list) - 1) ? '/' . $v_result : '');
3219
                }
3220
            }
3221
        }
3222
3223
        // ----- Return
3224
        return $v_result;
3225
    }
3226
3227
    // ---------------------------------------------------------------------------
3228
3229
    // ---------------------------------------------------------------------------
3230
    // Function : $this->_tool_PathInclusion()
3231
    // Description :
3232
    //   This function indicates if the path $p_path is under the $p_dir tree. Or,
3233
    //   said in an other way, if the file or sub-dir $p_path is inside the dir
3234
    //   $p_dir.
3235
    //   The function indicates also if the path is exactly the same as the dir.
3236
    //   This function supports path with duplicated '/' like '//', but does not
3237
    //   support '.' or '..' statements.
3238
    // Parameters :
3239
    // Return Values :
3240
    //   0 if $p_path is not inside directory $p_dir
3241
    //   1 if $p_path is inside directory $p_dir
3242
    //   2 if $p_path is exactly the same as $p_dir
3243
    // ---------------------------------------------------------------------------
3244
    /**
3245
     * _tool_PathInclusion()
3246
     *
3247
     * { Description }
3248
     * @param $p_dir
3249
     * @param $p_path
3250
     * @return int
3251
     */
3252
    public function _tool_PathInclusion($p_dir, $p_path)
3253
    {
3254
        $v_result = 1;
3255
3256
        // ----- Explode dir and path by directory separator
3257
        $v_list_dir       = explode('/', $p_dir);
3258
        $v_list_dir_size  = count($v_list_dir);
3259
        $v_list_path      = explode('/', $p_path);
3260
        $v_list_path_size = count($v_list_path);
3261
3262
        // ----- Study directories paths
3263
        $i = 0;
3264
        $j = 0;
3265
        while (($i < $v_list_dir_size) && ($j < $v_list_path_size) && $v_result) {
3266
3267
            // ----- Look for empty dir (path reduction)
3268
            if ($v_list_dir[$i] == '') {
3269
                ++$i;
3270
                continue;
3271
            }
3272
            if ($v_list_path[$j] == '') {
3273
                ++$j;
3274
                continue;
3275
            }
3276
3277
            // ----- Compare the items
3278
            if (($v_list_dir[$i] != $v_list_path[$j]) && ($v_list_dir[$i] != '') && ($v_list_path[$j] != '')) {
3279
                $v_result = 0;
3280
            }
3281
3282
            // ----- Next items
3283
            ++$i;
3284
            ++$j;
3285
        }
3286
3287
        // ----- Look if everything seems to be the same
3288
        if ($v_result) {
3289
            // ----- Skip all the empty items
3290
            while (($j < $v_list_path_size) && ($v_list_path[$j] == '')) {
3291
                ++$j;
3292
            }
3293
            while (($i < $v_list_dir_size) && ($v_list_dir[$i] == '')) {
3294
                ++$i;
3295
            }
3296
3297
            if (($i >= $v_list_dir_size) && ($j >= $v_list_path_size)) {
3298
                // ----- There are exactly the same
3299
                $v_result = 2;
3300
            } elseif ($i < $v_list_dir_size) {
3301
                // ----- The path is shorter than the dir
3302
                $v_result = 0;
3303
            }
3304
        }
3305
3306
        // ----- Return
3307
        return $v_result;
3308
    }
3309
3310
    // ---------------------------------------------------------------------------
3311
3312
    // ---------------------------------------------------------------------------
3313
    // Function : $this->_tool_CopyBlock()
3314
    // Description :
3315
    // Parameters :
3316
    //   $p_mode : read/write compression mode
3317
    //             0 : src & dest normal
3318
    //             1 : src gzip, dest normal
3319
    //             2 : src normal, dest gzip
3320
    //             3 : src & dest gzip
3321
    // Return Values :
3322
    // ---------------------------------------------------------------------------
3323
    /**
3324
     * _tool_CopyBlock()
3325
     *
3326
     * { Description }
3327
     *
3328
     * @param          $p_src
3329
     * @param          $p_dest
3330
     * @param          $p_size
3331
     * @param  integer $p_mode
3332
     * @return int
3333
     */
3334
    public function _tool_CopyBlock($p_src, $p_dest, $p_size, $p_mode = 0)
3335
    {
3336
        $v_result = 1;
3337
3338
        if ($p_mode == 0) {
3339
            while ($p_size != 0) {
3340
                $v_read_size = ($p_size < ARCHIVE_ZIP_READ_BLOCK_SIZE ? $p_size : ARCHIVE_ZIP_READ_BLOCK_SIZE);
3341
                $v_buffer    = @fread($p_src, $v_read_size);
3342
                @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...
3343
                $p_size -= $v_read_size;
3344
            }
3345 View Code Duplication
        } elseif ($p_mode == 1) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
3346
            while ($p_size != 0) {
3347
                $v_read_size = ($p_size < ARCHIVE_ZIP_READ_BLOCK_SIZE ? $p_size : ARCHIVE_ZIP_READ_BLOCK_SIZE);
3348
                $v_buffer    = @gzread($p_src, $v_read_size);
3349
                @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...
3350
                $p_size -= $v_read_size;
3351
            }
3352
        } elseif ($p_mode == 2) {
3353
            while ($p_size != 0) {
3354
                $v_read_size = ($p_size < ARCHIVE_ZIP_READ_BLOCK_SIZE ? $p_size : ARCHIVE_ZIP_READ_BLOCK_SIZE);
3355
                $v_buffer    = @fread($p_src, $v_read_size);
3356
                @gzwrite($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...
3357
                $p_size -= $v_read_size;
3358
            }
3359 View Code Duplication
        } elseif ($p_mode == 3) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
3360
            while ($p_size != 0) {
3361
                $v_read_size = ($p_size < ARCHIVE_ZIP_READ_BLOCK_SIZE ? $p_size : ARCHIVE_ZIP_READ_BLOCK_SIZE);
3362
                $v_buffer    = @gzread($p_src, $v_read_size);
3363
                @gzwrite($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...
3364
                $p_size -= $v_read_size;
3365
            }
3366
        }
3367
3368
        // ----- Return
3369
        return $v_result;
3370
    }
3371
3372
    // ---------------------------------------------------------------------------
3373
3374
    // ---------------------------------------------------------------------------
3375
    // Function : $this->_tool_Rename()
3376
    // Description :
3377
    //   This function tries to do a simple rename() function. If it fails, it
3378
    //   tries to copy the $p_src file in a new $p_dest file and then unlink the
3379
    //   first one.
3380
    // Parameters :
3381
    //   $p_src : Old filename
3382
    //   $p_dest : New filename
3383
    // Return Values :
3384
    //   1 on success, 0 on failure.
3385
    // ---------------------------------------------------------------------------
3386
    /**
3387
     * _tool_Rename()
3388
     *
3389
     * { Description }
3390
     * @param $p_src
3391
     * @param $p_dest
3392
     * @return int
3393
     */
3394
    public function _tool_Rename($p_src, $p_dest)
3395
    {
3396
        $v_result = 1;
3397
3398
        // ----- Try to rename the files
3399
        if (!@rename($p_src, $p_dest)) {
3400
3401
            // ----- Try to copy & unlink the src
3402
            if (!@copy($p_src, $p_dest)) {
3403
                $v_result = 0;
3404
            } elseif (!@unlink($p_src)) {
3405
                $v_result = 0;
3406
            }
3407
        }
3408
3409
        // ----- Return
3410
        return $v_result;
3411
    }
3412
3413
    // ---------------------------------------------------------------------------
3414
3415
    // ---------------------------------------------------------------------------
3416
    // Function : $this->_tool_TranslateWinPath()
3417
    // Description :
3418
    //   Translate windows path by replacing '\' by '/' and optionally removing
3419
    //   drive letter.
3420
    // Parameters :
3421
    //   $p_path : path to translate.
3422
    //   $p_remove_disk_letter : true | false
3423
    // Return Values :
3424
    //   The path translated.
3425
    // ---------------------------------------------------------------------------
3426
    /**
3427
     * _tool_TranslateWinPath()
3428
     *
3429
     * { Description }
3430
     *
3431
     * @param  [type] $p_remove_disk_letter
0 ignored issues
show
Documentation introduced by
The doc-type [type] could not be parsed: Unknown type name "" at position 0. [(view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
3432
     * @param  bool $p_remove_disk_letter
3433
     * @return string
3434
     */
3435
    public function _tool_TranslateWinPath($p_path, $p_remove_disk_letter = true)
3436
    {
3437
        if (false !== stripos(php_uname(), 'windows')) {
3438
            // ----- Look for potential disk letter
3439
            if ($p_remove_disk_letter && (($v_position = strpos($p_path, ':')) != false)) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $v_position = strpos($p_path, ':') of type integer to the boolean false. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
3440
                $p_path = substr($p_path, $v_position + 1);
3441
            }
3442
            // ----- Change potential windows directory separator
3443
            if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0, 1) === '\\')) {
3444
                $p_path = strtr($p_path, '\\', '/');
3445
            }
3446
        }
3447
3448
        return $p_path;
3449
    }
3450
    // ---------------------------------------------------------------------------
3451
}
3452
// End of class
3453