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

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