Archive_Zip   F
last analyzed

Complexity

Total Complexity 386

Size/Duplication

Total Lines 4450
Duplicated Lines 7.93 %

Coupling/Cohesion

Components 1
Dependencies 0

Importance

Changes 0
Metric Value
dl 353
loc 4450
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 20 2
B create() 18 47 6
B add() 20 55 6
A listContent() 0 20 3
B extract() 0 44 5
B delete() 0 44 8
B properties() 0 52 5
A duplicate() 0 33 5
A merge() 0 37 5
A errorCode() 0 4 1
A errorName() 0 28 5
A errorInfo() 0 8 2
A _checkFormat() 0 44 3
A _create() 0 32 2
D _add() 14 198 15
A _openFd() 5 24 3
A _closeFd() 0 14 2
B _addList() 0 64 6
C _addFileList() 0 108 14
F _addFile() 11 283 31
A _writeFileHeader() 6 44 3
B _writeCentralFileHeader() 6 63 4
A _writeCentralHeader() 0 22 2
B _list() 18 64 6
A _convertHeader2FileInfo() 0 28 1
F _extractByRule() 43 243 44
F _extractFile() 15 260 30
A _extractFileAsString() 0 52 4
B _readFileHeader() 29 120 6
C _readCentralFileHeader() 44 116 9
C _readEndCentralDir() 15 148 14
F _deleteByRule() 61 319 41
B _dirCheck() 0 44 9
F _merge() 23 226 17
B _duplicate() 7 62 6
B _check_parameters() 0 51 10
A _errorLog() 0 6 1
A _errorReset() 0 6 1
B _tool_PathReduction() 0 36 9
C _tool_PathInclusion() 0 78 17
C _tool_CopyBlock() 18 50 13
A _tool_Rename() 0 20 4
A _tool_TranslateWinPath() 0 19 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
108
    public $_zipname = '';
109
110
    /**
111
     * File descriptor of the opened Zip file.
112
     *
113
     * @var int Internal zip file descriptor
114
     */
115
116
    public $_zip_fd = 0;
117
118
    /**
119
     * @var int last error code
120
     */
121
122
    public $_error_code = 1;
123
124
    /**
125
     * @var string Last error description
126
     */
127
128
    public $_error_string = '';
129
130
    // {{{ constructor
131
132
    /**
133
     * Archive_Zip Class constructor. This flavour of the constructor only
134
     * declare a new Archive_Zip object, identifying it by the name of the
135
     * zip file.
136
     *
137
     * @param    string $p_zipname The name of the zip archive to create
138
     * @access public
139
     */
140
141
    //HACK by domifara
142
143
    //  function Archive_Zip($p_zipname)
144
145
    public function __construct($p_zipname)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
146
    {
147
        // ----- Check the zlib
148
149
        /*      if (!extension_loaded('zlib')) {
150
                  PEAR::loadExtension('zlib');
151
              }*/ // GIJ
152
153
        if (!extension_loaded('zlib')) {
154
            die("The extension 'zlib' couldn't be found.\n" . 'Please make sure your version of PHP was built ' . "with 'zlib' support.\n");
155
156
            return false;
0 ignored issues
show
Unused Code introduced by
return false; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
Bug introduced by
Constructors do not have meaningful return values, anything that is returned from here is discarded. Are you sure this is correct?
Loading history...
157
        }
158
159
        // ----- Set the attributes
160
161
        $this->_zipname = $p_zipname;
162
163
        $this->_zip_fd = 0;
164
    }
165
166
    // }}}
167
168
    // {{{ create()
169
170
    /**
171
     * This method creates a Zip Archive with the filename set with
172
     * the constructor.
173
     * The files and directories indicated in $p_filelist
174
     * are added in the archive.
175
     * When a directory is in the list, the directory and its content is added
176
     * in the archive.
177
     * The methods takes a variable list of parameters in $p_params.
178
     * The supported parameters for this method are :
179
     *   'add_path' : Add a path to the archived files.
180
     *   'remove_path' : Remove the specified 'root' path of the archived files.
181
     *   'remove_all_path' : Remove all the path of the archived files.
182
     *   'no_compression' : The archived files will not be compressed.
183
     *
184
     * @access public
185
     * @param  mixed $p_filelist   The list of the files or folders to add.
186
     *                             It can be a string with filenames separated
187
     *                             by a comma, or an array of filenames.
188
     * @param  mixed $p_params     An array of variable parameters and values.
189
     * @return mixed An array of file description on success,
190
     *                             an error code on error
191
     */
192
193
    public function create($p_filelist, $p_params = 0)
194
    {
195
        $this->_errorReset();
196
197
        // ----- Set default values
198
199
        if (0 === $p_params) {
200
            $p_params = [];
201
        }
202
203
        if (1 != $this->_check_parameters($p_params, [
204
                'no_compression' => false,
205
                'add_path' => '',
206
                'remove_path' => '',
207
                'remove_all_path' => false,
208
            ])) {
209
            return 0;
210
        }
211
212
        // ----- Look if the $p_filelist is really an array
213
214
        $p_result_list = [];
215
216 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...
217
            $v_result = $this->_create($p_filelist, $p_result_list, $p_params);
218
        } // ----- Look if the $p_filelist is a string
219
220
        elseif (is_string($p_filelist)) {
221
            // ----- Create a list with the elements from the string
222
223
            $v_list = explode(ARCHIVE_ZIP_SEPARATOR, $p_filelist);
224
225
            $v_result = $this->_create($v_list, $p_result_list, $p_params);
226
        } // ----- Invalid variable
227
228
        else {
229
            $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER, 'Invalid variable type p_filelist');
230
231
            $v_result = ARCHIVE_ZIP_ERR_INVALID_PARAMETER;
232
        }
233
234
        if (1 != $v_result) {
235
            return 0;
236
        }
237
238
        return $p_result_list;
239
    }
240
241
    // }}}
242
243
    // {{{ add()
244
245
    /**
246
     * This method add files or directory in an existing Zip Archive.
247
     * If the Zip Archive does not exist it is created.
248
     * The files and directories to add are indicated in $p_filelist.
249
     * When a directory is in the list, the directory and its content is added
250
     * in the archive.
251
     * The methods takes a variable list of parameters in $p_params.
252
     * The supported parameters for this method are :
253
     *   'add_path' : Add a path to the archived files.
254
     *   'remove_path' : Remove the specified 'root' path of the archived files.
255
     *   'remove_all_path' : Remove all the path of the archived files.
256
     *   'no_compression' : The archived files will not be compressed.
257
     *   'callback_pre_add' : A callback function that will be called before
258
     *                        each entry archiving.
259
     *   'callback_post_add' : A callback function that will be called after
260
     *                         each entry archiving.
261
     *
262
     * @access public
263
     * @param    mixed $p_filelist   The list of the files or folders to add.
264
     *                               It can be a string with filenames separated
265
     *                               by a comma, or an array of filenames.
266
     * @param    mixed $p_params     An array of variable parameters and values.
267
     * @return mixed An array of file description on success,
268
     *                               0 on an unrecoverable failure, an error code is logged.
269
     */
270
271
    public function add($p_filelist, $p_params = 0)
272
    {
273
        $this->_errorReset();
274
275
        // ----- Set default values
276
277
        if (0 === $p_params) {
278
            $p_params = [];
279
        }
280
281
        if (1 != $this->_check_parameters($p_params, [
282
                'no_compression' => false,
283
                'add_path' => '',
284
                'remove_path' => '',
285
                'remove_all_path' => false,
286
                'callback_pre_add' => '',
287
                'callback_post_add' => '',
288
            ])) {
289
            return 0;
290
        }
291
292
        // ----- Look if the $p_filelist is really an array
293
294
        $p_result_list = [];
295
296 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...
297
            // ----- Call the create fct
298
299
            $v_result = $this->_add($p_filelist, $p_result_list, $p_params);
300
        } // ----- Look if the $p_filelist is a string
301
302
        elseif (is_string($p_filelist)) {
303
            // ----- Create a list with the elements from the string
304
305
            $v_list = explode(ARCHIVE_ZIP_SEPARATOR, $p_filelist);
306
307
            // ----- Call the create fct
308
309
            $v_result = $this->_add($v_list, $p_result_list, $p_params);
310
        } // ----- Invalid variable
311
312
        else {
313
            $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER, 'add() : Invalid variable type p_filelist');
314
315
            $v_result = ARCHIVE_ZIP_ERR_INVALID_PARAMETER;
316
        }
317
318
        if (1 != $v_result) {
319
            return 0;
320
        }
321
322
        // ----- Return the result list
323
324
        return $p_result_list;
325
    }
326
327
    // }}}
328
329
    // {{{ listContent()
330
331
    /**
332
     * This method gives the names and properties of the files and directories
333
     * which are present in the zip archive.
334
     * The properties of each entries in the list are :
335
     *   filename : Name of the file.
336
     *              For create() or add() it's the filename given by the user.
337
     *              For an extract() it's the filename of the extracted file.
338
     *   stored_filename : Name of the file / directory stored in the archive.
339
     *   size : Size of the stored file.
340
     *   compressed_size : Size of the file's data compressed in the archive
341
     *                     (without the zip headers overhead)
342
     *   mtime : Last known modification date of the file (UNIX timestamp)
343
     *   comment : Comment associated with the file
344
     *   folder : true | false (indicates if the entry is a folder)
345
     *   index : index of the file in the archive (-1 when not available)
346
     *   status : status of the action on the entry (depending of the action) :
347
     *            Values are :
348
     *              ok : OK !
349
     *              filtered : the file/dir was not extracted (filtered by user)
350
     *              already_a_directory : the file can't be extracted because a
351
     *                                    directory with the same name already
352
     *                                    exists
353
     *              write_protected : the file can't be extracted because a file
354
     *                                with the same name already exists and is
355
     *                                write protected
356
     *              newer_exist : the file was not extracted because a newer
357
     *                            file already exists
358
     *              path_creation_fail : the file is not extracted because the
359
     *                                   folder does not exists and can't be
360
     *                                   created
361
     *              write_error : the file was not extracted because there was a
362
     *                            error while writing the file
363
     *              read_error : the file was not extracted because there was a
364
     *                           error while reading the file
365
     *              invalid_header : the file was not extracted because of an
366
     *                               archive format error (bad file header)
367
     * Note that each time a method can continue operating when there
368
     * is an error on a single file, the error is only logged in the file status.
369
     *
370
     * @access public
371
     * @return mixed An array of file description on success,
372
     *               0 on an unrecoverable failure, an error code is logged.
373
     */
374
375
    public function listContent()
376
    {
377
        $this->_errorReset();
378
379
        // ----- Check archive
380
381
        if (!$this->_checkFormat()) {
382
            return 0;
383
        }
384
385
        $v_list = [];
386
387
        if (1 != $this->_list($v_list)) {
388
            unset($v_list);
389
390
            return 0;
391
        }
392
393
        return $v_list;
394
    }
395
396
    // }}}
397
398
    // {{{ extract()
399
400
    /**
401
     * This method extract the files and folders which are in the zip archive.
402
     * It can extract all the archive or a part of the archive by using filter
403
     * feature (extract by name, by index, by ereg, by preg). The extraction
404
     * can occur in the current path or an other path.
405
     * All the advanced features are activated by the use of variable
406
     * parameters.
407
     * The return value is an array of entry descriptions which gives
408
     * information on extracted files (See listContent()).
409
     * The method may return a success value (an array) even if some files
410
     * are not correctly extracted (see the file status in listContent()).
411
     * The supported variable parameters for this method are :
412
     *   'add_path' : Path where the files and directories are to be extracted
413
     *   'remove_path' : First part ('root' part) of the memorized path
414
     *                   (if similar) to remove while extracting.
415
     *   'remove_all_path' : Remove all the memorized path while extracting.
416
     *   'extract_as_string' :
417
     *   'set_chmod' : After the extraction of the file the indicated mode
418
     *                 will be set.
419
     *   'by_name' : It can be a string with file/dir names separated by ',',
420
     *               or an array of file/dir names to extract from the archive.
421
     *   'by_index' : A string with range of indexes separated by ',',
422
     *                (sample "1,3-5,12").
423
     *   'by_ereg' : A regular expression (ereg) that must match the extracted
424
     *               filename.
425
     *   'by_preg' : A regular expression (preg) that must match the extracted
426
     *               filename.
427
     *   'callback_pre_extract' : A callback function that will be called before
428
     *                            each entry extraction.
429
     *   'callback_post_extract' : A callback function that will be called after
430
     *                            each entry extraction.
431
     *
432
     * @access public
433
     * @param    mixed $p_params An array of variable parameters and values.
434
     * @return mixed An array of file description on success,
435
     *                           0 on an unrecoverable failure, an error code is logged.
436
     */
437
438
    public function extract($p_params = 0)
439
    {
440
        $this->_errorReset();
441
442
        // ----- Check archive
443
444
        if (!$this->_checkFormat()) {
445
            return 0;
446
        }
447
448
        // ----- Set default values
449
450
        if (0 === $p_params) {
451
            $p_params = [];
452
        }
453
454
        if (1 != $this->_check_parameters($p_params, [
455
                'extract_as_string' => false,
456
                'add_path' => '',
457
                'remove_path' => '',
458
                'remove_all_path' => false,
459
                'callback_pre_extract' => '',
460
                'callback_post_extract' => '',
461
                'set_chmod' => 0,
462
                'by_name' => '',
463
                'by_index' => '',
464
                'by_ereg' => '',
465
                'by_preg' => '',
466
            ])) {
467
            return 0;
468
        }
469
470
        // ----- Call the extracting fct
471
472
        $v_list = [];
473
474
        if (1 != $this->_extractByRule($v_list, $p_params)) {
475
            unset($v_list);
476
477
            return 0;
478
        }
479
480
        return $v_list;
481
    }
482
483
    // }}}
484
485
    // {{{ delete()
486
487
    /**
488
     * This methods delete archive entries in the zip archive.
489
     * Notice that at least one filtering rule (set by the variable parameter
490
     * list) must be set.
491
     * Also notice that if you delete a folder entry, only the folder entry
492
     * is deleted, not all the files bellonging to this folder.
493
     * The supported variable parameters for this method are :
494
     *   'by_name' : It can be a string with file/dir names separated by ',',
495
     *               or an array of file/dir names to delete from the archive.
496
     *   'by_index' : A string with range of indexes separated by ',',
497
     *                (sample "1,3-5,12").
498
     *   'by_ereg' : A regular expression (ereg) that must match the extracted
499
     *               filename.
500
     *   'by_preg' : A regular expression (preg) that must match the extracted
501
     *               filename.
502
     *
503
     * @access public
504
     * @param    mixed $p_params An array of variable parameters and values.
505
     * @return mixed An array of file description on success,
506
     *                           0 on an unrecoverable failure, an error code is logged.
507
     */
508
509
    public function delete($p_params)
510
    {
511
        $this->_errorReset();
512
513
        // ----- Check archive
514
515
        if (!$this->_checkFormat()) {
516
            return 0;
517
        }
518
519
        // ----- Set default values
520
521
        if (1 != $this->_check_parameters($p_params, [
522
                'by_name' => '',
523
                'by_index' => '',
524
                'by_ereg' => '',
525
                'by_preg' => '',
526
            ])) {
527
            return 0;
528
        }
529
530
        // ----- Check that at least one rule is set
531
532
        if (('' == $p_params['by_name'])
533
            && ('' == $p_params['by_index'])
534
            && ('' == $p_params['by_ereg'])
535
            && ('' == $p_params['by_preg'])) {
536
            $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER, 'At least one filtering rule must' . ' be set as parameter');
537
538
            return 0;
539
        }
540
541
        // ----- Call the delete fct
542
543
        $v_list = [];
544
545
        if (1 != $this->_deleteByRule($v_list, $p_params)) {
546
            unset($v_list);
547
548
            return 0;
549
        }
550
551
        return $v_list;
552
    }
553
554
    // }}}
555
556
    // {{{ properties()
557
558
    /**
559
     * This method gives the global properties of the archive.
560
     *  The properties are :
561
     *    nb : Number of files in the archive
562
     *    comment : Comment associated with the archive file
563
     *    status : not_exist, ok
564
     *
565
     * @access   public
566
     * @return mixed An array with the global properties or 0 on error.
567
     * @internal param mixed $p_params {Description}
568
     */
569
570
    public function properties()
