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