PluginProbe
WP Database Backup – Unlimited Database & Files Backup by Backup for WP / 7.1
WP Database Backup – Unlimited Database & Files Backup by Backup for WP v7.1
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.1, at includes/admin/lib/class-pclzip.php

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