571
    {
572
        $this->_errorReset();
573
574
        // ----- Check archive
575
576
        if (!$this->_checkFormat()) {
577
            return 0;
578
        }
579
580
        // ----- Default properties
581
582
        $v_prop = [];
583
584
        $v_prop['comment'] = '';
585
586
        $v_prop['nb'] = 0;
587
588
        $v_prop['status'] = 'not_exist';
589
590
        // ----- Look if file exists
591
592
        if (@is_file($this->_zipname)) {
593
            // ----- Open the zip file
594
595
            if (0 == ($this->_zip_fd = @fopen($this->_zipname, 'rb'))) {
596
                $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \'' . $this->_zipname . '\' in binary read mode');
597
598
                return 0;
599
            }
600
601
            // ----- Read the central directory informations
602
603
            $v_central_dir = [];
604
605
            if (1 != ($v_result = $this->_readEndCentralDir($v_central_dir))) {
606
                return 0;
607
            }
608
609
            $this->_closeFd();
610
611
            // ----- Set the user attributes
612
613
            $v_prop['comment'] = $v_central_dir['comment'];
614
615
            $v_prop['nb'] = $v_central_dir['entries'];
616
617
            $v_prop['status'] = 'ok';
618
        }
619
620
        return $v_prop;
621
    }
622
623
    // }}}
624
625
    // {{{ duplicate()
626
627
    /**
628
     * This method creates an archive by copying the content of an other one.
629
     * If the archive already exist, it is replaced by the new one without
630
     * any warning.
631
     *
632
     * @access public
633
     * @param  mixed $p_archive   It can be a valid Archive_Zip object or
634
     *                            the filename of a valid zip archive.
635
     * @return int 1 on success, 0 on failure.
636
     */
637
638
    public function duplicate($p_archive)
639
    {
640
        $this->_errorReset();
641
642
        // ----- Look if the $p_archive is a Archive_Zip object
643
644
        if (is_object($p_archive)
645
            && ('archive_zip' == mb_strtolower(get_class($p_archive)))) {
646
            $v_result = $this->_duplicate($p_archive->_zipname);
647
        } // ----- Look if the $p_archive is a string (so a filename)
648
649
        elseif (is_string($p_archive)) {
650
            // ----- Check that $p_archive is a valid zip file
651
652
            // TBC : Should also check the archive format
653
654
            if (!is_file($p_archive)) {
655
                $this->_errorLog(ARCHIVE_ZIP_ERR_MISSING_FILE, "No file with filename '" . $p_archive . "'");
656
657
                $v_result = ARCHIVE_ZIP_ERR_MISSING_FILE;
658
            } else {
659
                $v_result = $this->_duplicate($p_archive);
660
            }
661
        } // ----- Invalid variable
662
663
        else {
664
            $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER, 'Invalid variable type p_archive_to_add');
665
666
            $v_result = ARCHIVE_ZIP_ERR_INVALID_PARAMETER;
667
        }
668
669
        return $v_result;
670
    }
671
672
    // }}}
673
674
    // {{{ merge()
675
676
    /**
677
     *  This method merge a valid zip archive at the end of the
678
     *  archive identified by the Archive_Zip object.
679
     *  If the archive ($this) does not exist, the merge becomes a duplicate.
680
     *  If the archive to add does not exist, the merge is a success.
681
     *
682
     * @access public
683
     * @param mixed $p_archive_to_add  It can be a valid Archive_Zip object or
684
     *                                 the filename of a valid zip archive.
685
     * @return int 1 on success, 0 on failure.
686
     */
687
688
    public function merge($p_archive_to_add)
689
    {
690
        $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...
691
692
        $this->_errorReset();
693
694
        // ----- Check archive
695
696
        if (!$this->_checkFormat()) {
697
            return 0;
698
        }
699
700
        // ----- Look if the $p_archive_to_add is a Archive_Zip object
701
702
        if (is_object($p_archive_to_add)
703
            && ('archive_zip' == mb_strtolower(get_class($p_archive_to_add)))) {
704
            $v_result = $this->_merge($p_archive_to_add);
705
        } // ----- Look if the $p_archive_to_add is a string (so a filename)
706
707
        elseif (is_string($p_archive_to_add)) {
708
            // ----- Create a temporary archive
709
710
            $v_object_archive = new self($p_archive_to_add);
711
712
            // ----- Merge the archive
713
714
            $v_result = $this->_merge($v_object_archive);
715
        } // ----- Invalid variable
716
717
        else {
718
            $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER, 'Invalid variable type p_archive_to_add');
719
720
            $v_result = ARCHIVE_ZIP_ERR_INVALID_PARAMETER;
721
        }
722
723
        return $v_result;
724
    }
725
726
    // }}}
727
728
    // {{{ errorCode()
729
730
    /**
731
     * Method that gives the lastest error code.
732
     *
733
     * @access public
734
     * @return int The error code value.
735
     */
736
737
    public function errorCode()
738
    {
739
        return $this->_error_code;
740
    }
741
742
    // }}}
743
744
    // {{{ errorName()
745
746
    /**
747
     * This method gives the latest error code name.
748
     *
749
     * @access public
750
     * @param  bool $p_with_code If true, gives the name and the int value.
751
     * @return string The error name.
752
     */
753
754
    public function errorName($p_with_code = false)
755
    {
756
        $v_const_list = get_defined_constants();
757
758
        // ----- Extract error constants from all const.
759
760
        for (reset($v_const_list); list($v_key, $v_value) = each($v_const_list);) {
761
            if ('ARCHIVE_ZIP_ERR_' == mb_substr($v_key, 0, mb_strlen('ARCHIVE_ZIP_ERR_'))) {
762
                $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...
763
            }
764
        }
765
766
        // ----- Search the name form the code value
767
768
        $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...
769
770
        if (false != $v_key) {
771
            $v_value = $v_key;
772
        } else {
773
            $v_value = 'NoName';
774
        }
775
776
        if ($p_with_code) {
777
            return ($v_value . ' (' . $this->_error_code . ')');
778
        }
779
780
        return $v_value;
781
    }
782
783
    // }}}
784
785
    // {{{ errorInfo()
786
787
    /**
788
     * This method returns the description associated with the latest error.
789
     *
790
     * @access public
791
     * @param  bool $p_full If set to true gives the description with the
792
     *                         error code, the name and the description.
793
     *                         If set to false gives only the description
794
     *                         and the error code.
795
     * @return string The error description.
796
     */
797
798
    public function errorInfo($p_full = false)
799
    {
800
        if ($p_full) {
801
            return ($this->errorName(true) . ' : ' . $this->_error_string);
802
        }
803
804
        return ($this->_error_string . ' [code ' . $this->_error_code . ']');
805
    }
806
807
    // }}}
808
809
    // -----------------------------------------------------------------------------
810
811
    // ***** UNDER THIS LINE ARE DEFINED PRIVATE INTERNAL FUNCTIONS *****
812
813
    // *****                                                        *****
814
815
    // *****       THESES FUNCTIONS MUST NOT BE USED DIRECTLY       *****
816
817
    // -----------------------------------------------------------------------------
818
819
    // ---------------------------------------------------------------------------
820
821
    // Function : _checkFormat()
822
823
    // Description :
824
825
    //   This method check that the archive exists and is a valid zip archive.
826
827
    //   Several level of check exists. (futur)
828
829
    // Parameters :
830
831
    //   $p_level : Level of check. Default 0.
832
833
    //              0 : Check the first bytes (magic codes) (default value))
834
835
    //              1 : 0 + Check the central directory (futur)
836
837
    //              2 : 1 + Check each file header (futur)
838
839
    // Return Values :
840
841
    //   true on success,
842
843
    //   false on error, the error code is set.
844
845
    // ---------------------------------------------------------------------------
846
847
    /**
848
     * Archive_Zip::_checkFormat()
849
     *
850
     * { Description }
851
     *
852
     * @param int $p_level
853
     * @return bool
854
     */
855
856
    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...
857
    {
858
        $v_result = true;
859
860
        // ----- Reset the error handler
861
862
        $this->_errorReset();
863
864
        // ----- Look if the file exits
865
866
        if (!is_file($this->_zipname)) {
867
            // ----- Error log
868
869
            $this->_errorLog(ARCHIVE_ZIP_ERR_MISSING_FILE, "Missing archive file '" . $this->_zipname . "'");
870
871
            return false;
872
        }
873
874
        // ----- Check that the file is readeable
875
876
        if (!is_readable($this->_zipname)) {
877
            // ----- Error log
878
879
            $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, "Unable to read archive '" . $this->_zipname . "'");
880
881
            return false;
882
        }
883
884
        // ----- Check the magic code
885
886
        // TBC
887
888
        // ----- Check the central header
889
890
        // TBC
891
892
        // ----- Check each file header
893
894
        // TBC
895
896
        // ----- Return
897
898
        return $v_result;
899
    }
900
901
    // ---------------------------------------------------------------------------
902
903
    // ---------------------------------------------------------------------------
904
905
    // Function : _create()
906
907
    // Description :
908
909
    // Parameters :
910
911
    // Return Values :
912
913
    // ---------------------------------------------------------------------------
914
915
    /**
916
     * Archive_Zip::_create()
917
     *
918
     * { Description }
919
     * @param $p_list
920
     * @param mixed $p_result_list
921
     * @param mixed $p_params
922
     * @return int
923
     */
924
925
    public function _create($p_list, &$p_result_list, &$p_params)
926
    {
927
        $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...
928
929
        $v_list_detail = [];
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...
930
931
        $p_add_dir = $p_params['add_path'];
932
933
        $p_remove_dir = $p_params['remove_path'];
934
935
        $p_remove_all_dir = $p_params['remove_all_path'];
936
937
        // ----- Open the file in write mode
938
939
        if (1 != ($v_result = $this->_openFd('wb'))) {
940
            // ----- Return
941
942
            return $v_result;
943
        }
944
945
        // ----- Add the list of files
946
947
        $v_result = $this->_addList($p_list, $p_result_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, $p_params);
948
949
        // ----- Close
950
951
        $this->_closeFd();
952
953
        // ----- Return
954
955
        return $v_result;
956
    }
957
958
    // ---------------------------------------------------------------------------
959
960
    // ---------------------------------------------------------------------------
961
962
    // Function : _add()
963
964
    // Description :
965
966
    // Parameters :
967
968
    // Return Values :
969
970
    // ---------------------------------------------------------------------------
971
972
    /**
973
     * Archive_Zip::_add()
974
     *
975
     * { Description }
976
     * @param $p_list
977
     * @param mixed $p_result_list
978
     * @param mixed $p_params
979
     * @return int
980
     */
981
982
    public function _add($p_list, &$p_result_list, &$p_params)
983
    {
984
        $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...
985
986
        $v_list_detail = [];
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...
987
988
        $p_add_dir = $p_params['add_path'];
989
990
        $p_remove_dir = $p_params['remove_path'];
991
992
        $p_remove_all_dir = $p_params['remove_all_path'];
993
994
        // ----- Look if the archive exists or is empty and need to be created
995
996
        if ((!is_file($this->_zipname)) || (0 == filesize($this->_zipname))) {
997
            $v_result = $this->_create($p_list, $p_result_list, $p_params);
998
999
            return $v_result;
1000
        }
1001
1002
        // ----- Open the zip file
1003
1004
        if (1 != ($v_result = $this->_openFd('rb'))) {
1005
            return $v_result;
1006
        }
1007
1008
        // ----- Read the central directory informations
1009
1010
        $v_central_dir = [];
1011
1012
        if (1 != ($v_result = $this->_readEndCentralDir($v_central_dir))) {
1013
            $this->_closeFd();
1014
1015
            return $v_result;
1016
        }
1017
1018
        // ----- Go to beginning of File
1019
1020
        @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...
1021
1022
        // ----- Creates a temporay file
1023
1024
        $v_zip_temp_name = ARCHIVE_ZIP_TEMPORARY_DIR . uniqid('archive_zip-') . '.tmp';
1025
1026
        // ----- Open the temporary file in write mode
1027
1028 View Code Duplication
        if (0 == ($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb'))) {
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...
1029
            $this->_closeFd();
1030
1031
            $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \'' . $v_zip_temp_name . '\' in binary write mode');
1032
1033
            return self::errorCode();
1034
        }
1035
1036
        // ----- Copy the files from the archive to the temporary file
1037
1038
        // TBC : Here I should better append the file and go back to erase the
1039
1040
        // central dir
1041
1042
        $v_size = $v_central_dir['offset'];
1043
1044
        while (0 != $v_size) {
1045
            $v_read_size = ($v_size < ARCHIVE_ZIP_READ_BLOCK_SIZE ? $v_size : ARCHIVE_ZIP_READ_BLOCK_SIZE);
1046
1047
            $v_buffer = fread($this->_zip_fd, $v_read_size);
1048
1049
            @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...
1050
1051
            $v_size -= $v_read_size;
1052
        }
1053
1054
        // ----- Swap the file descriptor
1055
1056
        // Here is a trick : I swap the temporary fd with the zip fd, in order to
1057
1058
        // use the following methods on the temporary fil and not the real archive
1059
1060
        $v_swap = $this->_zip_fd;
1061
1062
        $this->_zip_fd = $v_zip_temp_fd;
1063
1064
        $v_zip_temp_fd = $v_swap;
1065
1066
        // ----- Add the files
1067
1068
        $v_header_list = [];
1069
1070
        if (1 != ($v_result = $this->_addFileList($p_list, $v_header_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, $p_params))) {
1071
            fclose($v_zip_temp_fd);
1072
1073
            $this->_closeFd();
1074
1075
            @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...
1076
1077
            // ----- Return
1078
1079
            return $v_result;
1080
        }
1081
1082
        // ----- Store the offset of the central dir
1083
1084
        $v_offset = @ftell($this->_zip_fd);
1085
1086
        // ----- Copy the block of file headers from the old archive
1087
1088
        $v_size = $v_central_dir['size'];
1089
1090 View Code Duplication
        while (0 != $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...
1091
            $v_read_size = ($v_size < ARCHIVE_ZIP_READ_BLOCK_SIZE ? $v_size : ARCHIVE_ZIP_READ_BLOCK_SIZE);
1092
1093
            $v_buffer = @fread($v_zip_temp_fd, $v_read_size);
1094
1095
            @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...
1096
1097
            $v_size -= $v_read_size;
1098
        }
1099
1100
        // ----- Create the Central Dir files header
1101
1102
        for ($i = 0, $v_count = 0; $i < count($v_header_list); ++$i) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
1103
            // ----- Create the file header
1104
1105
            if ('ok' == $v_header_list[$i]['status']) {
1106
                if (1 != ($v_result = $this->_writeCentralFileHeader($v_header_list[$i]))) {
1107
                    fclose($v_zip_temp_fd);
1108
1109
                    $this->_closeFd();
1110
1111
                    @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...
1112
1113
                    // ----- Return
1114
1115
                    return $v_result;
1116
                }
1117
1118
                $v_count++;
1119
            }
1120
1121
            // ----- Transform the header to a 'usable' info
1122
1123
            $this->_convertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);
1124
        }
1125
1126
        // ----- Zip file comment
1127
1128
        $v_comment = '';
1129
1130
        // ----- Calculate the size of the central header
1131
1132
        $v_size = @ftell($this->_zip_fd) - $v_offset;
1133
1134
        // ----- Create the central dir footer
1135
1136
        if (1 != ($v_result = $this->_writeCentralHeader($v_count + $v_central_dir['entries'], $v_size, $v_offset, $v_comment))) {
1137
            // ----- Reset the file list
1138
1139
            unset($v_header_list);
1140
1141
            // ----- Return
1142
1143
            return $v_result;
1144
        }
1145
1146
        // ----- Swap back the file descriptor
1147
1148
        $v_swap = $this->_zip_fd;
1149
1150
        $this->_zip_fd = $v_zip_temp_fd;
1151
1152
        $v_zip_temp_fd = $v_swap;
1153
1154
        // ----- Close
1155
1156
        $this->_closeFd();
1157
1158
        // ----- Close the temporary file
1159
1160
        @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...
1161
1162
        // ----- Delete the zip file
1163
1164
        // TBC : I should test the result ...
1165
1166
        @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...
1167
1168
        // ----- Rename the temporary file
1169
1170
        // TBC : I should test the result ...
1171
1172
        //@rename($v_zip_temp_name, $this->_zipname);
1173
1174
        $this->_tool_Rename($v_zip_temp_name, $this->_zipname);
1175
1176
        // ----- Return
1177
1178
        return $v_result;
1179
    }
1180
1181
    // ---------------------------------------------------------------------------
1182
1183
    // ---------------------------------------------------------------------------
1184
1185
    // Function : _openFd()
1186
1187
    // Description :
1188
1189
    // Parameters :
1190
1191
    // ---------------------------------------------------------------------------
1192
1193
    /**
1194
     * Archive_Zip::_openFd()
1195
     *
1196
     * { Description }
1197
     * @param $p_mode
1198
     * @return int
1199
     */
1200
1201
    public function _openFd($p_mode)
1202
    {
1203
        $v_result = 1;
1204
1205
        // ----- Look if already open
1206
1207
        if (0 != $this->_zip_fd) {
1208
            $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, 'Zip file \'' . $this->_zipname . '\' already open');
1209
1210
            return self::errorCode();
1211
        }
1212
1213
        // ----- Open the zip file
