Merge branch 'MDL-52336-master' of git://github.com/marinaglancy/moodle
[moodle.git] / lib / phpexcel / PHPExcel / Shared / PCLZip / pclzip.lib.php
CommitLineData
c9fd90d4
CB
1<?php
2// --------------------------------------------------------------------------------
3// PhpConcept Library - Zip Module 2.8.2
4// --------------------------------------------------------------------------------
5// License GNU/LGPL - Vincent Blavet - August 2009
6// http://www.phpconcept.net
7// --------------------------------------------------------------------------------
8//
9// Presentation :
10// PclZip is a PHP library that manage ZIP archives.
11// So far tests show that archives generated by PclZip are readable by
12// WinZip application and other tools.
13//
14// Description :
15// See readme.txt and http://www.phpconcept.net
16//
17// Warning :
18// This library and the associated files are non commercial, non professional
19// work.
20// It should not have unexpected results. However if any damage is caused by
21// this software the author can not be responsible.
22// The use of this software is at the risk of the user.
23//
24// --------------------------------------------------------------------------------
25// $Id: pclzip.lib.php,v 1.60 2009/09/30 21:01:04 vblavet Exp $
26// --------------------------------------------------------------------------------
27
28// ----- Constants
29if (!defined('PCLZIP_READ_BLOCK_SIZE')) {
30 define('PCLZIP_READ_BLOCK_SIZE', 2048);
31}
32
33// ----- File list separator
34// In version 1.x of PclZip, the separator for file list is a space
35// (which is not a very smart choice, specifically for windows paths !).
36// A better separator should be a comma (,). This constant gives you the
37// abilty to change that.
38// However notice that changing this value, may have impact on existing
39// scripts, using space separated filenames.
40// Recommanded values for compatibility with older versions :
41//define('PCLZIP_SEPARATOR', ' ');
42// Recommanded values for smart separation of filenames.
43if (!defined('PCLZIP_SEPARATOR')) {
44 define('PCLZIP_SEPARATOR', ',');
45}
46
47// ----- Error configuration
48// 0 : PclZip Class integrated error handling
49// 1 : PclError external library error handling. By enabling this
50// you must ensure that you have included PclError library.
51// [2,...] : reserved for futur use
52if (!defined('PCLZIP_ERROR_EXTERNAL')) {
53 define('PCLZIP_ERROR_EXTERNAL', 0);
54}
55
56// ----- Optional static temporary directory
57// By default temporary files are generated in the script current
58// path.
59// If defined :
60// - MUST BE terminated by a '/'.
61// - MUST be a valid, already created directory
62// Samples :
63// define('PCLZIP_TEMPORARY_DIR', '/temp/');
64// define('PCLZIP_TEMPORARY_DIR', 'C:/Temp/');
65if (!defined('PCLZIP_TEMPORARY_DIR')) {
66 define('PCLZIP_TEMPORARY_DIR', '');
67}
68
69// ----- Optional threshold ratio for use of temporary files
70// Pclzip sense the size of the file to add/extract and decide to
71// use or not temporary file. The algorythm is looking for
72// memory_limit of PHP and apply a ratio.
73// threshold = memory_limit * ratio.
74// Recommended values are under 0.5. Default 0.47.
75// Samples :
76// define('PCLZIP_TEMPORARY_FILE_RATIO', 0.5);
77if (!defined('PCLZIP_TEMPORARY_FILE_RATIO')) {
78 define('PCLZIP_TEMPORARY_FILE_RATIO', 0.47);
79}
80
81// --------------------------------------------------------------------------------
82// ***** UNDER THIS LINE NOTHING NEEDS TO BE MODIFIED *****
83// --------------------------------------------------------------------------------
84
85// ----- Global variables
86$g_pclzip_version = "2.8.2";
87
88// ----- Error codes
89// -1 : Unable to open file in binary write mode
90// -2 : Unable to open file in binary read mode
91// -3 : Invalid parameters
92// -4 : File does not exist
93// -5 : Filename is too long (max. 255)
94// -6 : Not a valid zip file
95// -7 : Invalid extracted file size
96// -8 : Unable to create directory
97// -9 : Invalid archive extension
98// -10 : Invalid archive format
99// -11 : Unable to delete file (unlink)
100// -12 : Unable to rename file (rename)
101// -13 : Invalid header checksum
102// -14 : Invalid archive size
103define('PCLZIP_ERR_USER_ABORTED', 2);
104define('PCLZIP_ERR_NO_ERROR', 0);
105define('PCLZIP_ERR_WRITE_OPEN_FAIL', -1);
106define('PCLZIP_ERR_READ_OPEN_FAIL', -2);
107define('PCLZIP_ERR_INVALID_PARAMETER', -3);
108define('PCLZIP_ERR_MISSING_FILE', -4);
109define('PCLZIP_ERR_FILENAME_TOO_LONG', -5);
110define('PCLZIP_ERR_INVALID_ZIP', -6);
111define('PCLZIP_ERR_BAD_EXTRACTED_FILE', -7);
112define('PCLZIP_ERR_DIR_CREATE_FAIL', -8);
113define('PCLZIP_ERR_BAD_EXTENSION', -9);
114define('PCLZIP_ERR_BAD_FORMAT', -10);
115define('PCLZIP_ERR_DELETE_FILE_FAIL', -11);
116define('PCLZIP_ERR_RENAME_FILE_FAIL', -12);
117define('PCLZIP_ERR_BAD_CHECKSUM', -13);
118define('PCLZIP_ERR_INVALID_ARCHIVE_ZIP', -14);
119define('PCLZIP_ERR_MISSING_OPTION_VALUE', -15);
120define('PCLZIP_ERR_INVALID_OPTION_VALUE', -16);
121define('PCLZIP_ERR_ALREADY_A_DIRECTORY', -17);
122define('PCLZIP_ERR_UNSUPPORTED_COMPRESSION', -18);
123define('PCLZIP_ERR_UNSUPPORTED_ENCRYPTION', -19);
124define('PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE', -20);
125define('PCLZIP_ERR_DIRECTORY_RESTRICTION', -21);
126
127// ----- Options values
128define('PCLZIP_OPT_PATH', 77001);
129define('PCLZIP_OPT_ADD_PATH', 77002);
130define('PCLZIP_OPT_REMOVE_PATH', 77003);
131define('PCLZIP_OPT_REMOVE_ALL_PATH', 77004);
132define('PCLZIP_OPT_SET_CHMOD', 77005);
133define('PCLZIP_OPT_EXTRACT_AS_STRING', 77006);
134define('PCLZIP_OPT_NO_COMPRESSION', 77007);
135define('PCLZIP_OPT_BY_NAME', 77008);
136define('PCLZIP_OPT_BY_INDEX', 77009);
137define('PCLZIP_OPT_BY_EREG', 77010);
138define('PCLZIP_OPT_BY_PREG', 77011);
139define('PCLZIP_OPT_COMMENT', 77012);
140define('PCLZIP_OPT_ADD_COMMENT', 77013);
141define('PCLZIP_OPT_PREPEND_COMMENT', 77014);
142define('PCLZIP_OPT_EXTRACT_IN_OUTPUT', 77015);
143define('PCLZIP_OPT_REPLACE_NEWER', 77016);
144define('PCLZIP_OPT_STOP_ON_ERROR', 77017);
145// Having big trouble with crypt. Need to multiply 2 long int
146// which is not correctly supported by PHP ...
147//define('PCLZIP_OPT_CRYPT', 77018);
148define('PCLZIP_OPT_EXTRACT_DIR_RESTRICTION', 77019);
149define('PCLZIP_OPT_TEMP_FILE_THRESHOLD', 77020);
150define('PCLZIP_OPT_ADD_TEMP_FILE_THRESHOLD', 77020); // alias
151define('PCLZIP_OPT_TEMP_FILE_ON', 77021);
152define('PCLZIP_OPT_ADD_TEMP_FILE_ON', 77021); // alias
153define('PCLZIP_OPT_TEMP_FILE_OFF', 77022);
154define('PCLZIP_OPT_ADD_TEMP_FILE_OFF', 77022); // alias
155
156// ----- File description attributes
157define('PCLZIP_ATT_FILE_NAME', 79001);
158define('PCLZIP_ATT_FILE_NEW_SHORT_NAME', 79002);
159define('PCLZIP_ATT_FILE_NEW_FULL_NAME', 79003);
160define('PCLZIP_ATT_FILE_MTIME', 79004);
161define('PCLZIP_ATT_FILE_CONTENT', 79005);
162define('PCLZIP_ATT_FILE_COMMENT', 79006);
163
164// ----- Call backs values
165define('PCLZIP_CB_PRE_EXTRACT', 78001);
166define('PCLZIP_CB_POST_EXTRACT', 78002);
167define('PCLZIP_CB_PRE_ADD', 78003);
168define('PCLZIP_CB_POST_ADD', 78004);
169/* For futur use
170define('PCLZIP_CB_PRE_LIST', 78005);
171define('PCLZIP_CB_POST_LIST', 78006);
172define('PCLZIP_CB_PRE_DELETE', 78007);
173define('PCLZIP_CB_POST_DELETE', 78008);
174*/
175
176// --------------------------------------------------------------------------------
177// Class : PclZip
178// Description :
179// PclZip is the class that represent a Zip archive.
180// The public methods allow the manipulation of the archive.
181// Attributes :
182// Attributes must not be accessed directly.
183// Methods :
184// PclZip() : Object creator
185// create() : Creates the Zip archive
186// listContent() : List the content of the Zip archive
187// extract() : Extract the content of the archive
188// properties() : List the properties of the archive
189// --------------------------------------------------------------------------------
190class PclZip
191{
192 // ----- Filename of the zip file
193 public $zipname = '';
194
195 // ----- File descriptor of the zip file
196 public $zip_fd = 0;
197
198 // ----- Internal error handling
199 public $error_code = 1;
200 public $error_string = '';
201
202 // ----- Current status of the magic_quotes_runtime
203 // This value store the php configuration for magic_quotes
204 // The class can then disable the magic_quotes and reset it after
205 public $magic_quotes_status;
206
207 // --------------------------------------------------------------------------------
208 // Function : PclZip()
209 // Description :
210 // Creates a PclZip object and set the name of the associated Zip archive
211 // filename.
212 // Note that no real action is taken, if the archive does not exist it is not
213 // created. Use create() for that.
214 // --------------------------------------------------------------------------------
ace059fd 215 public function __construct($p_zipname)
c9fd90d4
CB
216 {
217
218 // ----- Tests the zlib
219 if (!function_exists('gzopen')) {
220 die('Abort '.basename(__FILE__).' : Missing zlib extensions');
221 }
222
223 // ----- Set the attributes
224 $this->zipname = $p_zipname;
225 $this->zip_fd = 0;
226 $this->magic_quotes_status = -1;
227
228 // ----- Return
229 return;
230 }
231 // --------------------------------------------------------------------------------
232
233 // --------------------------------------------------------------------------------
234 // Function :
235 // create($p_filelist, $p_add_dir="", $p_remove_dir="")
236 // create($p_filelist, $p_option, $p_option_value, ...)
237 // Description :
238 // This method supports two different synopsis. The first one is historical.
239 // This method creates a Zip Archive. The Zip file is created in the
240 // filesystem. The files and directories indicated in $p_filelist
241 // are added in the archive. See the parameters description for the
242 // supported format of $p_filelist.
243 // When a directory is in the list, the directory and its content is added
244 // in the archive.
245 // In this synopsis, the function takes an optional variable list of
246 // options. See bellow the supported options.
247 // Parameters :
248 // $p_filelist : An array containing file or directory names, or
249 // a string containing one filename or one directory name, or
250 // a string containing a list of filenames and/or directory
251 // names separated by spaces.
252 // $p_add_dir : A path to add before the real path of the archived file,
253 // in order to have it memorized in the archive.
254 // $p_remove_dir : A path to remove from the real path of the file to archive,
255 // in order to have a shorter path memorized in the archive.
256 // When $p_add_dir and $p_remove_dir are set, $p_remove_dir
257 // is removed first, before $p_add_dir is added.
258 // Options :
259 // PCLZIP_OPT_ADD_PATH :
260 // PCLZIP_OPT_REMOVE_PATH :
261 // PCLZIP_OPT_REMOVE_ALL_PATH :
262 // PCLZIP_OPT_COMMENT :
263 // PCLZIP_CB_PRE_ADD :
264 // PCLZIP_CB_POST_ADD :
265 // Return Values :
266 // 0 on failure,
267 // The list of the added files, with a status of the add action.
268 // (see PclZip::listContent() for list entry format)
269 // --------------------------------------------------------------------------------
270 public function create($p_filelist)
271 {
272 $v_result=1;
273
274 // ----- Reset the error handler
275 $this->privErrorReset();
276
277 // ----- Set default values
278 $v_options = array();
279 $v_options[PCLZIP_OPT_NO_COMPRESSION] = false;
280
281 // ----- Look for variable options arguments
282 $v_size = func_num_args();
283
284 // ----- Look for arguments
285 if ($v_size > 1) {
286 // ----- Get the arguments
287 $v_arg_list = func_get_args();
288
289 // ----- Remove from the options list the first argument
290 array_shift($v_arg_list);
291 $v_size--;
292
293 // ----- Look for first arg
294 if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
295 // ----- Parse the options
296 $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, array (
297 PCLZIP_OPT_REMOVE_PATH => 'optional',
298 PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
299 PCLZIP_OPT_ADD_PATH => 'optional',
300 PCLZIP_CB_PRE_ADD => 'optional',
301 PCLZIP_CB_POST_ADD => 'optional',
302 PCLZIP_OPT_NO_COMPRESSION => 'optional',
303 PCLZIP_OPT_COMMENT => 'optional',
304 PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
305 PCLZIP_OPT_TEMP_FILE_ON => 'optional',
306 PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
307 //, PCLZIP_OPT_CRYPT => 'optional'
308 ));
309 if ($v_result != 1) {
310 return 0;
311 }
312 } else {
313 // ----- Look for 2 args
314 // Here we need to support the first historic synopsis of the
315 // method.
316 // ----- Get the first argument
317 $v_options[PCLZIP_OPT_ADD_PATH] = $v_arg_list[0];
318
319 // ----- Look for the optional second argument
320 if ($v_size == 2) {
321 $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1];
322 } elseif ($v_size > 2) {
323 PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments");
324 return 0;
325 }
326 }
327 }
328
329 // ----- Look for default option values
330 $this->privOptionDefaultThreshold($v_options);
331
332 // ----- Init
333 $v_string_list = array();
334 $v_att_list = array();
335 $v_filedescr_list = array();
336 $p_result_list = array();
337
338 // ----- Look if the $p_filelist is really an array
339 if (is_array($p_filelist)) {
340 // ----- Look if the first element is also an array
341 // This will mean that this is a file description entry
342 if (isset($p_filelist[0]) && is_array($p_filelist[0])) {
343 $v_att_list = $p_filelist;
344 } else {
345 // ----- The list is a list of string names
346 $v_string_list = $p_filelist;
347 }
348 } elseif (is_string($p_filelist)) {
349 // ----- Look if the $p_filelist is a string
350 // ----- Create a list from the string
351 $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist);
352 } else {
353 // ----- Invalid variable type for $p_filelist
354 PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_filelist");
355 return 0;
356 }
357
358 // ----- Reformat the string list
359 if (sizeof($v_string_list) != 0) {
360 foreach ($v_string_list as $v_string) {
361 if ($v_string != '') {
362 $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string;
363 } else {
364 }
365 }
366 }
367
368 // ----- For each file in the list check the attributes
369 $v_supported_attributes = array(
370 PCLZIP_ATT_FILE_NAME => 'mandatory',
371 PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional',
372 PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional',
373 PCLZIP_ATT_FILE_MTIME => 'optional',
374 PCLZIP_ATT_FILE_CONTENT => 'optional',
375 PCLZIP_ATT_FILE_COMMENT => 'optional'
376 );
377 foreach ($v_att_list as $v_entry) {
378 $v_result = $this->privFileDescrParseAtt($v_entry, $v_filedescr_list[], $v_options, $v_supported_attributes);
379 if ($v_result != 1) {
380 return 0;
381 }
382 }
383
384 // ----- Expand the filelist (expand directories)
385 $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options);
386 if ($v_result != 1) {
387 return 0;
388 }
389
390 // ----- Call the create fct
391 $v_result = $this->privCreate($v_filedescr_list, $p_result_list, $v_options);
392 if ($v_result != 1) {
393 return 0;
394 }
395
396 // ----- Return
397 return $p_result_list;
398 }
399 // --------------------------------------------------------------------------------
400
401 // --------------------------------------------------------------------------------
402 // Function :
403 // add($p_filelist, $p_add_dir="", $p_remove_dir="")
404 // add($p_filelist, $p_option, $p_option_value, ...)
405 // Description :
406 // This method supports two synopsis. The first one is historical.
407 // This methods add the list of files in an existing archive.
408 // If a file with the same name already exists, it is added at the end of the
409 // archive, the first one is still present.
410 // If the archive does not exist, it is created.
411 // Parameters :
412 // $p_filelist : An array containing file or directory names, or
413 // a string containing one filename or one directory name, or
414 // a string containing a list of filenames and/or directory
415 // names separated by spaces.
416 // $p_add_dir : A path to add before the real path of the archived file,
417 // in order to have it memorized in the archive.
418 // $p_remove_dir : A path to remove from the real path of the file to archive,
419 // in order to have a shorter path memorized in the archive.
420 // When $p_add_dir and $p_remove_dir are set, $p_remove_dir
421 // is removed first, before $p_add_dir is added.
422 // Options :
423 // PCLZIP_OPT_ADD_PATH :
424 // PCLZIP_OPT_REMOVE_PATH :
425 // PCLZIP_OPT_REMOVE_ALL_PATH :
426 // PCLZIP_OPT_COMMENT :
427 // PCLZIP_OPT_ADD_COMMENT :
428 // PCLZIP_OPT_PREPEND_COMMENT :
429 // PCLZIP_CB_PRE_ADD :
430 // PCLZIP_CB_POST_ADD :
431 // Return Values :
432 // 0 on failure,
433 // The list of the added files, with a status of the add action.
434 // (see PclZip::listContent() for list entry format)
435 // --------------------------------------------------------------------------------
436 public function add($p_filelist)
437 {
438 $v_result=1;
439
440 // ----- Reset the error handler
441 $this->privErrorReset();
442
443 // ----- Set default values
444 $v_options = array();
445 $v_options[PCLZIP_OPT_NO_COMPRESSION] = false;
446
447 // ----- Look for variable options arguments
448 $v_size = func_num_args();
449
450 // ----- Look for arguments
451 if ($v_size > 1) {
452 // ----- Get the arguments
453 $v_arg_list = func_get_args();
454
455 // ----- Remove form the options list the first argument
456 array_shift($v_arg_list);
457 $v_size--;
458
459 // ----- Look for first arg
460 if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
461 // ----- Parse the options
462 $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, array (
463 PCLZIP_OPT_REMOVE_PATH => 'optional',
464 PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
465 PCLZIP_OPT_ADD_PATH => 'optional',
466 PCLZIP_CB_PRE_ADD => 'optional',
467 PCLZIP_CB_POST_ADD => 'optional',
468 PCLZIP_OPT_NO_COMPRESSION => 'optional',
469 PCLZIP_OPT_COMMENT => 'optional',
470 PCLZIP_OPT_ADD_COMMENT => 'optional',
471 PCLZIP_OPT_PREPEND_COMMENT => 'optional',
472 PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
473 PCLZIP_OPT_TEMP_FILE_ON => 'optional',
474 PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
475 //, PCLZIP_OPT_CRYPT => 'optional'
476 ));
477 if ($v_result != 1) {
478 return 0;
479 }
480 } else {
481 // ----- Look for 2 args
482 // Here we need to support the first historic synopsis of the
483 // method.
484 // ----- Get the first argument
485 $v_options[PCLZIP_OPT_ADD_PATH] = $v_add_path = $v_arg_list[0];
486
487 // ----- Look for the optional second argument
488 if ($v_size == 2) {
489 $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1];
490 } elseif ($v_size > 2) {
491 // ----- Error log
492 PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments");
493
494 // ----- Return
495 return 0;
496 }
497 }
498 }
499
500 // ----- Look for default option values
501 $this->privOptionDefaultThreshold($v_options);
502
503 // ----- Init
504 $v_string_list = array();
505 $v_att_list = array();
506 $v_filedescr_list = array();
507 $p_result_list = array();
508
509 // ----- Look if the $p_filelist is really an array
510 if (is_array($p_filelist)) {
511 // ----- Look if the first element is also an array
512 // This will mean that this is a file description entry
513 if (isset($p_filelist[0]) && is_array($p_filelist[0])) {
514 $v_att_list = $p_filelist;
515 } else {
516 // ----- The list is a list of string names
517 $v_string_list = $p_filelist;
518 }
519 } elseif (is_string($p_filelist)) {
520 // ----- Look if the $p_filelist is a string
521 // ----- Create a list from the string
522 $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist);
523 } else {
524 // ----- Invalid variable type for $p_filelist
525 PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type '".gettype($p_filelist)."' for p_filelist");
526 return 0;
527 }
528
529 // ----- Reformat the string list
530 if (sizeof($v_string_list) != 0) {
531 foreach ($v_string_list as $v_string) {
532 $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string;
533 }
534 }
535
536 // ----- For each file in the list check the attributes
537 $v_supported_attributes = array(
538 PCLZIP_ATT_FILE_NAME => 'mandatory',
539 PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional',
540 PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional',
541 PCLZIP_ATT_FILE_MTIME => 'optional',
542 PCLZIP_ATT_FILE_CONTENT => 'optional',
543 PCLZIP_ATT_FILE_COMMENT => 'optional',
544 );
545 foreach ($v_att_list as $v_entry) {
546 $v_result = $this->privFileDescrParseAtt($v_entry, $v_filedescr_list[], $v_options, $v_supported_attributes);
547 if ($v_result != 1) {
548 return 0;
549 }
550 }
551
552 // ----- Expand the filelist (expand directories)
553 $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options);
554 if ($v_result != 1) {
555 return 0;
556 }
557
558 // ----- Call the create fct
559 $v_result = $this->privAdd($v_filedescr_list, $p_result_list, $v_options);
560 if ($v_result != 1) {
561 return 0;
562 }
563
564 // ----- Return
565 return $p_result_list;
566 }
567 // --------------------------------------------------------------------------------
568
569 // --------------------------------------------------------------------------------
570 // Function : listContent()
571 // Description :
572 // This public method, gives the list of the files and directories, with their
573 // properties.
574 // The properties of each entries in the list are (used also in other functions) :
575 // filename : Name of the file. For a create or add action it is the filename
576 // given by the user. For an extract function it is the filename
577 // of the extracted file.
578 // stored_filename : Name of the file / directory stored in the archive.
579 // size : Size of the stored file.
580 // compressed_size : Size of the file's data compressed in the archive
581 // (without the headers overhead)
582 // mtime : Last known modification date of the file (UNIX timestamp)
583 // comment : Comment associated with the file
584 // folder : true | false
585 // index : index of the file in the archive
586 // status : status of the action (depending of the action) :
587 // Values are :
588 // ok : OK !
589 // filtered : the file / dir is not extracted (filtered by user)
590 // already_a_directory : the file can not be extracted because a
591 // directory with the same name already exists
592 // write_protected : the file can not be extracted because a file
593 // with the same name already exists and is
594 // write protected
595 // newer_exist : the file was not extracted because a newer file exists
596 // path_creation_fail : the file is not extracted because the folder
597 // does not exist and can not be created
598 // write_error : the file was not extracted because there was a
599 // error while writing the file
600 // read_error : the file was not extracted because there was a error
601 // while reading the file
602 // invalid_header : the file was not extracted because of an archive
603 // format error (bad file header)
604 // Note that each time a method can continue operating when there
605 // is an action error on a file, the error is only logged in the file status.
606 // Return Values :
607 // 0 on an unrecoverable failure,
608 // The list of the files in the archive.
609 // --------------------------------------------------------------------------------
610 public function listContent()
611 {
612 $v_result=1;
613
614 // ----- Reset the error handler
615 $this->privErrorReset();
616
617 // ----- Check archive
618 if (!$this->privCheckFormat()) {
619 return(0);
620 }
621
622 // ----- Call the extracting fct
623 $p_list = array();
624 if (($v_result = $this->privList($p_list)) != 1) {
625 unset($p_list);
626 return(0);
627 }
628
629 // ----- Return
630 return $p_list;
631 }
632 // --------------------------------------------------------------------------------
633
634 // --------------------------------------------------------------------------------
635 // Function :
636 // extract($p_path="./", $p_remove_path="")
637 // extract([$p_option, $p_option_value, ...])
638 // Description :
639 // This method supports two synopsis. The first one is historical.
640 // This method extract all the files / directories from the archive to the
641 // folder indicated in $p_path.
642 // If you want to ignore the 'root' part of path of the memorized files
643 // you can indicate this in the optional $p_remove_path parameter.
644 // By default, if a newer file with the same name already exists, the
645 // file is not extracted.
646 //
647 // If both PCLZIP_OPT_PATH and PCLZIP_OPT_ADD_PATH aoptions
648 // are used, the path indicated in PCLZIP_OPT_ADD_PATH is append
649 // at the end of the path value of PCLZIP_OPT_PATH.
650 // Parameters :
651 // $p_path : Path where the files and directories are to be extracted
652 // $p_remove_path : First part ('root' part) of the memorized path
653 // (if any similar) to remove while extracting.
654 // Options :
655 // PCLZIP_OPT_PATH :
656 // PCLZIP_OPT_ADD_PATH :
657 // PCLZIP_OPT_REMOVE_PATH :
658 // PCLZIP_OPT_REMOVE_ALL_PATH :
659 // PCLZIP_CB_PRE_EXTRACT :
660 // PCLZIP_CB_POST_EXTRACT :
661 // Return Values :
662 // 0 or a negative value on failure,
663 // The list of the extracted files, with a status of the action.
664 // (see PclZip::listContent() for list entry format)
665 // --------------------------------------------------------------------------------
666 public function extract()
667 {
668 $v_result=1;
669
670 // ----- Reset the error handler
671 $this->privErrorReset();
672
673 // ----- Check archive
674 if (!$this->privCheckFormat()) {
675 return(0);
676 }
677
678 // ----- Set default values
679 $v_options = array();
680 // $v_path = "./";
681 $v_path = '';
682 $v_remove_path = "";
683 $v_remove_all_path = false;
684
685 // ----- Look for variable options arguments
686 $v_size = func_num_args();
687
688 // ----- Default values for option
689 $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = false;
690
691 // ----- Look for arguments
692 if ($v_size > 0) {
693 // ----- Get the arguments
694 $v_arg_list = func_get_args();
695
696 // ----- Look for first arg
697 if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
698 // ----- Parse the options
699 $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, array (
700 PCLZIP_OPT_PATH => 'optional',
701 PCLZIP_OPT_REMOVE_PATH => 'optional',
702 PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
703 PCLZIP_OPT_ADD_PATH => 'optional',
704 PCLZIP_CB_PRE_EXTRACT => 'optional',
705 PCLZIP_CB_POST_EXTRACT => 'optional',
706 PCLZIP_OPT_SET_CHMOD => 'optional',
707 PCLZIP_OPT_BY_NAME => 'optional',
708 PCLZIP_OPT_BY_EREG => 'optional',
709 PCLZIP_OPT_BY_PREG => 'optional',
710 PCLZIP_OPT_BY_INDEX => 'optional',
711 PCLZIP_OPT_EXTRACT_AS_STRING => 'optional',
712 PCLZIP_OPT_EXTRACT_IN_OUTPUT => 'optional',
713 PCLZIP_OPT_REPLACE_NEWER => 'optional',
714 PCLZIP_OPT_STOP_ON_ERROR => 'optional',
715 PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional',
716 PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
717 PCLZIP_OPT_TEMP_FILE_ON => 'optional',
718 PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
719 ));
720 if ($v_result != 1) {
721 return 0;
722 }
723
724 // ----- Set the arguments
725 if (isset($v_options[PCLZIP_OPT_PATH])) {
726 $v_path = $v_options[PCLZIP_OPT_PATH];
727 }
728 if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) {
729 $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH];
730 }
731 if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) {
732 $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH];
733 }
734 if (isset($v_options[PCLZIP_OPT_ADD_PATH])) {
735 // ----- Check for '/' in last path char
736 if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) {
737 $v_path .= '/';
738 }
739 $v_path .= $v_options[PCLZIP_OPT_ADD_PATH];
740 }
741 } else {
742 // ----- Look for 2 args
743 // Here we need to support the first historic synopsis of the
744 // method.
745 // ----- Get the first argument
746 $v_path = $v_arg_list[0];
747
748 // ----- Look for the optional second argument
749 if ($v_size == 2) {
750 $v_remove_path = $v_arg_list[1];
751 } elseif ($v_size > 2) {
752 // ----- Error log
753 PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments");
754
755 // ----- Return
756 return 0;
757 }
758 }
759 }
760
761 // ----- Look for default option values
762 $this->privOptionDefaultThreshold($v_options);
763
764 // ----- Trace
765
766 // ----- Call the extracting fct
767 $p_list = array();
768 $v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, $v_remove_all_path, $v_options);
769 if ($v_result < 1) {
770 unset($p_list);
771 return(0);
772 }
773
774 // ----- Return
775 return $p_list;
776 }
777 // --------------------------------------------------------------------------------
778
779
780 // --------------------------------------------------------------------------------
781 // Function :
782 // extractByIndex($p_index, $p_path="./", $p_remove_path="")
783 // extractByIndex($p_index, [$p_option, $p_option_value, ...])
784 // Description :
785 // This method supports two synopsis. The first one is historical.
786 // This method is doing a partial extract of the archive.
787 // The extracted files or folders are identified by their index in the
788 // archive (from 0 to n).
789 // Note that if the index identify a folder, only the folder entry is
790 // extracted, not all the files included in the archive.
791 // Parameters :
792 // $p_index : A single index (integer) or a string of indexes of files to
793 // extract. The form of the string is "0,4-6,8-12" with only numbers
794 // and '-' for range or ',' to separate ranges. No spaces or ';'
795 // are allowed.
796 // $p_path : Path where the files and directories are to be extracted
797 // $p_remove_path : First part ('root' part) of the memorized path
798 // (if any similar) to remove while extracting.
799 // Options :
800 // PCLZIP_OPT_PATH :
801 // PCLZIP_OPT_ADD_PATH :
802 // PCLZIP_OPT_REMOVE_PATH :
803 // PCLZIP_OPT_REMOVE_ALL_PATH :
804 // PCLZIP_OPT_EXTRACT_AS_STRING : The files are extracted as strings and
805 // not as files.
806 // The resulting content is in a new field 'content' in the file
807 // structure.
808 // This option must be used alone (any other options are ignored).
809 // PCLZIP_CB_PRE_EXTRACT :
810 // PCLZIP_CB_POST_EXTRACT :
811 // Return Values :
812 // 0 on failure,
813 // The list of the extracted files, with a status of the action.
814 // (see PclZip::listContent() for list entry format)
815 // --------------------------------------------------------------------------------
816 //function extractByIndex($p_index, options...)
817 public function extractByIndex($p_index)
818 {
819 $v_result=1;
820
821 // ----- Reset the error handler
822 $this->privErrorReset();
823
824 // ----- Check archive
825 if (!$this->privCheckFormat()) {
826 return(0);
827 }
828
829 // ----- Set default values
830 $v_options = array();
831 // $v_path = "./";
832 $v_path = '';
833 $v_remove_path = "";
834 $v_remove_all_path = false;
835
836 // ----- Look for variable options arguments
837 $v_size = func_num_args();
838
839 // ----- Default values for option
840 $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = false;
841
842 // ----- Look for arguments
843 if ($v_size > 1) {
844 // ----- Get the arguments
845 $v_arg_list = func_get_args();
846
847 // ----- Remove form the options list the first argument
848 array_shift($v_arg_list);
849 $v_size--;
850
851 // ----- Look for first arg
852 if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) {
853 // ----- Parse the options
854 $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, array(
855 PCLZIP_OPT_PATH => 'optional',
856 PCLZIP_OPT_REMOVE_PATH => 'optional',
857 PCLZIP_OPT_REMOVE_ALL_PATH => 'optional',
858 PCLZIP_OPT_EXTRACT_AS_STRING => 'optional',
859 PCLZIP_OPT_ADD_PATH => 'optional',
860 PCLZIP_CB_PRE_EXTRACT => 'optional',
861 PCLZIP_CB_POST_EXTRACT => 'optional',
862 PCLZIP_OPT_SET_CHMOD => 'optional',
863 PCLZIP_OPT_REPLACE_NEWER => 'optional',
864 PCLZIP_OPT_STOP_ON_ERROR => 'optional',
865 PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional',
866 PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional',
867 PCLZIP_OPT_TEMP_FILE_ON => 'optional',
868 PCLZIP_OPT_TEMP_FILE_OFF => 'optional'
869 ));
870 if ($v_result != 1) {
871 return 0;
872 }
873
874 // ----- Set the arguments
875 if (isset($v_options[PCLZIP_OPT_PATH])) {
876 $v_path = $v_options[PCLZIP_OPT_PATH];
877 }
878 if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) {
879 $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH];
880 }
881 if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) {
882 $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH];
883 }
884 if (isset($v_options[PCLZIP_OPT_ADD_PATH])) {
885 // ----- Check for '/' in last path char
886 if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) {
887 $v_path .= '/';
888 }
889 $v_path .= $v_options[PCLZIP_OPT_ADD_PATH];
890 }
891 if (!isset($v_options[PCLZIP_OPT_EXTRACT_AS_STRING])) {
892 $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = false;
893 } else {
894 }
895 } else {
896 // ----- Look for 2 args
897 // Here we need to support the first historic synopsis of the
898 // method.
899
900 // ----- Get the first argument
901 $v_path = $v_arg_list[0];
902
903 // ----- Look for the optional second argument
904 if ($v_size == 2) {
905 $v_remove_path = $v_arg_list[1];
906 } elseif ($v_size > 2) {
907 // ----- Error log
908 PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments");
909
910 // ----- Return
911 return 0;
912 }
913 }
914 }
915
916 // ----- Trace
917
918 // ----- Trick
919 // Here I want to reuse extractByRule(), so I need to parse the $p_index
920 // with privParseOptions()
921 $v_arg_trick = array (PCLZIP_OPT_BY_INDEX, $p_index);
922 $v_options_trick = array();
923 $v_result = $this->privParseOptions($v_arg_trick, sizeof($v_arg_trick), $v_options_trick, array (PCLZIP_OPT_BY_INDEX => 'optional'));
924 if ($v_result != 1) {
925 return 0;
926 }
927 $v_options[PCLZIP_OPT_BY_INDEX] = $v_options_trick[PCLZIP_OPT_BY_INDEX];
928
929 // ----- Look for default option values
930 $this->privOptionDefaultThreshold($v_options);
931
932 // ----- Call the extracting fct
933 if (($v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, $v_remove_all_path, $v_options)) < 1) {
934 return(0);
935 }
936
937 // ----- Return
938 return $p_list;
939 }
940 // --------------------------------------------------------------------------------
941
942 // --------------------------------------------------------------------------------
943 // Function :
944 // delete([$p_option, $p_option_value, ...])
945 // Description :
946 // This method removes files from the archive.
947 // If no parameters are given, then all the archive is emptied.
948 // Parameters :
949 // None or optional arguments.
950 // Options :
951 // PCLZIP_OPT_BY_INDEX :
952 // PCLZIP_OPT_BY_NAME :
953 // PCLZIP_OPT_BY_EREG :
954 // PCLZIP_OPT_BY_PREG :
955 // Return Values :
956 // 0 on failure,
957 // The list of the files which are still present in the archive.
958 // (see PclZip::listContent() for list entry format)
959 // --------------------------------------------------------------------------------
960 public function delete()
961 {
962 $v_result=1;
963
964 // ----- Reset the error handler
965 $this->privErrorReset();
966
967 // ----- Check archive
968 if (!$this->privCheckFormat()) {
969 return(0);
970 }
971
972 // ----- Set default values
973 $v_options = array();
974
975 // ----- Look for variable options arguments
976 $v_size = func_num_args();
977
978 // ----- Look for arguments
979 if ($v_size > 0) {
980 // ----- Get the arguments
981 $v_arg_list = func_get_args();
982
983 // ----- Parse the options
984 $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, array (
985 PCLZIP_OPT_BY_NAME => 'optional',
986 PCLZIP_OPT_BY_EREG => 'optional',
987 PCLZIP_OPT_BY_PREG => 'optional',
988 PCLZIP_OPT_BY_INDEX => 'optional'
989 ));
990 if ($v_result != 1) {
991 return 0;
992 }
993 }
994
995 // ----- Magic quotes trick
996 $this->privDisableMagicQuotes();
997
998 // ----- Call the delete fct
999 $v_list = array();
1000 if (($v_result = $this->privDeleteByRule($v_list, $v_options)) != 1) {
1001 $this->privSwapBackMagicQuotes();
1002 unset($v_list);
1003 return(0);
1004 }
1005
1006 // ----- Magic quotes trick
1007 $this->privSwapBackMagicQuotes();
1008
1009 // ----- Return
1010 return $v_list;
1011 }
1012 // --------------------------------------------------------------------------------
1013
1014 // --------------------------------------------------------------------------------
1015 // Function : deleteByIndex()
1016 // Description :
1017 // ***** Deprecated *****
1018 // delete(PCLZIP_OPT_BY_INDEX, $p_index) should be prefered.
1019 // --------------------------------------------------------------------------------
1020 public function deleteByIndex($p_index)
1021 {
1022
1023 $p_list = $this->delete(PCLZIP_OPT_BY_INDEX, $p_index);
1024
1025 // ----- Return
1026 return $p_list;
1027 }
1028 // --------------------------------------------------------------------------------
1029
1030 // --------------------------------------------------------------------------------
1031 // Function : properties()
1032 // Description :
1033 // This method gives the properties of the archive.
1034 // The properties are :
1035 // nb : Number of files in the archive
1036 // comment : Comment associated with the archive file
1037 // status : not_exist, ok
1038 // Parameters :
1039 // None
1040 // Return Values :
1041 // 0 on failure,
1042 // An array with the archive properties.
1043 // --------------------------------------------------------------------------------
1044 public function properties()
1045 {
1046
1047 // ----- Reset the error handler
1048 $this->privErrorReset();
1049
1050 // ----- Magic quotes trick
1051 $this->privDisableMagicQuotes();
1052
1053 // ----- Check archive
1054 if (!$this->privCheckFormat()) {
1055 $this->privSwapBackMagicQuotes();
1056 return(0);
1057 }
1058
1059 // ----- Default properties
1060 $v_prop = array();
1061 $v_prop['comment'] = '';
1062 $v_prop['nb'] = 0;
1063 $v_prop['status'] = 'not_exist';
1064
1065 // ----- Look if file exists
1066 if (@is_file($this->zipname)) {
1067 // ----- Open the zip file
1068 if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0) {
1069 $this->privSwapBackMagicQuotes();
1070
1071 // ----- Error log
1072 PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in binary read mode');
1073
1074 // ----- Return
1075 return 0;
1076 }
1077
1078 // ----- Read the central directory informations
1079 $v_central_dir = array();
1080 if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) {
1081 $this->privSwapBackMagicQuotes();
1082 return 0;
1083 }
1084
1085 // ----- Close the zip file
1086 $this->privCloseFd();
1087
1088 // ----- Set the user attributes
1089 $v_prop['comment'] = $v_central_dir['comment'];
1090 $v_prop['nb'] = $v_central_dir['entries'];
1091 $v_prop['status'] = 'ok';
1092 }
1093
1094 // ----- Magic quotes trick
1095 $this->privSwapBackMagicQuotes();
1096
1097 // ----- Return
1098 return $v_prop;
1099 }
1100 // --------------------------------------------------------------------------------
1101
1102 // --------------------------------------------------------------------------------
1103 // Function : duplicate()
1104 // Description :
1105 // This method creates an archive by copying the content of an other one. If
1106 // the archive already exist, it is replaced by the new one without any warning.
1107 // Parameters :
1108 // $p_archive : The filename of a valid archive, or
1109 // a valid PclZip object.
1110 // Return Values :
1111 // 1 on success.
1112 // 0 or a negative value on error (error code).
1113 // --------------------------------------------------------------------------------
1114 public function duplicate($p_archive)
1115 {
1116 $v_result = 1;
1117
1118 // ----- Reset the error handler
1119 $this->privErrorReset();
1120
1121 // ----- Look if the $p_archive is a PclZip object
1122 if ((is_object($p_archive)) && (get_class($p_archive) == 'pclzip')) {
1123 // ----- Duplicate the archive
1124 $v_result = $this->privDuplicate($p_archive->zipname);
1125 } elseif (is_string($p_archive)) {
1126 // ----- Look if the $p_archive is a string (so a filename)
1127 // ----- Check that $p_archive is a valid zip file
1128 // TBC : Should also check the archive format
1129 if (!is_file($p_archive)) {
1130 // ----- Error log
1131 PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "No file with filename '".$p_archive."'");
1132 $v_result = PCLZIP_ERR_MISSING_FILE;
1133 } else {
1134 // ----- Duplicate the archive
1135 $v_result = $this->privDuplicate($p_archive);
1136 }
1137 } else {
1138 // ----- Invalid variable
1139 // ----- Error log
1140 PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add");
1141 $v_result = PCLZIP_ERR_INVALID_PARAMETER;
1142 }
1143
1144 // ----- Return
1145 return $v_result;
1146 }
1147 // --------------------------------------------------------------------------------
1148
1149 // --------------------------------------------------------------------------------
1150 // Function : merge()
1151 // Description :
1152 // This method merge the $p_archive_to_add archive at the end of the current
1153 // one ($this).
1154 // If the archive ($this) does not exist, the merge becomes a duplicate.
1155 // If the $p_archive_to_add archive does not exist, the merge is a success.
1156 // Parameters :
1157 // $p_archive_to_add : It can be directly the filename of a valid zip archive,
1158 // or a PclZip object archive.
1159 // Return Values :
1160 // 1 on success,
1161 // 0 or negative values on error (see below).
1162 // --------------------------------------------------------------------------------
1163 public function merge($p_archive_to_add)
1164 {
1165 $v_result = 1;
1166
1167 // ----- Reset the error handler
1168 $this->privErrorReset();
1169
1170 // ----- Check archive
1171 if (!$this->privCheckFormat()) {
1172 return(0);
1173 }
1174
1175 // ----- Look if the $p_archive_to_add is a PclZip object
1176 if ((is_object($p_archive_to_add)) && (get_class($p_archive_to_add) == 'pclzip')) {
1177 // ----- Merge the archive
1178 $v_result = $this->privMerge($p_archive_to_add);
1179 } elseif (is_string($p_archive_to_add)) {
1180 // ----- Look if the $p_archive_to_add is a string (so a filename)
1181 // ----- Create a temporary archive
1182 $v_object_archive = new PclZip($p_archive_to_add);
1183
1184 // ----- Merge the archive
1185 $v_result = $this->privMerge($v_object_archive);
1186 } else {
1187 // ----- Invalid variable
1188 // ----- Error log
1189 PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add");
1190 $v_result = PCLZIP_ERR_INVALID_PARAMETER;
1191 }
1192
1193 // ----- Return
1194 return $v_result;
1195 }
1196 // --------------------------------------------------------------------------------
1197
1198
1199
1200 // --------------------------------------------------------------------------------
1201 // Function : errorCode()
1202 // Description :
1203 // Parameters :
1204 // --------------------------------------------------------------------------------
1205 public function errorCode()
1206 {
1207 if (PCLZIP_ERROR_EXTERNAL == 1) {
1208 return(PclErrorCode());
1209 } else {
1210 return($this->error_code);
1211 }
1212 }
1213 // --------------------------------------------------------------------------------
1214
1215 // --------------------------------------------------------------------------------
1216 // Function : errorName()
1217 // Description :
1218 // Parameters :
1219 // --------------------------------------------------------------------------------
1220 public function errorName($p_with_code = false)
1221 {
1222 $v_name = array(
1223 PCLZIP_ERR_NO_ERROR => 'PCLZIP_ERR_NO_ERROR',
1224 PCLZIP_ERR_WRITE_OPEN_FAIL => 'PCLZIP_ERR_WRITE_OPEN_FAIL',
1225 PCLZIP_ERR_READ_OPEN_FAIL => 'PCLZIP_ERR_READ_OPEN_FAIL',
1226 PCLZIP_ERR_INVALID_PARAMETER => 'PCLZIP_ERR_INVALID_PARAMETER',
1227 PCLZIP_ERR_MISSING_FILE => 'PCLZIP_ERR_MISSING_FILE',
1228 PCLZIP_ERR_FILENAME_TOO_LONG => 'PCLZIP_ERR_FILENAME_TOO_LONG',
1229 PCLZIP_ERR_INVALID_ZIP => 'PCLZIP_ERR_INVALID_ZIP',
1230 PCLZIP_ERR_BAD_EXTRACTED_FILE => 'PCLZIP_ERR_BAD_EXTRACTED_FILE',
1231 PCLZIP_ERR_DIR_CREATE_FAIL => 'PCLZIP_ERR_DIR_CREATE_FAIL',
1232 PCLZIP_ERR_BAD_EXTENSION => 'PCLZIP_ERR_BAD_EXTENSION',
1233 PCLZIP_ERR_BAD_FORMAT => 'PCLZIP_ERR_BAD_FORMAT',
1234 PCLZIP_ERR_DELETE_FILE_FAIL => 'PCLZIP_ERR_DELETE_FILE_FAIL',
1235 PCLZIP_ERR_RENAME_FILE_FAIL => 'PCLZIP_ERR_RENAME_FILE_FAIL',
1236 PCLZIP_ERR_BAD_CHECKSUM => 'PCLZIP_ERR_BAD_CHECKSUM',
1237 PCLZIP_ERR_INVALID_ARCHIVE_ZIP => 'PCLZIP_ERR_INVALID_ARCHIVE_ZIP',
1238 PCLZIP_ERR_MISSING_OPTION_VALUE => 'PCLZIP_ERR_MISSING_OPTION_VALUE',
1239 PCLZIP_ERR_INVALID_OPTION_VALUE => 'PCLZIP_ERR_INVALID_OPTION_VALUE',
1240 PCLZIP_ERR_UNSUPPORTED_COMPRESSION => 'PCLZIP_ERR_UNSUPPORTED_COMPRESSION',
1241 PCLZIP_ERR_UNSUPPORTED_ENCRYPTION => 'PCLZIP_ERR_UNSUPPORTED_ENCRYPTION',
1242 PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE => 'PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE',
1243 PCLZIP_ERR_DIRECTORY_RESTRICTION => 'PCLZIP_ERR_DIRECTORY_RESTRICTION',
1244 );
1245
1246 if (isset($v_name[$this->error_code])) {
1247 $v_value = $v_name[$this->error_code];
1248 } else {
1249 $v_value = 'NoName';
1250 }
1251
1252 if ($p_with_code) {
1253 return($v_value.' ('.$this->error_code.')');
1254 } else {
1255 return($v_value);
1256 }
1257 }
1258 // --------------------------------------------------------------------------------
1259
1260 // --------------------------------------------------------------------------------
1261 // Function : errorInfo()
1262 // Description :
1263 // Parameters :
1264 // --------------------------------------------------------------------------------
1265 public function errorInfo($p_full = false)
1266 {
1267 if (PCLZIP_ERROR_EXTERNAL == 1) {
1268 return(PclErrorString());
1269 } else {
1270 if ($p_full) {
1271 return($this->errorName(true)." : ".$this->error_string);
1272 } else {
1273 return($this->error_string." [code ".$this->error_code."]");
1274 }
1275 }
1276 }
1277 // --------------------------------------------------------------------------------
1278
1279
1280 // --------------------------------------------------------------------------------
1281 // ***** UNDER THIS LINE ARE DEFINED PRIVATE INTERNAL FUNCTIONS *****
1282 // ***** *****
1283 // ***** THESES FUNCTIONS MUST NOT BE USED DIRECTLY *****
1284 // --------------------------------------------------------------------------------
1285
1286
1287
1288 // --------------------------------------------------------------------------------
1289 // Function : privCheckFormat()
1290 // Description :
1291 // This method check that the archive exists and is a valid zip archive.
1292 // Several level of check exists. (futur)
1293 // Parameters :
1294 // $p_level : Level of check. Default 0.
1295 // 0 : Check the first bytes (magic codes) (default value))
1296 // 1 : 0 + Check the central directory (futur)
1297 // 2 : 1 + Check each file header (futur)
1298 // Return Values :
1299 // true on success,
1300 // false on error, the error code is set.
1301 // --------------------------------------------------------------------------------
1302 public function privCheckFormat($p_level = 0)
1303 {
1304 $v_result = true;
1305
1306 // ----- Reset the file system cache
1307 clearstatcache();
1308
1309 // ----- Reset the error handler
1310 $this->privErrorReset();
1311
1312 // ----- Look if the file exits
1313 if (!is_file($this->zipname)) {
1314 // ----- Error log
1315 PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "Missing archive file '".$this->zipname."'");
1316 return(false);
1317 }
1318
1319 // ----- Check that the file is readeable
1320 if (!is_readable($this->zipname)) {
1321 // ----- Error log
1322 PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to read archive '".$this->zipname."'");
1323 return(false);
1324 }
1325
1326 // ----- Check the magic code
1327 // TBC
1328
1329 // ----- Check the central header
1330 // TBC
1331
1332 // ----- Check each file header
1333 // TBC
1334
1335 // ----- Return
1336 return $v_result;
1337 }
1338 // --------------------------------------------------------------------------------
1339
1340 // --------------------------------------------------------------------------------
1341 // Function : privParseOptions()
1342 // Description :
1343 // This internal methods reads the variable list of arguments ($p_options_list,
1344 // $p_size) and generate an array with the options and values ($v_result_list).
1345 // $v_requested_options contains the options that can be present and those that
1346 // must be present.
1347 // $v_requested_options is an array, with the option value as key, and 'optional',
1348 // or 'mandatory' as value.
1349 // Parameters :
1350 // See above.
1351 // Return Values :
1352 // 1 on success.
1353 // 0 on failure.
1354 // --------------------------------------------------------------------------------
1355 public function privParseOptions(&$p_options_list, $p_size, &$v_result_list, $v_requested_options = false)
1356 {
1357 $v_result=1;
1358
1359 // ----- Read the options
1360 $i=0;
1361 while ($i<$p_size) {
1362 // ----- Check if the option is supported
1363 if (!isset($v_requested_options[$p_options_list[$i]])) {
1364 // ----- Error log
1365 PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid optional parameter '".$p_options_list[$i]."' for this method");
1366
1367 // ----- Return
1368 return PclZip::errorCode();
1369 }
1370
1371 // ----- Look for next option
1372 switch ($p_options_list[$i]) {
1373 // ----- Look for options that request a path value
1374 case PCLZIP_OPT_PATH:
1375 case PCLZIP_OPT_REMOVE_PATH:
1376 case PCLZIP_OPT_ADD_PATH:
1377 // ----- Check the number of parameters
1378 if (($i+1) >= $p_size) {
1379 // ----- Error log
1380 PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1381
1382 // ----- Return
1383 return PclZip::errorCode();
1384 }
1385
1386 // ----- Get the value
1387 $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i+1], false);
1388 $i++;
1389 break;
1390
1391 case PCLZIP_OPT_TEMP_FILE_THRESHOLD:
1392 // ----- Check the number of parameters
1393 if (($i+1) >= $p_size) {
1394 PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1395 return PclZip::errorCode();
1396 }
1397
1398 // ----- Check for incompatible options
1399 if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) {
1400 PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'");
1401 return PclZip::errorCode();
1402 }
1403
1404 // ----- Check the value
1405 $v_value = $p_options_list[$i+1];
1406 if ((!is_integer($v_value)) || ($v_value<0)) {
1407 PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Integer expected for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1408 return PclZip::errorCode();
1409 }
1410
1411 // ----- Get the value (and convert it in bytes)
1412 $v_result_list[$p_options_list[$i]] = $v_value*1048576;
1413 $i++;
1414 break;
1415
1416 case PCLZIP_OPT_TEMP_FILE_ON:
1417 // ----- Check for incompatible options
1418 if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) {
1419 PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'");
1420 return PclZip::errorCode();
1421 }
1422
1423 $v_result_list[$p_options_list[$i]] = true;
1424 break;
1425
1426 case PCLZIP_OPT_TEMP_FILE_OFF:
1427 // ----- Check for incompatible options
1428 if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_ON])) {
1429 PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_ON'");
1430 return PclZip::errorCode();
1431 }
1432 // ----- Check for incompatible options
1433 if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) {
1434 PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_THRESHOLD'");
1435 return PclZip::errorCode();
1436 }
1437 $v_result_list[$p_options_list[$i]] = true;
1438 break;
1439
1440 case PCLZIP_OPT_EXTRACT_DIR_RESTRICTION:
1441 // ----- Check the number of parameters
1442 if (($i+1) >= $p_size) {
1443 // ----- Error log
1444 PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1445 // ----- Return
1446 return PclZip::errorCode();
1447 }
1448
1449 // ----- Get the value
1450 if (is_string($p_options_list[$i+1]) && ($p_options_list[$i+1] != '')) {
1451 $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i+1], false);
1452 $i++;
1453 } else {
1454 }
1455 break;
1456 // ----- Look for options that request an array of string for value
1457 case PCLZIP_OPT_BY_NAME:
1458 // ----- Check the number of parameters
1459 if (($i+1) >= $p_size) {
1460 // ----- Error log
1461 PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1462 // ----- Return
1463 return PclZip::errorCode();
1464 }
1465
1466 // ----- Get the value
1467 if (is_string($p_options_list[$i+1])) {
1468 $v_result_list[$p_options_list[$i]][0] = $p_options_list[$i+1];
1469 } elseif (is_array($p_options_list[$i+1])) {
1470 $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1];
1471 } else {
1472 // ----- Error log
1473 PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1474 // ----- Return
1475 return PclZip::errorCode();
1476 }
1477 $i++;
1478 break;
1479 // ----- Look for options that request an EREG or PREG expression
1480 case PCLZIP_OPT_BY_EREG:
1481 // ereg() is deprecated starting with PHP 5.3. Move PCLZIP_OPT_BY_EREG
1482 // to PCLZIP_OPT_BY_PREG
1483 $p_options_list[$i] = PCLZIP_OPT_BY_PREG;
1484 case PCLZIP_OPT_BY_PREG:
1485 //case PCLZIP_OPT_CRYPT :
1486 // ----- Check the number of parameters
1487 if (($i+1) >= $p_size) {
1488 // ----- Error log
1489 PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1490 // ----- Return
1491 return PclZip::errorCode();
1492 }
1493
1494 // ----- Get the value
1495 if (is_string($p_options_list[$i+1])) {
1496 $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1];
1497 } else {
1498 // ----- Error log
1499 PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1500 // ----- Return
1501 return PclZip::errorCode();
1502 }
1503 $i++;
1504 break;
1505
1506 // ----- Look for options that takes a string
1507 case PCLZIP_OPT_COMMENT:
1508 case PCLZIP_OPT_ADD_COMMENT:
1509 case PCLZIP_OPT_PREPEND_COMMENT:
1510 // ----- Check the number of parameters
1511 if (($i+1) >= $p_size) {
1512 // ----- Error log
1513 PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1514
1515 // ----- Return
1516 return PclZip::errorCode();
1517 }
1518
1519 // ----- Get the value
1520 if (is_string($p_options_list[$i+1])) {
1521 $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1];
1522 } else {
1523 // ----- Error log
1524 PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '" .PclZipUtilOptionText($p_options_list[$i]) ."'");
1525
1526 // ----- Return
1527 return PclZip::errorCode();
1528 }
1529 $i++;
1530 break;
1531
1532 // ----- Look for options that request an array of index
1533 case PCLZIP_OPT_BY_INDEX:
1534 // ----- Check the number of parameters
1535 if (($i+1) >= $p_size) {
1536 // ----- Error log
1537 PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1538
1539 // ----- Return
1540 return PclZip::errorCode();
1541 }
1542
1543 // ----- Get the value
1544 $v_work_list = array();
1545 if (is_string($p_options_list[$i+1])) {
1546 // ----- Remove spaces
1547 $p_options_list[$i+1] = strtr($p_options_list[$i+1], ' ', '');
1548
1549 // ----- Parse items
1550 $v_work_list = explode(",", $p_options_list[$i+1]);
1551 } elseif (is_integer($p_options_list[$i+1])) {
1552 $v_work_list[0] = $p_options_list[$i+1].'-'.$p_options_list[$i+1];
1553 } elseif (is_array($p_options_list[$i+1])) {
1554 $v_work_list = $p_options_list[$i+1];
1555 } else {
1556 // ----- Error log
1557 PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Value must be integer, string or array for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1558
1559 // ----- Return
1560 return PclZip::errorCode();
1561 }
1562
1563 // ----- Reduce the index list
1564 // each index item in the list must be a couple with a start and
1565 // an end value : [0,3], [5-5], [8-10], ...
1566 // ----- Check the format of each item
1567 $v_sort_flag=false;
1568 $v_sort_value=0;
1569 for ($j=0; $j<sizeof($v_work_list); $j++) {
1570 // ----- Explode the item
1571 $v_item_list = explode("-", $v_work_list[$j]);
1572 $v_size_item_list = sizeof($v_item_list);
1573
1574 // ----- TBC : Here we might check that each item is a
1575 // real integer ...
1576
1577 // ----- Look for single value
1578 if ($v_size_item_list == 1) {
1579 // ----- Set the option value
1580 $v_result_list[$p_options_list[$i]][$j]['start'] = $v_item_list[0];
1581 $v_result_list[$p_options_list[$i]][$j]['end'] = $v_item_list[0];
1582 } elseif ($v_size_item_list == 2) {
1583 // ----- Set the option value
1584 $v_result_list[$p_options_list[$i]][$j]['start'] = $v_item_list[0];
1585 $v_result_list[$p_options_list[$i]][$j]['end'] = $v_item_list[1];
1586 } else {
1587 // ----- Error log
1588 PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Too many values in index range for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1589
1590 // ----- Return
1591 return PclZip::errorCode();
1592 }
1593
1594
1595 // ----- Look for list sort
1596 if ($v_result_list[$p_options_list[$i]][$j]['start'] < $v_sort_value) {
1597 $v_sort_flag=true;
1598
1599 // ----- TBC : An automatic sort should be writen ...
1600 // ----- Error log
1601 PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Invalid order of index range for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1602
1603 // ----- Return
1604 return PclZip::errorCode();
1605 }
1606 $v_sort_value = $v_result_list[$p_options_list[$i]][$j]['start'];
1607 }
1608
1609 // ----- Sort the items
1610 if ($v_sort_flag) {
1611 // TBC : To Be Completed
1612 }
1613 // ----- Next option
1614 $i++;
1615 break;
1616 // ----- Look for options that request no value
1617 case PCLZIP_OPT_REMOVE_ALL_PATH:
1618 case PCLZIP_OPT_EXTRACT_AS_STRING:
1619 case PCLZIP_OPT_NO_COMPRESSION:
1620 case PCLZIP_OPT_EXTRACT_IN_OUTPUT:
1621 case PCLZIP_OPT_REPLACE_NEWER:
1622 case PCLZIP_OPT_STOP_ON_ERROR:
1623 $v_result_list[$p_options_list[$i]] = true;
1624 break;
1625 // ----- Look for options that request an octal value
1626 case PCLZIP_OPT_SET_CHMOD:
1627 // ----- Check the number of parameters
1628 if (($i+1) >= $p_size) {
1629 // ----- Error log
1630 PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1631 // ----- Return
1632 return PclZip::errorCode();
1633 }
1634 // ----- Get the value
1635 $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1];
1636 $i++;
1637 break;
1638
1639 // ----- Look for options that request a call-back
1640 case PCLZIP_CB_PRE_EXTRACT:
1641 case PCLZIP_CB_POST_EXTRACT:
1642 case PCLZIP_CB_PRE_ADD:
1643 case PCLZIP_CB_POST_ADD:
1644 /* for futur use
1645 case PCLZIP_CB_PRE_DELETE :
1646 case PCLZIP_CB_POST_DELETE :
1647 case PCLZIP_CB_PRE_LIST :
1648 case PCLZIP_CB_POST_LIST :
1649 */
1650 // ----- Check the number of parameters
1651 if (($i+1) >= $p_size) {
1652 // ----- Error log
1653 PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1654 // ----- Return
1655 return PclZip::errorCode();
1656 }
1657
1658 // ----- Get the value
1659 $v_function_name = $p_options_list[$i+1];
1660
1661 // ----- Check that the value is a valid existing function
1662 if (!function_exists($v_function_name)) {
1663 // ----- Error log
1664 PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Function '".$v_function_name."()' is not an existing function for option '".PclZipUtilOptionText($p_options_list[$i])."'");
1665 // ----- Return
1666 return PclZip::errorCode();
1667 }
1668
1669 // ----- Set the attribute
1670 $v_result_list[$p_options_list[$i]] = $v_function_name;
1671 $i++;
1672 break;
1673 default:
1674 // ----- Error log
1675 PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Unknown parameter '" .$p_options_list[$i]."'");
1676
1677 // ----- Return
1678 return PclZip::errorCode();
1679 }
1680
1681 // ----- Next options
1682 $i++;
1683 }
1684
1685 // ----- Look for mandatory options
1686 if ($v_requested_options !== false) {
1687 for ($key=reset($v_requested_options); $key=key($v_requested_options); $key=next($v_requested_options)) {
1688 // ----- Look for mandatory option
1689 if ($v_requested_options[$key] == 'mandatory') {
1690 // ----- Look if present
1691 if (!isset($v_result_list[$key])) {
1692 // ----- Error log
1693 PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter ".PclZipUtilOptionText($key)."(".$key.")");
1694
1695 // ----- Return
1696 return PclZip::errorCode();
1697 }
1698 }
1699 }
1700 }
1701
1702 // ----- Look for default values
1703 if (!isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) {
1704 }
1705
1706 // ----- Return
1707 return $v_result;
1708 }
1709 // --------------------------------------------------------------------------------
1710
1711 // --------------------------------------------------------------------------------
1712 // Function : privOptionDefaultThreshold()
1713 // Description :
1714 // Parameters :
1715 // Return Values :
1716 // --------------------------------------------------------------------------------
1717 public function privOptionDefaultThreshold(&$p_options)
1718 {
1719 $v_result=1;
1720
1721 if (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) || isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) {
1722 return $v_result;
1723 }
1724
1725 // ----- Get 'memory_limit' configuration value
1726 $v_memory_limit = ini_get('memory_limit');
1727 $v_memory_limit = trim($v_memory_limit);
1728 $last = strtolower(substr($v_memory_limit, -1));
1729
1730 if ($last == 'g') {
1731 //$v_memory_limit = $v_memory_limit*1024*1024*1024;
1732 $v_memory_limit = $v_memory_limit*1073741824;
1733 }
1734 if ($last == 'm') {
1735 //$v_memory_limit = $v_memory_limit*1024*1024;
1736 $v_memory_limit = $v_memory_limit*1048576;
1737 }
1738 if ($last == 'k') {
1739 $v_memory_limit = $v_memory_limit*1024;
1740 }
1741
1742 $p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] = floor($v_memory_limit*PCLZIP_TEMPORARY_FILE_RATIO);
1743
1744 // ----- Sanity check : No threshold if value lower than 1M
1745 if ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] < 1048576) {
1746 unset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]);
1747 }
1748
1749 // ----- Return
1750 return $v_result;
1751 }
1752 // --------------------------------------------------------------------------------
1753
1754 // --------------------------------------------------------------------------------
1755 // Function : privFileDescrParseAtt()
1756 // Description :
1757 // Parameters :
1758 // Return Values :
1759 // 1 on success.
1760 // 0 on failure.
1761 // --------------------------------------------------------------------------------
1762 public function privFileDescrParseAtt(&$p_file_list, &$p_filedescr, $v_options, $v_requested_options = false)
1763 {
1764 $v_result=1;
1765
1766 // ----- For each file in the list check the attributes
1767 foreach ($p_file_list as $v_key => $v_value) {
1768 // ----- Check if the option is supported
1769 if (!isset($v_requested_options[$v_key])) {
1770 // ----- Error log
1771 PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file attribute '".$v_key."' for this file");
1772
1773 // ----- Return
1774 return PclZip::errorCode();
1775 }
1776
1777 // ----- Look for attribute
1778 switch ($v_key) {
1779 case PCLZIP_ATT_FILE_NAME:
1780 if (!is_string($v_value)) {
1781 PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'");
1782 return PclZip::errorCode();
1783 }
1784
1785 $p_filedescr['filename'] = PclZipUtilPathReduction($v_value);
1786
1787 if ($p_filedescr['filename'] == '') {
1788 PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty filename for attribute '".PclZipUtilOptionText($v_key)."'");
1789 return PclZip::errorCode();
1790 }
1791 break;
1792 case PCLZIP_ATT_FILE_NEW_SHORT_NAME:
1793 if (!is_string($v_value)) {
1794 PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'");
1795 return PclZip::errorCode();
1796 }
1797
1798 $p_filedescr['new_short_name'] = PclZipUtilPathReduction($v_value);
1799
1800 if ($p_filedescr['new_short_name'] == '') {
1801 PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty short filename for attribute '".PclZipUtilOptionText($v_key)."'");
1802 return PclZip::errorCode();
1803 }
1804 break;
1805 case PCLZIP_ATT_FILE_NEW_FULL_NAME:
1806 if (!is_string($v_value)) {
1807 PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'");
1808 return PclZip::errorCode();
1809 }
1810
1811 $p_filedescr['new_full_name'] = PclZipUtilPathReduction($v_value);
1812
1813 if ($p_filedescr['new_full_name'] == '') {
1814 PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty full filename for attribute '".PclZipUtilOptionText($v_key)."'");
1815 return PclZip::errorCode();
1816 }
1817 break;
1818 // ----- Look for options that takes a string
1819 case PCLZIP_ATT_FILE_COMMENT:
1820 if (!is_string($v_value)) {
1821 PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'");
1822 return PclZip::errorCode();
1823 }
1824 $p_filedescr['comment'] = $v_value;
1825 break;
1826 case PCLZIP_ATT_FILE_MTIME:
1827 if (!is_integer($v_value)) {
1828 PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". Integer expected for attribute '".PclZipUtilOptionText($v_key)."'");
1829 return PclZip::errorCode();
1830 }
1831 $p_filedescr['mtime'] = $v_value;
1832 break;
1833 case PCLZIP_ATT_FILE_CONTENT:
1834 $p_filedescr['content'] = $v_value;
1835 break;
1836 default:
1837 // ----- Error log
1838 PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Unknown parameter '".$v_key."'");
1839
1840 // ----- Return
1841 return PclZip::errorCode();
1842 }
1843
1844 // ----- Look for mandatory options
1845 if ($v_requested_options !== false) {
1846 for ($key = reset($v_requested_options); $key = key($v_requested_options); $key = next($v_requested_options)) {
1847 // ----- Look for mandatory option
1848 if ($v_requested_options[$key] == 'mandatory') {
1849 // ----- Look if present
1850 if (!isset($p_file_list[$key])) {
1851 PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter ".PclZipUtilOptionText($key)."(".$key.")");
1852 return PclZip::errorCode();
1853 }
1854 }
1855 }
1856 }
1857 }
1858
1859 // ----- Return
1860 return $v_result;
1861 }
1862 // --------------------------------------------------------------------------------
1863
1864 // --------------------------------------------------------------------------------
1865 // Function : privFileDescrExpand()
1866 // Description :
1867 // This method look for each item of the list to see if its a file, a folder
1868 // or a string to be added as file. For any other type of files (link, other)
1869 // just ignore the item.
1870 // Then prepare the information that will be stored for that file.
1871 // When its a folder, expand the folder with all the files that are in that
1872 // folder (recursively).
1873 // Parameters :
1874 // Return Values :
1875 // 1 on success.
1876 // 0 on failure.
1877 // --------------------------------------------------------------------------------
1878 public function privFileDescrExpand(&$p_filedescr_list, &$p_options)
1879 {
1880 $v_result=1;
1881
1882 // ----- Create a result list
1883 $v_result_list = array();
1884
1885 // ----- Look each entry
1886 for ($i=0; $i<sizeof($p_filedescr_list); $i++) {
1887 // ----- Get filedescr
1888 $v_descr = $p_filedescr_list[$i];
1889
1890 // ----- Reduce the filename
1891 $v_descr['filename'] = PclZipUtilTranslateWinPath($v_descr['filename'], false);
1892 $v_descr['filename'] = PclZipUtilPathReduction($v_descr['filename']);
1893
1894 // ----- Look for real file or folder
1895 if (file_exists($v_descr['filename'])) {
1896 if (@is_file($v_descr['filename'])) {
1897 $v_descr['type'] = 'file';
1898 } elseif (@is_dir($v_descr['filename'])) {
1899 $v_descr['type'] = 'folder';
1900 } elseif (@is_link($v_descr['filename'])) {
1901 // skip
1902 continue;
1903 } else {
1904 // skip
1905 continue;
1906 }
1907 } elseif (isset($v_descr['content'])) {
1908 // ----- Look for string added as file
1909 $v_descr['type'] = 'virtual_file';
1910 } else {
1911 // ----- Missing file
1912 // ----- Error log
1913 PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "File '".$v_descr['filename']."' does not exist");
1914
1915 // ----- Return
1916 return PclZip::errorCode();
1917 }
1918
1919 // ----- Calculate the stored filename
1920 $this->privCalculateStoredFilename($v_descr, $p_options);
1921
1922 // ----- Add the descriptor in result list
1923 $v_result_list[sizeof($v_result_list)] = $v_descr;
1924
1925 // ----- Look for folder
1926 if ($v_descr['type'] == 'folder') {
1927 // ----- List of items in folder
1928 $v_dirlist_descr = array();
1929 $v_dirlist_nb = 0;
1930 if ($v_folder_handler = @opendir($v_descr['filename'])) {
1931 while (($v_item_handler = @readdir($v_folder_handler)) !== false) {
1932 // ----- Skip '.' and '..'
1933 if (($v_item_handler == '.') || ($v_item_handler == '..')) {
1934 continue;
1935 }
1936
1937 // ----- Compose the full filename
1938 $v_dirlist_descr[$v_dirlist_nb]['filename'] = $v_descr['filename'].'/'.$v_item_handler;
1939
1940 // ----- Look for different stored filename
1941 // Because the name of the folder was changed, the name of the
1942 // files/sub-folders also change
1943 if (($v_descr['stored_filename'] != $v_descr['filename'])
1944 && (!isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH]))) {
1945 if ($v_descr['stored_filename'] != '') {
1946 $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_descr['stored_filename'].'/'.$v_item_handler;
1947 } else {
1948 $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_item_handler;
1949 }
1950 }
1951 $v_dirlist_nb++;
1952 }
1953
1954 @closedir($v_folder_handler);
1955 } else {
1956 // TBC : unable to open folder in read mode
1957 }
1958
1959 // ----- Expand each element of the list
1960 if ($v_dirlist_nb != 0) {
1961 // ----- Expand
1962 if (($v_result = $this->privFileDescrExpand($v_dirlist_descr, $p_options)) != 1) {
1963 return $v_result;
1964 }
1965
1966 // ----- Concat the resulting list
1967 $v_result_list = array_merge($v_result_list, $v_dirlist_descr);
1968 }
1969
1970 // ----- Free local array
1971 unset($v_dirlist_descr);
1972 }
1973 }
1974
1975 // ----- Get the result list
1976 $p_filedescr_list = $v_result_list;
1977
1978 // ----- Return
1979 return $v_result;
1980 }
1981 // --------------------------------------------------------------------------------
1982
1983 // --------------------------------------------------------------------------------
1984 // Function : privCreate()
1985 // Description :
1986 // Parameters :
1987 // Return Values :
1988 // --------------------------------------------------------------------------------
1989 public function privCreate($p_filedescr_list, &$p_result_list, &$p_options)
1990 {
1991 $v_result=1;
1992 $v_list_detail = array();
1993
1994 // ----- Magic quotes trick
1995 $this->privDisableMagicQuotes();
1996
1997 // ----- Open the file in write mode
1998 if (($v_result = $this->privOpenFd('wb')) != 1) {
1999 // ----- Return
2000 return $v_result;
2001 }
2002
2003 // ----- Add the list of files
2004 $v_result = $this->privAddList($p_filedescr_list, $p_result_list, $p_options);
2005
2006 // ----- Close
2007 $this->privCloseFd();
2008
2009 // ----- Magic quotes trick
2010 $this->privSwapBackMagicQuotes();
2011
2012 // ----- Return
2013 return $v_result;
2014 }
2015 // --------------------------------------------------------------------------------
2016
2017 // --------------------------------------------------------------------------------
2018 // Function : privAdd()
2019 // Description :
2020 // Parameters :
2021 // Return Values :
2022 // --------------------------------------------------------------------------------
2023 public function privAdd($p_filedescr_list, &$p_result_list, &$p_options)
2024 {
2025 $v_result=1;
2026 $v_list_detail = array();
2027
2028 // ----- Look if the archive exists or is empty
2029 if ((!is_file($this->zipname)) || (filesize($this->zipname) == 0)) {
2030 // ----- Do a create
2031 $v_result = $this->privCreate($p_filedescr_list, $p_result_list, $p_options);
2032
2033 // ----- Return
2034 return $v_result;
2035 }
2036 // ----- Magic quotes trick
2037 $this->privDisableMagicQuotes();
2038
2039 // ----- Open the zip file
2040 if (($v_result=$this->privOpenFd('rb')) != 1) {
2041 // ----- Magic quotes trick
2042 $this->privSwapBackMagicQuotes();
2043
2044 // ----- Return
2045 return $v_result;
2046 }
2047
2048 // ----- Read the central directory informations
2049 $v_central_dir = array();
2050 if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) {
2051 $this->privCloseFd();
2052 $this->privSwapBackMagicQuotes();
2053 return $v_result;
2054 }
2055
2056 // ----- Go to beginning of File
2057 @rewind($this->zip_fd);
2058
2059 // ----- Creates a temporay file
2060 $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp';
2061
2062 // ----- Open the temporary file in write mode
2063 if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) {
2064 $this->privCloseFd();
2065 $this->privSwapBackMagicQuotes();
2066
2067 PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_zip_temp_name.'\' in binary write mode');
2068
2069 // ----- Return
2070 return PclZip::errorCode();
2071 }
2072
2073 // ----- Copy the files from the archive to the temporary file
2074 // TBC : Here I should better append the file and go back to erase the central dir
2075 $v_size = $v_central_dir['offset'];
2076 while ($v_size != 0) {
2077 $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
2078 $v_buffer = fread($this->zip_fd, $v_read_size);
2079 @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
2080 $v_size -= $v_read_size;
2081 }
2082
2083 // ----- Swap the file descriptor
2084 // Here is a trick : I swap the temporary fd with the zip fd, in order to use
2085 // the following methods on the temporary fil and not the real archive
2086 $v_swap = $this->zip_fd;
2087 $this->zip_fd = $v_zip_temp_fd;
2088 $v_zip_temp_fd = $v_swap;
2089
2090 // ----- Add the files
2091 $v_header_list = array();
2092 if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1) {
2093 fclose($v_zip_temp_fd);
2094 $this->privCloseFd();
2095 @unlink($v_zip_temp_name);
2096 $this->privSwapBackMagicQuotes();
2097
2098 // ----- Return
2099 return $v_result;
2100 }
2101
2102 // ----- Store the offset of the central dir
2103 $v_offset = @ftell($this->zip_fd);
2104
2105 // ----- Copy the block of file headers from the old archive
2106 $v_size = $v_central_dir['size'];
2107 while ($v_size != 0) {
2108 $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
2109 $v_buffer = @fread($v_zip_temp_fd, $v_read_size);
2110 @fwrite($this->zip_fd, $v_buffer, $v_read_size);
2111 $v_size -= $v_read_size;
2112 }
2113
2114 // ----- Create the Central Dir files header
2115 for ($i=0, $v_count=0; $i<sizeof($v_header_list); $i++) {
2116 // ----- Create the file header
2117 if ($v_header_list[$i]['status'] == 'ok') {
2118 if (($v_result = $this->privWriteCentralFileHeader($v_header_list[$i])) != 1) {
2119 fclose($v_zip_temp_fd);
2120 $this->privCloseFd();
2121 @unlink($v_zip_temp_name);
2122 $this->privSwapBackMagicQuotes();
2123
2124 // ----- Return
2125 return $v_result;
2126 }
2127 $v_count++;
2128 }
2129
2130 // ----- Transform the header to a 'usable' info
2131 $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);
2132 }
2133
2134 // ----- Zip file comment
2135 $v_comment = $v_central_dir['comment'];
2136 if (isset($p_options[PCLZIP_OPT_COMMENT])) {
2137 $v_comment = $p_options[PCLZIP_OPT_COMMENT];
2138 }
2139 if (isset($p_options[PCLZIP_OPT_ADD_COMMENT])) {
2140 $v_comment = $v_comment.$p_options[PCLZIP_OPT_ADD_COMMENT];
2141 }
2142 if (isset($p_options[PCLZIP_OPT_PREPEND_COMMENT])) {
2143 $v_comment = $p_options[PCLZIP_OPT_PREPEND_COMMENT].$v_comment;
2144 }
2145
2146 // ----- Calculate the size of the central header
2147 $v_size = @ftell($this->zip_fd)-$v_offset;
2148
2149 // ----- Create the central dir footer
2150 if (($v_result = $this->privWriteCentralHeader($v_count+$v_central_dir['entries'], $v_size, $v_offset, $v_comment)) != 1) {
2151 // ----- Reset the file list
2152 unset($v_header_list);
2153 $this->privSwapBackMagicQuotes();
2154
2155 // ----- Return
2156 return $v_result;
2157 }
2158
2159 // ----- Swap back the file descriptor
2160 $v_swap = $this->zip_fd;
2161 $this->zip_fd = $v_zip_temp_fd;
2162 $v_zip_temp_fd = $v_swap;
2163
2164 // ----- Close
2165 $this->privCloseFd();
2166
2167 // ----- Close the temporary file
2168 @fclose($v_zip_temp_fd);
2169
2170 // ----- Magic quotes trick
2171 $this->privSwapBackMagicQuotes();
2172
2173 // ----- Delete the zip file
2174 // TBC : I should test the result ...
2175 @unlink($this->zipname);
2176
2177 // ----- Rename the temporary file
2178 // TBC : I should test the result ...
2179 //@rename($v_zip_temp_name, $this->zipname);
2180 PclZipUtilRename($v_zip_temp_name, $this->zipname);
2181
2182 // ----- Return
2183 return $v_result;
2184 }
2185 // --------------------------------------------------------------------------------
2186
2187 // --------------------------------------------------------------------------------
2188 // Function : privOpenFd()
2189 // Description :
2190 // Parameters :
2191 // --------------------------------------------------------------------------------
2192 public function privOpenFd($p_mode)
2193 {
2194 $v_result=1;
2195
2196 // ----- Look if already open
2197 if ($this->zip_fd != 0) {
2198 // ----- Error log
2199 PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Zip file \''.$this->zipname.'\' already open');
2200
2201 // ----- Return
2202 return PclZip::errorCode();
2203 }
2204
2205 // ----- Open the zip file
2206 if (($this->zip_fd = @fopen($this->zipname, $p_mode)) == 0) {
2207 // ----- Error log
2208 PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in '.$p_mode.' mode');
2209
2210 // ----- Return
2211 return PclZip::errorCode();
2212 }
2213
2214 // ----- Return
2215 return $v_result;
2216 }
2217 // --------------------------------------------------------------------------------
2218
2219 // --------------------------------------------------------------------------------
2220 // Function : privCloseFd()
2221 // Description :
2222 // Parameters :
2223 // --------------------------------------------------------------------------------
2224 public function privCloseFd()
2225 {
2226 $v_result=1;
2227
2228 if ($this->zip_fd != 0) {
2229 @fclose($this->zip_fd);
2230 }
2231 $this->zip_fd = 0;
2232
2233 // ----- Return
2234 return $v_result;
2235 }
2236 // --------------------------------------------------------------------------------
2237
2238 // --------------------------------------------------------------------------------
2239 // Function : privAddList()
2240 // Description :
2241 // $p_add_dir and $p_remove_dir will give the ability to memorize a path which is
2242 // different from the real path of the file. This is usefull if you want to have PclTar
2243 // running in any directory, and memorize relative path from an other directory.
2244 // Parameters :
2245 // $p_list : An array containing the file or directory names to add in the tar
2246 // $p_result_list : list of added files with their properties (specially the status field)
2247 // $p_add_dir : Path to add in the filename path archived
2248 // $p_remove_dir : Path to remove in the filename path archived
2249 // Return Values :
2250 // --------------------------------------------------------------------------------
2251 // public function privAddList($p_list, &$p_result_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, &$p_options)
2252 public function privAddList($p_filedescr_list, &$p_result_list, &$p_options)
2253 {
2254 $v_result=1;
2255
2256 // ----- Add the files
2257 $v_header_list = array();
2258 if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1) {
2259 // ----- Return
2260 return $v_result;
2261 }
2262
2263 // ----- Store the offset of the central dir
2264 $v_offset = @ftell($this->zip_fd);
2265
2266 // ----- Create the Central Dir files header
2267 for ($i=0, $v_count=0; $i<sizeof($v_header_list); $i++) {
2268 // ----- Create the file header
2269 if ($v_header_list[$i]['status'] == 'ok') {
2270 if (($v_result = $this->privWriteCentralFileHeader($v_header_list[$i])) != 1) {
2271 // ----- Return
2272 return $v_result;
2273 }
2274 $v_count++;
2275 }
2276
2277 // ----- Transform the header to a 'usable' info
2278 $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]);
2279 }
2280
2281 // ----- Zip file comment
2282 $v_comment = '';
2283 if (isset($p_options[PCLZIP_OPT_COMMENT])) {
2284 $v_comment = $p_options[PCLZIP_OPT_COMMENT];
2285 }
2286
2287 // ----- Calculate the size of the central header
2288 $v_size = @ftell($this->zip_fd)-$v_offset;
2289
2290 // ----- Create the central dir footer
2291 if (($v_result = $this->privWriteCentralHeader($v_count, $v_size, $v_offset, $v_comment)) != 1) {
2292 // ----- Reset the file list
2293 unset($v_header_list);
2294
2295 // ----- Return
2296 return $v_result;
2297 }
2298
2299 // ----- Return
2300 return $v_result;
2301 }
2302 // --------------------------------------------------------------------------------
2303
2304 // --------------------------------------------------------------------------------
2305 // Function : privAddFileList()
2306 // Description :
2307 // Parameters :
2308 // $p_filedescr_list : An array containing the file description
2309 // or directory names to add in the zip
2310 // $p_result_list : list of added files with their properties (specially the status field)
2311 // Return Values :
2312 // --------------------------------------------------------------------------------
2313 public function privAddFileList($p_filedescr_list, &$p_result_list, &$p_options)
2314 {
2315 $v_result=1;
2316 $v_header = array();
2317
2318 // ----- Recuperate the current number of elt in list
2319 $v_nb = sizeof($p_result_list);
2320
2321 // ----- Loop on the files
2322 for ($j=0; ($j<sizeof($p_filedescr_list)) && ($v_result==1); $j++) {
2323 // ----- Format the filename
2324 $p_filedescr_list[$j]['filename'] = PclZipUtilTranslateWinPath($p_filedescr_list[$j]['filename'], false);
2325
2326 // ----- Skip empty file names
2327 // TBC : Can this be possible ? not checked in DescrParseAtt ?
2328 if ($p_filedescr_list[$j]['filename'] == "") {
2329 continue;
2330 }
2331
2332 // ----- Check the filename
2333 if (($p_filedescr_list[$j]['type'] != 'virtual_file') && (!file_exists($p_filedescr_list[$j]['filename']))) {
2334 PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "File '".$p_filedescr_list[$j]['filename']."' does not exist");
2335 return PclZip::errorCode();
2336 }
2337
2338 // ----- Look if it is a file or a dir with no all path remove option
2339 // or a dir with all its path removed
2340 // if ( (is_file($p_filedescr_list[$j]['filename']))
2341 // || ( is_dir($p_filedescr_list[$j]['filename'])
2342 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]))) {
2343 // ----- Add the file
2344 $v_result = $this->privAddFile($p_filedescr_list[$j], $v_header, $p_options);
2345 if ($v_result != 1) {
2346 return $v_result;
2347 }
2348
2349 // ----- Store the file infos
2350 $p_result_list[$v_nb++] = $v_header;
2351 }
2352 }
2353
2354 // ----- Return
2355 return $v_result;
2356 }
2357 // --------------------------------------------------------------------------------
2358
2359 // --------------------------------------------------------------------------------
2360 // Function : privAddFile()
2361 // Description :
2362 // Parameters :
2363 // Return Values :
2364 // --------------------------------------------------------------------------------
2365 public function privAddFile($p_filedescr, &$p_header, &$p_options)
2366 {
2367 $v_result=1;
2368
2369 // ----- Working variable
2370 $p_filename = $p_filedescr['filename'];
2371
2372 // TBC : Already done in the fileAtt check ... ?
2373 if ($p_filename == "") {
2374 // ----- Error log
2375 PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file list parameter (invalid or empty list)");
2376
2377 // ----- Return
2378 return PclZip::errorCode();
2379 }
2380
2381 // ----- Look for a stored different filename
2382 /* TBC : Removed
2383 if (isset($p_filedescr['stored_filename'])) {
2384 $v_stored_filename = $p_filedescr['stored_filename'];
2385 }
2386 else {
2387 $v_stored_filename = $p_filedescr['stored_filename'];
2388 }
2389 */
2390
2391 // ----- Set the file properties
2392 clearstatcache();
2393 $p_header['version'] = 20;
2394 $p_header['version_extracted'] = 10;
2395 $p_header['flag'] = 0;
2396 $p_header['compression'] = 0;
2397 $p_header['crc'] = 0;
2398 $p_header['compressed_size'] = 0;
2399 $p_header['filename_len'] = strlen($p_filename);
2400 $p_header['extra_len'] = 0;
2401 $p_header['disk'] = 0;
2402 $p_header['internal'] = 0;
2403 $p_header['offset'] = 0;
2404 $p_header['filename'] = $p_filename;
2405 // TBC : Removed $p_header['stored_filename'] = $v_stored_filename;
2406 $p_header['stored_filename'] = $p_filedescr['stored_filename'];
2407 $p_header['extra'] = '';
2408 $p_header['status'] = 'ok';
2409 $p_header['index'] = -1;
2410
2411 // ----- Look for regular file
2412 if ($p_filedescr['type']=='file') {
2413 $p_header['external'] = 0x00000000;
2414 $p_header['size'] = filesize($p_filename);
2415 } elseif ($p_filedescr['type']=='folder') {
2416 // ----- Look for regular folder
2417 $p_header['external'] = 0x00000010;
2418 $p_header['mtime'] = filemtime($p_filename);
2419 $p_header['size'] = filesize($p_filename);
2420 } elseif ($p_filedescr['type'] == 'virtual_file') {
2421 // ----- Look for virtual file
2422 $p_header['external'] = 0x00000000;
2423 $p_header['size'] = strlen($p_filedescr['content']);
2424 }
2425
2426 // ----- Look for filetime
2427 if (isset($p_filedescr['mtime'])) {
2428 $p_header['mtime'] = $p_filedescr['mtime'];
2429 } elseif ($p_filedescr['type'] == 'virtual_file') {
2430 $p_header['mtime'] = time();
2431 } else {
2432 $p_header['mtime'] = filemtime($p_filename);
2433 }
2434
2435 // ------ Look for file comment
2436 if (isset($p_filedescr['comment'])) {
2437 $p_header['comment_len'] = strlen($p_filedescr['comment']);
2438 $p_header['comment'] = $p_filedescr['comment'];
2439 } else {
2440 $p_header['comment_len'] = 0;
2441 $p_header['comment'] = '';
2442 }
2443
2444 // ----- Look for pre-add callback
2445 if (isset($p_options[PCLZIP_CB_PRE_ADD])) {
2446 // ----- Generate a local information
2447 $v_local_header = array();
2448 $this->privConvertHeader2FileInfo($p_header, $v_local_header);
2449
2450 // ----- Call the callback
2451 // Here I do not use call_user_func() because I need to send a reference to the
2452 // header.
2453 // eval('$v_result = '.$p_options[PCLZIP_CB_PRE_ADD].'(PCLZIP_CB_PRE_ADD, $v_local_header);');
2454 $v_result = $p_options[PCLZIP_CB_PRE_ADD](PCLZIP_CB_PRE_ADD, $v_local_header);
2455 if ($v_result == 0) {
2456 // ----- Change the file status
2457 $p_header['status'] = "skipped";
2458 $v_result = 1;
2459 }
2460
2461 // ----- Update the informations
2462 // Only some fields can be modified
2463 if ($p_header['stored_filename'] != $v_local_header['stored_filename']) {
2464 $p_header['stored_filename'] = PclZipUtilPathReduction($v_local_header['stored_filename']);
2465 }
2466 }
2467
2468 // ----- Look for empty stored filename
2469 if ($p_header['stored_filename'] == "") {
2470 $p_header['status'] = "filtered";
2471 }
2472
2473 // ----- Check the path length
2474 if (strlen($p_header['stored_filename']) > 0xFF) {
2475 $p_header['status'] = 'filename_too_long';
2476 }
2477
2478 // ----- Look if no error, or file not skipped
2479 if ($p_header['status'] == 'ok') {
2480 // ----- Look for a file
2481 if ($p_filedescr['type'] == 'file') {
2482 // ----- Look for using temporary file to zip
2483 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'])))) {
2484 $v_result = $this->privAddFileUsingTempFile($p_filedescr, $p_header, $p_options);
2485 if ($v_result < PCLZIP_ERR_NO_ERROR) {
2486 return $v_result;
2487 }
2488 } else {
2489 // ----- Use "in memory" zip algo
2490 // ----- Open the source file
2491 if (($v_file = @fopen($p_filename, "rb")) == 0) {
2492 PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode");
2493 return PclZip::errorCode();
2494 }
2495
2496 // ----- Read the file content
2497 $v_content = @fread($v_file, $p_header['size']);
2498
2499 // ----- Close the file
2500 @fclose($v_file);
2501
2502 // ----- Calculate the CRC
2503 $p_header['crc'] = @crc32($v_content);
2504
2505 // ----- Look for no compression
2506 if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) {
2507 // ----- Set header parameters
2508 $p_header['compressed_size'] = $p_header['size'];
2509 $p_header['compression'] = 0;
2510 } else {
2511 // ----- Look for normal compression
2512 // ----- Compress the content
2513 $v_content = @gzdeflate($v_content);
2514
2515 // ----- Set header parameters
2516 $p_header['compressed_size'] = strlen($v_content);
2517 $p_header['compression'] = 8;
2518 }
2519
2520 // ----- Call the header generation
2521 if (($v_result = $this->privWriteFileHeader($p_header)) != 1) {
2522 @fclose($v_file);
2523 return $v_result;
2524 }
2525
2526 // ----- Write the compressed (or not) content
2527 @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']);
2528 }
2529 } elseif ($p_filedescr['type'] == 'virtual_file') {
2530 // ----- Look for a virtual file (a file from string)
2531 $v_content = $p_filedescr['content'];
2532
2533 // ----- Calculate the CRC
2534 $p_header['crc'] = @crc32($v_content);
2535
2536 // ----- Look for no compression
2537 if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) {
2538 // ----- Set header parameters
2539 $p_header['compressed_size'] = $p_header['size'];
2540 $p_header['compression'] = 0;
2541 } else {
2542 // ----- Look for normal compression
2543 // ----- Compress the content
2544 $v_content = @gzdeflate($v_content);
2545
2546 // ----- Set header parameters
2547 $p_header['compressed_size'] = strlen($v_content);
2548 $p_header['compression'] = 8;
2549 }
2550
2551 // ----- Call the header generation
2552 if (($v_result = $this->privWriteFileHeader($p_header)) != 1) {
2553 @fclose($v_file);
2554 return $v_result;
2555 }
2556
2557 // ----- Write the compressed (or not) content
2558 @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']);
2559 } elseif ($p_filedescr['type'] == 'folder') {
2560 // ----- Look for a directory
2561 // ----- Look for directory last '/'
2562 if (@substr($p_header['stored_filename'], -1) != '/') {
2563 $p_header['stored_filename'] .= '/';
2564 }
2565
2566 // ----- Set the file properties
2567 $p_header['size'] = 0;
2568 //$p_header['external'] = 0x41FF0010; // Value for a folder : to be checked
2569 $p_header['external'] = 0x00000010; // Value for a folder : to be checked
2570
2571 // ----- Call the header generation
2572 if (($v_result = $this->privWriteFileHeader($p_header)) != 1) {
2573 return $v_result;
2574 }
2575 }
2576 }
2577
2578 // ----- Look for post-add callback
2579 if (isset($p_options[PCLZIP_CB_POST_ADD])) {
2580 // ----- Generate a local information
2581 $v_local_header = array();
2582 $this->privConvertHeader2FileInfo($p_header, $v_local_header);
2583
2584 // ----- Call the callback
2585 // Here I do not use call_user_func() because I need to send a reference to the
2586 // header.
2587 // eval('$v_result = '.$p_options[PCLZIP_CB_POST_ADD].'(PCLZIP_CB_POST_ADD, $v_local_header);');
2588 $v_result = $p_options[PCLZIP_CB_POST_ADD](PCLZIP_CB_POST_ADD, $v_local_header);
2589 if ($v_result == 0) {
2590 // ----- Ignored
2591 $v_result = 1;
2592 }
2593
2594 // ----- Update the informations
2595 // Nothing can be modified
2596 }
2597
2598 // ----- Return
2599 return $v_result;
2600 }
2601 // --------------------------------------------------------------------------------
2602
2603 // --------------------------------------------------------------------------------
2604 // Function : privAddFileUsingTempFile()
2605 // Description :
2606 // Parameters :
2607 // Return Values :
2608 // --------------------------------------------------------------------------------
2609 public function privAddFileUsingTempFile($p_filedescr, &$p_header, &$p_options)
2610 {
2611 $v_result=PCLZIP_ERR_NO_ERROR;
2612
2613 // ----- Working variable
2614 $p_filename = $p_filedescr['filename'];
2615
2616
2617 // ----- Open the source file
2618 if (($v_file = @fopen($p_filename, "rb")) == 0) {
2619 PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode");
2620 return PclZip::errorCode();
2621 }
2622
2623 // ----- Creates a compressed temporary file
2624 $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.gz';
2625 if (($v_file_compressed = @gzopen($v_gzip_temp_name, "wb")) == 0) {
2626 fclose($v_file);
2627 PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary write mode');
2628 return PclZip::errorCode();
2629 }
2630
2631 // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
2632 $v_size = filesize($p_filename);
2633 while ($v_size != 0) {
2634 $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
2635 $v_buffer = @fread($v_file, $v_read_size);
2636 //$v_binary_data = pack('a'.$v_read_size, $v_buffer);
2637 @gzputs($v_file_compressed, $v_buffer, $v_read_size);
2638 $v_size -= $v_read_size;
2639 }
2640
2641 // ----- Close the file
2642 @fclose($v_file);
2643 @gzclose($v_file_compressed);
2644
2645 // ----- Check the minimum file size
2646 if (filesize($v_gzip_temp_name) < 18) {
2647 PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'gzip temporary file \''.$v_gzip_temp_name.'\' has invalid filesize - should be minimum 18 bytes');
2648 return PclZip::errorCode();
2649 }
2650
2651 // ----- Extract the compressed attributes
2652 if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0) {
2653 PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode');
2654 return PclZip::errorCode();
2655 }
2656
2657 // ----- Read the gzip file header
2658 $v_binary_data = @fread($v_file_compressed, 10);
2659 $v_data_header = unpack('a1id1/a1id2/a1cm/a1flag/Vmtime/a1xfl/a1os', $v_binary_data);
2660
2661 // ----- Check some parameters
2662 $v_data_header['os'] = bin2hex($v_data_header['os']);
2663
2664 // ----- Read the gzip file footer
2665 @fseek($v_file_compressed, filesize($v_gzip_temp_name)-8);
2666 $v_binary_data = @fread($v_file_compressed, 8);
2667 $v_data_footer = unpack('Vcrc/Vcompressed_size', $v_binary_data);
2668
2669 // ----- Set the attributes
2670 $p_header['compression'] = ord($v_data_header['cm']);
2671 //$p_header['mtime'] = $v_data_header['mtime'];
2672 $p_header['crc'] = $v_data_footer['crc'];
2673 $p_header['compressed_size'] = filesize($v_gzip_temp_name)-18;
2674
2675 // ----- Close the file
2676 @fclose($v_file_compressed);
2677
2678 // ----- Call the header generation
2679 if (($v_result = $this->privWriteFileHeader($p_header)) != 1) {
2680 return $v_result;
2681 }
2682
2683 // ----- Add the compressed data
2684 if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0) {
2685 PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode');
2686 return PclZip::errorCode();
2687 }
2688
2689 // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
2690 fseek($v_file_compressed, 10);
2691 $v_size = $p_header['compressed_size'];
2692 while ($v_size != 0) {
2693 $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
2694 $v_buffer = @fread($v_file_compressed, $v_read_size);
2695 //$v_binary_data = pack('a'.$v_read_size, $v_buffer);
2696 @fwrite($this->zip_fd, $v_buffer, $v_read_size);
2697 $v_size -= $v_read_size;
2698 }
2699
2700 // ----- Close the file
2701 @fclose($v_file_compressed);
2702
2703 // ----- Unlink the temporary file
2704 @unlink($v_gzip_temp_name);
2705
2706 // ----- Return
2707 return $v_result;
2708 }
2709 // --------------------------------------------------------------------------------
2710
2711 // --------------------------------------------------------------------------------
2712 // Function : privCalculateStoredFilename()
2713 // Description :
2714 // Based on file descriptor properties and global options, this method
2715 // calculate the filename that will be stored in the archive.
2716 // Parameters :
2717 // Return Values :
2718 // --------------------------------------------------------------------------------
2719 public function privCalculateStoredFilename(&$p_filedescr, &$p_options)
2720 {
2721 $v_result=1;
2722
2723 // ----- Working variables
2724 $p_filename = $p_filedescr['filename'];
2725 if (isset($p_options[PCLZIP_OPT_ADD_PATH])) {
2726 $p_add_dir = $p_options[PCLZIP_OPT_ADD_PATH];
2727 } else {
2728 $p_add_dir = '';
2729 }
2730 if (isset($p_options[PCLZIP_OPT_REMOVE_PATH])) {
2731 $p_remove_dir = $p_options[PCLZIP_OPT_REMOVE_PATH];
2732 } else {
2733 $p_remove_dir = '';
2734 }
2735 if (isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH])) {
2736 $p_remove_all_dir = $p_options[PCLZIP_OPT_REMOVE_ALL_PATH];
2737 } else {
2738 $p_remove_all_dir = 0;
2739 }
2740
2741 // ----- Look for full name change
2742 if (isset($p_filedescr['new_full_name'])) {
2743 // ----- Remove drive letter if any
2744 $v_stored_filename = PclZipUtilTranslateWinPath($p_filedescr['new_full_name']);
2745 } else {
2746 // ----- Look for path and/or short name change
2747 // ----- Look for short name change
2748 // Its when we cahnge just the filename but not the path
2749 if (isset($p_filedescr['new_short_name'])) {
2750 $v_path_info = pathinfo($p_filename);
2751 $v_dir = '';
2752 if ($v_path_info['dirname'] != '') {
2753 $v_dir = $v_path_info['dirname'].'/';
2754 }
2755 $v_stored_filename = $v_dir.$p_filedescr['new_short_name'];
2756 } else {
2757 // ----- Calculate the stored filename
2758 $v_stored_filename = $p_filename;
2759 }
2760
2761 // ----- Look for all path to remove
2762 if ($p_remove_all_dir) {
2763 $v_stored_filename = basename($p_filename);
2764 } elseif ($p_remove_dir != "") {
2765 // ----- Look for partial path remove
2766 if (substr($p_remove_dir, -1) != '/') {
2767 $p_remove_dir .= "/";
2768 }
2769
2770 if ((substr($p_filename, 0, 2) == "./") || (substr($p_remove_dir, 0, 2) == "./")) {
2771 if ((substr($p_filename, 0, 2) == "./") && (substr($p_remove_dir, 0, 2) != "./")) {
2772 $p_remove_dir = "./".$p_remove_dir;
2773 }
2774 if ((substr($p_filename, 0, 2) != "./") && (substr($p_remove_dir, 0, 2) == "./")) {
2775 $p_remove_dir = substr($p_remove_dir, 2);
2776 }
2777 }
2778
2779 $v_compare = PclZipUtilPathInclusion($p_remove_dir, $v_stored_filename);
2780 if ($v_compare > 0) {
2781 if ($v_compare == 2) {
2782 $v_stored_filename = "";
2783 } else {
2784 $v_stored_filename = substr($v_stored_filename, strlen($p_remove_dir));
2785 }
2786 }
2787 }
2788
2789 // ----- Remove drive letter if any
2790 $v_stored_filename = PclZipUtilTranslateWinPath($v_stored_filename);
2791
2792 // ----- Look for path to add
2793 if ($p_add_dir != "") {
2794 if (substr($p_add_dir, -1) == "/") {
2795 $v_stored_filename = $p_add_dir.$v_stored_filename;
2796 } else {
2797 $v_stored_filename = $p_add_dir."/".$v_stored_filename;
2798 }
2799 }
2800 }
2801
2802 // ----- Filename (reduce the path of stored name)
2803 $v_stored_filename = PclZipUtilPathReduction($v_stored_filename);
2804 $p_filedescr['stored_filename'] = $v_stored_filename;
2805
2806 // ----- Return
2807 return $v_result;
2808 }
2809 // --------------------------------------------------------------------------------
2810
2811 // --------------------------------------------------------------------------------
2812 // Function : privWriteFileHeader()
2813 // Description :
2814 // Parameters :
2815 // Return Values :
2816 // --------------------------------------------------------------------------------
2817 public function privWriteFileHeader(&$p_header)
2818 {
2819 $v_result=1;
2820
2821 // ----- Store the offset position of the file
2822 $p_header['offset'] = ftell($this->zip_fd);
2823
2824 // ----- Transform UNIX mtime to DOS format mdate/mtime
2825 $v_date = getdate($p_header['mtime']);
2826 $v_mtime = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2;
2827 $v_mdate = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday'];
2828
2829 // ----- Packed data
2830 $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']);
2831
2832 // ----- Write the first 148 bytes of the header in the archive
2833 fputs($this->zip_fd, $v_binary_data, 30);
2834
2835 // ----- Write the variable fields
2836 if (strlen($p_header['stored_filename']) != 0) {
2837 fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename']));
2838 }
2839 if ($p_header['extra_len'] != 0) {
2840 fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']);
2841 }
2842
2843 // ----- Return
2844 return $v_result;
2845 }
2846 // --------------------------------------------------------------------------------
2847
2848 // --------------------------------------------------------------------------------
2849 // Function : privWriteCentralFileHeader()
2850 // Description :
2851 // Parameters :
2852 // Return Values :
2853 // --------------------------------------------------------------------------------
2854 public function privWriteCentralFileHeader(&$p_header)
2855 {
2856 $v_result=1;
2857
2858 // TBC
2859 //for(reset($p_header); $key = key($p_header); next($p_header)) {
2860 //}
2861
2862 // ----- Transform UNIX mtime to DOS format mdate/mtime
2863 $v_date = getdate($p_header['mtime']);
2864 $v_mtime = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2;
2865 $v_mdate = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday'];
2866
2867
2868 // ----- Packed data
2869 $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']);
2870
2871 // ----- Write the 42 bytes of the header in the zip file
2872 fputs($this->zip_fd, $v_binary_data, 46);
2873
2874 // ----- Write the variable fields
2875 if (strlen($p_header['stored_filename']) != 0) {
2876 fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename']));
2877 }
2878 if ($p_header['extra_len'] != 0) {
2879 fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']);
2880 }
2881 if ($p_header['comment_len'] != 0) {
2882 fputs($this->zip_fd, $p_header['comment'], $p_header['comment_len']);
2883 }
2884
2885 // ----- Return
2886 return $v_result;
2887 }
2888 // --------------------------------------------------------------------------------
2889
2890 // --------------------------------------------------------------------------------
2891 // Function : privWriteCentralHeader()
2892 // Description :
2893 // Parameters :
2894 // Return Values :
2895 // --------------------------------------------------------------------------------
2896 public function privWriteCentralHeader($p_nb_entries, $p_size, $p_offset, $p_comment)
2897 {
2898 $v_result = 1;
2899
2900 // ----- Packed data
2901 $v_binary_data = pack("VvvvvVVv", 0x06054b50, 0, 0, $p_nb_entries, $p_nb_entries, $p_size, $p_offset, strlen($p_comment));
2902
2903 // ----- Write the 22 bytes of the header in the zip file
2904 fputs($this->zip_fd, $v_binary_data, 22);
2905
2906 // ----- Write the variable fields
2907 if (strlen($p_comment) != 0) {
2908 fputs($this->zip_fd, $p_comment, strlen($p_comment));
2909 }
2910
2911 // ----- Return
2912 return $v_result;
2913 }
2914 // --------------------------------------------------------------------------------
2915
2916 // --------------------------------------------------------------------------------
2917 // Function : privList()
2918 // Description :
2919 // Parameters :
2920 // Return Values :
2921 // --------------------------------------------------------------------------------
2922 public function privList(&$p_list)
2923 {
2924 $v_result = 1;
2925
2926 // ----- Magic quotes trick
2927 $this->privDisableMagicQuotes();
2928
2929 // ----- Open the zip file
2930 if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0) {
2931 // ----- Magic quotes trick
2932 $this->privSwapBackMagicQuotes();
2933
2934 // ----- Error log
2935 PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in binary read mode');
2936
2937 // ----- Return
2938 return PclZip::errorCode();
2939 }
2940
2941 // ----- Read the central directory informations
2942 $v_central_dir = array();
2943 if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) {
2944 $this->privSwapBackMagicQuotes();
2945 return $v_result;
2946 }
2947
2948 // ----- Go to beginning of Central Dir
2949 @rewind($this->zip_fd);
2950 if (@fseek($this->zip_fd, $v_central_dir['offset'])) {
2951 $this->privSwapBackMagicQuotes();
2952
2953 // ----- Error log
2954 PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
2955
2956 // ----- Return
2957 return PclZip::errorCode();
2958 }
2959
2960 // ----- Read each entry
2961 for ($i=0; $i<$v_central_dir['entries']; $i++) {
2962 // ----- Read the file header
2963 if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1) {
2964 $this->privSwapBackMagicQuotes();
2965 return $v_result;
2966 }
2967 $v_header['index'] = $i;
2968
2969 // ----- Get the only interesting attributes
2970 $this->privConvertHeader2FileInfo($v_header, $p_list[$i]);
2971 unset($v_header);
2972 }
2973
2974 // ----- Close the zip file
2975 $this->privCloseFd();
2976
2977 // ----- Magic quotes trick
2978 $this->privSwapBackMagicQuotes();
2979
2980 // ----- Return
2981 return $v_result;
2982 }
2983 // --------------------------------------------------------------------------------
2984
2985 // --------------------------------------------------------------------------------
2986 // Function : privConvertHeader2FileInfo()
2987 // Description :
2988 // This function takes the file informations from the central directory
2989 // entries and extract the interesting parameters that will be given back.
2990 // The resulting file infos are set in the array $p_info
2991 // $p_info['filename'] : Filename with full path. Given by user (add),
2992 // extracted in the filesystem (extract).
2993 // $p_info['stored_filename'] : Stored filename in the archive.
2994 // $p_info['size'] = Size of the file.
2995 // $p_info['compressed_size'] = Compressed size of the file.
2996 // $p_info['mtime'] = Last modification date of the file.
2997 // $p_info['comment'] = Comment associated with the file.
2998 // $p_info['folder'] = true/false : indicates if the entry is a folder or not.
2999 // $p_info['status'] = status of the action on the file.
3000 // $p_info['crc'] = CRC of the file content.
3001 // Parameters :
3002 // Return Values :
3003 // --------------------------------------------------------------------------------
3004 public function privConvertHeader2FileInfo($p_header, &$p_info)
3005 {
3006 $v_result=1;
3007
3008 // ----- Get the interesting attributes
3009 $v_temp_path = PclZipUtilPathReduction($p_header['filename']);
3010 $p_info['filename'] = $v_temp_path;
3011 $v_temp_path = PclZipUtilPathReduction($p_header['stored_filename']);
3012 $p_info['stored_filename'] = $v_temp_path;
3013 $p_info['size'] = $p_header['size'];
3014 $p_info['compressed_size'] = $p_header['compressed_size'];
3015 $p_info['mtime'] = $p_header['mtime'];
3016 $p_info['comment'] = $p_header['comment'];
3017 $p_info['folder'] = (($p_header['external']&0x00000010)==0x00000010);
3018 $p_info['index'] = $p_header['index'];
3019 $p_info['status'] = $p_header['status'];
3020 $p_info['crc'] = $p_header['crc'];
3021
3022 // ----- Return
3023 return $v_result;
3024 }
3025 // --------------------------------------------------------------------------------
3026
3027 // --------------------------------------------------------------------------------
3028 // Function : privExtractByRule()
3029 // Description :
3030 // Extract a file or directory depending of rules (by index, by name, ...)
3031 // Parameters :
3032 // $p_file_list : An array where will be placed the properties of each
3033 // extracted file
3034 // $p_path : Path to add while writing the extracted files
3035 // $p_remove_path : Path to remove (from the file memorized path) while writing the
3036 // extracted files. If the path does not match the file path,
3037 // the file is extracted with its memorized path.
3038 // $p_remove_path does not apply to 'list' mode.
3039 // $p_path and $p_remove_path are commulative.
3040 // Return Values :
3041 // 1 on success,0 or less on error (see error code list)
3042 // --------------------------------------------------------------------------------
3043 public function privExtractByRule(&$p_file_list, $p_path, $p_remove_path, $p_remove_all_path, &$p_options)
3044 {
3045 $v_result=1;
3046
3047 // ----- Magic quotes trick
3048 $this->privDisableMagicQuotes();
3049
3050 // ----- Check the path
3051 if (($p_path == "") || ((substr($p_path, 0, 1) != "/") && (substr($p_path, 0, 3) != "../") && (substr($p_path, 1, 2)!=":/"))) {
3052 $p_path = "./".$p_path;
3053 }
3054
3055 // ----- Reduce the path last (and duplicated) '/'
3056 if (($p_path != "./") && ($p_path != "/")) {
3057 // ----- Look for the path end '/'
3058 while (substr($p_path, -1) == "/") {
3059 $p_path = substr($p_path, 0, strlen($p_path)-1);
3060 }
3061 }
3062
3063 // ----- Look for path to remove format (should end by /)
3064 if (($p_remove_path != "") && (substr($p_remove_path, -1) != '/')) {
3065 $p_remove_path .= '/';
3066 }
3067 $p_remove_path_size = strlen($p_remove_path);
3068
3069 // ----- Open the zip file
3070 if (($v_result = $this->privOpenFd('rb')) != 1) {
3071 $this->privSwapBackMagicQuotes();
3072 return $v_result;
3073 }
3074
3075 // ----- Read the central directory informations
3076 $v_central_dir = array();
3077 if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) {
3078 // ----- Close the zip file
3079 $this->privCloseFd();
3080 $this->privSwapBackMagicQuotes();
3081
3082 return $v_result;
3083 }
3084
3085 // ----- Start at beginning of Central Dir
3086 $v_pos_entry = $v_central_dir['offset'];
3087
3088 // ----- Read each entry
3089 $j_start = 0;
3090 for ($i=0, $v_nb_extracted=0; $i<$v_central_dir['entries']; $i++) {
3091 // ----- Read next Central dir entry
3092 @rewind($this->zip_fd);
3093 if (@fseek($this->zip_fd, $v_pos_entry)) {
3094 // ----- Close the zip file
3095 $this->privCloseFd();
3096 $this->privSwapBackMagicQuotes();
3097
3098 // ----- Error log
3099 PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
3100
3101 // ----- Return
3102 return PclZip::errorCode();
3103 }
3104
3105 // ----- Read the file header
3106 $v_header = array();
3107 if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1) {
3108 // ----- Close the zip file
3109 $this->privCloseFd();
3110 $this->privSwapBackMagicQuotes();
3111
3112 return $v_result;
3113 }
3114
3115 // ----- Store the index
3116 $v_header['index'] = $i;
3117
3118 // ----- Store the file position
3119 $v_pos_entry = ftell($this->zip_fd);
3120
3121 // ----- Look for the specific extract rules
3122 $v_extract = false;
3123
3124 // ----- Look for extract by name rule
3125 if ((isset($p_options[PCLZIP_OPT_BY_NAME])) && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) {
3126 // ----- Look if the filename is in the list
3127 for ($j=0; ($j<sizeof($p_options[PCLZIP_OPT_BY_NAME])) && (!$v_extract); $j++) {
3128 // ----- Look for a directory
3129 if (substr($p_options[PCLZIP_OPT_BY_NAME][$j], -1) == "/") {
3130 // ----- Look if the directory is in the filename path
3131 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])) {
3132 $v_extract = true;
3133 }
3134 } elseif ($v_header['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) {
3135 // ----- Look for a filename
3136 $v_extract = true;
3137 }
3138 }
3139 } elseif ((isset($p_options[PCLZIP_OPT_BY_PREG])) && ($p_options[PCLZIP_OPT_BY_PREG] != "")) {
3140 // ----- Look for extract by preg rule
3141 if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header['stored_filename'])) {
3142 $v_extract = true;
3143 }
3144 } elseif ((isset($p_options[PCLZIP_OPT_BY_INDEX])) && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) {
3145 // ----- Look for extract by index rule
3146 // ----- Look if the index is in the list
3147 for ($j=$j_start; ($j<sizeof($p_options[PCLZIP_OPT_BY_INDEX])) && (!$v_extract); $j++) {
3148 if (($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i<=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) {
3149 $v_extract = true;
3150 }
3151 if ($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) {
3152 $j_start = $j+1;
3153 }
3154
3155 if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start']>$i) {
3156 break;
3157 }
3158 }
3159 } else {
3160 // ----- Look for no rule, which means extract all the archive
3161 $v_extract = true;
3162 }
3163
3164 // ----- Check compression method
3165 if (($v_extract) && (($v_header['compression'] != 8) && ($v_header['compression'] != 0))) {
3166 $v_header['status'] = 'unsupported_compression';
3167
3168 // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
3169 if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) {
3170 $this->privSwapBackMagicQuotes();
3171
3172 PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_COMPRESSION, "Filename '".$v_header['stored_filename']."' is compressed by an unsupported compression method (".$v_header['compression'].") ");
3173
3174 return PclZip::errorCode();
3175 }
3176 }
3177
3178 // ----- Check encrypted files
3179 if (($v_extract) && (($v_header['flag'] & 1) == 1)) {
3180 $v_header['status'] = 'unsupported_encryption';
3181 // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
3182 if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) {
3183 $this->privSwapBackMagicQuotes();
3184
3185 PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, "Unsupported encryption for filename '".$v_header['stored_filename']."'");
3186
3187 return PclZip::errorCode();
3188 }
3189 }
3190
3191 // ----- Look for real extraction
3192 if (($v_extract) && ($v_header['status'] != 'ok')) {
3193 $v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++]);
3194 if ($v_result != 1) {
3195 $this->privCloseFd();
3196 $this->privSwapBackMagicQuotes();
3197 return $v_result;
3198 }
3199
3200 $v_extract = false;
3201 }
3202
3203 // ----- Look for real extraction
3204 if ($v_extract) {
3205 // ----- Go to the file position
3206 @rewind($this->zip_fd);
3207 if (@fseek($this->zip_fd, $v_header['offset'])) {
3208 // ----- Close the zip file
3209 $this->privCloseFd();
3210
3211 $this->privSwapBackMagicQuotes();
3212
3213 // ----- Error log
3214 PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
3215
3216 // ----- Return
3217 return PclZip::errorCode();
3218 }
3219
3220 // ----- Look for extraction as string
3221 if ($p_options[PCLZIP_OPT_EXTRACT_AS_STRING]) {
3222 $v_string = '';
3223
3224 // ----- Extracting the file
3225 $v_result1 = $this->privExtractFileAsString($v_header, $v_string, $p_options);
3226 if ($v_result1 < 1) {
3227 $this->privCloseFd();
3228 $this->privSwapBackMagicQuotes();
3229 return $v_result1;
3230 }
3231
3232 // ----- Get the only interesting attributes
3233 if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted])) != 1) {
3234 // ----- Close the zip file
3235 $this->privCloseFd();
3236 $this->privSwapBackMagicQuotes();
3237
3238 return $v_result;
3239 }
3240
3241 // ----- Set the file content
3242 $p_file_list[$v_nb_extracted]['content'] = $v_string;
3243
3244 // ----- Next extracted file
3245 $v_nb_extracted++;
3246
3247 // ----- Look for user callback abort
3248 if ($v_result1 == 2) {
3249 break;
3250 }
3251 } elseif ((isset($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) && ($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) {
3252 // ----- Look for extraction in standard output
3253 // ----- Extracting the file in standard output
3254 $v_result1 = $this->privExtractFileInOutput($v_header, $p_options);
3255 if ($v_result1 < 1) {
3256 $this->privCloseFd();
3257 $this->privSwapBackMagicQuotes();
3258 return $v_result1;
3259 }
3260
3261 // ----- Get the only interesting attributes
3262 if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) {
3263 $this->privCloseFd();
3264 $this->privSwapBackMagicQuotes();
3265 return $v_result;
3266 }
3267
3268 // ----- Look for user callback abort
3269 if ($v_result1 == 2) {
3270 break;
3271 }
3272 } else {
3273 // ----- Look for normal extraction
3274 // ----- Extracting the file
3275 $v_result1 = $this->privExtractFile($v_header, $p_path, $p_remove_path, $p_remove_all_path, $p_options);
3276 if ($v_result1 < 1) {
3277 $this->privCloseFd();
3278 $this->privSwapBackMagicQuotes();
3279 return $v_result1;
3280 }
3281
3282 // ----- Get the only interesting attributes
3283 if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) {
3284 // ----- Close the zip file
3285 $this->privCloseFd();
3286 $this->privSwapBackMagicQuotes();
3287
3288 return $v_result;
3289 }
3290
3291 // ----- Look for user callback abort
3292 if ($v_result1 == 2) {
3293 break;
3294 }
3295 }
3296 }
3297 }
3298
3299 // ----- Close the zip file
3300 $this->privCloseFd();
3301 $this->privSwapBackMagicQuotes();
3302
3303 // ----- Return
3304 return $v_result;
3305 }
3306 // --------------------------------------------------------------------------------
3307
3308 // --------------------------------------------------------------------------------
3309 // Function : privExtractFile()
3310 // Description :
3311 // Parameters :
3312 // Return Values :
3313 //
3314 // 1 : ... ?
3315 // PCLZIP_ERR_USER_ABORTED(2) : User ask for extraction stop in callback
3316 // --------------------------------------------------------------------------------
3317 public function privExtractFile(&$p_entry, $p_path, $p_remove_path, $p_remove_all_path, &$p_options)
3318 {
3319 $v_result=1;
3320
3321 // ----- Read the file header
3322 if (($v_result = $this->privReadFileHeader($v_header)) != 1) {
3323 // ----- Return
3324 return $v_result;
3325 }
3326
3327
3328 // ----- Check that the file header is coherent with $p_entry info
3329 if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) {
3330 // TBC
3331 }
3332
3333 // ----- Look for all path to remove
3334 if ($p_remove_all_path == true) {
3335 // ----- Look for folder entry that not need to be extracted
3336 if (($p_entry['external']&0x00000010)==0x00000010) {
3337 $p_entry['status'] = "filtered";
3338
3339 return $v_result;
3340 }
3341
3342 // ----- Get the basename of the path
3343 $p_entry['filename'] = basename($p_entry['filename']);
3344 } elseif ($p_remove_path != "") {
3345 // ----- Look for path to remove
3346 if (PclZipUtilPathInclusion($p_remove_path, $p_entry['filename']) == 2) {
3347 // ----- Change the file status
3348 $p_entry['status'] = "filtered";
3349
3350 // ----- Return
3351 return $v_result;
3352 }
3353
3354 $p_remove_path_size = strlen($p_remove_path);
3355 if (substr($p_entry['filename'], 0, $p_remove_path_size) == $p_remove_path) {
3356 // ----- Remove the path
3357 $p_entry['filename'] = substr($p_entry['filename'], $p_remove_path_size);
3358 }
3359 }
3360
3361 // ----- Add the path
3362 if ($p_path != '') {
3363 $p_entry['filename'] = $p_path."/".$p_entry['filename'];
3364 }
3365
3366 // ----- Check a base_dir_restriction
3367 if (isset($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION])) {
3368 $v_inclusion = PclZipUtilPathInclusion($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION], $p_entry['filename']);
3369 if ($v_inclusion == 0) {
3370 PclZip::privErrorLog(PCLZIP_ERR_DIRECTORY_RESTRICTION, "Filename '".$p_entry['filename']."' is outside PCLZIP_OPT_EXTRACT_DIR_RESTRICTION");
3371
3372 return PclZip::errorCode();
3373 }
3374 }
3375
3376 // ----- Look for pre-extract callback
3377 if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) {
3378 // ----- Generate a local information
3379 $v_local_header = array();
3380 $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
3381
3382 // ----- Call the callback
3383 // Here I do not use call_user_func() because I need to send a reference to the
3384 // header.
3385 // eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);');
3386 $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header);
3387 if ($v_result == 0) {
3388 // ----- Change the file status
3389 $p_entry['status'] = "skipped";
3390 $v_result = 1;
3391 }
3392
3393 // ----- Look for abort result
3394 if ($v_result == 2) {
3395 // ----- This status is internal and will be changed in 'skipped'
3396 $p_entry['status'] = "aborted";
3397 $v_result = PCLZIP_ERR_USER_ABORTED;
3398 }
3399
3400 // ----- Update the informations
3401 // Only some fields can be modified
3402 $p_entry['filename'] = $v_local_header['filename'];
3403 }
3404
3405 // ----- Look if extraction should be done
3406 if ($p_entry['status'] == 'ok') {
3407 // ----- Look for specific actions while the file exist
3408 if (file_exists($p_entry['filename'])) {
3409 // ----- Look if file is a directory
3410 if (is_dir($p_entry['filename'])) {
3411 // ----- Change the file status
3412 $p_entry['status'] = "already_a_directory";
3413
3414 // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
3415 // For historical reason first PclZip implementation does not stop
3416 // when this kind of error occurs.
3417 if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) {
3418 PclZip::privErrorLog(PCLZIP_ERR_ALREADY_A_DIRECTORY, "Filename '".$p_entry['filename']."' is already used by an existing directory");
3419 return PclZip::errorCode();
3420 }
3421 } elseif (!is_writeable($p_entry['filename'])) {
3422 // ----- Look if file is write protected
3423 // ----- Change the file status
3424 $p_entry['status'] = "write_protected";
3425
3426 // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
3427 // For historical reason first PclZip implementation does not stop
3428 // when this kind of error occurs.
3429 if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) {
3430 PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, "Filename '".$p_entry['filename']."' exists and is write protected");
3431 return PclZip::errorCode();
3432 }
3433 } elseif (filemtime($p_entry['filename']) > $p_entry['mtime']) {
3434 // ----- Look if the extracted file is older
3435 // ----- Change the file status
3436 if ((isset($p_options[PCLZIP_OPT_REPLACE_NEWER])) && ($p_options[PCLZIP_OPT_REPLACE_NEWER] === true)) {
3437 } else {
3438 $p_entry['status'] = "newer_exist";
3439
3440 // ----- Look for PCLZIP_OPT_STOP_ON_ERROR
3441 // For historical reason first PclZip implementation does not stop
3442 // when this kind of error occurs.
3443 if ((isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) && ($p_options[PCLZIP_OPT_STOP_ON_ERROR] === true)) {
3444 PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, "Newer version of '".$p_entry['filename']."' exists and option PCLZIP_OPT_REPLACE_NEWER is not selected");
3445 return PclZip::errorCode();
3446 }
3447 }
3448 } else {
3449 }
3450 } else {
3451 // ----- Check the directory availability and create it if necessary
3452 if ((($p_entry['external']&0x00000010)==0x00000010) || (substr($p_entry['filename'], -1) == '/')) {
3453 $v_dir_to_check = $p_entry['filename'];
3454 } elseif (!strstr($p_entry['filename'], "/")) {
3455 $v_dir_to_check = "";
3456 } else {
3457 $v_dir_to_check = dirname($p_entry['filename']);
3458 }
3459
3460 if (($v_result = $this->privDirCheck($v_dir_to_check, (($p_entry['external']&0x00000010)==0x00000010))) != 1) {
3461 // ----- Change the file status
3462 $p_entry['status'] = "path_creation_fail";
3463
3464 // ----- Return
3465 //return $v_result;
3466 $v_result = 1;
3467 }
3468 }
3469 }
3470
3471 // ----- Look if extraction should be done
3472 if ($p_entry['status'] == 'ok') {
3473 // ----- Do the extraction (if not a folder)
3474 if (!(($p_entry['external']&0x00000010) == 0x00000010)) {
3475 // ----- Look for not compressed file
3476 if ($p_entry['compression'] == 0) {
3477 // ----- Opening destination file
3478 if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) {
3479 // ----- Change the file status
3480 $p_entry['status'] = "write_error";
3481
3482 // ----- Return
3483 return $v_result;
3484 }
3485
3486 // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
3487 $v_size = $p_entry['compressed_size'];
3488 while ($v_size != 0) {
3489 $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
3490 $v_buffer = @fread($this->zip_fd, $v_read_size);
3491 /* Try to speed up the code
3492 $v_binary_data = pack('a'.$v_read_size, $v_buffer);
3493 @fwrite($v_dest_file, $v_binary_data, $v_read_size);
3494 */
3495 @fwrite($v_dest_file, $v_buffer, $v_read_size);
3496 $v_size -= $v_read_size;
3497 }
3498
3499 // ----- Closing the destination file
3500 fclose($v_dest_file);
3501
3502 // ----- Change the file mtime
3503 touch($p_entry['filename'], $p_entry['mtime']);
3504 } else {
3505 // ----- TBC
3506 // Need to be finished
3507 if (($p_entry['flag'] & 1) == 1) {
3508 PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, 'File \''.$p_entry['filename'].'\' is encrypted. Encrypted files are not supported.');
3509 return PclZip::errorCode();
3510 }
3511
3512 // ----- Look for using temporary file to unzip
3513 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'])))) {
3514 $v_result = $this->privExtractFileUsingTempFile($p_entry, $p_options);
3515 if ($v_result < PCLZIP_ERR_NO_ERROR) {
3516 return $v_result;
3517 }
3518 } else {
3519 // ----- Look for extract in memory
3520 // ----- Read the compressed file in a buffer (one shot)
3521 $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']);
3522
3523 // ----- Decompress the file
3524 $v_file_content = @gzinflate($v_buffer);
3525 unset($v_buffer);
3526 if ($v_file_content === false) {
3527 // ----- Change the file status
3528 // TBC
3529 $p_entry['status'] = "error";
3530
3531 return $v_result;
3532 }
3533
3534 // ----- Opening destination file
3535 if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) {
3536 // ----- Change the file status
3537 $p_entry['status'] = "write_error";
3538
3539 return $v_result;
3540 }
3541
3542 // ----- Write the uncompressed data
3543 @fwrite($v_dest_file, $v_file_content, $p_entry['size']);
3544 unset($v_file_content);
3545
3546 // ----- Closing the destination file
3547 @fclose($v_dest_file);
3548 }
3549
3550 // ----- Change the file mtime
3551 @touch($p_entry['filename'], $p_entry['mtime']);
3552 }
3553
3554 // ----- Look for chmod option
3555 if (isset($p_options[PCLZIP_OPT_SET_CHMOD])) {
3556 // ----- Change the mode of the file
3557 @chmod($p_entry['filename'], $p_options[PCLZIP_OPT_SET_CHMOD]);
3558 }
3559 }
3560 }
3561
3562 // ----- Change abort status
3563 if ($p_entry['status'] == "aborted") {
3564 $p_entry['status'] = "skipped";
3565 } elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) {
3566 // ----- Look for post-extract callback
3567 // ----- Generate a local information
3568 $v_local_header = array();
3569 $this->privConvertHeader2FileInfo($p_entry, $v_local_header);
3570
3571 // ----- Call the callback
3572 // Here I do not use call_user_func() because I need to send a reference to the
3573 // header.
3574 // eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);');
3575 $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header);
3576
3577 // ----- Look for abort result
3578 if ($v_result == 2) {
3579 $v_result = PCLZIP_ERR_USER_ABORTED;
3580 }
3581 }
3582
3583 // ----- Return
3584 return $v_result;
3585 }
3586 // --------------------------------------------------------------------------------
3587
3588 // --------------------------------------------------------------------------------
3589 // Function : privExtractFileUsingTempFile()
3590 // Description :
3591 // Parameters :
3592 // Return Values :
3593 // --------------------------------------------------------------------------------
3594 public function privExtractFileUsingTempFile(&$p_entry, &$p_options)
3595 {
3596 $v_result=1;
3597
3598 // ----- Creates a temporary file
3599 $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.gz';
3600 if (($v_dest_file = @fopen($v_gzip_temp_name, "wb")) == 0) {
3601 fclose($v_file);
3602 PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary write mode');
3603 return PclZip::errorCode();
3604 }
3605
3606 // ----- Write gz file format header
3607 $v_binary_data = pack('va1a1Va1a1', 0x8b1f, Chr($p_entry['compression']), Chr(0x00), time(), Chr(0x00), Chr(3));
3608 @fwrite($v_dest_file, $v_binary_data, 10);
3609
3610 // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
3611 $v_size = $p_entry['compressed_size'];
3612 while ($v_size != 0) {
3613 $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
3614 $v_buffer = @fread($this->zip_fd, $v_read_size);
3615 //$v_binary_data = pack('a'.$v_read_size, $v_buffer);
3616 @fwrite($v_dest_file, $v_buffer, $v_read_size);
3617 $v_size -= $v_read_size;
3618 }
3619
3620 // ----- Write gz file format footer
3621 $v_binary_data = pack('VV', $p_entry['crc'], $p_entry['size']);
3622 @fwrite($v_dest_file, $v_binary_data, 8);
3623
3624 // ----- Close the temporary file
3625 @fclose($v_dest_file);
3626
3627 // ----- Opening destination file
3628 if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) {
3629 $p_entry['status'] = "write_error";
3630 return $v_result;
3631 }
3632
3633 // ----- Open the temporary gz file
3634 if (($v_src_file = @gzopen($v_gzip_temp_name, 'rb')) == 0) {
3635 @fclose($v_dest_file);
3636 $p_entry['status'] = "read_error";
3637 PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode');
3638 return PclZip::errorCode();
3639 }
3640
3641 // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
3642 $v_size = $p_entry['size'];