[ Index ] |
|
Code source de Joomla 1.0.13 |
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: Tar.php 49 2005-09-15 02:55:27Z rhuk $ 20 21 // no direct access 22 defined( '_VALID_MOS' ) or die( 'Restricted access' ); 23 24 require_once $GLOBALS['mosConfig_absolute_path'] . '/includes/PEAR/PEAR.php'; 25 26 define ('ARCHIVE_TAR_ATT_SEPARATOR', 90001); 27 28 /** 29 * Creates a (compressed) Tar archive 30 * 31 * @author Vincent Blavet <vincent@blavet.net> 32 * @version $Revision: 49 $ 33 * @package Archive 34 */ 35 class Archive_Tar extends PEAR 36 { 37 /** 38 * @var string Name of the Tar 39 */ 40 var $_tarname=''; 41 42 /** 43 * @var boolean if true, the Tar file will be gzipped 44 */ 45 var $_compress=false; 46 47 /** 48 * @var string Type of compression : 'none', 'gz' or 'bz2' 49 */ 50 var $_compress_type='none'; 51 52 /** 53 * @var string Explode separator 54 */ 55 var $_separator=' '; 56 57 /** 58 * @var file descriptor 59 */ 60 var $_file=0; 61 62 /** 63 * @var string Local Tar name of a remote Tar (http:// or ftp://) 64 */ 65 var $_temp_tarname=''; 66 67 // {{{ constructor 68 /** 69 * Archive_Tar Class constructor. This flavour of the constructor only 70 * declare a new Archive_Tar object, identifying it by the name of the 71 * tar file. 72 * If the compress argument is set the tar will be read or created as a 73 * gzip or bz2 compressed TAR file. 74 * 75 * @param string $p_tarname The name of the tar archive to create 76 * @param string $p_compress can be null, 'gz' or 'bz2'. This 77 * parameter indicates if gzip or bz2 compression 78 * is required. For compatibility reason the 79 * boolean value 'true' means 'gz'. 80 * @access public 81 */ 82 function Archive_Tar($p_tarname, $p_compress = null) 83 { 84 $this->PEAR(); 85 $this->_compress = false; 86 $this->_compress_type = 'none'; 87 if ($p_compress === null) { 88 if (@file_exists($p_tarname)) { 89 if ($fp = @fopen($p_tarname, "rb")) { 90 // look for gzip magic cookie 91 $data = fread($fp, 2); 92 fclose($fp); 93 if ($data == "\37\213") { 94 $this->_compress = true; 95 $this->_compress_type = 'gz'; 96 // No sure it's enought for a magic code .... 97 } elseif ($data == "BZ") { 98 $this->_compress = true; 99 $this->_compress_type = 'bz2'; 100 } 101 } 102 } else { 103 // probably a remote file or some file accessible 104 // through a stream interface 105 if (substr($p_tarname, -2) == 'gz') { 106 $this->_compress = true; 107 $this->_compress_type = 'gz'; 108 } elseif ((substr($p_tarname, -3) == 'bz2') || 109 (substr($p_tarname, -2) == 'bz')) { 110 $this->_compress = true; 111 $this->_compress_type = 'bz2'; 112 } 113 } 114 } else { 115 if (($p_compress === true) || ($p_compress == 'gz')) { 116 $this->_compress = true; 117 $this->_compress_type = 'gz'; 118 } else if ($p_compress == 'bz2') { 119 $this->_compress = true; 120 $this->_compress_type = 'bz2'; 121 } 122 } 123 $this->_tarname = $p_tarname; 124 if ($this->_compress) { // assert zlib or bz2 extension support 125 if ($this->_compress_type == 'gz') 126 $extname = 'zlib'; 127 else if ($this->_compress_type == 'bz2') 128 $extname = 'bz2'; 129 130 if (!extension_loaded($extname)) { 131 PEAR::loadExtension($extname); 132 } 133 if (!extension_loaded($extname)) { 134 die("The extension '$extname' couldn't be found.\n". 135 "Please make sure your version of PHP was built ". 136 "with '$extname' support.\n"); 137 return false; 138 } 139 } 140 } 141 // }}} 142 143 // {{{ destructor 144 function _Archive_Tar() 145 { 146 $this->_close(); 147 // ----- Look for a local copy to delete 148 if ($this->_temp_tarname != '') 149 @unlink($this->_temp_tarname); 150 $this->_PEAR(); 151 } 152 // }}} 153 154 // {{{ create() 155 /** 156 * This method creates the archive file and add the files / directories 157 * that are listed in $p_filelist. 158 * If a file with the same name exist and is writable, it is replaced 159 * by the new tar. 160 * The method return false and a PEAR error text. 161 * The $p_filelist parameter can be an array of string, each string 162 * representing a filename or a directory name with their path if 163 * needed. It can also be a single string with names separated by a 164 * single blank. 165 * For each directory added in the archive, the files and 166 * sub-directories are also added. 167 * See also createModify() method for more details. 168 * 169 * @param array $p_filelist An array of filenames and directory names, or a single 170 * string with names separated by a single blank space. 171 * @return true on success, false on error. 172 * @see createModify() 173 * @access public 174 */ 175 function create($p_filelist) 176 { 177 return $this->createModify($p_filelist, '', ''); 178 } 179 // }}} 180 181 // {{{ add() 182 /** 183 * This method add the files / directories that are listed in $p_filelist in 184 * the archive. If the archive does not exist it is created. 185 * The method return false and a PEAR error text. 186 * The files and directories listed are only added at the end of the archive, 187 * even if a file with the same name is already archived. 188 * See also createModify() method for more details. 189 * 190 * @param array $p_filelist An array of filenames and directory names, or a single 191 * string with names separated by a single blank space. 192 * @return true on success, false on error. 193 * @see createModify() 194 * @access public 195 */ 196 function add($p_filelist) 197 { 198 return $this->addModify($p_filelist, '', ''); 199 } 200 // }}} 201 202 // {{{ extract() 203 function extract($p_path='') 204 { 205 return $this->extractModify($p_path, ''); 206 } 207 // }}} 208 209 // {{{ listContent() 210 function listContent() 211 { 212 $v_list_detail = array(); 213 214 if ($this->_openRead()) { 215 if (!$this->_extractList('', $v_list_detail, "list", '', '')) { 216 unset($v_list_detail); 217 $v_list_detail = 0; 218 } 219 $this->_close(); 220 } 221 222 return $v_list_detail; 223 } 224 // }}} 225 226 // {{{ createModify() 227 /** 228 * This method creates the archive file and add the files / directories 229 * that are listed in $p_filelist. 230 * If the file already exists and is writable, it is replaced by the 231 * new tar. It is a create and not an add. If the file exists and is 232 * read-only or is a directory it is not replaced. The method return 233 * false and a PEAR error text. 234 * The $p_filelist parameter can be an array of string, each string 235 * representing a filename or a directory name with their path if 236 * needed. It can also be a single string with names separated by a 237 * single blank. 238 * The path indicated in $p_remove_dir will be removed from the 239 * memorized path of each file / directory listed when this path 240 * exists. By default nothing is removed (empty path '') 241 * The path indicated in $p_add_dir will be added at the beginning of 242 * the memorized path of each file / directory listed. However it can 243 * be set to empty ''. The adding of a path is done after the removing 244 * of path. 245 * The path add/remove ability enables the user to prepare an archive 246 * for extraction in a different path than the origin files are. 247 * See also addModify() method for file adding properties. 248 * 249 * @param array $p_filelist An array of filenames and directory names, or a single 250 * string with names separated by a single blank space. 251 * @param string $p_add_dir A string which contains a path to be added to the 252 * memorized path of each element in the list. 253 * @param string $p_remove_dir A string which contains a path to be removed from 254 * the memorized path of each element in the list, when 255 * relevant. 256 * @return boolean true on success, false on error. 257 * @access public 258 * @see addModify() 259 */ 260 function createModify($p_filelist, $p_add_dir, $p_remove_dir='') 261 { 262 $v_result = true; 263 264 if (!$this->_openWrite()) 265 return false; 266 267 if ($p_filelist != '') { 268 if (is_array($p_filelist)) 269 $v_list = $p_filelist; 270 elseif (is_string($p_filelist)) 271 $v_list = explode($this->_separator, $p_filelist); 272 else { 273 $this->_cleanFile(); 274 $this->_error('Invalid file list'); 275 return false; 276 } 277 278 $v_result = $this->_addList($v_list, $p_add_dir, $p_remove_dir); 279 } 280 281 if ($v_result) { 282 $this->_writeFooter(); 283 $this->_close(); 284 } else 285 $this->_cleanFile(); 286 287 return $v_result; 288 } 289 // }}} 290 291 // {{{ addModify() 292 /** 293 * This method add the files / directories listed in $p_filelist at the 294 * end of the existing archive. If the archive does not yet exists it 295 * is created. 296 * The $p_filelist parameter can be an array of string, each string 297 * representing a filename or a directory name with their path if 298 * needed. It can also be a single string with names separated by a 299 * single blank. 300 * The path indicated in $p_remove_dir will be removed from the 301 * memorized path of each file / directory listed when this path 302 * exists. By default nothing is removed (empty path '') 303 * The path indicated in $p_add_dir will be added at the beginning of 304 * the memorized path of each file / directory listed. However it can 305 * be set to empty ''. The adding of a path is done after the removing 306 * of path. 307 * The path add/remove ability enables the user to prepare an archive 308 * for extraction in a different path than the origin files are. 309 * If a file/dir is already in the archive it will only be added at the 310 * end of the archive. There is no update of the existing archived 311 * file/dir. However while extracting the archive, the last file will 312 * replace the first one. This results in a none optimization of the 313 * archive size. 314 * If a file/dir does not exist the file/dir is ignored. However an 315 * error text is send to PEAR error. 316 * If a file/dir is not readable the file/dir is ignored. However an 317 * error text is send to PEAR error. 318 * 319 * @param array $p_filelist An array of filenames and directory names, or a single 320 * string with names separated by a single blank space. 321 * @param string $p_add_dir A string which contains a path to be added to the 322 * memorized path of each element in the list. 323 * @param string $p_remove_dir A string which contains a path to be removed from 324 * the memorized path of each element in the list, when 325 * relevant. 326 * @return true on success, false on error. 327 * @access public 328 */ 329 function addModify($p_filelist, $p_add_dir, $p_remove_dir='') 330 { 331 $v_result = true; 332 333 if (!@is_file($this->_tarname)) 334 $v_result = $this->createModify($p_filelist, $p_add_dir, $p_remove_dir); 335 else { 336 if (is_array($p_filelist)) 337 $v_list = $p_filelist; 338 elseif (is_string($p_filelist)) 339 $v_list = explode($this->_separator, $p_filelist); 340 else { 341 $this->_error('Invalid file list'); 342 return false; 343 } 344 345 $v_result = $this->_append($v_list, $p_add_dir, $p_remove_dir); 346 } 347 348 return $v_result; 349 } 350 // }}} 351 352 // {{{ addString() 353 /** 354 * This method add a single string as a file at the 355 * end of the existing archive. If the archive does not yet exists it 356 * is created. 357 * 358 * @param string $p_filename A string which contains the full filename path 359 * that will be associated with the string. 360 * @param string $p_string The content of the file added in the archive. 361 * @return true on success, false on error. 362 * @access public 363 */ 364 function addString($p_filename, $p_string) 365 { 366 $v_result = true; 367 368 if (!@is_file($this->_tarname)) { 369 if (!$this->_openWrite()) { 370 return false; 371 } 372 $this->_close(); 373 } 374 375 if (!$this->_openAppend()) 376 return false; 377 378 // Need to check the get back to the temporary file ? .... 379 $v_result = $this->_addString($p_filename, $p_string); 380 381 $this->_writeFooter(); 382 383 $this->_close(); 384 385 return $v_result; 386 } 387 // }}} 388 389 // {{{ extractModify() 390 /** 391 * This method extract all the content of the archive in the directory 392 * indicated by $p_path. When relevant the memorized path of the 393 * files/dir can be modified by removing the $p_remove_path path at the 394 * beginning of the file/dir path. 395 * While extracting a file, if the directory path does not exists it is 396 * created. 397 * While extracting a file, if the file already exists it is replaced 398 * without looking for last modification date. 399 * While extracting a file, if the file already exists and is write 400 * protected, the extraction is aborted. 401 * While extracting a file, if a directory with the same name already 402 * exists, the extraction is aborted. 403 * While extracting a directory, if a file with the same name already 404 * exists, the extraction is aborted. 405 * While extracting a file/directory if the destination directory exist 406 * and is write protected, or does not exist but can not be created, 407 * the extraction is aborted. 408 * If after extraction an extracted file does not show the correct 409 * stored file size, the extraction is aborted. 410 * When the extraction is aborted, a PEAR error text is set and false 411 * is returned. However the result can be a partial extraction that may 412 * need to be manually cleaned. 413 * 414 * @param string $p_path The path of the directory where the files/dir need to by 415 * extracted. 416 * @param string $p_remove_path Part of the memorized path that can be removed if 417 * present at the beginning of the file/dir path. 418 * @return boolean true on success, false on error. 419 * @access public 420 * @see extractList() 421 */ 422 function extractModify($p_path, $p_remove_path) 423 { 424 $v_result = true; 425 $v_list_detail = array(); 426 427 if ($v_result = $this->_openRead()) { 428 $v_result = $this->_extractList($p_path, $v_list_detail, "complete", 0, $p_remove_path); 429 $this->_close(); 430 } 431 432 return $v_result; 433 } 434 // }}} 435 436 // {{{ extractInString() 437 /** 438 * This method extract from the archive one file identified by $p_filename. 439 * The return value is a string with the file content, or NULL on error. 440 * @param string $p_filename The path of the file to extract in a string. 441 * @return a string with the file content or NULL. 442 * @access public 443 */ 444 function extractInString($p_filename) 445 { 446 if ($this->_openRead()) { 447 $v_result = $this->_extractInString($p_filename); 448 $this->_close(); 449 } else { 450 $v_result = NULL; 451 } 452 453 return $v_result; 454 } 455 // }}} 456 457 // {{{ extractList() 458 /** 459 * This method extract from the archive only the files indicated in the 460 * $p_filelist. These files are extracted in the current directory or 461 * in the directory indicated by the optional $p_path parameter. 462 * If indicated the $p_remove_path can be used in the same way as it is 463 * used in extractModify() method. 464 * @param array $p_filelist An array of filenames and directory names, or a single 465 * string with names separated by a single blank space. 466 * @param string $p_path The path of the directory where the files/dir need to by 467 * extracted. 468 * @param string $p_remove_path Part of the memorized path that can be removed if 469 * present at the beginning of the file/dir path. 470 * @return true on success, false on error. 471 * @access public 472 * @see extractModify() 473 */ 474 function extractList($p_filelist, $p_path='', $p_remove_path='') 475 { 476 $v_result = true; 477 $v_list_detail = array(); 478 479 if (is_array($p_filelist)) 480 $v_list = $p_filelist; 481 elseif (is_string($p_filelist)) 482 $v_list = explode($this->_separator, $p_filelist); 483 else { 484 $this->_error('Invalid string list'); 485 return false; 486 } 487 488 if ($v_result = $this->_openRead()) { 489 $v_result = $this->_extractList($p_path, $v_list_detail, "partial", $v_list, $p_remove_path); 490 $this->_close(); 491 } 492 493 return $v_result; 494 } 495 // }}} 496 497 // {{{ setAttribute() 498 /** 499 * This method set specific attributes of the archive. It uses a variable 500 * list of parameters, in the format attribute code + attribute values : 501 * $arch->setAttribute(ARCHIVE_TAR_ATT_SEPARATOR, ','); 502 * @param mixed $argv variable list of attributes and values 503 * @return true on success, false on error. 504 * @access public 505 */ 506 function setAttribute() 507 { 508 $v_result = true; 509 510 // ----- Get the number of variable list of arguments 511 if (($v_size = func_num_args()) == 0) { 512 return true; 513 } 514 515 // ----- Get the arguments 516 $v_att_list = &func_get_args(); 517 518 // ----- Read the attributes 519 $i=0; 520 while ($i<$v_size) { 521 522 // ----- Look for next option 523 switch ($v_att_list[$i]) { 524 // ----- Look for options that request a string value 525 case ARCHIVE_TAR_ATT_SEPARATOR : 526 // ----- Check the number of parameters 527 if (($i+1) >= $v_size) { 528 $this->_error('Invalid number of parameters for attribute ARCHIVE_TAR_ATT_SEPARATOR'); 529 return false; 530 } 531 532 // ----- Get the value 533 $this->_separator = $v_att_list[$i+1]; 534 $i++; 535 break; 536 537 default : 538 $this->_error('Unknow attribute code '.$v_att_list[$i].''); 539 return false; 540 } 541 542 // ----- Next attribute 543 $i++; 544 } 545 546 return $v_result; 547 } 548 // }}} 549 550 // {{{ _error() 551 function _error($p_message) 552 { 553 // ----- To be completed 554 $this->raiseError($p_message); 555 } 556 // }}} 557 558 // {{{ _warning() 559 function _warning($p_message) 560 { 561 // ----- To be completed 562 $this->raiseError($p_message); 563 } 564 // }}} 565 566 // {{{ _openWrite() 567 function _openWrite() 568 { 569 if ($this->_compress_type == 'gz') 570 $this->_file = @gzopen($this->_tarname, "wb"); 571 else if ($this->_compress_type == 'bz2') 572 $this->_file = @bzopen($this->_tarname, "wb"); 573 else if ($this->_compress_type == 'none') 574 $this->_file = @fopen($this->_tarname, "wb"); 575 else 576 $this->_error('Unknown or missing compression type ('.$this->_compress_type.')'); 577 578 if ($this->_file == 0) { 579 $this->_error('Unable to open in write mode \''.$this->_tarname.'\''); 580 return false; 581 } 582 583 return true; 584 } 585 // }}} 586 587 // {{{ _openRead() 588 function _openRead() 589 { 590 if (strtolower(substr($this->_tarname, 0, 7)) == 'http://') { 591 592 // ----- Look if a local copy need to be done 593 if ($this->_temp_tarname == '') { 594 $this->_temp_tarname = uniqid('tar').'.tmp'; 595 if (!$v_file_from = @fopen($this->_tarname, 'rb')) { 596 $this->_error('Unable to open in read mode \''.$this->_tarname.'\''); 597 $this->_temp_tarname = ''; 598 return false; 599 } 600 if (!$v_file_to = @fopen($this->_temp_tarname, 'wb')) { 601 $this->_error('Unable to open in write mode \''.$this->_temp_tarname.'\''); 602 $this->_temp_tarname = ''; 603 return false; 604 } 605 while ($v_data = @fread($v_file_from, 1024)) 606 @fwrite($v_file_to, $v_data); 607 @fclose($v_file_from); 608 @fclose($v_file_to); 609 } 610 611 // ----- File to open if the local copy 612 $v_filename = $this->_temp_tarname; 613 614 } else 615 // ----- File to open if the normal Tar file 616 $v_filename = $this->_tarname; 617 618 if ($this->_compress_type == 'gz') 619 $this->_file = @gzopen($v_filename, "rb"); 620 else if ($this->_compress_type == 'bz2') 621 $this->_file = @bzopen($v_filename, "rb"); 622 else if ($this->_compress_type == 'none') 623 $this->_file = @fopen($v_filename, "rb"); 624 else 625 $this->_error('Unknown or missing compression type ('.$this->_compress_type.')'); 626 627 if ($this->_file == 0) { 628 $this->_error('Unable to open in read mode \''.$v_filename.'\''); 629 return false; 630 } 631 632 return true; 633 } 634 // }}} 635 636 // {{{ _openReadWrite() 637 function _openReadWrite() 638 { 639 if ($this->_compress_type == 'gz') 640 $this->_file = @gzopen($this->_tarname, "r+b"); 641 else if ($this->_compress_type == 'bz2') 642 $this->_file = @bzopen($this->_tarname, "r+b"); 643 else if ($this->_compress_type == 'none') 644 $this->_file = @fopen($this->_tarname, "r+b"); 645 else 646 $this->_error('Unknown or missing compression type ('.$this->_compress_type.')'); 647 648 if ($this->_file == 0) { 649 $this->_error('Unable to open in read/write mode \''.$this->_tarname.'\''); 650 return false; 651 } 652 653 return true; 654 } 655 // }}} 656 657 // {{{ _close() 658 function _close() 659 { 660 //if (isset($this->_file)) { 661 if (is_resource($this->_file)) { 662 if ($this->_compress_type == 'gz') 663 @gzclose($this->_file); 664 else if ($this->_compress_type == 'bz2') 665 @bzclose($this->_file); 666 else if ($this->_compress_type == 'none') 667 @fclose($this->_file); 668 else 669 $this->_error('Unknown or missing compression type ('.$this->_compress_type.')'); 670 671 $this->_file = 0; 672 } 673 674 // ----- Look if a local copy need to be erase 675 // Note that it might be interesting to keep the url for a time : ToDo 676 if ($this->_temp_tarname != '') { 677 @unlink($this->_temp_tarname); 678 $this->_temp_tarname = ''; 679 } 680 681 return true; 682 } 683 // }}} 684 685 // {{{ _cleanFile() 686 function _cleanFile() 687 { 688 $this->_close(); 689 690 // ----- Look for a local copy 691 if ($this->_temp_tarname != '') { 692 // ----- Remove the local copy but not the remote tarname 693 @unlink($this->_temp_tarname); 694 $this->_temp_tarname = ''; 695 } else { 696 // ----- Remove the local tarname file 697 @unlink($this->_tarname); 698 } 699 $this->_tarname = ''; 700 701 return true; 702 } 703 // }}} 704 705 // {{{ _writeBlock() 706 function _writeBlock($p_binary_data, $p_len=null) 707 { 708 if (is_resource($this->_file)) { 709 if ($p_len === null) { 710 if ($this->_compress_type == 'gz') 711 @gzputs($this->_file, $p_binary_data); 712 else if ($this->_compress_type == 'bz2') 713 @bzwrite($this->_file, $p_binary_data); 714 else if ($this->_compress_type == 'none') 715 @fputs($this->_file, $p_binary_data); 716 else 717 $this->_error('Unknown or missing compression type ('.$this->_compress_type.')'); 718 } else { 719 if ($this->_compress_type == 'gz') 720 @gzputs($this->_file, $p_binary_data, $p_len); 721 else if ($this->_compress_type == 'bz2') 722 @bzwrite($this->_file, $p_binary_data, $p_len); 723 else if ($this->_compress_type == 'none') 724 @fputs($this->_file, $p_binary_data, $p_len); 725 else 726 $this->_error('Unknown or missing compression type ('.$this->_compress_type.')'); 727 728 } 729 } 730 return true; 731 } 732 // }}} 733 734 // {{{ _readBlock() 735 function _readBlock($p_len=null) 736 { 737 $v_block = null; 738 if (is_resource($this->_file)) { 739 if ($p_len === null) 740 $p_len = 512; 741 742 if ($this->_compress_type == 'gz') 743 $v_block = @gzread($this->_file, 512); 744 else if ($this->_compress_type == 'bz2') 745 $v_block = @bzread($this->_file, 512); 746 else if ($this->_compress_type == 'none') 747 $v_block = @fread($this->_file, 512); 748 else 749 $this->_error('Unknown or missing compression type ('.$this->_compress_type.')'); 750 751 } 752 return $v_block; 753 } 754 // }}} 755 756 // {{{ _jumpBlock() 757 function _jumpBlock($p_len=null) 758 { 759 if (is_resource($this->_file)) { 760 if ($p_len === null) 761 $p_len = 1; 762 763 if ($this->_compress_type == 'gz') 764 @gzseek($this->_file, @gztell($this->_file)+($p_len*512)); 765 else if ($this->_compress_type == 'bz2') { 766 // ----- Replace missing bztell() and bzseek() 767 for ($i=0; $i<$p_len; $i++) 768 $this->_readBlock(); 769 } else if ($this->_compress_type == 'none') 770 @fseek($this->_file, @ftell($this->_file)+($p_len*512)); 771 else 772 $this->_error('Unknown or missing compression type ('.$this->_compress_type.')'); 773 774 } 775 return true; 776 } 777 // }}} 778 779 // {{{ _writeFooter() 780 function _writeFooter() 781 { 782 if (is_resource($this->_file)) { 783 // ----- Write the last 0 filled block for end of archive 784 $v_binary_data = pack("a512", ''); 785 $this->_writeBlock($v_binary_data); 786 } 787 return true; 788 } 789 // }}} 790 791 // {{{ _addList() 792 function _addList($p_list, $p_add_dir, $p_remove_dir) 793 { 794 $v_result=true; 795 $v_header = array(); 796 797 // ----- Remove potential windows directory separator 798 $p_add_dir = $this->_translateWinPath($p_add_dir); 799 $p_remove_dir = $this->_translateWinPath($p_remove_dir, false); 800 801 if (!$this->_file) { 802 $this->_error('Invalid file descriptor'); 803 return false; 804 } 805 806 if (sizeof($p_list) == 0) 807 return true; 808 809 for ($j=0; ($j<count($p_list)) && ($v_result); $j++) { 810 $v_filename = $p_list[$j]; 811 812 // ----- Skip the current tar name 813 if ($v_filename == $this->_tarname) 814 continue; 815 816 if ($v_filename == '') 817 continue; 818 819 if (!file_exists($v_filename)) { 820 $this->_warning("File '$v_filename' does not exist"); 821 continue; 822 } 823 824 // ----- Add the file or directory header 825 if (!$this->_addFile($v_filename, $v_header, $p_add_dir, $p_remove_dir)) 826 return false; 827 828 if (@is_dir($v_filename)) { 829 if (!($p_hdir = opendir($v_filename))) { 830 $this->_warning("Directory '$v_filename' can not be read"); 831 continue; 832 } 833 $p_hitem = readdir($p_hdir); // '.' directory 834 $p_hitem = readdir($p_hdir); // '..' directory 835 while (false !== ($p_hitem = readdir($p_hdir))) { 836 if ($v_filename != ".") 837 $p_temp_list[0] = $v_filename.'/'.$p_hitem; 838 else 839 $p_temp_list[0] = $p_hitem; 840 841 $v_result = $this->_addList($p_temp_list, $p_add_dir, $p_remove_dir); 842 } 843 844 unset($p_temp_list); 845 unset($p_hdir); 846 unset($p_hitem); 847 } 848 } 849 850 return $v_result; 851 } 852 // }}} 853 854 // {{{ _addFile() 855 function _addFile($p_filename, &$p_header, $p_add_dir, $p_remove_dir) 856 { 857 if (!$this->_file) { 858 $this->_error('Invalid file descriptor'); 859 return false; 860 } 861 862 if ($p_filename == '') { 863 $this->_error('Invalid file name'); 864 return false; 865 } 866 867 // ----- Calculate the stored filename 868 $p_filename = $this->_translateWinPath($p_filename, false);; 869 $v_stored_filename = $p_filename; 870 if (strcmp($p_filename, $p_remove_dir) == 0) { 871 return true; 872 } 873 if ($p_remove_dir != '') { 874 if (substr($p_remove_dir, -1) != '/') 875 $p_remove_dir .= '/'; 876 877 if (substr($p_filename, 0, strlen($p_remove_dir)) == $p_remove_dir) 878 $v_stored_filename = substr($p_filename, strlen($p_remove_dir)); 879 } 880 $v_stored_filename = $this->_translateWinPath($v_stored_filename); 881 if ($p_add_dir != '') { 882 if (substr($p_add_dir, -1) == '/') 883 $v_stored_filename = $p_add_dir.$v_stored_filename; 884 else 885 $v_stored_filename = $p_add_dir.'/'.$v_stored_filename; 886 } 887 888 $v_stored_filename = $this->_pathReduction($v_stored_filename); 889 890 if (is_file($p_filename)) { 891 if (($v_file = @fopen($p_filename, "rb")) == 0) { 892 $this->_warning("Unable to open file '$p_filename' in binary read mode"); 893 return true; 894 } 895 896 if (!$this->_writeHeader($p_filename, $v_stored_filename)) 897 return false; 898 899 while (($v_buffer = fread($v_file, 512)) != '') { 900 $v_binary_data = pack("a512", "$v_buffer"); 901 $this->_writeBlock($v_binary_data); 902 } 903 904 fclose($v_file); 905 906 } else { 907 // ----- Only header for dir 908 if (!$this->_writeHeader($p_filename, $v_stored_filename)) 909 return false; 910 } 911 912 return true; 913 } 914 // }}} 915 916 // {{{ _addString() 917 function _addString($p_filename, $p_string) 918 { 919 if (!$this->_file) { 920 $this->_error('Invalid file descriptor'); 921 return false; 922 } 923 924 if ($p_filename == '') { 925 $this->_error('Invalid file name'); 926 return false; 927 } 928 929 // ----- Calculate the stored filename 930 $p_filename = $this->_translateWinPath($p_filename, false);; 931 932 if (!$this->_writeHeaderBlock($p_filename, strlen($p_string), 0, 0, "", 0, 0)) 933 return false; 934 935 $i=0; 936 while (($v_buffer = substr($p_string, (($i++)*512), 512)) != '') { 937 $v_binary_data = pack("a512", $v_buffer); 938 $this->_writeBlock($v_binary_data); 939 } 940 941 return true; 942 } 943 // }}} 944 945 // {{{ _writeHeader() 946 function _writeHeader($p_filename, $p_stored_filename) 947 { 948 if ($p_stored_filename == '') 949 $p_stored_filename = $p_filename; 950 $v_reduce_filename = $this->_pathReduction($p_stored_filename); 951 952 if (strlen($v_reduce_filename) > 99) { 953 if (!$this->_writeLongHeader($v_reduce_filename)) 954 return false; 955 } 956 957 $v_info = stat($p_filename); 958 $v_uid = sprintf("%6s ", DecOct($v_info[4])); 959 $v_gid = sprintf("%6s ", DecOct($v_info[5])); 960 $v_perms = sprintf("%6s ", DecOct(fileperms($p_filename))); 961 962 $v_mtime = sprintf("%11s", DecOct(filemtime($p_filename))); 963 964 if (@is_dir($p_filename)) { 965 $v_typeflag = "5"; 966 $v_size = sprintf("%11s ", DecOct(0)); 967 } else { 968 $v_typeflag = ''; 969 clearstatcache(); 970 $v_size = sprintf("%11s ", DecOct(filesize($p_filename))); 971 } 972 973 $v_linkname = ''; 974 975 $v_magic = ''; 976 977 $v_version = ''; 978 979 $v_uname = ''; 980 981 $v_gname = ''; 982 983 $v_devmajor = ''; 984 985 $v_devminor = ''; 986 987 $v_prefix = ''; 988 989 $v_binary_data_first = pack("a100a8a8a8a12A12", $v_reduce_filename, $v_perms, $v_uid, $v_gid, $v_size, $v_mtime); 990 $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12", $v_typeflag, $v_linkname, $v_magic, $v_version, $v_uname, $v_gname, $v_devmajor, $v_devminor, $v_prefix, ''); 991 992 // ----- Calculate the checksum 993 $v_checksum = 0; 994 // ..... First part of the header 995 for ($i=0; $i<148; $i++) 996 $v_checksum += ord(substr($v_binary_data_first,$i,1)); 997 // ..... Ignore the checksum value and replace it by ' ' (space) 998 for ($i=148; $i<156; $i++) 999 $v_checksum += ord(' '); 1000 // ..... Last part of the header 1001 for ($i=156, $j=0; $i<512; $i++, $j++) 1002 $v_checksum += ord(substr($v_binary_data_last,$j,1)); 1003 1004 // ----- Write the first 148 bytes of the header in the archive 1005 $this->_writeBlock($v_binary_data_first, 148); 1006 1007 // ----- Write the calculated checksum 1008 $v_checksum = sprintf("%6s ", DecOct($v_checksum)); 1009 $v_binary_data = pack("a8", $v_checksum); 1010 $this->_writeBlock($v_binary_data, 8); 1011 1012 // ----- Write the last 356 bytes of the header in the archive 1013 $this->_writeBlock($v_binary_data_last, 356); 1014 1015 return true; 1016 } 1017 // }}} 1018 1019 // {{{ _writeHeaderBlock() 1020 function _writeHeaderBlock($p_filename, $p_size, $p_mtime=0, $p_perms=0, $p_type='', $p_uid=0, $p_gid=0) 1021 { 1022 $p_filename = $this->_pathReduction($p_filename); 1023 1024 if (strlen($p_filename) > 99) { 1025 if (!$this->_writeLongHeader($p_filename)) 1026 return false; 1027 } 1028 1029 if ($p_type == "5") { 1030 $v_size = sprintf("%11s ", DecOct(0)); 1031 } else { 1032 $v_size = sprintf("%11s ", DecOct($p_size)); 1033 } 1034 1035 $v_uid = sprintf("%6s ", DecOct($p_uid)); 1036 $v_gid = sprintf("%6s ", DecOct($p_gid)); 1037 $v_perms = sprintf("%6s ", DecOct($p_perms)); 1038 1039 $v_mtime = sprintf("%11s", DecOct($p_mtime)); 1040 1041 $v_linkname = ''; 1042 1043 $v_magic = ''; 1044 1045 $v_version = ''; 1046 1047 $v_uname = ''; 1048 1049 $v_gname = ''; 1050 1051 $v_devmajor = ''; 1052 1053 $v_devminor = ''; 1054 1055 $v_prefix = ''; 1056 1057 $v_binary_data_first = pack("a100a8a8a8a12A12", $p_filename, $v_perms, $v_uid, $v_gid, $v_size, $v_mtime); 1058 $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12", $p_type, $v_linkname, $v_magic, $v_version, $v_uname, $v_gname, $v_devmajor, $v_devminor, $v_prefix, ''); 1059 1060 // ----- Calculate the checksum 1061 $v_checksum = 0; 1062 // ..... First part of the header 1063 for ($i=0; $i<148; $i++) 1064 $v_checksum += ord(substr($v_binary_data_first,$i,1)); 1065 // ..... Ignore the checksum value and replace it by ' ' (space) 1066 for ($i=148; $i<156; $i++) 1067 $v_checksum += ord(' '); 1068 // ..... Last part of the header 1069 for ($i=156, $j=0; $i<512; $i++, $j++) 1070 $v_checksum += ord(substr($v_binary_data_last,$j,1)); 1071 1072 // ----- Write the first 148 bytes of the header in the archive 1073 $this->_writeBlock($v_binary_data_first, 148); 1074 1075 // ----- Write the calculated checksum 1076 $v_checksum = sprintf("%6s ", DecOct($v_checksum)); 1077 $v_binary_data = pack("a8", $v_checksum); 1078 $this->_writeBlock($v_binary_data, 8); 1079 1080 // ----- Write the last 356 bytes of the header in the archive 1081 $this->_writeBlock($v_binary_data_last, 356); 1082 1083 return true; 1084 } 1085 // }}} 1086 1087 // {{{ _writeLongHeader() 1088 function _writeLongHeader($p_filename) 1089 { 1090 $v_size = sprintf("%11s ", DecOct(strlen($p_filename))); 1091 1092 $v_typeflag = 'L'; 1093 1094 $v_linkname = ''; 1095 1096 $v_magic = ''; 1097 1098 $v_version = ''; 1099 1100 $v_uname = ''; 1101 1102 $v_gname = ''; 1103 1104 $v_devmajor = ''; 1105 1106 $v_devminor = ''; 1107 1108 $v_prefix = ''; 1109 1110 $v_binary_data_first = pack("a100a8a8a8a12A12", '././@LongLink', 0, 0, 0, $v_size, 0); 1111 $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12", $v_typeflag, $v_linkname, $v_magic, $v_version, $v_uname, $v_gname, $v_devmajor, $v_devminor, $v_prefix, ''); 1112 1113 // ----- Calculate the checksum 1114 $v_checksum = 0; 1115 // ..... First part of the header 1116 for ($i=0; $i<148; $i++) 1117 $v_checksum += ord(substr($v_binary_data_first,$i,1)); 1118 // ..... Ignore the checksum value and replace it by ' ' (space) 1119 for ($i=148; $i<156; $i++) 1120 $v_checksum += ord(' '); 1121 // ..... Last part of the header 1122 for ($i=156, $j=0; $i<512; $i++, $j++) 1123 $v_checksum += ord(substr($v_binary_data_last,$j,1)); 1124 1125 // ----- Write the first 148 bytes of the header in the archive 1126 $this->_writeBlock($v_binary_data_first, 148); 1127 1128 // ----- Write the calculated checksum 1129 $v_checksum = sprintf("%6s ", DecOct($v_checksum)); 1130 $v_binary_data = pack("a8", $v_checksum); 1131 $this->_writeBlock($v_binary_data, 8); 1132 1133 // ----- Write the last 356 bytes of the header in the archive 1134 $this->_writeBlock($v_binary_data_last, 356); 1135 1136 // ----- Write the filename as content of the block 1137 $i=0; 1138 while (($v_buffer = substr($p_filename, (($i++)*512), 512)) != '') { 1139 $v_binary_data = pack("a512", "$v_buffer"); 1140 $this->_writeBlock($v_binary_data); 1141 } 1142 1143 return true; 1144 } 1145 // }}} 1146 1147 // {{{ _readHeader() 1148 function _readHeader($v_binary_data, &$v_header) 1149 { 1150 if (strlen($v_binary_data)==0) { 1151 $v_header['filename'] = ''; 1152 return true; 1153 } 1154 1155 if (strlen($v_binary_data) != 512) { 1156 $v_header['filename'] = ''; 1157 $this->_error('Invalid block size : '.strlen($v_binary_data)); 1158 return false; 1159 } 1160 1161 // ----- Calculate the checksum 1162 $v_checksum = 0; 1163 // ..... First part of the header 1164 for ($i=0; $i<148; $i++) 1165 $v_checksum+=ord(substr($v_binary_data,$i,1)); 1166 // ..... Ignore the checksum value and replace it by ' ' (space) 1167 for ($i=148; $i<156; $i++) 1168 $v_checksum += ord(' '); 1169 // ..... Last part of the header 1170 for ($i=156; $i<512; $i++) 1171 $v_checksum+=ord(substr($v_binary_data,$i,1)); 1172 1173 $v_data = unpack("a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/a8checksum/a1typeflag/a100link/a6magic/a2version/a32uname/a32gname/a8devmajor/a8devminor", $v_binary_data); 1174 1175 // ----- Extract the checksum 1176 $v_header['checksum'] = OctDec(trim($v_data['checksum'])); 1177 if ($v_header['checksum'] != $v_checksum) { 1178 $v_header['filename'] = ''; 1179 1180 // ----- Look for last block (empty block) 1181 if (($v_checksum == 256) && ($v_header['checksum'] == 0)) 1182 return true; 1183 1184 $this->_error('Invalid checksum for file "'.$v_data['filename'].'" : '.$v_checksum.' calculated, '.$v_header['checksum'].' expected'); 1185 return false; 1186 } 1187 1188 // ----- Extract the properties 1189 $v_header['filename'] = trim($v_data['filename']); 1190 $v_header['mode'] = OctDec(trim($v_data['mode'])); 1191 $v_header['uid'] = OctDec(trim($v_data['uid'])); 1192 $v_header['gid'] = OctDec(trim($v_data['gid'])); 1193 $v_header['size'] = OctDec(trim($v_data['size'])); 1194 $v_header['mtime'] = OctDec(trim($v_data['mtime'])); 1195 if (($v_header['typeflag'] = $v_data['typeflag']) == "5") { 1196 $v_header['size'] = 0; 1197 } 1198 /* ----- All these fields are removed form the header because they do not carry interesting info 1199 $v_header[link] = trim($v_data[link]); 1200 $v_header[magic] = trim($v_data[magic]); 1201 $v_header[version] = trim($v_data[version]); 1202 $v_header[uname] = trim($v_data[uname]); 1203 $v_header[gname] = trim($v_data[gname]); 1204 $v_header[devmajor] = trim($v_data[devmajor]); 1205 $v_header[devminor] = trim($v_data[devminor]); 1206 */ 1207 1208 return true; 1209 } 1210 // }}} 1211 1212 // {{{ _readLongHeader() 1213 function _readLongHeader(&$v_header) 1214 { 1215 $v_filename = ''; 1216 $n = floor($v_header['size']/512); 1217 for ($i=0; $i<$n; $i++) { 1218 $v_content = $this->_readBlock(); 1219 $v_filename .= $v_content; 1220 } 1221 if (($v_header['size'] % 512) != 0) { 1222 $v_content = $this->_readBlock(); 1223 $v_filename .= $v_content; 1224 } 1225 1226 // ----- Read the next header 1227 $v_binary_data = $this->_readBlock(); 1228 1229 if (!$this->_readHeader($v_binary_data, $v_header)) 1230 return false; 1231 1232 $v_header['filename'] = $v_filename; 1233 1234 return true; 1235 } 1236 // }}} 1237 1238 // {{{ _extractInString() 1239 /** 1240 * This method extract from the archive one file identified by $p_filename. 1241 * The return value is a string with the file content, or NULL on error. 1242 * @param string $p_filename The path of the file to extract in a string. 1243 * @return a string with the file content or NULL. 1244 * @access private 1245 */ 1246 function _extractInString($p_filename) 1247 { 1248 $v_result_str = ""; 1249 1250 While (strlen($v_binary_data = $this->_readBlock()) != 0) 1251 { 1252 if (!$this->_readHeader($v_binary_data, $v_header)) 1253 return NULL; 1254 1255 if ($v_header['filename'] == '') 1256 continue; 1257 1258 // ----- Look for long filename 1259 if ($v_header['typeflag'] == 'L') { 1260 if (!$this->_readLongHeader($v_header)) 1261 return NULL; 1262 } 1263 1264 if ($v_header['filename'] == $p_filename) { 1265 if ($v_header['typeflag'] == "5") { 1266 $this->_error('Unable to extract in string a directory entry {'.$v_header['filename'].'}'); 1267 return NULL; 1268 } else { 1269 $n = floor($v_header['size']/512); 1270 for ($i=0; $i<$n; $i++) { 1271 $v_result_str .= $this->_readBlock(); 1272 } 1273 if (($v_header['size'] % 512) != 0) { 1274 $v_content = $this->_readBlock(); 1275 $v_result_str .= substr($v_content, 0, ($v_header['size'] % 512)); 1276 } 1277 return $v_result_str; 1278 } 1279 } else { 1280 $this->_jumpBlock(ceil(($v_header['size']/512))); 1281 } 1282 } 1283 1284 return NULL; 1285 } 1286 // }}} 1287 1288 // {{{ _extractList() 1289 function _extractList($p_path, &$p_list_detail, $p_mode, $p_file_list, $p_remove_path) 1290 { 1291 $v_result=true; 1292 $v_nb = 0; 1293 $v_extract_all = true; 1294 $v_listing = false; 1295 1296 $p_path = $this->_translateWinPath($p_path, false); 1297 if ($p_path == '' || (substr($p_path, 0, 1) != '/' && substr($p_path, 0, 3) != "../" && !strpos($p_path, ':'))) { 1298 $p_path = "./".$p_path; 1299 } 1300 $p_remove_path = $this->_translateWinPath($p_remove_path); 1301 1302 // ----- Look for path to remove format (should end by /) 1303 if (($p_remove_path != '') && (substr($p_remove_path, -1) != '/')) 1304 $p_remove_path .= '/'; 1305 $p_remove_path_size = strlen($p_remove_path); 1306 1307 switch ($p_mode) { 1308 case "complete" : 1309 $v_extract_all = TRUE; 1310 $v_listing = FALSE; 1311 break; 1312 case "partial" : 1313 $v_extract_all = FALSE; 1314 $v_listing = FALSE; 1315 break; 1316 case "list" : 1317 $v_extract_all = FALSE; 1318 $v_listing = TRUE; 1319 break; 1320 default : 1321 $this->_error('Invalid extract mode ('.$p_mode.')'); 1322 return false; 1323 } 1324 1325 clearstatcache(); 1326 1327 While (strlen($v_binary_data = $this->_readBlock()) != 0) 1328 { 1329 $v_extract_file = FALSE; 1330 $v_extraction_stopped = 0; 1331 1332 if (!$this->_readHeader($v_binary_data, $v_header)) 1333 return false; 1334 1335 if ($v_header['filename'] == '') 1336 continue; 1337 1338 // ----- Look for long filename 1339 if ($v_header['typeflag'] == 'L') { 1340 if (!$this->_readLongHeader($v_header)) 1341 return false; 1342 } 1343 1344 if ((!$v_extract_all) && (is_array($p_file_list))) { 1345 // ----- By default no unzip if the file is not found 1346 $v_extract_file = false; 1347 1348 for ($i=0; $i<sizeof($p_file_list); $i++) { 1349 // ----- Look if it is a directory 1350 if (substr($p_file_list[$i], -1) == '/') { 1351 // ----- Look if the directory is in the filename path 1352 if ((strlen($v_header['filename']) > strlen($p_file_list[$i])) && (substr($v_header['filename'], 0, strlen($p_file_list[$i])) == $p_file_list[$i])) { 1353 $v_extract_file = TRUE; 1354 break; 1355 } 1356 } 1357 1358 // ----- It is a file, so compare the file names 1359 elseif ($p_file_list[$i] == $v_header['filename']) { 1360 $v_extract_file = TRUE; 1361 break; 1362 } 1363 } 1364 } else { 1365 $v_extract_file = TRUE; 1366 } 1367 1368 // ----- Look if this file need to be extracted 1369 if (($v_extract_file) && (!$v_listing)) 1370 { 1371 if (($p_remove_path != '') 1372 && (substr($v_header['filename'], 0, $p_remove_path_size) == $p_remove_path)) 1373 $v_header['filename'] = substr($v_header['filename'], $p_remove_path_size); 1374 if (($p_path != './') && ($p_path != '/')) { 1375 while (substr($p_path, -1) == '/') 1376 $p_path = substr($p_path, 0, strlen($p_path)-1); 1377 1378 if (substr($v_header['filename'], 0, 1) == '/') 1379 $v_header['filename'] = $p_path.$v_header['filename']; 1380 else 1381 $v_header['filename'] = $p_path.'/'.$v_header['filename']; 1382 } 1383 if (file_exists($v_header['filename'])) { 1384 if ((@is_dir($v_header['filename'])) && ($v_header['typeflag'] == '')) { 1385 $this->_error('File '.$v_header['filename'].' already exists as a directory'); 1386 return false; 1387 } 1388 if ((is_file($v_header['filename'])) && ($v_header['typeflag'] == "5")) { 1389 $this->_error('Directory '.$v_header['filename'].' already exists as a file'); 1390 return false; 1391 } 1392 if (!is_writeable($v_header['filename'])) { 1393 $this->_error('File '.$v_header['filename'].' already exists and is write protected'); 1394 return false; 1395 } 1396 if (filemtime($v_header['filename']) > $v_header['mtime']) { 1397 // To be completed : An error or silent no replace ? 1398 } 1399 } 1400 1401 // ----- Check the directory availability and create it if necessary 1402 elseif (($v_result = $this->_dirCheck(($v_header['typeflag'] == "5"?$v_header['filename']:dirname($v_header['filename'])))) != 1) { 1403 $this->_error('Unable to create path for '.$v_header['filename']); 1404 return false; 1405 } 1406 1407 if ($v_extract_file) { 1408 if ($v_header['typeflag'] == "5") { 1409 if (!@file_exists($v_header['filename'])) { 1410 if (!@mkdir($v_header['filename'], 0777)) { 1411 $this->_error('Unable to create directory {'.$v_header['filename'].'}'); 1412 return false; 1413 } 1414 } 1415 } else { 1416 if (($v_dest_file = @fopen($v_header['filename'], "wb")) == 0) { 1417 $this->_error('Error while opening {'.$v_header['filename'].'} in write binary mode'); 1418 return false; 1419 } else { 1420 $n = floor($v_header['size']/512); 1421 for ($i=0; $i<$n; $i++) { 1422 $v_content = $this->_readBlock(); 1423 fwrite($v_dest_file, $v_content, 512); 1424 } 1425 if (($v_header['size'] % 512) != 0) { 1426 $v_content = $this->_readBlock(); 1427 fwrite($v_dest_file, $v_content, ($v_header['size'] % 512)); 1428 } 1429 1430 @fclose($v_dest_file); 1431 1432 // ----- Change the file mode, mtime 1433 @touch($v_header['filename'], $v_header['mtime']); 1434 // To be completed 1435 //chmod($v_header[filename], DecOct($v_header[mode])); 1436 } 1437 1438 // ----- Check the file size 1439 clearstatcache(); 1440 if (filesize($v_header['filename']) != $v_header['size']) { 1441 $this->_error('Extracted file '.$v_header['filename'].' does not have the correct file size \''.filesize($v_filename).'\' ('.$v_header['size'].' expected). Archive may be corrupted.'); 1442 return false; 1443 } 1444 } 1445 } else { 1446 $this->_jumpBlock(ceil(($v_header['size']/512))); 1447 } 1448 } else { 1449 $this->_jumpBlock(ceil(($v_header['size']/512))); 1450 } 1451 1452 /* TBC : Seems to be unused ... 1453 if ($this->_compress) 1454 $v_end_of_file = @gzeof($this->_file); 1455 else 1456 $v_end_of_file = @feof($this->_file); 1457 */ 1458 1459 if ($v_listing || $v_extract_file || $v_extraction_stopped) { 1460 // ----- Log extracted files 1461 if (($v_file_dir = dirname($v_header['filename'])) == $v_header['filename']) 1462 $v_file_dir = ''; 1463 if ((substr($v_header['filename'], 0, 1) == '/') && ($v_file_dir == '')) 1464 $v_file_dir = '/'; 1465 1466 $p_list_detail[$v_nb++] = $v_header; 1467 } 1468 } 1469 1470 return true; 1471 } 1472 // }}} 1473 1474 // {{{ _openAppend() 1475 function _openAppend() 1476 { 1477 if (filesize($this->_tarname) == 0) 1478 return $this->_openWrite(); 1479 1480 if ($this->_compress) { 1481 $this->_close(); 1482 1483 if (!@rename($this->_tarname, $this->_tarname.".tmp")) { 1484 $this->_error('Error while renaming \''.$this->_tarname.'\' to temporary file \''.$this->_tarname.'.tmp\''); 1485 return false; 1486 } 1487 1488 if ($this->_compress_type == 'gz') 1489 $v_temp_tar = @gzopen($this->_tarname.".tmp", "rb"); 1490 elseif ($this->_compress_type == 'bz2') 1491 $v_temp_tar = @bzopen($this->_tarname.".tmp", "rb"); 1492 1493 if ($v_temp_tar == 0) { 1494 $this->_error('Unable to open file \''.$this->_tarname.'.tmp\' in binary read mode'); 1495 @rename($this->_tarname.".tmp", $this->_tarname); 1496 return false; 1497 } 1498 1499 if (!$this->_openWrite()) { 1500 @rename($this->_tarname.".tmp", $this->_tarname); 1501 return false; 1502 } 1503 1504 if ($this->_compress_type == 'gz') { 1505 $v_buffer = @gzread($v_temp_tar, 512); 1506 1507 // ----- Read the following blocks but not the last one 1508 if (!@gzeof($v_temp_tar)) { 1509 do{ 1510 $v_binary_data = pack("a512", $v_buffer); 1511 $this->_writeBlock($v_binary_data); 1512 $v_buffer = @gzread($v_temp_tar, 512); 1513 1514 } while (!@gzeof($v_temp_tar)); 1515 } 1516 1517 @gzclose($v_temp_tar); 1518 } 1519 elseif ($this->_compress_type == 'bz2') { 1520 $v_buffered_lines = array(); 1521 $v_buffered_lines[] = @bzread($v_temp_tar, 512); 1522 1523 // ----- Read the following blocks but not the last one 1524 while (strlen($v_buffered_lines[] = @bzread($v_temp_tar, 512)) > 0) { 1525 $v_binary_data = pack("a512", array_shift($v_buffered_lines)); 1526 $this->_writeBlock($v_binary_data); 1527 } 1528 1529 @bzclose($v_temp_tar); 1530 } 1531 1532 if (!@unlink($this->_tarname.".tmp")) { 1533 $this->_error('Error while deleting temporary file \''.$this->_tarname.'.tmp\''); 1534 } 1535 1536 } else { 1537 // ----- For not compressed tar, just add files before the last 512 bytes block 1538 if (!$this->_openReadWrite()) 1539 return false; 1540 1541 clearstatcache(); 1542 $v_size = filesize($this->_tarname); 1543 fseek($this->_file, $v_size-512); 1544 } 1545 1546 return true; 1547 } 1548 // }}} 1549 1550 // {{{ _append() 1551 function _append($p_filelist, $p_add_dir='', $p_remove_dir='') 1552 { 1553 if (!$this->_openAppend()) 1554 return false; 1555 1556 if ($this->_addList($p_filelist, $p_add_dir, $p_remove_dir)) 1557 $this->_writeFooter(); 1558 1559 $this->_close(); 1560 1561 return true; 1562 } 1563 // }}} 1564 1565 // {{{ _dirCheck() 1566 1567 /** 1568 * Check if a directory exists and create it (including parent 1569 * dirs) if not. 1570 * 1571 * @param string $p_dir directory to check 1572 * 1573 * @return bool TRUE if the directory exists or was created 1574 */ 1575 function _dirCheck($p_dir) 1576 { 1577 if ((@is_dir($p_dir)) || ($p_dir == '')) 1578 return true; 1579 1580 $p_parent_dir = dirname($p_dir); 1581 1582 if (($p_parent_dir != $p_dir) && 1583 ($p_parent_dir != '') && 1584 (!$this->_dirCheck($p_parent_dir))) 1585 return false; 1586 1587 if (!@mkdir($p_dir, 0777)) { 1588 $this->_error("Unable to create directory '$p_dir'"); 1589 return false; 1590 } 1591 1592 return true; 1593 } 1594 1595 // }}} 1596 1597 // {{{ _pathReduction() 1598 1599 /** 1600 * Compress path by changing for example "/dir/foo/../bar" to "/dir/bar", and 1601 * remove double slashes. 1602 * 1603 * @param string $p_dir path to reduce 1604 * 1605 * @return string reduced path 1606 * 1607 * @access private 1608 * 1609 */ 1610 function _pathReduction($p_dir) 1611 { 1612 $v_result = ''; 1613 1614 // ----- Look for not empty path 1615 if ($p_dir != '') { 1616 // ----- Explode path by directory names 1617 $v_list = explode('/', $p_dir); 1618 1619 // ----- Study directories from last to first 1620 for ($i=sizeof($v_list)-1; $i>=0; $i--) { 1621 // ----- Look for current path 1622 if ($v_list[$i] == ".") { 1623 // ----- Ignore this directory 1624 // Should be the first $i=0, but no check is done 1625 } 1626 else if ($v_list[$i] == "..") { 1627 // ----- Ignore it and ignore the $i-1 1628 $i--; 1629 } 1630 else if (($v_list[$i] == '') && ($i!=(sizeof($v_list)-1)) && ($i!=0)) { 1631 // ----- Ignore only the double '//' in path, 1632 // but not the first and last / 1633 } else { 1634 $v_result = $v_list[$i].($i!=(sizeof($v_list)-1)?'/'.$v_result:''); 1635 } 1636 } 1637 } 1638 $v_result = strtr($v_result, '\\', '/'); 1639 return $v_result; 1640 } 1641 1642 // }}} 1643 1644 // {{{ _translateWinPath() 1645 function _translateWinPath($p_path, $p_remove_disk_letter=true) 1646 { 1647 if (OS_WINDOWS) { 1648 // ----- Look for potential disk letter 1649 if (($p_remove_disk_letter) && (($v_position = strpos($p_path, ':')) != false)) { 1650 $p_path = substr($p_path, $v_position+1); 1651 } 1652 // ----- Change potential windows directory separator 1653 if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0,1) == '\\')) { 1654 $p_path = strtr($p_path, '\\', '/'); 1655 } 1656 } 1657 return $p_path; 1658 } 1659 // }}} 1660 1661 } 1662 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Wed Nov 21 14:43:32 2007 | par Balluche grâce à PHPXref 0.7 |
![]() |