1214
1215 View Code Duplication
        if (0 == ($this->_zip_fd = @fopen($this->_zipname, $p_mode))) {
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...
1216
            $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \'' . $this->_zipname . '\' in ' . $p_mode . ' mode');
1217
1218
            return self::errorCode();
1219
        }
1220
1221
        // ----- Return
1222
1223
        return $v_result;
1224
    }
1225
1226
    // ---------------------------------------------------------------------------
1227
1228
    // ---------------------------------------------------------------------------
1229
1230
    // Function : _closeFd()
1231
1232
    // Description :
1233
1234
    // Parameters :
1235
1236
    // ---------------------------------------------------------------------------
1237
1238
    /**
1239
     * Archive_Zip::_closeFd()
1240
     *
1241
     * { Description }
1242
     */
1243
1244
    public function _closeFd()
1245
    {
1246
        $v_result = 1;
1247
1248
        if (0 != $this->_zip_fd) {
1249
            @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...
1250
        }
1251
1252
        $this->_zip_fd = 0;
1253
1254
        // ----- Return
1255
1256
        return $v_result;
1257
    }
1258
1259
    // ---------------------------------------------------------------------------
1260
1261
    // ---------------------------------------------------------------------------
1262
1263
    // Function : _addList()
1264
1265
    // Description :
1266
1267
    //   $p_add_dir and $p_remove_dir will give the ability to memorize a path which is
1268
1269
    //   different from the real path of the file. This is usefull if you want to have PclTar
1270
1271
    //   running in any directory, and memorize relative path from an other directory.
1272
1273
    // Parameters :
1274
1275
    //   $p_list : An array containing the file or directory names to add in the tar
1276
1277
    //   $p_result_list : list of added files with their properties (specially the status field)
1278
1279
    //   $p_add_dir : Path to add in the filename path archived
1280
1281
    //   $p_remove_dir : Path to remove in the filename path archived
1282
1283
    // Return Values :
1284
1285
    // ---------------------------------------------------------------------------
1286
1287
    /**
1288
     * Archive_Zip::_addList()
1289
     *
1290
     * { Description }
1291
     * @param $p_list
1292
     * @param $p_add_dir
1293
     * @param $p_remove_dir
1294
     * @param $p_remove_all_dir
1295
     * @param mixed $p_result_list
1296
     * @param mixed $p_params
1297
     * @return int
1298
     */
1299
1300
    public function _addList(
1301
        $p_list,
1302
        &$p_result_list,
1303
        $p_add_dir,
1304
        $p_remove_dir,
1305
        $p_remove_all_dir,
1306
        &$p_params
1307
    ) {
1308
        $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...
1309
1310
        // ----- Add the files
1311
1312
        $v_header_list = [];
1313
1314
        if (1 != ($v_result = $this->_addFileList($p_list, $v_header_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, $p_params))) {
1315
            return $v_result;
1316
        }
1317
1318
        // ----- Store the offset of the central dir
1319
1320
        $v_offset = @ftell($this->_zip_fd);
1321
1322
        // ----- Create the Central Dir files header
1323
1324
        for ($i = 0, $v_count = 0; $i < count($v_header_list); ++$i) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
1325
            // ----- Create the file header
1326
1327
            if ('ok' == $v_header_list[$i]['status']) {
1328
                if (1 != ($v_result = $this->_writeCentralFileHeader($v_header_list[$i]))) {
1329
                    return $v_result;
1330
                }
1331
1332
                $v_count++;
1333
            }
1334
1335
            // ----- Transform the header to a 'usable' info
1336
1337
            $this->_convertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);
1338
        }
1339
1340
        // ----- Zip file comment
1341
1342
        $v_comment = '';
1343
1344
        // ----- Calculate the size of the central header
1345
1346
        $v_size = @ftell($this->_zip_fd) - $v_offset;
1347
1348
        // ----- Create the central dir footer
1349
1350
        if (1 != ($v_result = $this->_writeCentralHeader($v_count, $v_size, $v_offset, $v_comment))) {
1351
            // ----- Reset the file list
1352
1353
            unset($v_header_list);
1354
1355
            // ----- Return
1356
1357
            return $v_result;
1358
        }
1359
1360
        // ----- Return
1361
1362
        return $v_result;
1363
    }
1364
1365
    // ---------------------------------------------------------------------------
1366
1367
    // ---------------------------------------------------------------------------
1368
1369
    // Function : _addFileList()
1370
1371
    // Description :
1372
1373
    //   $p_add_dir and $p_remove_dir will give the ability to memorize a path which is
1374
1375
    //   different from the real path of the file. This is usefull if you want to
1376
1377
    //   run the lib in any directory, and memorize relative path from an other directory.
1378
1379
    // Parameters :
1380
1381
    //   $p_list : An array containing the file or directory names to add in the tar
1382
1383
    //   $p_result_list : list of added files with their properties (specially the status field)
1384
1385
    //   $p_add_dir : Path to add in the filename path archived
1386
1387
    //   $p_remove_dir : Path to remove in the filename path archived
1388
1389
    // Return Values :
1390
1391
    // ---------------------------------------------------------------------------
1392
1393
    /**
1394
     * Archive_Zip::_addFileList()
1395
     *
1396
     * { Description }
1397
     * @param $p_list
1398
     * @param $p_add_dir
1399
     * @param $p_remove_dir
1400
     * @param $p_remove_all_dir
1401
     * @param mixed $p_result_list
1402
     * @param mixed $p_params
1403
     * @return int
1404
     */
1405
1406
    public function _addFileList(
1407
        $p_list,
1408
        &$p_result_list,
1409
        $p_add_dir,
1410
        $p_remove_dir,
1411
        $p_remove_all_dir,
1412
        &$p_params
1413
    ) {
1414
        $v_result = 1;
1415
1416
        $v_header = [];
1417
1418
        // ----- Recuperate the current number of elt in list
1419
1420
        $v_nb = count($p_result_list);
1421
1422
        // ----- Loop on the files
1423
1424
        for ($j = 0; ($j < count($p_list)) && (1 == $v_result); $j++) {
1425
            // ----- Recuperate the filename
1426
1427
            $p_filename = $this->_tool_TranslateWinPath($p_list[$j], false);
1428
1429
            // ----- Skip empty file names
1430
1431
            if ('' == $p_filename) {
1432
                continue;
1433
            }
1434
1435
            // ----- Check the filename
1436
1437
            if (!file_exists($p_filename)) {
1438
                $this->_errorLog(ARCHIVE_ZIP_ERR_MISSING_FILE, "File '$p_filename' does not exists");
1439
1440
                return self::errorCode();
1441
            }
1442
1443
            // ----- Look if it is a file or a dir with no all pathnre move
1444
1445
            if (is_file($p_filename) || (is_dir($p_filename) && !$p_remove_all_dir)) {
1446
                // ----- Add the file
1447
1448
                if (1 != ($v_result = $this->_addFile($p_filename, $v_header, $p_add_dir, $p_remove_dir, $p_remove_all_dir, $p_params))) {
1449
                    // ----- Return status
1450
1451
                    return $v_result;
1452
                }
1453
1454
                // ----- Store the file infos
1455
1456
                $p_result_list[$v_nb++] = $v_header;
1457
            }
1458
1459
            // ----- Look for directory
1460
1461
            if (is_dir($p_filename)) {
1462
                // ----- Look for path
1463
1464
                if ('.' != $p_filename) {
1465
                    $v_path = $p_filename . '/';
1466
                } else {
1467
                    $v_path = '';
1468
                }
1469
1470
                // ----- Read the directory for files and sub-directories
1471
1472
                $p_hdir = opendir($p_filename);
1473
1474
                $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...
1475
                $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...
1476
                while ($p_hitem = readdir($p_hdir)) {
1477
                    // ----- Look for a file
1478
1479
                    if (is_file($v_path . $p_hitem)) {
1480
                        // ----- Add the file
1481
1482
                        if (1 != ($v_result = $this->_addFile($v_path . $p_hitem, $v_header, $p_add_dir, $p_remove_dir, $p_remove_all_dir, $p_params))) {
1483
                            // ----- Return status
1484
1485
                            return $v_result;
1486
                        }
1487
1488
                        // ----- Store the file infos
1489
1490
                        $p_result_list[$v_nb++] = $v_header;
1491
                    } // ----- Recursive call to _addFileList()
1492
1493
                    else {
1494
                        // ----- Need an array as parameter
1495
1496
                        $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...
1497
1498
                        $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...
1499
1500
                        // ----- Update the number of elements of the list
1501
1502
                        $v_nb = count($p_result_list);
1503
                    }
1504
                }
1505
1506
                // ----- Free memory for the recursive loop
1507
1508
                unset($p_temp_list, $p_hdir, $p_hitem);
1509
            }
1510
        }
1511
1512
        return $v_result;
1513
    }
1514
1515
    // ---------------------------------------------------------------------------
1516
1517
    // ---------------------------------------------------------------------------
1518
1519
    // Function : _addFile()
1520
1521
    // Description :
1522
1523
    // Parameters :
1524
1525
    // Return Values :
1526
1527
    // ---------------------------------------------------------------------------
1528
1529
    /**
1530
     * Archive_Zip::_addFile()
1531
     *
1532
     * { Description }
1533
     * @param $p_filename
1534
     * @param $p_add_dir
1535
     * @param $p_remove_dir
1536
     * @param $p_remove_all_dir
1537
     * @param $p_params
1538
     * @param mixed $p_header
1539
     * @return int
1540
     */
1541
1542
    public function _addFile($p_filename, &$p_header, $p_add_dir, $p_remove_dir, $p_remove_all_dir, $p_params)
1543
    {
1544
        $v_result = 1;
1545
1546
        if ('' == $p_filename) {
1547
            // ----- Error log
1548
1549
            $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER, 'Invalid file list parameter (invalid or empty list)');
1550
1551
            // ----- Return
1552
1553
            return self::errorCode();
1554
        }
1555
1556
        // ----- Calculate the stored filename
1557
1558
        $v_stored_filename = $p_filename;
1559
1560
        // ----- Look for all path to remove
1561
1562
        if ($p_remove_all_dir) {
1563
            $v_stored_filename = basename($p_filename);
1564
        } // ----- Look for partial path remove
