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