PluginProbe
WP Database Backup – Unlimited Database & Files Backup by Backup for WP / 7.13
WP Database Backup – Unlimited Database & Files Backup by Backup for WP v7.13
7.13 7.12 trunk 1.1 2.1.1 5.9 6.0 6.1 6.10 6.11 6.12 6.12.1 6.2 6.3 6.4 6.5 6.5.1 6.6 6.7 6.8 6.9 7.0 7.0.1 7.1 7.10 All 34 releases
wp-database-backup / includes / admin / lib / class-pclzip.php

class-pclzip.php in WP Database Backup – Unlimited Database & Files Backup by Backup for WP 7.13, at includes/admin/lib/class-pclzip.php

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