1565
1566
        elseif ('' != $p_remove_dir) {
1567
            if ('/' != mb_substr($p_remove_dir, -1)) {
1568
                $p_remove_dir .= '/';
1569
            }
1570
1571
            if (('./' == mb_substr($p_filename, 0, 2)) || ('./' == mb_substr($p_remove_dir, 0, 2))) {
1572 View Code Duplication
                if (('./' == mb_substr($p_filename, 0, 2)) && ('./' != mb_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...
1573
                    $p_remove_dir = './' . $p_remove_dir;
1574
                }
1575
1576 View Code Duplication
                if (('./' != mb_substr($p_filename, 0, 2)) && ('./' == mb_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...
1577
                    $p_remove_dir = mb_substr($p_remove_dir, 2);
1578
                }
1579
            }
1580
1581
            $v_compare = $this->_tool_PathInclusion($p_remove_dir, $p_filename);
1582
1583
            if ($v_compare > 0) {
1584
                //      if (substr($p_filename, 0, strlen($p_remove_dir)) == $p_remove_dir)
1585
1586
                if (2 == $v_compare) {
1587
                    $v_stored_filename = '';
1588
                } else {
1589
                    $v_stored_filename = mb_substr($p_filename, mb_strlen($p_remove_dir));
1590
                }
1591
            }
1592
        }
1593
1594
        // ----- Look for path to add
1595
1596
        if ('' != $p_add_dir) {
1597
            if ('/' == mb_substr($p_add_dir, -1)) {
1598
                $v_stored_filename = $p_add_dir . $v_stored_filename;
1599
            } else {
1600
                $v_stored_filename = $p_add_dir . '/' . $v_stored_filename;
1601
            }
1602
        }
1603
1604
        // ----- Filename (reduce the path of stored name)
1605
1606
        $v_stored_filename = $this->_tool_PathReduction($v_stored_filename);
1607
1608
        /* filename length moved after call-back in release 1.3
1609
        // ----- Check the path length
1610
        if (strlen($v_stored_filename) > 0xFF)
1611
        {
1612
          // ----- Error log
1613
          $this->_errorLog(-5, "Stored file name is too long (max. 255) : '$v_stored_filename'");
1614
1615
          // ----- Return
1616
          return Archive_Zip::errorCode();
1617
        }
1618
        */
1619
1620
        // ----- Set the file properties
1621
1622
        clearstatcache();
1623
1624
        $p_header['version'] = 20;
1625
1626
        $p_header['version_extracted'] = 10;
1627
1628
        $p_header['flag'] = 0;
1629
1630
        $p_header['compression'] = 0;
1631
1632
        $p_header['mtime'] = filemtime($p_filename);
1633
1634
        $p_header['crc'] = 0;
1635
1636
        $p_header['compressed_size'] = 0;
1637
1638
        $p_header['size'] = filesize($p_filename);
1639
1640
        $p_header['filename_len'] = mb_strlen($p_filename);
1641
1642
        $p_header['extra_len'] = 0;
1643
1644
        $p_header['comment_len'] = 0;
1645
1646
        $p_header['disk'] = 0;
1647
1648
        $p_header['internal'] = 0;
1649
1650
        $p_header['external'] = (is_file($p_filename) ? 0xFE49FFE0 : 0x41FF0010);
1651
1652
        $p_header['offset'] = 0;
1653
1654
        $p_header['filename'] = $p_filename;
1655
1656
        $p_header['stored_filename'] = $v_stored_filename;
1657
1658
        $p_header['extra'] = '';
1659
1660
        $p_header['comment'] = '';
1661
1662
        $p_header['status'] = 'ok';
1663
1664
        $p_header['index'] = -1;
1665
1666
        // ----- Look for pre-add callback
1667
1668
        if (isset($p_params[ARCHIVE_ZIP_PARAM_PRE_ADD])
1669
            && ('' != $p_params[ARCHIVE_ZIP_PARAM_PRE_ADD])) {
1670
            // ----- Generate a local information
1671
1672
            $v_local_header = [];
1673
1674
            $this->_convertHeader2FileInfo($p_header, $v_local_header);
1675
1676
            // ----- Call the callback
1677
1678
            // Here I do not use call_user_func() because I need to send a reference to the
1679
1680
            // header.
1681
1682
            eval('$v_result = ' . $p_params[ARCHIVE_ZIP_PARAM_PRE_ADD] . '(ARCHIVE_ZIP_PARAM_PRE_ADD, $v_local_header);');
1683
1684
            if (0 == $v_result) {
1685
                // ----- Change the file status
1686
1687
                $p_header['status'] = 'skipped';
1688
1689
                $v_result = 1;
1690
            }
1691
1692
            // ----- Update the informations
1693
1694
            // Only some fields can be modified
1695
1696
            if ($p_header['stored_filename'] != $v_local_header['stored_filename']) {
1697
                $p_header['stored_filename'] = $this->_tool_PathReduction($v_local_header['stored_filename']);
1698
            }
1699
        }
1700
1701
        // ----- Look for empty stored filename
1702
1703
        if ('' == $p_header['stored_filename']) {
1704
            $p_header['status'] = 'filtered';
1705
        }
1706
1707
        // ----- Check the path length
1708
1709
        if (mb_strlen($p_header['stored_filename']) > 0xFF) {
1710
            $p_header['status'] = 'filename_too_long';
1711
        }
1712
1713
        // ----- Look if no error, or file not skipped
1714
1715
        if ('ok' == $p_header['status']) {
1716
            // ----- Look for a file
1717
1718
            if (is_file($p_filename)) {
1719
                // ----- Open the source file
1720
1721 View Code Duplication
                if (0 == ($v_file = @fopen($p_filename, 'rb'))) {
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...
1722
                    $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode");
1723
1724
                    return self::errorCode();
1725
                }
1726
1727
                if ($p_params['no_compression']) {
1728
                    // ----- Read the file content
1729
1730
                    $v_content_compressed = @fread($v_file, $p_header['size']);
1731
1732
                    // ----- Calculate the CRC
1733
1734
                    $p_header['crc'] = crc32($v_content_compressed);
1735
                } else {
1736
                    // ----- Read the file content
1737
1738
                    $v_content = @fread($v_file, $p_header['size']);
1739
1740
                    // ----- Calculate the CRC
1741
1742
                    $p_header['crc'] = crc32($v_content);
1743
1744
                    // ----- Compress the file
1745
1746
                    $v_content_compressed = gzdeflate($v_content);
1747
                }
1748
1749
                // ----- Set header parameters
1750
1751
                $p_header['compressed_size'] = mb_strlen($v_content_compressed);
1752
1753
                $p_header['compression'] = 8;
1754
1755
                // ----- Call the header generation
1756
1757
                if (1 != ($v_result = $this->_writeFileHeader($p_header))) {
1758
                    @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...
1759
1760
                    return $v_result;
1761
                }
1762
1763
                // ----- Write the compressed content
1764
1765
                $v_binary_data = pack('a' . $p_header['compressed_size'], $v_content_compressed);
1766
1767
                @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...
1768
1769
                // ----- Close the file
1770
1771
                @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...
1772
            } // ----- Look for a directory
1773
1774
            else {
1775
                // ----- Set the file properties
1776
1777
                $p_header['filename'] .= '/';
1778
1779
                $p_header['filename_len']++;
1780
1781
                $p_header['size'] = 0;
1782
1783
                $p_header['external'] = 0x41FF0010;   // Value for a folder : to be checked
1784
1785
                // ----- Call the header generation
1786
1787
                if (1 != ($v_result = $this->_writeFileHeader($p_header))) {
1788
                    return $v_result;
1789
                }
1790
            }
1791
        }
1792
1793
        // ----- Look for pre-add callback
1794
1795
        if (isset($p_params[ARCHIVE_ZIP_PARAM_POST_ADD])
1796
            && ('' != $p_params[ARCHIVE_ZIP_PARAM_POST_ADD])) {
1797
            // ----- Generate a local information
1798
1799
            $v_local_header = [];
1800
1801
            $this->_convertHeader2FileInfo($p_header, $v_local_header);
1802
1803
            // ----- Call the callback
1804
1805
            // Here I do not use call_user_func() because I need to send a reference to the
1806
1807
            // header.
1808
1809
            eval('$v_result = ' . $p_params[ARCHIVE_ZIP_PARAM_POST_ADD] . '(ARCHIVE_ZIP_PARAM_POST_ADD, $v_local_header);');
1810
1811
            if (0 == $v_result) {
1812
                // ----- Ignored
1813
1814
                $v_result = 1;
1815
            }
1816
1817
            // ----- Update the informations
1818
            // Nothing can be modified
1819
        }
1820
1821
        // ----- Return
1822
1823
        return $v_result;
1824
    }
1825
1826
    // ---------------------------------------------------------------------------
1827
1828
    // ---------------------------------------------------------------------------
1829
1830
    // Function : _writeFileHeader()
1831
1832
    // Description :
1833
1834
    // Parameters :
1835
1836
    // Return Values :
1837
1838
    // ---------------------------------------------------------------------------
1839
1840
    /**
1841
     * Archive_Zip::_writeFileHeader()
1842
     *
1843
     * { Description }
1844
     * @param mixed $p_header
1845
     * @return int
1846
     */
1847
1848
    public function _writeFileHeader(&$p_header)
1849
    {
1850
        $v_result = 1;
1851
1852
        // TBC
1853
1854
        //for(reset($p_header); $key = key($p_header); next($p_header)) {
1855
1856
        //}
1857
1858
        // ----- Store the offset position of the file
1859
1860
        $p_header['offset'] = ftell($this->_zip_fd);
1861
1862
        // ----- Transform UNIX mtime to DOS format mdate/mtime
1863
1864
        $v_date = getdate($p_header['mtime']);
1865
1866
        $v_mtime = ($v_date['hours'] << 11) + ($v_date['minutes'] << 5) + $v_date['seconds'] / 2;
1867
1868
        $v_mdate = (($v_date['year'] - 1980) << 9) + ($v_date['mon'] << 5) + $v_date['mday'];
1869
1870
        // ----- Packed data
1871
1872
        $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'], mb_strlen($p_header['stored_filename']), $p_header['extra_len']);
1873
1874
        // ----- Write the first 148 bytes of the header in the archive
1875
1876
        fwrite($this->_zip_fd, $v_binary_data, 30);
1877
1878
        // ----- Write the variable fields
1879
1880 View Code Duplication
        if (0 != mb_strlen($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...
1881
            fwrite($this->_zip_fd, $p_header['stored_filename'], mb_strlen($p_header['stored_filename']));
1882
        }
1883
1884 View Code Duplication
        if (0 != $p_header['extra_len']) {
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...
1885
            fwrite($this->_zip_fd, $p_header['extra'], $p_header['extra_len']);
1886
        }
1887
1888
        // ----- Return
1889
1890
        return $v_result;
1891
    }
1892
1893
    // ---------------------------------------------------------------------------
1894
1895
    // ---------------------------------------------------------------------------
1896
1897
    // Function : _writeCentralFileHeader()
1898
1899
    // Description :
1900
1901
    // Parameters :
1902
1903
    // Return Values :
1904
1905
    // ---------------------------------------------------------------------------
1906
1907
    /**
1908
     * Archive_Zip::_writeCentralFileHeader()
1909
     *
1910
     * { Description }
1911
     * @param $p_header
1912
     * @return int
1913
     */
1914
1915
    public function _writeCentralFileHeader($p_header)
1916
    {
1917
        $v_result = 1;
1918
1919
        // TBC
1920
1921
        //for(reset($p_header); $key = key($p_header); next($p_header)) {
1922
1923
        //}
1924
1925
        // ----- Transform UNIX mtime to DOS format mdate/mtime
1926
1927
        $v_date = getdate($p_header['mtime']);
1928
1929
        $v_mtime = ($v_date['hours'] << 11) + ($v_date['minutes'] << 5) + $v_date['seconds'] / 2;
1930
1931
        $v_mdate = (($v_date['year'] - 1980) << 9) + ($v_date['mon'] << 5) + $v_date['mday'];
1932
1933
        // ----- Packed data
1934
1935
        $v_binary_data = pack(
1936
            'VvvvvvvVVVvvvvvVV',
1937
            0x02014b50,
1938
            $p_header['version'],
1939
            $p_header['version_extracted'],
1940
            $p_header['flag'],
1941
            $p_header['compression'],
1942
            $v_mtime,
1943
            $v_mdate,
1944
            $p_header['crc'],
1945
            $p_header['compressed_size'],
1946
            $p_header['size'],
1947
            mb_strlen($p_header['stored_filename']),
1948
            $p_header['extra_len'],
1949
            $p_header['comment_len'],
1950
            $p_header['disk'],
1951
            $p_header['internal'],
1952
            $p_header['external'],
1953
            $p_header['offset']
1954
        );
1955
1956
        // ----- Write the 42 bytes of the header in the zip file
1957
1958
        fwrite($this->_zip_fd, $v_binary_data, 46);
1959
1960
        // ----- Write the variable fields
1961
1962 View Code Duplication
        if (0 != mb_strlen($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...
1963
            fwrite($this->_zip_fd, $p_header['stored_filename'], mb_strlen($p_header['stored_filename']));
1964
        }
1965
1966 View Code Duplication
        if (0 != $p_header['extra_len']) {
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...
1967
            fwrite($this->_zip_fd, $p_header['extra'], $p_header['extra_len']);
1968
        }
1969
1970
        if (0 != $p_header['comment_len']) {
1971
            fwrite($this->_zip_fd, $p_header['comment'], $p_header['comment_len']);
1972
        }
1973
1974
        // ----- Return
1975
1976
        return $v_result;
1977
    }
1978
1979
    // ---------------------------------------------------------------------------
1980
1981
    // ---------------------------------------------------------------------------
1982
1983
    // Function : _writeCentralHeader()
1984
1985
    // Description :
1986
1987
    // Parameters :
1988
1989
    // Return Values :
1990
1991
    // ---------------------------------------------------------------------------
1992
1993
    /**
1994
     * Archive_Zip::_writeCentralHeader()
1995
     *
1996
     * { Description }
1997
     * @param $p_nb_entries
1998
     * @param $p_size
1999
     * @param $p_offset
2000
     * @param $p_comment
2001
     * @return int
2002
     */
2003
2004
    public function _writeCentralHeader($p_nb_entries, $p_size, $p_offset, $p_comment)
2005
    {
2006
        $v_result = 1;
2007
2008
        // ----- Packed data
2009
2010
        $v_binary_data = pack('VvvvvVVv', 0x06054b50, 0, 0, $p_nb_entries, $p_nb_entries, $p_size, $p_offset, mb_strlen($p_comment));
2011
2012
        // ----- Write the 22 bytes of the header in the zip file
2013
2014
        fwrite($this->_zip_fd, $v_binary_data, 22);
2015
2016
        // ----- Write the variable fields
2017
2018
        if (0 != mb_strlen($p_comment)) {
2019
            fwrite($this->_zip_fd, $p_comment, mb_strlen($p_comment));
2020
        }
2021
2022
        // ----- Return
2023
2024
        return $v_result;
2025
    }
2026
2027
    // ---------------------------------------------------------------------------
2028
2029
    // ---------------------------------------------------------------------------
2030
2031
    // Function : _list()
2032
2033
    // Description :
2034
2035
    // Parameters :
2036
2037
    // Return Values :
2038
2039
    // ---------------------------------------------------------------------------
2040
2041
    /**
2042
     * Archive_Zip::_list()
2043
     *
2044
     * { Description }
2045
     * @param mixed $p_list
2046
     * @return int
2047
     */
2048
2049
    public function _list(&$p_list)
2050
    {
2051
        $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...
2052
2053
        // ----- Open the zip file
2054
2055 View Code Duplication
        if (0 == ($this->_zip_fd = @fopen($this->_zipname, 'rb'))) {
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...
2056
            // ----- Error log
2057
2058
            $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \'' . $this->_zipname . '\' in binary read mode');
2059
2060
            // ----- Return
2061
2062
            return self::errorCode();
2063
        }
2064
2065
        // ----- Read the central directory informations
2066
2067
        $v_central_dir = [];
2068
2069
        if (1 != ($v_result = $this->_readEndCentralDir($v_central_dir))) {
2070
            return $v_result;
2071
        }
2072
2073
        // ----- Go to beginning of Central Dir
2074
2075
        @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...
2076
2077 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...
2078
            // ----- Error log
2079
2080
            $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
2081
2082
            // ----- Return
2083
2084
            return self::errorCode();
2085
        }
2086
2087
        // ----- Read each entry
2088
2089
        for ($i = 0; $i < $v_central_dir['entries']; ++$i) {
2090
            // ----- Read the file header
2091
2092
            if (1 != ($v_result = $this->_readCentralFileHeader($v_header))) {
2093
                return $v_result;
2094
            }
2095
2096
            $v_header['index'] = $i;
2097
2098
            // ----- Get the only interesting attributes
2099
2100
            $this->_convertHeader2FileInfo($v_header, $p_list[$i]);
2101
2102
            unset($v_header);
2103
        }
2104
2105
        // ----- Close the zip file
2106
2107
        $this->_closeFd();
2108
2109
        // ----- Return
2110
2111
        return $v_result;
2112
    }
2113
2114
    // ---------------------------------------------------------------------------
2115
2116
    // ---------------------------------------------------------------------------
2117
2118
    // Function : _convertHeader2FileInfo()
2119
2120
    // Description :
2121
2122
    //   This function takes the file informations from the central directory
2123
2124
    //   entries and extract the interesting parameters that will be given back.
2125
2126
    //   The resulting file infos are set in the array $p_info
2127
2128
    //     $p_info['filename'] : Filename with full path. Given by user (add),
2129
2130
    //                           extracted in the filesystem (extract).
2131
2132
    //     $p_info['stored_filename'] : Stored filename in the archive.
2133
2134
    //     $p_info['size'] = Size of the file.
2135
2136
    //     $p_info['compressed_size'] = Compressed size of the file.
2137
2138
    //     $p_info['mtime'] = Last modification date of the file.
2139
2140
    //     $p_info['comment'] = Comment associated with the file.
2141
2142
    //     $p_info['folder'] = true/false : indicates if the entry is a folder or not.
2143
2144
    //     $p_info['status'] = status of the action on the file.
2145
2146
    // Parameters :
2147
2148
    // Return Values :
2149
2150
    // ---------------------------------------------------------------------------
2151
2152
    /**
2153
     * Archive_Zip::_convertHeader2FileInfo()
2154
     *
2155
     * { Description }
2156
     * @param $p_header
2157
     * @param mixed $p_info
2158
     * @return int
2159
     */
2160
2161
    public function _convertHeader2FileInfo($p_header, &$p_info)
2162
    {
2163
        $v_result = 1;
2164
2165
        // ----- Get the interesting attributes
2166
2167
        $p_info['filename'] = $p_header['filename'];
2168
2169
        $p_info['stored_filename'] = $p_header['stored_filename'];
2170
2171
        $p_info['size'] = $p_header['size'];
2172
2173
        $p_info['compressed_size'] = $p_header['compressed_size'];
2174
2175
        $p_info['mtime'] = $p_header['mtime'];
2176
2177
        $p_info['comment'] = $p_header['comment'];
2178
2179
        $p_info['folder'] = (0x00000010 == ($p_header['external'] & 0x00000010));
2180
2181
        $p_info['index'] = $p_header['index'];
2182
2183
        $p_info['status'] = $p_header['status'];
2184
2185
        // ----- Return
2186
2187
        return $v_result;
2188
    }
2189
2190
    // ---------------------------------------------------------------------------
2191
2192
    // ---------------------------------------------------------------------------
2193
2194
    // Function : _extractByRule()
2195
2196
    // Description :
2197
2198
    //   Extract a file or directory depending of rules (by index, by name, ...)
2199
2200
    // Parameters :
2201
2202
    //   $p_file_list : An array where will be placed the properties of each
2203
2204
    //                  extracted file
2205
2206
    //   $p_path : Path to add while writing the extracted files
2207
2208
    //   $p_remove_path : Path to remove (from the file memorized path) while writing the
2209
2210
    //                    extracted files. If the path does not match the file path,
2211
2212
    //                    the file is extracted with its memorized path.
2213
2214
    //                    $p_remove_path does not apply to 'list' mode.
2215
2216
    //                    $p_path and $p_remove_path are commulative.
2217
2218
    // Return Values :
2219
2220
    //   1 on success,0 or less on error (see error code list)
2221
2222
    // ---------------------------------------------------------------------------
2223
2224
    /**
2225
     * Archive_Zip::_extractByRule()
2226
     *
2227
     * { Description }
2228
     * @param $p_params
2229
     * @param mixed $p_file_list
2230
     * @return int
2231
     */
2232
2233
    public function _extractByRule(&$p_file_list, $p_params)
2234
    {
2235
        $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...
2236
2237
        $p_path = $p_params['add_path'];
2238
2239
        $p_remove_path = $p_params['remove_path'];
2240
2241
        $p_remove_all_path = $p_params['remove_all_path'];
2242
2243
        // ----- Check the path
2244
2245
        if (('' == $p_path)
2246
            || (('/' != mb_substr($p_path, 0, 1))
2247
                && ('../' != mb_substr($p_path, 0, 3))
2248
                && (':/' != mb_substr($p_path, 1, 2)))) {
2249
            $p_path = './' . $p_path;
2250
        }
2251
2252
        // ----- Reduce the path last (and duplicated) '/'
2253
2254
        if (('./' != $p_path) && ('/' != $p_path)) {
2255
            // ----- Look for the path end '/'
2256
2257
            while ('/' == mb_substr($p_path, -1)) {
2258
                $p_path = mb_substr($p_path, 0, mb_strlen($p_path) - 1);
2259
            }
2260
        }
2261
2262
        // ----- Look for path to remove format (should end by /)
2263
2264
        if (('' != $p_remove_path) && ('/' != mb_substr($p_remove_path, -1))) {
2265
            $p_remove_path .= '/';
2266
        }
2267
2268
        $p_remove_path_size = mb_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...
2269
2270
        // ----- Open the zip file
2271
2272
        if (1 != ($v_result = $this->_openFd('rb'))) {
2273
            return $v_result;
2274
        }
2275
2276
        // ----- Read the central directory informations
2277
2278
        $v_central_dir = [];
2279
2280
        if (1 != ($v_result = $this->_readEndCentralDir($v_central_dir))) {
2281
            // ----- Close the zip file
2282
2283
            $this->_closeFd();
2284
2285
            return $v_result;
2286
        }
2287
2288
        // ----- Start at beginning of Central Dir
2289
2290
        $v_pos_entry = $v_central_dir['offset'];
2291
2292
        // ----- Read each entry
2293
2294
        $j_start = 0;
2295
2296
        for ($i = 0, $v_nb_extracted = 0; $i < $v_central_dir['entries']; ++$i) {
2297
            // ----- Read next Central dir entry
2298
2299
            @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...
2300
2301 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...
2302
                $this->_closeFd();
2303
2304
                $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
2305
2306
                return self::errorCode();
2307
            }
2308
2309
            // ----- Read the file header
2310
2311
            $v_header = [];
2312
2313
            if (1 != ($v_result = $this->_readCentralFileHeader($v_header))) {
2314
                $this->_closeFd();
2315
2316
                return $v_result;
2317
            }
2318
2319
            // ----- Store the index
2320
2321
            $v_header['index'] = $i;
2322
2323
            // ----- Store the file position
2324
2325
            $v_pos_entry = ftell($this->_zip_fd);
2326
2327
            // ----- Look for the specific extract rules
2328
2329
            $v_extract = false;
2330
2331
            // ----- Look for extract by name rule
2332
2333
            if (isset($p_params[ARCHIVE_ZIP_PARAM_BY_NAME])
2334
                && (0 != $p_params[ARCHIVE_ZIP_PARAM_BY_NAME])) {
2335
                // ----- Look if the filename is in the list
2336
2337
                for ($j = 0; ($j < count($p_params[ARCHIVE_ZIP_PARAM_BY_NAME]))
2338
                             && (!$v_extract); $j++) {
2339
                    // ----- Look for a directory
2340
2341
                    if ('/' == mb_substr($p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j], -1)) {
2342
                        // ----- Look if the directory is in the filename path
2343
2344
                        if ((mb_strlen($v_header['stored_filename']) > mb_strlen($p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j]))
2345
                            && (mb_substr($v_header['stored_filename'], 0, mb_strlen($p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j])) == $p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j])) {
2346
                            $v_extract = true;
2347
                        }
2348
                    } // ----- Look for a filename
