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