2349
2350
                    elseif ($v_header['stored_filename'] == $p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j]) {
2351
                        $v_extract = true;
2352
                    }
2353
                }
2354
            } // ----- Look for extract by ereg rule
2355
2356
            elseif (isset($p_params[ARCHIVE_ZIP_PARAM_BY_EREG])
2357
                    && ('' != $p_params[ARCHIVE_ZIP_PARAM_BY_EREG])) {
2358
                if (ereg($p_params[ARCHIVE_ZIP_PARAM_BY_EREG], $v_header['stored_filename'])) {
2359
                    $v_extract = true;
2360
                }
2361
            } // ----- Look for extract by preg rule
2362
2363 View Code Duplication
            elseif (isset($p_params[ARCHIVE_ZIP_PARAM_BY_PREG])
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
                    && ('' != $p_params[ARCHIVE_ZIP_PARAM_BY_PREG])) {
2365
                if (preg_match($p_params[ARCHIVE_ZIP_PARAM_BY_PREG], $v_header['stored_filename'])) {
2366
                    $v_extract = true;
2367
                }
2368
            } // ----- Look for extract by index rule
2369
2370 View Code Duplication
            elseif (isset($p_params[ARCHIVE_ZIP_PARAM_BY_INDEX])
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...
2371
                    && (0 != $p_params[ARCHIVE_ZIP_PARAM_BY_INDEX])) {
2372
                // ----- Look if the index is in the list
2373
2374
                for ($j = $j_start; ($j < count($p_params[ARCHIVE_ZIP_PARAM_BY_INDEX])) && (!$v_extract); $j++) {
2375
                    if (($i >= $p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['start']) && ($i <= $p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['end'])) {
2376
                        $v_extract = true;
2377
                    }
2378
2379
                    if ($i >= $p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['end']) {
2380
                        $j_start = $j + 1;
2381
                    }
2382
2383
                    if ($p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['start'] > $i) {
2384
                        break;
2385
                    }
2386
                }
2387
            } // ----- Look for no rule, which means extract all the archive
2388
2389
            else {
2390
                $v_extract = true;
2391
            }
2392
2393
            // ----- Look for real extraction
2394
2395
            if ($v_extract) {
2396
                // ----- Go to the file position
2397
2398
                @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...
2399
2400 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...
2401
                    // ----- Close the zip file
2402
2403
                    $this->_closeFd();
2404
2405
                    // ----- Error log
2406
2407
                    $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
2408
2409
                    // ----- Return
2410
2411
                    return self::errorCode();
2412
                }
2413
2414
                // ----- Look for extraction as string
2415
2416
                if ($p_params[ARCHIVE_ZIP_PARAM_EXTRACT_AS_STRING]) {
2417
                    // ----- Extracting the file
2418
2419
                    if (1 != ($v_result = $this->_extractFileAsString($v_header, $v_string))) {
2420
                        // ----- Close the zip file
2421
2422
                        $this->_closeFd();
2423
2424
                        return $v_result;
2425
                    }
2426
2427
                    // ----- Get the only interesting attributes
2428
2429
                    if (1 != ($v_result = $this->_convertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted]))) {
2430
                        // ----- Close the zip file
2431
2432
                        $this->_closeFd();
2433
2434
                        return $v_result;
2435
                    }
2436
2437
                    // ----- Set the file content
2438
2439
                    $p_file_list[$v_nb_extracted]['content'] = $v_string;
2440
2441
                    // ----- Next extracted file
2442
2443
                    $v_nb_extracted++;
2444
                } else {
2445
                    // ----- Extracting the file
2446
2447
                    if (1 != ($v_result = $this->_extractFile($v_header, $p_path, $p_remove_path, $p_remove_all_path, $p_params))) {
2448
                        // ----- Close the zip file
2449
2450
                        $this->_closeFd();
2451
2452
                        return $v_result;
2453
                    }
2454
2455
                    // ----- Get the only interesting attributes
2456
2457
                    if (1 != ($v_result = $this->_convertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++]))) {
2458
                        // ----- Close the zip file
2459
2460
                        $this->_closeFd();
2461
2462
                        return $v_result;
2463
                    }
2464
                }
2465
            }
2466
        }
2467
2468
        // ----- Close the zip file
2469
2470
        $this->_closeFd();
2471
2472
        // ----- Return
2473
2474
        return $v_result;
2475
    }
2476
2477
    // ---------------------------------------------------------------------------
2478
2479
    // ---------------------------------------------------------------------------
2480
2481
    // Function : _extractFile()
2482
2483
    // Description :
2484
2485
    // Parameters :
2486
2487
    // Return Values :
2488
2489
    // ---------------------------------------------------------------------------
2490
2491
    /**
2492
     * Archive_Zip::_extractFile()
2493
     *
2494
     * { Description }
2495
     * @param $p_path
2496
     * @param $p_remove_path
2497
     * @param $p_remove_all_path
2498
     * @param $p_params
2499
     * @param mixed $p_entry
2500
     * @return int
2501
     */
2502
2503
    public function _extractFile(&$p_entry, $p_path, $p_remove_path, $p_remove_all_path, $p_params)
2504
    {
2505
        $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...
2506
2507
        // ----- Read the file header
2508
2509
        if (1 != ($v_result = $this->_readFileHeader($v_header))) {
2510
            // ----- Return
2511
2512
            return $v_result;
2513
        }
2514
2515
        // ----- Check that the file header is coherent with $p_entry info
2516
2517
        // TBC
2518
2519
        // ----- Look for all path to remove
2520
2521
        if (true === $p_remove_all_path) {
2522
            // ----- Get the basename of the path
2523
2524
            $p_entry['filename'] = basename($p_entry['filename']);
2525
        } // ----- Look for path to remove
2526
2527
        elseif ('' != $p_remove_path) {
2528
            //if (strcmp($p_remove_path, $p_entry['filename'])==0)
2529
2530
            if (2 == $this->_tool_PathInclusion($p_remove_path, $p_entry['filename'])) {
2531
                // ----- Change the file status
2532
2533
                $p_entry['status'] = 'filtered';
2534
2535
                // ----- Return
2536
2537
                return $v_result;
2538
            }
2539
2540
            $p_remove_path_size = mb_strlen($p_remove_path);
2541
2542
            if (mb_substr($p_entry['filename'], 0, $p_remove_path_size) == $p_remove_path) {
2543
                // ----- Remove the path
2544
2545
                $p_entry['filename'] = mb_substr($p_entry['filename'], $p_remove_path_size);
2546
            }
2547
        }
2548
2549
        // ----- Add the path
2550
2551
        if ('' != $p_path) {
2552
            $p_entry['filename'] = $p_path . '/' . $p_entry['filename'];
2553
        }
2554
2555
        // ----- Look for pre-extract callback
2556
2557
        if (isset($p_params[ARCHIVE_ZIP_PARAM_PRE_EXTRACT])
2558
            && ('' != $p_params[ARCHIVE_ZIP_PARAM_PRE_EXTRACT])) {
2559
            // ----- Generate a local information
2560
2561
            $v_local_header = [];
2562
2563
            $this->_convertHeader2FileInfo($p_entry, $v_local_header);
2564
2565
            // ----- Call the callback
2566
2567
            // Here I do not use call_user_func() because I need to send a reference to the
2568
2569
            // header.
2570
2571
            eval('$v_result = ' . $p_params[ARCHIVE_ZIP_PARAM_PRE_EXTRACT] . '(ARCHIVE_ZIP_PARAM_PRE_EXTRACT, $v_local_header);');
2572
2573
            if (0 == $v_result) {
2574
                // ----- Change the file status
2575
2576
                $p_entry['status'] = 'skipped';
2577
2578
                $v_result = 1;
2579
            }
2580
2581
            // ----- Update the informations
2582
2583
            // Only some fields can be modified
2584
2585
            $p_entry['filename'] = $v_local_header['filename'];
2586
        }
2587
2588
        // ----- Trace
2589
2590
        // ----- Look if extraction should be done
2591
2592
        if ('ok' == $p_entry['status']) {
2593
            // ----- Look for specific actions while the file exist
2594
2595
            if (file_exists($p_entry['filename'])) {
2596
                // ----- Look if file is a directory
2597
2598
                if (is_dir($p_entry['filename'])) {
2599
                    // ----- Change the file status
2600
2601
                    $p_entry['status'] = 'already_a_directory';
2602
2603
                // ----- Return
2604
                    //return $v_result;
2605
                } // ----- Look if file is write protected
2606
                elseif (!is_writable($p_entry['filename'])) {
2607
                    // ----- Change the file status
2608
2609
                    $p_entry['status'] = 'write_protected';
2610
2611
                // ----- Return
2612
                    //return $v_result;
2613
                } // ----- Look if the extracted file is older
2614
                elseif (filemtime($p_entry['filename']) > $p_entry['mtime']) {
2615
                    // ----- Change the file status
2616
2617
                    $p_entry['status'] = 'newer_exist';
2618
2619
                    // ----- Return
2620
                    //return $v_result;
2621
                }
2622
            } // ----- Check the directory availability and create it if necessary
2623
2624
            else {
2625
                if ((0x00000010 == ($p_entry['external'] & 0x00000010)) || ('/' == mb_substr($p_entry['filename'], -1))) {
2626
                    $v_dir_to_check = $p_entry['filename'];
2627
                } elseif (!mb_strstr($p_entry['filename'], '/')) {
2628
                    $v_dir_to_check = '';
2629
                } else {
2630
                    $v_dir_to_check = dirname($p_entry['filename']);
2631
                }
2632
2633
                if (1 != ($v_result = $this->_dirCheck($v_dir_to_check, 0x00000010 == ($p_entry['external'] & 0x00000010)))) {
2634
                    // ----- Change the file status
2635
2636
                    $p_entry['status'] = 'path_creation_fail';
2637
2638
                    // ----- Return
2639
2640
                    //return $v_result;
2641
2642
                    $v_result = 1;
2643
                }
2644
            }
2645
        }
2646
2647
        // ----- Look if extraction should be done
2648
2649
        if ('ok' == $p_entry['status']) {
2650
            // ----- Do the extraction (if not a folder)
2651
2652
            if (!(0x00000010 == ($p_entry['external'] & 0x00000010))) {
2653
                // ----- Look for not compressed file
2654
2655
                if ($p_entry['compressed_size'] == $p_entry['size']) {
2656
                    // ----- Opening destination file
2657
2658 View Code Duplication
                    if (0 == ($v_dest_file = @fopen($p_entry['filename'], 'wb'))) {
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...
2659
                        // ----- Change the file status
2660
2661
                        $p_entry['status'] = 'write_error';
2662
2663
                        // ----- Return
2664
2665
                        return $v_result;
2666
                    }
2667
2668
                    // ----- Read the file by ARCHIVE_ZIP_READ_BLOCK_SIZE octets blocks
2669
2670
                    $v_size = $p_entry['compressed_size'];
2671
2672
                    while (0 != $v_size) {
2673
                        $v_read_size = ($v_size < ARCHIVE_ZIP_READ_BLOCK_SIZE ? $v_size : ARCHIVE_ZIP_READ_BLOCK_SIZE);
2674
2675
                        $v_buffer = fread($this->_zip_fd, $v_read_size);
2676
2677
                        $v_binary_data = pack('a' . $v_read_size, $v_buffer);
2678
2679
                        @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...
2680
2681
                        $v_size -= $v_read_size;
2682
                    }
2683
2684
                    // ----- Closing the destination file
2685
2686
                    fclose($v_dest_file);
2687
2688
                    // ----- Change the file mtime
2689
2690
                    touch($p_entry['filename'], $p_entry['mtime']);
2691
                } else {
2692
                    // ----- Trace
2693
2694
                    // ----- Opening destination file
2695
2696 View Code Duplication
                    if (0 == ($v_dest_file = @fopen($p_entry['filename'], 'wb'))) {
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...
2697
                        // ----- Change the file status
2698
2699
                        $p_entry['status'] = 'write_error';
2700
2701
                        return $v_result;
2702
                    }
2703
2704
                    // ----- Read the compressed file in a buffer (one shot)
2705
2706
                    $v_buffer = @fread($this->_zip_fd, $p_entry['compressed_size']);
2707
2708
                    // ----- Decompress the file
2709
2710
                    $v_file_content = gzinflate($v_buffer);
2711
2712
                    unset($v_buffer);
2713
2714
                    // ----- Write the uncompressed data
2715
2716
                    @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...
2717
2718
                    unset($v_file_content);
2719
2720
                    // ----- Closing the destination file
2721
2722
                    @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...
2723
2724
                    // ----- Change the file mtime
2725
2726
                    touch($p_entry['filename'], $p_entry['mtime']);
2727
                }
2728
2729
                // ----- Look for chmod option
2730
2731
                if (isset($p_params[ARCHIVE_ZIP_PARAM_SET_CHMOD])
2732
                    && (0 != $p_params[ARCHIVE_ZIP_PARAM_SET_CHMOD])) {
2733
                    // ----- Change the mode of the file
2734
2735
                    chmod($p_entry['filename'], $p_params[ARCHIVE_ZIP_PARAM_SET_CHMOD]);
2736
                }
2737
            }
2738
        }
2739
2740
        // ----- Look for post-extract callback
2741
2742
        if (isset($p_params[ARCHIVE_ZIP_PARAM_POST_EXTRACT])
2743
            && ('' != $p_params[ARCHIVE_ZIP_PARAM_POST_EXTRACT])) {
2744
            // ----- Generate a local information
2745
2746
            $v_local_header = [];
2747
2748
            $this->_convertHeader2FileInfo($p_entry, $v_local_header);
2749
2750
            // ----- Call the callback
2751
2752
            // Here I do not use call_user_func() because I need to send a reference to the
2753
2754
            // header.
2755
2756
            eval('$v_result = ' . $p_params[ARCHIVE_ZIP_PARAM_POST_EXTRACT] . '(ARCHIVE_ZIP_PARAM_POST_EXTRACT, $v_local_header);');
2757
        }
2758
2759
        // ----- Return
2760
2761
        return $v_result;
2762
    }
2763
2764
    // ---------------------------------------------------------------------------
2765
2766
    // ---------------------------------------------------------------------------
2767
2768
    // Function : _extractFileAsString()
2769
2770
    // Description :
2771
2772
    // Parameters :
2773
2774
    // Return Values :
2775
2776
    // ---------------------------------------------------------------------------
2777
2778
    /**
2779
     * Archive_Zip::_extractFileAsString()
2780
     *
2781
     * { Description }
2782
     * @param $p_entry
2783
     * @param mixed $p_string
2784
     * @return int
2785
     */
2786
2787
    public function _extractFileAsString($p_entry, &$p_string)
2788
    {
2789
        $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...
2790
2791
        // ----- Read the file header
2792
2793
        $v_header = [];
2794
2795
        if (1 != ($v_result = $this->_readFileHeader($v_header))) {
2796
            // ----- Return
2797
2798
            return $v_result;
2799
        }
2800
2801
        // ----- Check that the file header is coherent with $p_entry info
2802
2803
        // TBC
2804
2805
        // ----- Trace
2806
2807
        // ----- Do the extraction (if not a folder)
2808
2809
        if (!(0x00000010 == ($p_entry['external'] & 0x00000010))) {
2810
            // ----- Look for not compressed file
2811
2812
            if ($p_entry['compressed_size'] == $p_entry['size']) {
2813
                // ----- Trace
2814
2815
                // ----- Reading the file
2816
2817
                $p_string = fread($this->_zip_fd, $p_entry['compressed_size']);
2818
            } else {
2819
                // ----- Trace
2820
2821
                // ----- Reading the file
2822
2823
                $v_data = fread($this->_zip_fd, $p_entry['compressed_size']);
2824
2825
                // ----- Decompress the file
2826
2827
                $p_string = gzinflate($v_data);
2828
            }
2829
2830
            // ----- Trace
2831
        }
2832
2833
        // TBC : error : can not extract a folder in a string
2834
2835
        // ----- Return
2836
2837
        return $v_result;
2838
    }
2839
2840
    // ---------------------------------------------------------------------------
2841
2842
    // ---------------------------------------------------------------------------
2843
2844
    // Function : _readFileHeader()
2845
2846
    // Description :
2847
2848
    // Parameters :
2849
2850
    // Return Values :
2851
2852
    // ---------------------------------------------------------------------------
2853
2854
    /**
2855
     * Archive_Zip::_readFileHeader()
2856
     *
2857
     * { Description }
2858
     * @param mixed $p_header
2859
     * @return int
2860
     */
2861
2862
    public function _readFileHeader(&$p_header)
2863
    {
2864
        $v_result = 1;
2865
2866
        // ----- Read the 4 bytes signature
2867
2868
        $v_binary_data = @fread($this->_zip_fd, 4);
2869
2870
        $v_data = unpack('Vid', $v_binary_data);
2871
2872
        // ----- Check signature
2873
2874
        if (0x04034b50 != $v_data['id']) {
2875
            // ----- Error log
2876
2877
            $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, 'Invalid archive structure');
2878
2879
            // ----- Return
2880
2881
            return self::errorCode();
2882
        }
2883
2884
        // ----- Read the first 42 bytes of the header
2885
2886
        $v_binary_data = fread($this->_zip_fd, 26);
2887
2888
        // ----- Look for invalid block size
2889
2890 View Code Duplication
        if (26 != mb_strlen($v_binary_data)) {
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...
2891
            $p_header['filename'] = '';
2892
2893
            $p_header['status'] = 'invalid_header';
2894
2895
            // ----- Error log
2896
2897
            $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, 'Invalid block size : ' . mb_strlen($v_binary_data));
2898
2899
            // ----- Return
2900
2901
            return self::errorCode();
2902
        }
2903
2904
        // ----- Extract the values
2905
2906
        $v_data = unpack('vversion/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len', $v_binary_data);
2907
2908
        // ----- Get filename
2909
2910
        $p_header['filename'] = fread($this->_zip_fd, $v_data['filename_len']);
2911
2912
        // ----- Get extra_fields
2913
2914
        if (0 != $v_data['extra_len']) {
2915
            $p_header['extra'] = fread($this->_zip_fd, $v_data['extra_len']);
2916
        } else {
2917
            $p_header['extra'] = '';
2918
        }
2919
2920
        // ----- Extract properties
2921
2922
        $p_header['compression'] = $v_data['compression'];
2923
2924
        $p_header['size'] = $v_data['size'];
2925
2926
        $p_header['compressed_size'] = $v_data['compressed_size'];
2927
2928
        $p_header['crc'] = $v_data['crc'];
2929
2930
        $p_header['flag'] = $v_data['flag'];
2931
2932
        // ----- Recuperate date in UNIX format
2933
2934
        $p_header['mdate'] = $v_data['mdate'];
2935
2936
        $p_header['mtime'] = $v_data['mtime'];
2937
2938 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...
2939
            // ----- Extract time
2940
2941
            $v_hour = ($p_header['mtime'] & 0xF800) >> 11;
2942
2943
            $v_minute = ($p_header['mtime'] & 0x07E0) >> 5;
2944
2945
            $v_seconde = ($p_header['mtime'] & 0x001F) * 2;
2946
2947
            // ----- Extract date
2948
2949
            $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980;
2950
2951
            $v_month = ($p_header['mdate'] & 0x01E0) >> 5;
2952
2953
            $v_day = $p_header['mdate'] & 0x001F;
2954
2955
            // ----- Get UNIX date format
2956
2957
            $p_header['mtime'] = mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year);
2958
        } else {
2959
            $p_header['mtime'] = time();
2960
        }
2961
2962
        // ----- Other informations
2963
2964
        // TBC
2965
2966
        //for(reset($v_data); $key = key($v_data); next($v_data)) {
2967
2968
        //}
2969
2970
        // ----- Set the stored filename
2971
2972
        $p_header['stored_filename'] = $p_header['filename'];
2973
2974
        // ----- Set the status field
2975
2976
        $p_header['status'] = 'ok';
2977
2978
        // ----- Return
2979
2980
        return $v_result;
2981
    }
2982
2983
    // ---------------------------------------------------------------------------
2984
2985
    // ---------------------------------------------------------------------------
2986
2987
    // Function : _readCentralFileHeader()
2988
2989
    // Description :
2990
2991
    // Parameters :
2992
2993
    // Return Values :
2994
2995
    // ---------------------------------------------------------------------------
2996
2997
    /**
2998
     * Archive_Zip::_readCentralFileHeader()
2999
     *
3000
     * { Description }
3001
     * @param mixed $p_header
3002
     * @return int
3003
     */
3004
3005
    public function _readCentralFileHeader(&$p_header)
3006
    {
3007
        $v_result = 1;
3008
3009
        // ----- Read the 4 bytes signature
3010
3011
        $v_binary_data = @fread($this->_zip_fd, 4);
3012
3013
        $v_data = unpack('Vid', $v_binary_data);
3014
3015
        // ----- Check signature
3016
3017
        if (0x02014b50 != $v_data['id']) {
3018
            // ----- Error log
3019
3020
            $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, 'Invalid archive structure');
3021
3022
            // ----- Return
3023
3024
            return self::errorCode();
3025
        }
3026
3027
        // ----- Read the first 42 bytes of the header
3028
3029
        $v_binary_data = fread($this->_zip_fd, 42);
3030
3031
        // ----- Look for invalid block size
3032
3033 View Code Duplication
        if (42 != mb_strlen($v_binary_data)) {
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...
3034
            $p_header['filename'] = '';
3035
3036
            $p_header['status'] = 'invalid_header';
3037
3038
            // ----- Error log
3039
3040
            $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, 'Invalid block size : ' . mb_strlen($v_binary_data));
3041
3042
            // ----- Return
3043
3044
            return self::errorCode();
3045
        }
3046
3047
        // ----- Extract the values
3048
3049
        $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);
3050
3051
        // ----- Get filename
3052
3053 View Code Duplication
        if (0 != $p_header['filename_len']) {
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...
3054
            $p_header['filename'] = fread($this->_zip_fd, $p_header['filename_len']);
3055
        } else {
3056
            $p_header['filename'] = '';
3057
        }
3058
3059
        // ----- Get extra
3060
3061 View Code Duplication
        if (0 != $p_header['extra_len']) {
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...
3062
            $p_header['extra'] = fread($this->_zip_fd, $p_header['extra_len']);
3063
        } else {
3064
            $p_header['extra'] = '';
3065
        }
3066
3067
        // ----- Get comment
3068
3069 View Code Duplication
        if (0 != $p_header['comment_len']) {
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...
3070
            $p_header['comment'] = fread($this->_zip_fd, $p_header['comment_len']);
3071
        } else {
3072
            $p_header['comment'] = '';
3073
        }
3074
3075
        // ----- Extract properties
3076
3077
        // ----- Recuperate date in UNIX format
3078
3079 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...
3080
            // ----- Extract time
3081
3082
            $v_hour = ($p_header['mtime'] & 0xF800) >> 11;
3083
3084
            $v_minute = ($p_header['mtime'] & 0x07E0) >> 5;
3085
3086
            $v_seconde = ($p_header['mtime'] & 0x001F) * 2;
3087
3088
            // ----- Extract date
3089
3090
            $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980;
3091
3092
            $v_month = ($p_header['mdate'] & 0x01E0) >> 5;
3093
3094
            $v_day = $p_header['mdate'] & 0x001F;
3095
3096
            // ----- Get UNIX date format
3097
3098
            $p_header['mtime'] = mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year);
3099
        } else {
3100
            $p_header['mtime'] = time();
3101
        }
3102
3103
        // ----- Set the stored filename
3104
3105
        $p_header['stored_filename'] = $p_header['filename'];
3106
3107
        // ----- Set default status to ok
3108
3109
        $p_header['status'] = 'ok';
3110
3111
        // ----- Look if it is a directory
3112
3113
        if ('/' == mb_substr($p_header['filename'], -1)) {
3114
            $p_header['external'] = 0x41FF0010;
3115
        }
3116
3117
        // ----- Return
3118
3119
        return $v_result;
3120
    }
3121
3122
    // ---------------------------------------------------------------------------
3123
3124
    // ---------------------------------------------------------------------------
3125
3126
    // Function : _readEndCentralDir()
3127
3128
    // Description :
3129
3130
    // Parameters :
3131
3132
    // Return Values :
3133
3134
    // ---------------------------------------------------------------------------
3135
3136
    /**
3137
     * Archive_Zip::_readEndCentralDir()
3138
     *
3139
     * { Description }
3140
     * @param mixed $p_central_dir
3141
     * @return int
3142
     */
3143
3144
    public function _readEndCentralDir(&$p_central_dir)
3145
    {
3146
        $v_result = 1;
3147
3148
        // ----- Go to the end of the zip file
3149
3150
        $v_size = filesize($this->_zipname);
3151
3152
        @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...
3153
3154 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...
3155
            $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, 'Unable to go to the end of the archive \'' . $this->_zipname . '\'');
3156
3157
            return self::errorCode();
3158
        }
3159
3160
        // ----- First try : look if this is an archive with no commentaries
3161
3162
        // (most of the time)
3163
3164
        // in this case the end of central dir is at 22 bytes of the file end
3165
3166
        $v_found = 0;
3167
3168
        if ($v_size > 26) {
3169
            @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...
3170
3171 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...
3172
                $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \'' . $this->_zipname . '\'');
3173
3174
                return self::errorCode();
3175
            }
3176
3177
            // ----- Read for bytes
3178
3179
            $v_binary_data = @fread($this->_zip_fd, 4);
3180
3181
            $v_data = unpack('Vid', $v_binary_data);
3182
3183
            // ----- Check signature
3184
3185
            if (0x06054b50 == $v_data['id']) {
3186
                $v_found = 1;
3187
            }
3188
3189
            $v_pos = ftell($this->_zip_fd);
3190
        }
3191
3192
        // ----- Go back to the maximum possible size of the Central Dir End Record
3193
3194
        if (!$v_found) {
3195
            $v_maximum_size = 65557; // 0xFFFF + 22;
3196
3197
            if ($v_maximum_size > $v_size) {
3198
                $v_maximum_size = $v_size;
3199
            }
3200
3201
            @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...
3202
3203 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...
3204
                $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \'' . $this->_zipname . '\'');
3205
3206
                return self::errorCode();
3207
            }
3208
3209
            // ----- Read byte per byte in order to find the signature
3210
3211
            $v_pos = ftell($this->_zip_fd);
3212
3213
            $v_bytes = 0x00000000;
3214
3215
            while ($v_pos < $v_size) {
3216
                // ----- Read a byte
3217
3218
                $v_byte = @fread($this->_zip_fd, 1);
3219
3220
                // -----  Add the byte
3221
3222
                $v_bytes = ($v_bytes << 8) | ord($v_byte);
3223
3224
                // ----- Compare the bytes
3225
3226
                if (0x504b0506 == $v_bytes) {
3227
                    $v_pos++;
3228
3229
                    break;
3230
                }
3231
3232
                $v_pos++;
3233
            }
3234
3235
            // ----- Look if not found end of central dir
3236
3237
            if ($v_pos == $v_size) {
3238
                $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, 'Unable to find End of Central Dir Record signature');
3239
3240
                return self::errorCode();
3241
            }
3242
        }
3243
3244
        // ----- Read the first 18 bytes of the header
3245
3246
        $v_binary_data = fread($this->_zip_fd, 18);
3247
3248
        // ----- Look for invalid block size
3249
3250
        if (18 != mb_strlen($v_binary_data)) {
3251
            $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, 'Invalid End of Central Dir Record size : ' . mb_strlen($v_binary_data));
3252
3253
            return self::errorCode();
3254
        }
3255
3256
        // ----- Extract the values
3257
3258
        $v_data = unpack('vdisk/vdisk_start/vdisk_entries/ventries/Vsize/Voffset/vcomment_size', $v_binary_data);
3259
3260
        // ----- Check the global size
3261
3262
        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...
3263
            $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, 'Fail to find the right signature');
3264
3265
            return self::errorCode();
3266
        }
3267
3268
        // ----- Get comment
3269
3270
        if (0 != $v_data['comment_size']) {
3271
            $p_central_dir['comment'] = fread($this->_zip_fd, $v_data['comment_size']);
3272
        } else {
3273
            $p_central_dir['comment'] = '';
3274
        }
3275
3276
        $p_central_dir['entries'] = $v_data['entries'];
3277
3278
        $p_central_dir['disk_entries'] = $v_data['disk_entries'];
3279
3280
        $p_central_dir['offset'] = $v_data['offset'];
3281
3282
        $p_central_dir['size'] = $v_data['size'];
3283
3284
        $p_central_dir['disk'] = $v_data['disk'];
3285
3286
        $p_central_dir['disk_start'] = $v_data['disk_start'];
3287
3288
        // ----- Return
3289
3290
        return $v_result;
3291
    }
3292
3293
    // ---------------------------------------------------------------------------
3294
3295
    // ---------------------------------------------------------------------------
3296
3297
    // Function : _deleteByRule()
3298
3299
    // Description :
3300
3301
    // Parameters :
3302
3303
    // Return Values :
3304
3305
    // ---------------------------------------------------------------------------
3306
3307
    /**
3308
     * Archive_Zip::_deleteByRule()
3309
     *
3310
     * { Description }
3311
     * @param $p_params
3312
     * @param mixed $p_result_list
3313
     * @return int
3314
     */
3315
3316
    public function _deleteByRule(&$p_result_list, $p_params)
3317
    {
3318
        $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...
3319
3320
        $v_list_detail = [];
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...
3321
3322
        // ----- Open the zip file
3323
3324
        if (1 != ($v_result = $this->_openFd('rb'))) {
3325
            // ----- Return
3326
3327
            return $v_result;
3328
        }
3329
3330
        // ----- Read the central directory informations
3331
3332
        $v_central_dir = [];
3333
3334
        if (1 != ($v_result = $this->_readEndCentralDir($v_central_dir))) {
3335
            $this->_closeFd();
3336
3337
            return $v_result;
3338
        }
3339
3340
        // ----- Go to beginning of File
3341
3342
        @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...
3343
3344
        // ----- Scan all the files
3345
3346
        // ----- Start at beginning of Central Dir
3347
3348
        $v_pos_entry = $v_central_dir['offset'];
3349
3350
        @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...
3351
3352 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...
3353
            // ----- Clean
3354
3355
            $this->_closeFd();
3356
3357
            $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
3358
3359
            return self::errorCode();
3360
        }
3361
3362
        // ----- Read each entry
3363
3364
        $v_header_list = [];
3365
3366
        $j_start = 0;
3367
3368
        for ($i = 0, $v_nb_extracted = 0; $i < $v_central_dir['entries']; ++$i) {
3369
            // ----- Read the file header
3370
3371
            $v_header_list[$v_nb_extracted] = [];
3372
3373
            $v_result = $this->_readCentralFileHeader($v_header_list[$v_nb_extracted]);
3374
3375
            if (1 != $v_result) {
3376
                // ----- Clean
3377
3378
                $this->_closeFd();
3379
3380
                return $v_result;
3381
            }
3382
3383
            // ----- Store the index
3384
3385
            $v_header_list[$v_nb_extracted]['index'] = $i;
3386
3387
            // ----- Look for the specific extract rules
3388
3389
            $v_found = false;
3390
3391
            // ----- Look for extract by name rule
3392
3393
            if (isset($p_params[ARCHIVE_ZIP_PARAM_BY_NAME])
3394
                && (0 != $p_params[ARCHIVE_ZIP_PARAM_BY_NAME])) {
3395
                // ----- Look if the filename is in the list
3396
3397
                for ($j = 0; ($j < count($p_params[ARCHIVE_ZIP_PARAM_BY_NAME]))
3398
                             && (!$v_found); $j++) {
3399
                    // ----- Look for a directory
3400
3401
                    if ('/' == mb_substr($p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j], -1)) {
3402
                        // ----- Look if the directory is in the filename path
3403
3404
                        if ((mb_strlen($v_header_list[$v_nb_extracted]['stored_filename']) > mb_strlen($p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j]))
3405
                            && (mb_substr($v_header_list[$v_nb_extracted]['stored_filename'], 0, mb_strlen($p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j])) == $p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j])) {
3406
                            $v_found = true;
3407
                        } elseif ((0x00000010 == ($v_header_list[$v_nb_extracted]['external'] & 0x00000010)) /* Indicates a folder */
3408
                                  && ($v_header_list[$v_nb_extracted]['stored_filename'] . '/' == $p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j])) {
3409
                            $v_found = true;
3410
                        }
3411
                    } // ----- Look for a filename
3412
3413
                    elseif ($v_header_list[$v_nb_extracted]['stored_filename'] == $p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j]) {
3414
                        $v_found = true;
3415
                    }
3416
                }
3417
            } // ----- Look for extract by ereg rule
3418
3419 View Code Duplication
            elseif (isset($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...
3420
                    && ('' != $p_params[ARCHIVE_ZIP_PARAM_BY_EREG])) {
3421
                if (ereg($p_params[ARCHIVE_ZIP_PARAM_BY_EREG], $v_header_list[$v_nb_extracted]['stored_filename'])) {
3422
                    $v_found = true;
3423
                }
3424
            } // ----- Look for extract by preg rule
3425
3426 View Code Duplication
            elseif (isset($p_params[ARCHIVE_ZIP_PARAM_BY_PREG])
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...
3427
                    && ('' != $p_params[ARCHIVE_ZIP_PARAM_BY_PREG])) {
3428
                if (preg_match($p_params[ARCHIVE_ZIP_PARAM_BY_PREG], $v_header_list[$v_nb_extracted]['stored_filename'])) {
3429
                    $v_found = true;
3430
                }
3431
            } // ----- Look for extract by index rule
3432
3433 View Code Duplication
            elseif (isset($p_params[ARCHIVE_ZIP_PARAM_BY_INDEX])
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...
3434
                    && (0 != $p_params[ARCHIVE_ZIP_PARAM_BY_INDEX])) {
3435
                // ----- Look if the index is in the list
3436
3437
                for ($j = $j_start; ($j < count($p_params[ARCHIVE_ZIP_PARAM_BY_INDEX]))
3438
                                    && (!$v_found); $j++) {
3439
                    if (($i >= $p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['start'])
3440
                        && ($i <= $p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['end'])) {
3441
                        $v_found = true;
3442
                    }
3443
3444
                    if ($i >= $p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['end']) {
3445
                        $j_start = $j + 1;
3446
                    }
3447
3448
                    if ($p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['start'] > $i) {
3449
                        break;
3450
                    }
3451
                }
3452
            }
3453
3454
            // ----- Look for deletion
3455
3456
            if ($v_found) {
3457
                unset($v_header_list[$v_nb_extracted]);
3458
            } else {
3459
                $v_nb_extracted++;
3460
            }
3461
        }
3462
3463
        // ----- Look if something need to be deleted
3464
3465
        if ($v_nb_extracted > 0) {
3466
            // ----- Creates a temporay file
3467
3468
            $v_zip_temp_name = ARCHIVE_ZIP_TEMPORARY_DIR . uniqid('archive_zip-') . '.tmp';
3469
3470
            // ----- Creates a temporary zip archive
3471
3472
            $v_temp_zip = new self($v_zip_temp_name);
3473
3474
            // ----- Open the temporary zip file in write mode
3475
3476
            if (1 != ($v_result = $v_temp_zip->_openFd('wb'))) {
3477
                $this->_closeFd();
3478
3479
                // ----- Return
3480
3481
                return $v_result;
3482
            }
3483
3484
            // ----- Look which file need to be kept
3485
3486
            for ($i = 0; $i < count($v_header_list); ++$i) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
3487
                // ----- Calculate the position of the header
3488
3489
                @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...
3490
3491
                if (@fseek($this->_zip_fd, $v_header_list[$i]['offset'])) {
3492
                    // ----- Clean
3493
3494
                    $this->_closeFd();
3495
3496
                    $v_temp_zip->_closeFd();
3497
3498
                    @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...
3499
3500
                    $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
3501
3502
                    return self::errorCode();
3503
                }
3504
3505
                // ----- Read the file header
3506
3507 View Code Duplication
                if (1 != ($v_result = $this->_readFileHeader($v_header_list[$i]))) {
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...
3508
                    // ----- Clean
3509
3510
                    $this->_closeFd();
3511
3512
                    $v_temp_zip->_closeFd();
3513
3514
                    @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...
3515
3516
                    return $v_result;
3517
                }
3518
3519
                // ----- Write the file header
3520
3521
                $v_result = $v_temp_zip->_writeFileHeader($v_header_list[$i]);
3522
3523
                if (1 != $v_result) {
3524
                    // ----- Clean
3525
3526
                    $this->_closeFd();
3527
3528
                    $v_temp_zip->_closeFd();
3529
3530
                    @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...
3531
3532
                    return $v_result;
3533
                }
3534
3535
                // ----- Read/write the data block
3536
3537
                $v_result = $this->_tool_CopyBlock($this->_zip_fd, $v_temp_zip->_zip_fd, $v_header_list[$i]['compressed_size']);
3538
3539
                if (1 != $v_result) {
3540
                    // ----- Clean
3541
3542
                    $this->_closeFd();
3543
3544
                    $v_temp_zip->_closeFd();
3545
3546
                    @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...
3547
3548
                    return $v_result;
3549
                }
3550
            }
3551
3552
            // ----- Store the offset of the central dir
3553
3554
            $v_offset = @ftell($v_temp_zip->_zip_fd);
3555
3556
            // ----- Re-Create the Central Dir files header
3557
3558
            for ($i = 0; $i < count($v_header_list); ++$i) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
3559
                // ----- Create the file header
3560
3561
                $v_result = $v_temp_zip->_writeCentralFileHeader($v_header_list[$i]);
3562
3563
                if (1 != $v_result) {
3564
                    // ----- Clean
3565
3566
                    $v_temp_zip->_closeFd();
3567
3568
                    $this->_closeFd();
3569
3570
                    @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...
3571
3572
                    return $v_result;
3573
                }
3574
3575
                // ----- Transform the header to a 'usable' info
3576
3577
                $v_temp_zip->_convertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);
3578
            }
3579
3580
            // ----- Zip file comment
3581
3582
            $v_comment = '';
3583
3584
            // ----- Calculate the size of the central header
3585
3586
            $v_size = @ftell($v_temp_zip->_zip_fd) - $v_offset;
3587
3588
            // ----- Create the central dir footer
3589
3590
            $v_result = $v_temp_zip->_writeCentralHeader(count($v_header_list), $v_size, $v_offset, $v_comment);
3591
3592 View Code Duplication
            if (1 != $v_result) {
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...
3593
                // ----- Clean
3594
3595
                unset($v_header_list);
3596
3597
                $v_temp_zip->_closeFd();
3598
3599
                $this->_closeFd();
3600
3601
                @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...
3602
3603
                return $v_result;
3604
            }
3605
3606
            // ----- Close
3607
3608
            $v_temp_zip->_closeFd();
3609
3610
            $this->_closeFd();
3611
3612
            // ----- Delete the zip file
3613
3614
            // TBC : I should test the result ...
3615
3616
            @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...
3617
3618
            // ----- Rename the temporary file
3619
3620
            // TBC : I should test the result ...
3621
3622
            //@rename($v_zip_temp_name, $this->_zipname);
3623
3624
            $this->_tool_Rename($v_zip_temp_name, $this->_zipname);
3625
3626
            // ----- Destroy the temporary archive
3627
3628
            unset($v_temp_zip);
3629
        }
3630
3631
        // ----- Return
3632
3633
        return $v_result;
3634
    }
3635
3636
    // ---------------------------------------------------------------------------
3637
3638
    // ---------------------------------------------------------------------------
3639
3640
    // Function : _dirCheck()
3641
3642
    // Description :
3643
3644
    //   Check if a directory exists, if not it creates it and all the parents directory
3645
3646
    //   which may be useful.
3647
3648
    // Parameters :
3649
3650
    //   $p_dir : Directory path to check.
3651
3652
    // Return Values :
3653
3654
    //    1 : OK
3655
3656
    //   -1 : Unable to create directory
3657
3658
    // ---------------------------------------------------------------------------
3659
3660
    /**
3661
     * Archive_Zip::_dirCheck()
3662
     *
3663
     * { Description }
3664
     *
3665
     * @param [type] $p_is_dir
3666
     * @param bool $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...
3667
     * @param mixed $p_dir
3668
     * @return int
3669
     */
3670
3671
    public function _dirCheck($p_dir, $p_is_dir = false)
3672
    {
3673
        $v_result = 1;
3674
3675
        // ----- Remove the final '/'
3676
3677
        if ($p_is_dir && ('/' == mb_substr($p_dir, -1))) {
3678
            $p_dir = mb_substr($p_dir, 0, mb_strlen($p_dir) - 1);
3679
        }
3680
3681
        // ----- Check the directory availability
3682
3683
        if (is_dir($p_dir) || ('' == $p_dir)) {
3684
            return 1;
3685
        }
3686
3687
        // ----- Extract parent directory
3688
3689
        $p_parent_dir = dirname($p_dir);
3690
3691
        // ----- Just a check
3692
3693
        if ($p_parent_dir != $p_dir) {
3694
            // ----- Look for parent directory
3695
3696
            if ('' != $p_parent_dir) {
3697
                if (1 != ($v_result = $this->_dirCheck($p_parent_dir))) {
3698
                    return $v_result;
3699
                }
3700
            }
3701
        }
3702
3703
        // ----- Create the directory
3704
3705
        if (!@mkdir($p_dir, 0777)) {
3706
            $this->_errorLog(ARCHIVE_ZIP_ERR_DIR_CREATE_FAIL, "Unable to create directory '$p_dir'");
3707
3708
            return self::errorCode();
3709
        }
3710
3711
        // ----- Return
3712
3713
        return $v_result;
3714
    }
3715
3716
    // ---------------------------------------------------------------------------
3717
3718
    // ---------------------------------------------------------------------------
3719
3720
    // Function : _merge()
3721
3722
    // Description :
3723
3724
    //   If $p_archive_to_add does not exist, the function exit with a success result.
3725
3726
    // Parameters :
3727
3728
    // Return Values :
3729
3730
    // ---------------------------------------------------------------------------
3731
3732
    /**
3733
     * Archive_Zip::_merge()
3734
     *
3735
     * { Description }
3736
     * @param $p_archive_to_add
3737
     * @return int
3738
     */
3739
3740
    public function _merge($p_archive_to_add)
3741
    {
3742
        $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...
3743
3744
        // ----- Look if the archive_to_add exists
3745
3746
        if (!is_file($p_archive_to_add->_zipname)) {
3747
            // ----- Nothing to merge, so merge is a success
3748
3749
            return 1;
3750
        }
3751
3752
        // ----- Look if the archive exists
3753
3754
        if (!is_file($this->_zipname)) {
3755
            // ----- Do a duplicate
3756
3757
            $v_result = $this->_duplicate($p_archive_to_add->_zipname);
3758
3759
            return $v_result;
3760
        }
3761
3762
        // ----- Open the zip file
3763
3764
        if (1 != ($v_result = $this->_openFd('rb'))) {
3765
            return $v_result;
3766
        }
3767
3768
        // ----- Read the central directory informations
3769
3770
        $v_central_dir = [];
3771
3772
        if (1 != ($v_result = $this->_readEndCentralDir($v_central_dir))) {
3773
            $this->_closeFd();
3774
3775
            return $v_result;
3776
        }
3777
3778
        // ----- Go to beginning of File
3779
3780
        @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...
3781
3782
        // ----- Open the archive_to_add file
3783
3784
        if (1 != ($v_result = $p_archive_to_add->_openFd('rb'))) {
3785
            $this->_closeFd();
3786
3787
            return $v_result;
3788
        }
3789
3790
        // ----- Read the central directory informations
3791
3792
        $v_central_dir_to_add = [];
3793
3794
        $v_result = $p_archive_to_add->_readEndCentralDir($v_central_dir_to_add);
3795
3796
        if (1 != $v_result) {
3797
            $this->_closeFd();
3798
3799
            $p_archive_to_add->_closeFd();
3800
3801
            return $v_result;
3802
        }
3803
3804
        // ----- Go to beginning of File
3805
3806
        @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...
3807
3808
        // ----- Creates a temporay file
3809
3810
        $v_zip_temp_name = ARCHIVE_ZIP_TEMPORARY_DIR . uniqid('archive_zip-') . '.tmp';
3811
3812
        // ----- Open the temporary file in write mode
3813
3814 View Code Duplication
        if (0 == ($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb'))) {
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...
3815
            $this->_closeFd();
3816
3817
            $p_archive_to_add->_closeFd();
3818
3819
            $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \'' . $v_zip_temp_name . '\' in binary write mode');
3820
3821
            return self::errorCode();
3822
        }
3823
3824
        // ----- Copy the files from the archive to the temporary file
3825
3826
        // TBC : Here I should better append the file and go back to erase the
3827
3828
        // central dir
3829
3830
        $v_size = $v_central_dir['offset'];
3831
3832
        while (0 != $v_size) {
3833
            $v_read_size = ($v_size < ARCHIVE_ZIP_READ_BLOCK_SIZE ? $v_size : ARCHIVE_ZIP_READ_BLOCK_SIZE);
3834
3835
            $v_buffer = fread($this->_zip_fd, $v_read_size);
3836
3837
            @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...
3838
3839
            $v_size -= $v_read_size;
3840
        }
3841
3842
        // ----- Copy the files from the archive_to_add into the temporary file
3843
3844
        $v_size = $v_central_dir_to_add['offset'];
3845
3846
        while (0 != $v_size) {
3847
            $v_read_size = ($v_size < ARCHIVE_ZIP_READ_BLOCK_SIZE ? $v_size : ARCHIVE_ZIP_READ_BLOCK_SIZE);
3848
3849
            $v_buffer = fread($p_archive_to_add->_zip_fd, $v_read_size);
3850
3851
            @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...
3852
3853
            $v_size -= $v_read_size;
3854
        }
3855
3856
        // ----- Store the offset of the central dir
3857
3858
        $v_offset = @ftell($v_zip_temp_fd);
3859
3860
        // ----- Copy the block of file headers from the old archive
3861
3862
        $v_size = $v_central_dir['size'];
3863
3864 View Code Duplication
        while (0 != $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...
3865
            $v_read_size = ($v_size < ARCHIVE_ZIP_READ_BLOCK_SIZE ? $v_size : ARCHIVE_ZIP_READ_BLOCK_SIZE);
3866
3867
            $v_buffer = @fread($this->_zip_fd, $v_read_size);
3868
3869
            @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...
3870
3871
            $v_size -= $v_read_size;
3872
        }
3873
3874
        // ----- Copy the block of file headers from the archive_to_add
3875
3876
        $v_size = $v_central_dir_to_add['size'];
3877
3878 View Code Duplication
        while (0 != $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...
3879
            $v_read_size = ($v_size < ARCHIVE_ZIP_READ_BLOCK_SIZE ? $v_size : ARCHIVE_ZIP_READ_BLOCK_SIZE);
3880
3881
            $v_buffer = @fread($p_archive_to_add->_zip_fd, $v_read_size);
3882
3883
            @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...
3884
3885
            $v_size -= $v_read_size;
3886
        }
3887
3888
        // ----- Zip file comment
3889
3890
        // TBC : I should merge the two comments
3891
3892
        $v_comment = '';
3893
3894
        // ----- Calculate the size of the (new) central header
3895
3896
        $v_size = @ftell($v_zip_temp_fd) - $v_offset;
3897
3898
        // ----- Swap the file descriptor
3899
3900
        // Here is a trick : I swap the temporary fd with the zip fd, in order to use
3901
3902
        // the following methods on the temporary fil and not the real archive fd
3903
3904
        $v_swap = $this->_zip_fd;
3905
3906
        $this->_zip_fd = $v_zip_temp_fd;
3907
3908
        $v_zip_temp_fd = $v_swap;
3909
3910
        // ----- Create the central dir footer
3911
3912
        if (1 != ($v_result = $this->_writeCentralHeader($v_central_dir['entries'] + $v_central_dir_to_add['entries'], $v_size, $v_offset, $v_comment))) {
3913
            $this->_closeFd();
3914
3915
            $p_archive_to_add->_closeFd();
3916
3917
            @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...
3918
3919
            $this->_zip_fd = null;
3920
3921
            // ----- Reset the file list
3922
3923
            unset($v_header_list);
3924
3925
            // ----- Return
3926
3927
            return $v_result;
3928
        }
3929
3930
        // ----- Swap back the file descriptor
3931
3932
        $v_swap = $this->_zip_fd;
3933
3934
        $this->_zip_fd = $v_zip_temp_fd;
3935
3936
        $v_zip_temp_fd = $v_swap;
3937
3938
        // ----- Close
3939
3940
        $this->_closeFd();
3941
3942
        $p_archive_to_add->_closeFd();
3943
3944
        // ----- Close the temporary file
3945
3946
        @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...
3947
3948
        // ----- Delete the zip file
3949
3950
        // TBC : I should test the result ...
3951
3952
        @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...
3953
3954
        // ----- Rename the temporary file
3955
3956
        // TBC : I should test the result ...
3957
3958
        //@rename($v_zip_temp_name, $this->_zipname);
3959
3960
        $this->_tool_Rename($v_zip_temp_name, $this->_zipname);
3961
3962
        // ----- Return
3963
3964
        return $v_result;
3965
    }
3966
3967
    // ---------------------------------------------------------------------------
3968
3969
    // ---------------------------------------------------------------------------
3970
3971
    // Function : _duplicate()
3972
3973
    // Description :
3974
3975
    // Parameters :
3976
3977
    // Return Values :
3978
3979
    // ---------------------------------------------------------------------------
3980
3981
    /**
3982
     * Archive_Zip::_duplicate()
3983
     *
3984
     * { Description }
3985
     * @param $p_archive_filename
3986
     * @return int
3987
     */
3988
3989
    public function _duplicate($p_archive_filename)
3990
    {
3991
        $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...
3992
3993
        // ----- Look if the $p_archive_filename exists
3994
3995
        if (!is_file($p_archive_filename)) {
3996
            // ----- Nothing to duplicate, so duplicate is a success.
3997
3998
            $v_result = 1;
3999
4000
            // ----- Return
4001
4002
            return $v_result;
4003
        }
4004
4005
        // ----- Open the zip file
4006
4007
        if (1 != ($v_result = $this->_openFd('wb'))) {
4008
            // ----- Return
4009
4010
            return $v_result;
4011
        }
4012
4013
        // ----- Open the temporary file in write mode
4014
4015 View Code Duplication
        if (0 == ($v_zip_temp_fd = @fopen($p_archive_filename, 'rb'))) {
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...
4016
            $this->_closeFd();
4017
4018
            $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive file \'' . $p_archive_filename . '\' in binary write mode');
4019
4020
            return self::errorCode();
4021
        }
4022
4023
        // ----- Copy the files from the archive to the temporary file
4024
4025
        // TBC : Here I should better append the file and go back to erase the
4026
4027
        // central dir
4028
4029
        $v_size = filesize($p_archive_filename);
4030
4031
        while (0 != $v_size) {
4032
            $v_read_size = ($v_size < ARCHIVE_ZIP_READ_BLOCK_SIZE ? $v_size : ARCHIVE_ZIP_READ_BLOCK_SIZE);
4033
4034
            $v_buffer = fread($v_zip_temp_fd, $v_read_size);
4035
4036
            @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...
4037
4038
            $v_size -= $v_read_size;
4039
        }
4040
4041
        // ----- Close
4042
4043
        $this->_closeFd();
4044
4045
        // ----- Close the temporary file
4046
4047
        @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...
4048
4049
        return $v_result;
4050
    }
4051
4052
    // ---------------------------------------------------------------------------
4053
4054
    /**
4055
     * Archive_Zip::_check_parameters()
4056
     *
4057
     * { Description }
4058
     *
4059
     * @param $p_default
4060
     * @param mixed $p_params
4061
     * @return int
4062
     * @internal param int $p_error_code
4063
     * @internal param string $p_error_string
4064
     */
4065
4066
    public function _check_parameters(&$p_params, $p_default)
4067
    {
4068
        // ----- Check that param is an array
4069
4070
        if (!is_array($p_params)) {
4071
            $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER, 'Unsupported parameter, waiting for an array');
4072
4073
            return self::errorCode();
4074
        }
4075
4076
        // ----- Check that all the params are valid
4077
4078
        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...
4079
            if (!isset($p_default[$v_key])) {
4080
                $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER, 'Unsupported parameter with key \'' . $v_key . '\'');
4081
4082
                return self::errorCode();
4083
            }
4084
        }
4085
4086
        // ----- Set the default values
4087
4088
        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...
4089
            if (!isset($p_params[$v_key])) {
4090
                $p_params[$v_key] = $p_default[$v_key];
4091
            }
4092
        }
4093
4094
        // ----- Check specific parameters
4095
4096
        $v_callback_list = [
4097
            'callback_pre_add',
4098
            'callback_post_add',
4099
            'callback_pre_extract',
4100
            'callback_post_extract',
4101
        ];
4102
4103
        for ($i = 0; $i < count($v_callback_list); ++$i) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
4104
            $v_key = $v_callback_list[$i];
4105
4106
            if (isset($p_params[$v_key]) && ('' != $p_params[$v_key])) {
4107
                if (!function_exists($p_params[$v_key])) {
4108
                    $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAM_VALUE, "Callback '" . $p_params[$v_key] . "()' is not an existing function for " . "parameter '" . $v_key . "'");
4109
4110
                    return self::errorCode();
4111
                }
4112
            }
4113
        }
4114
4115
        return 1;
4116
    }
4117
4118
    // ---------------------------------------------------------------------------
4119
4120
    // ---------------------------------------------------------------------------
4121
4122
    // Function : _errorLog()
4123
4124
    // Description :
4125
4126
    // Parameters :
4127
4128
    // ---------------------------------------------------------------------------
4129
4130
    /**
4131
     * Archive_Zip::_errorLog()
4132
     *
4133
     * { Description }
4134
     *
4135
     * @param int $p_error_code
4136
     * @param string  $p_error_string
4137
     */
4138
4139
    public function _errorLog($p_error_code = 0, $p_error_string = '')
4140
    {
4141
        $this->_error_code = $p_error_code;
4142
4143
        $this->_error_string = $p_error_string;
4144
    }
4145
4146
    // ---------------------------------------------------------------------------
4147
4148
    // ---------------------------------------------------------------------------
4149
4150
    // Function : _errorReset()
4151
4152
    // Description :
4153
4154
    // Parameters :
4155
4156
    // ---------------------------------------------------------------------------
4157
4158
    /**
4159
     * Archive_Zip::_errorReset()
4160
     *
4161
     * { Description }
4162
     */
4163
4164
    public function _errorReset()
4165
    {
4166
        $this->_error_code = 1;
4167
4168
        $this->_error_string = '';
4169
    }
4170
4171
    // ---------------------------------------------------------------------------
4172
4173
    // ---------------------------------------------------------------------------
4174
4175
    // Function : $this->_tool_PathReduction()
4176
4177
    // Description :
4178
4179
    // Parameters :
4180
4181
    // Return Values :
4182
4183
    // ---------------------------------------------------------------------------
4184
4185
    /**
4186
     * _tool_PathReduction()
4187
     *
4188
     * { Description }
4189
     * @param $p_dir
4190
     * @return string
4191
     */
4192
4193
    public function _tool_PathReduction($p_dir)
4194
    {
4195
        $v_result = '';
4196
4197
        // ----- Look for not empty path
4198
4199
        if ('' != $p_dir) {
4200
            // ----- Explode path by directory names
4201
4202
            $v_list = explode('/', $p_dir);
4203
4204
            // ----- Study directories from last to first
4205
4206
            for ($i = count($v_list) - 1; $i >= 0; $i--) {
4207
                // ----- Look for current path
4208
4209
                if ('.' == $v_list[$i]) {
4210
                    // ----- Ignore this directory
4211
                    // Should be the first $i=0, but no check is done
4212
                } elseif ('..' == $v_list[$i]) {
4213
                    // ----- Ignore it and ignore the $i-1
4214
4215
                    $i--;
4216
                } elseif (('' == $v_list[$i]) && ($i != (count($v_list) - 1)) && (0 != $i)) {
4217
                    // ----- Ignore only the double '//' in path,
4218
                    // but not the first and last '/'
4219
                } else {
4220
                    $v_result = $v_list[$i] . ($i != (count($v_list) - 1) ? '/' . $v_result : '');
4221
                }
4222
            }
4223
        }
4224
4225
        // ----- Return
4226
4227
        return $v_result;
4228
    }
4229
4230
    // ---------------------------------------------------------------------------
4231
4232
    // ---------------------------------------------------------------------------
4233
4234
    // Function : $this->_tool_PathInclusion()
4235
4236
    // Description :
4237
4238
    //   This function indicates if the path $p_path is under the $p_dir tree. Or,
4239
4240
    //   said in an other way, if the file or sub-dir $p_path is inside the dir
4241
4242
    //   $p_dir.
4243
4244
    //   The function indicates also if the path is exactly the same as the dir.
4245
4246
    //   This function supports path with duplicated '/' like '//', but does not
4247
4248
    //   support '.' or '..' statements.
4249
4250
    // Parameters :
4251
4252
    // Return Values :
4253
4254
    //   0 if $p_path is not inside directory $p_dir
4255
4256
    //   1 if $p_path is inside directory $p_dir
4257
4258
    //   2 if $p_path is exactly the same as $p_dir
4259
4260
    // ---------------------------------------------------------------------------
4261
4262
    /**
4263
     * _tool_PathInclusion()
4264
     *
4265
     * { Description }
4266
     * @param $p_dir
4267
     * @param $p_path
4268
     * @return int
4269
     */
4270
4271
    public function _tool_PathInclusion($p_dir, $p_path)
4272
    {
4273
        $v_result = 1;
4274
4275
        // ----- Explode dir and path by directory separator
4276
4277
        $v_list_dir = explode('/', $p_dir);
4278
4279
        $v_list_dir_size = count($v_list_dir);
4280
4281
        $v_list_path = explode('/', $p_path);
4282
4283
        $v_list_path_size = count($v_list_path);
4284
4285
        // ----- Study directories paths
4286
4287
        $i = 0;
4288
4289
        $j = 0;
4290
4291
        while (($i < $v_list_dir_size) && ($j < $v_list_path_size) && $v_result) {
4292
            // ----- Look for empty dir (path reduction)
4293
4294
            if ('' == $v_list_dir[$i]) {
4295
                $i++;
4296
4297
                continue;
4298
            }
4299
4300
            if ('' == $v_list_path[$j]) {
4301
                $j++;
4302
4303
                continue;
4304
            }
4305
4306
            // ----- Compare the items
4307
4308
            if (($v_list_dir[$i] != $v_list_path[$j])
4309
                && ('' != $v_list_dir[$i])
4310
                && ('' != $v_list_path[$j])) {
4311
                $v_result = 0;
4312
            }
4313
4314
            // ----- Next items
4315
4316
            $i++;
4317
4318
            $j++;
4319
        }
4320
4321
        // ----- Look if everything seems to be the same
4322
4323
        if ($v_result) {
4324
            // ----- Skip all the empty items
4325
4326
            while (($j < $v_list_path_size) && ('' == $v_list_path[$j])) {
4327
                $j++;
4328
            }
4329
4330
            while (($i < $v_list_dir_size) && ('' == $v_list_dir[$i])) {
4331
                $i++;
4332
            }
4333
4334
            if (($i >= $v_list_dir_size) && ($j >= $v_list_path_size)) {
4335
                // ----- There are exactly the same
4336
4337
                $v_result = 2;
4338
            } elseif ($i < $v_list_dir_size) {
4339
                // ----- The path is shorter than the dir
4340
4341
                $v_result = 0;
4342
            }
4343
        }
4344
4345
        // ----- Return
4346
4347
        return $v_result;
4348
    }
4349
4350
    // ---------------------------------------------------------------------------
4351
4352
    // ---------------------------------------------------------------------------
4353
4354
    // Function : $this->_tool_CopyBlock()
4355
4356
    // Description :
4357
4358
    // Parameters :
4359
4360
    //   $p_mode : read/write compression mode
4361
4362
    //             0 : src & dest normal
4363
4364
    //             1 : src gzip, dest normal
4365
4366
    //             2 : src normal, dest gzip
4367
4368
    //             3 : src & dest gzip
4369
4370
    // Return Values :
4371
4372
    // ---------------------------------------------------------------------------
4373
4374
    /**
4375
     * _tool_CopyBlock()
4376
     *
4377
     * { Description }
4378
     *
4379
     * @param         $p_src
4380
     * @param         $p_dest
4381
     * @param         $p_size
4382
     * @param int $p_mode
4383
     * @return int
4384
     */
4385
4386
    public function _tool_CopyBlock($p_src, $p_dest, $p_size, $p_mode = 0)
4387
    {
4388
        $v_result = 1;
4389
4390
        if (0 == $p_mode) {
4391
            while (0 != $p_size) {
4392
                $v_read_size = ($p_size < ARCHIVE_ZIP_READ_BLOCK_SIZE ? $p_size : ARCHIVE_ZIP_READ_BLOCK_SIZE);
4393
4394
                $v_buffer = @fread($p_src, $v_read_size);
4395
4396
                @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...
4397
4398
                $p_size -= $v_read_size;
4399
            }
4400 View Code Duplication
        } elseif (1 == $p_mode) {
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...
4401
            while (0 != $p_size) {
4402
                $v_read_size = ($p_size < ARCHIVE_ZIP_READ_BLOCK_SIZE ? $p_size : ARCHIVE_ZIP_READ_BLOCK_SIZE);
4403
4404
                $v_buffer = @gzread($p_src, $v_read_size);
4405
4406
                @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...
4407
4408
                $p_size -= $v_read_size;
4409
            }
4410
        } elseif (2 == $p_mode) {
4411
            while (0 != $p_size) {
4412
                $v_read_size = ($p_size < ARCHIVE_ZIP_READ_BLOCK_SIZE ? $p_size : ARCHIVE_ZIP_READ_BLOCK_SIZE);
4413
4414
                $v_buffer = @fread($p_src, $v_read_size);
4415
4416
                @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...
4417
4418
                $p_size -= $v_read_size;
4419
            }
4420 View Code Duplication
        } elseif (3 == $p_mode) {
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...
4421
            while (0 != $p_size) {
4422
                $v_read_size = ($p_size < ARCHIVE_ZIP_READ_BLOCK_SIZE ? $p_size : ARCHIVE_ZIP_READ_BLOCK_SIZE);
4423
4424
                $v_buffer = @gzread($p_src, $v_read_size);
4425
4426
                @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...
4427
4428
                $p_size -= $v_read_size;
4429
            }
4430
        }
4431
4432
        // ----- Return
4433
4434
        return $v_result;
4435
    }
4436
4437
    // ---------------------------------------------------------------------------
4438
4439
    // ---------------------------------------------------------------------------
4440
4441
    // Function : $this->_tool_Rename()
4442
4443
    // Description :
4444
4445
    //   This function tries to do a simple rename() function. If it fails, it
4446
4447
    //   tries to copy the $p_src file in a new $p_dest file and then unlink the
4448
4449
    //   first one.
4450
4451
    // Parameters :
4452
4453
    //   $p_src : Old filename
4454
4455
    //   $p_dest : New filename
4456
4457
    // Return Values :
4458
4459
    //   1 on success, 0 on failure.
4460
4461
    // ---------------------------------------------------------------------------
4462
4463
    /**
4464
     * _tool_Rename()
4465
     *
4466
     * { Description }
4467
     * @param $p_src
4468
     * @param $p_dest
4469
     * @return int
4470
     */
4471
4472
    public function _tool_Rename($p_src, $p_dest)
4473
    {
4474
        $v_result = 1;
4475
4476
        // ----- Try to rename the files
4477
4478
        if (!@rename($p_src, $p_dest)) {
4479
            // ----- Try to copy & unlink the src
4480
4481
            if (!@copy($p_src, $p_dest)) {
4482
                $v_result = 0;
4483
            } elseif (!@unlink($p_src)) {
4484
                $v_result = 0;
4485
            }
4486
        }
4487
4488
        // ----- Return
4489
4490
        return $v_result;
4491
    }
4492
4493
    // ---------------------------------------------------------------------------
4494
4495
    // ---------------------------------------------------------------------------
4496
4497
    // Function : $this->_tool_TranslateWinPath()
4498
4499
    // Description :
4500
4501
    //   Translate windows path by replacing '\' by '/' and optionally removing
4502
4503
    //   drive letter.
4504
4505
    // Parameters :
4506
4507
    //   $p_path : path to translate.
4508
4509
    //   $p_remove_disk_letter : true | false
4510
4511
    // Return Values :
4512
4513
    //   The path translated.
4514
4515
    // ---------------------------------------------------------------------------
4516
4517
    /**
4518
     * _tool_TranslateWinPath()
4519
     *
4520
     * { Description }
4521
     *
4522
     * @param [type] $p_remove_disk_letter
4523
     * @param bool $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...
4524
     * @param mixed $p_path
4525
     * @return bool|string
4526
     */
4527
4528
    public function _tool_TranslateWinPath($p_path, $p_remove_disk_letter = true)
4529
    {
4530
        if (mb_stristr(php_uname(), 'windows')) {
4531
            // ----- Look for potential disk letter
4532
4533
            if ($p_remove_disk_letter
4534
                && (false != ($v_position = mb_strpos($p_path, ':')))) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $v_position = mb_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...
4535
                $p_path = mb_substr($p_path, $v_position + 1);
4536
            }
4537
4538
            // ----- Change potential windows directory separator
4539
4540
            if ((mb_strpos($p_path, '\\') > 0) || ('\\' == mb_substr($p_path, 0, 1))) {
4541
                $p_path = strtr($p_path, '\\', '/');
4542
            }
4543
        }
4544
4545
        return $p_path;
4546
    }
4547
4548
    // ---------------------------------------------------------------------------
4549
}
4550
// End of class
4551