|
eZ Publish
[4.0]
|
00001 <?php 00002 /* vim: set ts=4 sw=4: */ 00003 // +----------------------------------------------------------------------+ 00004 // | PHP Version 5 | 00005 // +----------------------------------------------------------------------+ 00006 // | Copyright (c) 1997-2004 The PHP Group | 00007 // +----------------------------------------------------------------------+ 00008 // | This source file is subject to version 3.0 of the PHP license, | 00009 // | that is bundled with this package in the file LICENSE, and is | 00010 // | available through the world-wide-web at the following url: | 00011 // | http://www.php.net/license/3_0.txt. | 00012 // | If you did not receive a copy of the PHP license and are unable to | 00013 // | obtain it through the world-wide-web, please send a note to | 00014 // | license@php.net so we can mail you a copy immediately. | 00015 // +----------------------------------------------------------------------+ 00016 // | Author: Vincent Blavet <vincent@blavet.net> | 00017 // +----------------------------------------------------------------------+ 00018 // 00019 // $Id: Tar.php,v 1.20 2004/01/08 17:33:09 sniper Exp $ 00020 00021 //include_once( 'lib/ezfile/classes/ezarchivehandler.php' ); 00022 00023 /** 00024 * Creates a (compressed) Tar archive 00025 * 00026 * @author Vincent Blavet <vincent@blavet.net> 00027 * @version $Revision: 1.20 $ 00028 * @package Archive 00029 */ 00030 class eZTARArchiveHandler extends eZArchiveHandler 00031 { 00032 /** 00033 * @var string Name of the Tar 00034 */ 00035 public $_tarname=''; 00036 00037 /** 00038 * @var boolean if true, the Tar file will be gzipped 00039 */ 00040 public $_compress=false; 00041 00042 // /** 00043 // * @var file descriptor 00044 // */ 00045 // public $_file=0; 00046 /** 00047 * @var string Type of compression : 'none', 'gz' or 'bz2' 00048 */ 00049 public $_compress_type='none'; 00050 00051 /** 00052 * @var string Local Tar name of a remote Tar (http:// or ftp://) 00053 */ 00054 public $_temp_tarname=''; 00055 00056 // {{{ constructor 00057 /** 00058 * Archive_Tar Class constructor. This flavour of the constructor only 00059 * declare a new Archive_Tar object, identifying it by the name of the 00060 * tar file. 00061 * If the compress argument is set the tar will be read or created as a 00062 * gzip or bz2 compressed TAR file. 00063 * 00064 * @param string $p_tarname The name of the tar archive to create 00065 * @param string $p_compress can be null, 'gz' or 'bz2'. This 00066 * parameter indicates if gzip or bz2 compression 00067 * is required. For compatibility reason the 00068 * boolean value 'true' means 'gz'. 00069 * @access public 00070 */ 00071 function eZTARArchiveHandler( &$fileHandler, $p_tarname, $p_compress = false ) 00072 { 00073 $this->eZArchiveHandler( $fileHandler ); 00074 // $this->PEAR(); 00075 $this->_tarname = $p_tarname; 00076 // if ($p_compress) { // assert zlib extension support 00077 // $extname = 'zlib'; 00078 // if (!extension_loaded($extname)) { 00079 // $dlext = (OS_WINDOWS) ? '.dll' : '.so'; 00080 // @dl($extname . $dlext); 00081 // } 00082 // if (!extension_loaded($extname)) { 00083 // die("The extension '$extname' couldn't be loaded. ". 00084 // 'Probably you don\'t have support in your PHP '. 00085 // 'to this extension'); 00086 // return false; 00087 // } 00088 // } 00089 $this->_compress = $p_compress; 00090 } 00091 // }}} 00092 00093 // {{{ destructor 00094 function _eZTARArchiveHandler() 00095 { 00096 $this->_close(); 00097 // ----- Look for a local copy to delete 00098 if ( $this->_temp_tarname != '' ) 00099 $this->fileUnlink( $this->_temp_tarname ); 00100 // $this->_PEAR(); 00101 } 00102 // }}} 00103 00104 // {{{ create() 00105 /** 00106 * This method creates the archive file and add the files / directories 00107 * that are listed in $p_filelist. 00108 * If a file with the same name exist and is writable, it is replaced 00109 * by the new tar. 00110 * The method return false and a PEAR error text. 00111 * The $p_filelist parameter can be an array of string, each string 00112 * representing a filename or a directory name with their path if 00113 * needed. It can also be a single string with names separated by a 00114 * single blank. 00115 * For each directory added in the archive, the files and 00116 * sub-directories are also added. 00117 * See also createModify() method for more details. 00118 * 00119 * @param array $p_filelist An array of filenames and directory names, or a single 00120 * string with names separated by a single blank space. 00121 * @return true on success, false on error. 00122 * @see createModify() 00123 * @access public 00124 */ 00125 function create($p_filelist) 00126 { 00127 return $this->createModify($p_filelist, '', ''); 00128 } 00129 // }}} 00130 00131 // {{{ add() 00132 /** 00133 * This method add the files / directories that are listed in $p_filelist in 00134 * the archive. If the archive does not exist it is created. 00135 * The method return false and a PEAR error text. 00136 * The files and directories listed are only added at the end of the archive, 00137 * even if a file with the same name is already archived. 00138 * See also createModify() method for more details. 00139 * 00140 * @param array $p_filelist An array of filenames and directory names, or a single 00141 * string with names separated by a single blank space. 00142 * @return true on success, false on error. 00143 * @see createModify() 00144 * @access public 00145 */ 00146 function add($p_filelist) 00147 { 00148 return $this->addModify($p_filelist, '', ''); 00149 } 00150 // }}} 00151 00152 // {{{ extract() 00153 function extract($p_path='') 00154 { 00155 return $this->extractModify($p_path, ''); 00156 } 00157 // }}} 00158 00159 // {{{ listContent() 00160 function listContent() 00161 { 00162 $v_list_detail = array(); 00163 00164 if ($this->_openRead()) { 00165 if (!$this->_extractList('', $v_list_detail, "list", '', '')) { 00166 unset($v_list_detail); 00167 $v_list_detail = 0; 00168 } 00169 $this->_close(); 00170 } 00171 00172 return $v_list_detail; 00173 } 00174 // }}} 00175 00176 // {{{ createModify() 00177 /** 00178 * This method creates the archive file and add the files / directories 00179 * that are listed in $p_filelist. 00180 * If the file already exists and is writable, it is replaced by the 00181 * new tar. It is a create and not an add. If the file exists and is 00182 * read-only or is a directory it is not replaced. The method return 00183 * false and a PEAR error text. 00184 * The $p_filelist parameter can be an array of string, each string 00185 * representing a filename or a directory name with their path if 00186 * needed. It can also be a single string with names separated by a 00187 * single blank. 00188 * The path indicated in $p_remove_dir will be removed from the 00189 * memorized path of each file / directory listed when this path 00190 * exists. By default nothing is removed (empty path '') 00191 * The path indicated in $p_add_dir will be added at the beginning of 00192 * the memorized path of each file / directory listed. However it can 00193 * be set to empty ''. The adding of a path is done after the removing 00194 * of path. 00195 * The path add/remove ability enables the user to prepare an archive 00196 * for extraction in a different path than the origin files are. 00197 * See also addModify() method for file adding properties. 00198 * 00199 * @param array $p_filelist An array of filenames and directory names, or a single 00200 * string with names separated by a single blank space. 00201 * @param string $p_add_dir A string which contains a path to be added to the 00202 * memorized path of each element in the list. 00203 * @param string $p_remove_dir A string which contains a path to be removed from 00204 * the memorized path of each element in the list, when 00205 * relevant. 00206 * @return boolean true on success, false on error. 00207 * @access public 00208 * @see addModify() 00209 */ 00210 function createModify($p_filelist, $p_add_dir, $p_remove_dir='') 00211 { 00212 $v_result = true; 00213 00214 if (!$this->_openWrite()) 00215 return false; 00216 00217 if ($p_filelist != '') { 00218 if (is_array($p_filelist)) 00219 $v_list = $p_filelist; 00220 elseif (is_string($p_filelist)) 00221 $v_list = explode(" ", $p_filelist); 00222 else { 00223 $this->_cleanFile(); 00224 $this->_error('Invalid file list'); 00225 return false; 00226 } 00227 00228 $v_result = $this->_addList($v_list, $p_add_dir, $p_remove_dir); 00229 } 00230 00231 if ($v_result) { 00232 $this->_writeFooter(); 00233 $this->_close(); 00234 } else 00235 $this->_cleanFile(); 00236 00237 return $v_result; 00238 } 00239 // }}} 00240 00241 // {{{ addModify() 00242 /** 00243 * This method add the files / directories listed in $p_filelist at the 00244 * end of the existing archive. If the archive does not yet exists it 00245 * is created. 00246 * The $p_filelist parameter can be an array of string, each string 00247 * representing a filename or a directory name with their path if 00248 * needed. It can also be a single string with names separated by a 00249 * single blank. 00250 * The path indicated in $p_remove_dir will be removed from the 00251 * memorized path of each file / directory listed when this path 00252 * exists. By default nothing is removed (empty path '') 00253 * The path indicated in $p_add_dir will be added at the beginning of 00254 * the memorized path of each file / directory listed. However it can 00255 * be set to empty ''. The adding of a path is done after the removing 00256 * of path. 00257 * The path add/remove ability enables the user to prepare an archive 00258 * for extraction in a different path than the origin files are. 00259 * If a file/dir is already in the archive it will only be added at the 00260 * end of the archive. There is no update of the existing archived 00261 * file/dir. However while extracting the archive, the last file will 00262 * replace the first one. This results in a none optimization of the 00263 * archive size. 00264 * If a file/dir does not exist the file/dir is ignored. However an 00265 * error text is send to PEAR error. 00266 * If a file/dir is not readable the file/dir is ignored. However an 00267 * error text is send to PEAR error. 00268 * 00269 * @param array $p_filelist An array of filenames and directory names, or a single 00270 * string with names separated by a single blank space. 00271 * @param string $p_add_dir A string which contains a path to be added to the 00272 * memorized path of each element in the list. 00273 * @param string $p_remove_dir A string which contains a path to be removed from 00274 * the memorized path of each element in the list, when 00275 * relevant. 00276 * @return true on success, false on error. 00277 * @access public 00278 */ 00279 function addModify($p_filelist, $p_add_dir, $p_remove_dir='') 00280 { 00281 $v_result = true; 00282 00283 if (!@is_file($this->_tarname)) 00284 $v_result = $this->createModify($p_filelist, $p_add_dir, $p_remove_dir); 00285 else { 00286 if (is_array($p_filelist)) 00287 $v_list = $p_filelist; 00288 elseif (is_string($p_filelist)) 00289 $v_list = explode(" ", $p_filelist); 00290 else { 00291 $this->_error('Invalid file list'); 00292 return false; 00293 } 00294 00295 $v_result = $this->_append($v_list, $p_add_dir, $p_remove_dir); 00296 } 00297 00298 return $v_result; 00299 } 00300 // }}} 00301 00302 // {{{ addString() 00303 /** 00304 * This method add a single string as a file at the 00305 * end of the existing archive. If the archive does not yet exists it 00306 * is created. 00307 * 00308 * @param string $p_filename A string which contains the full filename path 00309 * that will be associated with the string. 00310 * @param string $p_string The content of the file added in the archive. 00311 * @return true on success, false on error. 00312 * @access public 00313 */ 00314 function addString($p_filename, $p_string) 00315 { 00316 $v_result = true; 00317 00318 if (!@is_file($this->_tarname)) { 00319 if (!$this->_openWrite()) { 00320 return false; 00321 } 00322 $this->_close(); 00323 } 00324 00325 if (!$this->_openAppend()) 00326 return false; 00327 00328 // Need to check the get back to the temporary file ? .... 00329 $v_result = $this->_addString($p_filename, $p_string); 00330 00331 $this->_writeFooter(); 00332 00333 $this->_close(); 00334 00335 return $v_result; 00336 } 00337 // }}} 00338 00339 // {{{ extractModify() 00340 /** 00341 * This method extract all the content of the archive in the directory 00342 * indicated by $p_path. When relevant the memorized path of the 00343 * files/dir can be modified by removing the $p_remove_path path at the 00344 * beginning of the file/dir path. 00345 * While extracting a file, if the directory path does not exists it is 00346 * created. 00347 * While extracting a file, if the file already exists it is replaced 00348 * without looking for last modification date. 00349 * While extracting a file, if the file already exists and is write 00350 * protected, the extraction is aborted. 00351 * While extracting a file, if a directory with the same name already 00352 * exists, the extraction is aborted. 00353 * While extracting a directory, if a file with the same name already 00354 * exists, the extraction is aborted. 00355 * While extracting a file/directory if the destination directory exist 00356 * and is write protected, or does not exist but can not be created, 00357 * the extraction is aborted. 00358 * If after extraction an extracted file does not show the correct 00359 * stored file size, the extraction is aborted. 00360 * When the extraction is aborted, a PEAR error text is set and false 00361 * is returned. However the result can be a partial extraction that may 00362 * need to be manually cleaned. 00363 * 00364 * @param string $p_path The path of the directory where the files/dir need to by 00365 * extracted. 00366 * @param string $p_remove_path Part of the memorized path that can be removed if 00367 * present at the beginning of the file/dir path. 00368 * @return boolean true on success, false on error. 00369 * @access public 00370 * @see extractList() 00371 */ 00372 function extractModify($p_path, $p_remove_path) 00373 { 00374 $v_result = true; 00375 $v_list_detail = array(); 00376 00377 if ($v_result = $this->_openRead()) { 00378 $v_result = $this->_extractList($p_path, $v_list_detail, "complete", 0, $p_remove_path); 00379 $this->_close(); 00380 } 00381 00382 return $v_result; 00383 } 00384 // }}} 00385 00386 // {{{ extractInString() 00387 /** 00388 * This method extract from the archive one file identified by $p_filename. 00389 * The return value is a string with the file content, or NULL on error. 00390 * @param string $p_filename The path of the file to extract in a string. 00391 * @return a string with the file content or NULL. 00392 * @access public 00393 */ 00394 function extractInString($p_filename) 00395 { 00396 if ($this->_openRead()) { 00397 $v_result = $this->_extractInString($p_filename); 00398 $this->_close(); 00399 } else { 00400 $v_result = NULL; 00401 } 00402 00403 return $v_result; 00404 } 00405 // }}} 00406 00407 // {{{ extractList() 00408 /** 00409 * This method extract from the archive only the files indicated in the 00410 * $p_filelist. These files are extracted in the current directory or 00411 * in the directory indicated by the optional $p_path parameter. 00412 * If indicated the $p_remove_path can be used in the same way as it is 00413 * used in extractModify() method. 00414 * @param array $p_filelist An array of filenames and directory names, or a single 00415 * string with names separated by a single blank space. 00416 * @param string $p_path The path of the directory where the files/dir need to by 00417 * extracted. 00418 * @param string $p_remove_path Part of the memorized path that can be removed if 00419 * present at the beginning of the file/dir path. 00420 * @return true on success, false on error. 00421 * @access public 00422 * @see extractModify() 00423 */ 00424 function extractList($p_filelist, $p_path='', $p_remove_path='') 00425 { 00426 $v_result = true; 00427 $v_list_detail = array(); 00428 00429 if (is_array($p_filelist)) 00430 $v_list = $p_filelist; 00431 elseif (is_string($p_filelist)) 00432 $v_list = explode(" ", $p_filelist); 00433 else { 00434 $this->_error('Invalid string list'); 00435 return false; 00436 } 00437 00438 if ($v_result = $this->_openRead()) { 00439 $v_result = $this->_extractList($p_path, $v_list_detail, "partial", $v_list, $p_remove_path); 00440 $this->_close(); 00441 } 00442 00443 return $v_result; 00444 } 00445 // }}} 00446 00447 // {{{ _error() 00448 function _error($p_message) 00449 { 00450 // ----- To be completed 00451 // $this->raiseError($p_message); 00452 eZDebug::writeError( $p_message, 'eZTARArchiveHandler' ); 00453 } 00454 // }}} 00455 00456 // {{{ _warning() 00457 function _warning($p_message) 00458 { 00459 // ----- To be completed 00460 // $this->raiseError($p_message); 00461 eZDebug::writeWarning( $p_message, 'eZTARArchiveHandler' ); 00462 } 00463 // }}} 00464 00465 // {{{ _openWrite() 00466 function _openWrite() 00467 { 00468 $result = $this->fileOpen( $this->_tarname, 'w' ); 00469 // if ($this->_compress) 00470 // $this->_file = @gzopen($this->_tarname, "w"); 00471 // else 00472 // $this->_file = @fopen($this->_tarname, "w"); 00473 00474 if ( $result == 0 ) 00475 { 00476 $this->_error('Unable to open in write mode \''.$this->_tarname.'\''); 00477 return false; 00478 } 00479 00480 return true; 00481 } 00482 // }}} 00483 00484 // {{{ _openRead() 00485 function _openRead() 00486 { 00487 if (strtolower(substr($this->_tarname, 0, 7)) == 'http://') { 00488 00489 // ----- Look if a local copy need to be done 00490 if ($this->_temp_tarname == '') 00491 { 00492 $this->_temp_tarname = uniqid('tar').'.tmp'; 00493 eZFileHandler::copy( $this->_tarname, 00494 $this->_temp_tarname ); 00495 // if (!$v_file_from = @fopen($this->_tarname, 'rb')) 00496 // { 00497 // $this->_error('Unable to open in read mode \''.$this->_tarname.'\''); 00498 // $this->_temp_tarname = ''; 00499 // return false; 00500 // } 00501 // if (!$v_file_to = @fopen($this->_temp_tarname, 'wb')) 00502 // { 00503 // $this->_error('Unable to open in write mode \''.$this->_temp_tarname.'\''); 00504 // $this->_temp_tarname = ''; 00505 // return false; 00506 // } 00507 // while ($v_data = @fread($v_file_from, 1024)) 00508 // @fwrite($v_file_to, $v_data); 00509 // @fclose($v_file_from); 00510 // @fclose($v_file_to); 00511 } 00512 00513 // ----- File to open if the local copy 00514 $v_filename = $this->_temp_tarname; 00515 00516 } else 00517 // ----- File to open if the normal Tar file 00518 $v_filename = $this->_tarname; 00519 00520 $result = $this->fileOpen( $v_filename, 'rb' ); 00521 // if ($this->_compress) 00522 // $this->_file = @gzopen($v_filename, "rb"); 00523 // else 00524 // $this->_file = @fopen($v_filename, "rb"); 00525 00526 if ( $result == 0 ) 00527 { 00528 $this->_error('Unable to open in read mode \''.$v_filename.'\''); 00529 return false; 00530 } 00531 00532 return true; 00533 } 00534 // }}} 00535 00536 // {{{ _openReadWrite() 00537 function _openReadWrite() 00538 { 00539 $result = $this->fileOpen( $this->_tarname, 'r+b' ); 00540 // if ($this->_compress) 00541 // $this->_file = @gzopen($this->_tarname, "r+b"); 00542 // else 00543 // $this->_file = @fopen($this->_tarname, "r+b"); 00544 00545 if ( $result == 0 ) 00546 { 00547 $this->_error('Unable to open in read/write mode \''.$this->_tarname.'\''); 00548 return false; 00549 } 00550 00551 return true; 00552 } 00553 // }}} 00554 00555 // {{{ _close() 00556 function _close() 00557 { 00558 // if (isset($this->_file)) 00559 // { 00560 // if ($this->_compress) 00561 // @gzclose($this->_file); 00562 // else 00563 // @fclose($this->_file); 00564 00565 // $this->_file = 0; 00566 // } 00567 $this->fileClose(); 00568 00569 // ----- Look if a local copy need to be erased 00570 // Note that it might be interesting to keep the url for a time : ToDo 00571 if ( $this->_temp_tarname != '' ) 00572 { 00573 $this->fileUnlink( $this->_temp_tarname ); 00574 $this->_temp_tarname = ''; 00575 } 00576 00577 return true; 00578 } 00579 // }}} 00580 00581 // {{{ _cleanFile() 00582 function _cleanFile() 00583 { 00584 $this->_close(); 00585 00586 // ----- Look for a local copy 00587 if ($this->_temp_tarname != '') 00588 { 00589 // ----- Remove the local copy but not the remote tarname 00590 $this->fileUnlink( $this->_temp_tarname ); 00591 $this->_temp_tarname = ''; 00592 } 00593 else 00594 { 00595 // ----- Remove the local tarname file 00596 $this->fileUnlink(); 00597 } 00598 $this->_tarname = ''; 00599 00600 return true; 00601 } 00602 // }}} 00603 00604 // {{{ _writeBlock() 00605 function _writeBlock($p_binary_data, $p_len=null) 00606 { 00607 if ($this->_file) { 00608 if ($p_len === null) { 00609 if ($this->_compress_type == 'gz') 00610 @gzputs($this->_file, $p_binary_data); 00611 else if ($this->_compress_type == 'bz2') 00612 @bzwrite($this->_file, $p_binary_data); 00613 else if ($this->_compress_type == 'none') 00614 @fputs($this->_file, $p_binary_data); 00615 else 00616 $this->_error('Unknown or missing compression type ('.$this->_compress_type.')'); 00617 } else { 00618 if ($this->_compress_type == 'gz') 00619 @gzputs($this->_file, $p_binary_data, $p_len); 00620 else if ($this->_compress_type == 'bz2') 00621 @bzwrite($this->_file, $p_binary_data, $p_len); 00622 else if ($this->_compress_type == 'none') 00623 @fputs($this->_file, $p_binary_data, $p_len); 00624 else 00625 $this->_error('Unknown or missing compression type ('.$this->_compress_type.')'); 00626 00627 } 00628 } 00629 return true; 00630 } 00631 // }}} 00632 00633 // {{{ _readBlock() 00634 function _readBlock($p_len=null) 00635 { 00636 $v_block = null; 00637 if ($this->_file) { 00638 if ($p_len === null) 00639 $p_len = 512; 00640 00641 if ($this->_compress_type == 'gz') 00642 $v_block = @gzread($this->_file, 512); 00643 else if ($this->_compress_type == 'bz2') 00644 $v_block = @bzread($this->_file, 512); 00645 else if ($this->_compress_type == 'none') 00646 $v_block = @fread($this->_file, 512); 00647 else 00648 $this->_error('Unknown or missing compression type ('.$this->_compress_type.')'); 00649 00650 } 00651 return $v_block; 00652 } 00653 // }}} 00654 00655 // {{{ _jumpBlock() 00656 function _jumpBlock($p_len=null) 00657 { 00658 if ($this->_file) { 00659 if ($p_len === null) 00660 $p_len = 1; 00661 00662 if ($this->_compress_type == 'gz') 00663 @gzseek($this->_file, @gztell($this->_file)+($p_len*512)); 00664 else if ($this->_compress_type == 'bz2') { 00665 // ----- Replace missing bztell() and bzseek() 00666 for ($i=0; $i<$p_len; $i++) 00667 $this->_readBlock(); 00668 } else if ($this->_compress_type == 'none') 00669 @fseek($this->_file, @ftell($this->_file)+($p_len*512)); 00670 else 00671 $this->_error('Unknown or missing compression type ('.$this->_compress_type.')'); 00672 00673 } 00674 return true; 00675 } 00676 // }}} 00677 00678 // {{{ _addFile() 00679 function _addFile($p_filename, &$p_header, $p_add_dir, $p_remove_dir) 00680 { 00681 // if (!$this->_file) 00682 // { 00683 // $this->_error('Invalid file descriptor'); 00684 // return false; 00685 // } 00686 if ( !$this->fileIsOpen() ) 00687 { 00688 $this->_error( 'File is not open' ); 00689 return false; 00690 } 00691 00692 if ($p_filename == '') 00693 { 00694 $this->_error('Invalid file name'); 00695 return false; 00696 } 00697 00698 // ----- Calculate the stored filename 00699 $p_filename = $this->_translateWinPath($p_filename, false); 00700 $v_stored_filename = $p_filename; 00701 if (strcmp($p_filename, $p_remove_dir) == 0) 00702 { 00703 return true; 00704 } 00705 if ($p_remove_dir != '') 00706 { 00707 if (substr($p_remove_dir, -1) != '/') 00708 $p_remove_dir .= '/'; 00709 00710 if (substr($p_filename, 0, strlen($p_remove_dir)) == $p_remove_dir) 00711 $v_stored_filename = substr($p_filename, strlen($p_remove_dir)); 00712 } 00713 $v_stored_filename = $this->_translateWinPath($v_stored_filename); 00714 if ($p_add_dir != '') { 00715 if (substr($p_add_dir, -1) == '/') 00716 $v_stored_filename = $p_add_dir.$v_stored_filename; 00717 else 00718 $v_stored_filename = $p_add_dir.'/'.$v_stored_filename; 00719 } 00720 00721 $isFile = $this->fileIsFile( $p_filename ); 00722 if ( !$isFile ) 00723 { 00724 // Make sure directory names end with a slash 00725 if ( $v_stored_filename[ strlen( $v_stored_filename ) - 1 ] != '/' ) 00726 $v_stored_filename .= '/'; 00727 } 00728 00729 if (strlen($v_stored_filename) > 99) 00730 { 00731 $this->_warning("Stored file name is too long (max. 99) : '$v_stored_filename'"); 00732 // Cannot do this, $v_file is not available 00733 // fclose($v_file); 00734 return true; 00735 } 00736 $v_stored_filename = $this->_pathReduction($v_stored_filename); 00737 00738 if ( $isFile ) 00739 { 00740 if (($v_file = @fopen($p_filename, "rb")) == 0) 00741 { 00742 $this->_warning("Unable to open file '$p_filename' in binary read mode"); 00743 return true; 00744 } 00745 00746 if (!$this->_writeHeader($p_filename, $v_stored_filename)) 00747 return false; 00748 00749 while (($v_buffer = fread($v_file, 512)) != '') 00750 { 00751 $v_binary_data = pack("a512", "$v_buffer"); 00752 // if ($this->_compress) 00753 // @gzputs($this->_file, $v_binary_data); 00754 // else 00755 // @fputs($this->_file, $v_binary_data); 00756 $this->fileWrite( $v_binary_data ); 00757 } 00758 00759 fclose($v_file); 00760 00761 } 00762 else 00763 { 00764 // ----- Only header for dir 00765 if (!$this->_writeHeader($p_filename, $v_stored_filename)) 00766 return false; 00767 } 00768 00769 return true; 00770 } 00771 // }}} 00772 00773 // {{{ _addString() 00774 function _addString($p_filename, $p_string) 00775 { 00776 if (!$this->_file) { 00777 $this->_error('Invalid file descriptor'); 00778 return false; 00779 } 00780 00781 if ($p_filename == '') { 00782 $this->_error('Invalid file name'); 00783 return false; 00784 } 00785 00786 // ----- Calculate the stored filename 00787 $p_filename = $this->_translateWinPath($p_filename, false); 00788 00789 if (!$this->_writeHeaderBlock($p_filename, strlen($p_string), 0, 0, "", 0, 0)) 00790 return false; 00791 00792 $i=0; 00793 while (($v_buffer = substr($p_string, (($i++)*512), 512)) != '') { 00794 $v_binary_data = pack("a512", $v_buffer); 00795 $this->_writeBlock($v_binary_data); 00796 } 00797 00798 return true; 00799 } 00800 // }}} 00801 00802 // {{{ _writeFooter() 00803 function _writeFooter() 00804 { 00805 if ( $this->fileIsOpen() ) 00806 { 00807 $endBlocks = ( filesize( $this->_tarname ) / 512 ) + 1; 00808 $blockPadding = 20; 00809 $modulo = $endBlocks % $blockPadding; 00810 if ( $modulo == 0 ) 00811 { 00812 $blockCount = $blockPadding; 00813 } 00814 else 00815 { 00816 $blockCount = ( $blockPadding - $modulo ) + 1; 00817 } 00818 // ----- Write the last 0 filled block for end of archive and pad it to 20 blocks 00819 for ( $i = 0; $i < $blockCount; ++$i ) 00820 { 00821 $v_binary_data = pack("a512", ''); 00822 $this->fileWrite( $v_binary_data ); 00823 } 00824 } 00825 return true; 00826 } 00827 // }}} 00828 00829 // {{{ _addList() 00830 function _addList($p_list, $p_add_dir, $p_remove_dir) 00831 { 00832 $v_result=true; 00833 $v_header = array(); 00834 00835 // if (!$this->_file ) 00836 // { 00837 // $this->_error('Invalid file descriptor'); 00838 // return false; 00839 // } 00840 if ( !$this->fileIsOpen() ) 00841 { 00842 $this->_error( 'File is not open' ); 00843 // ----- Remove potential windows directory separator 00844 // $p_add_dir = $this->_translateWinPath($p_add_dir); 00845 // $p_remove_dir = $this->_translateWinPath($p_remove_dir, false); 00846 // 00847 // if (!$this->_file) { 00848 // $this->_error('Invalid file descriptor'); 00849 return false; 00850 } 00851 00852 if ( sizeof($p_list) == 0 ) 00853 return true; 00854 00855 for ( $j = 0; ( $j < count( $p_list ) ) && ( $v_result ); $j++ ) 00856 { 00857 $v_filename = $p_list[$j]; 00858 00859 // ----- Skip the current tar name 00860 if ($v_filename == $this->_tarname) 00861 continue; 00862 00863 if ($v_filename == '') 00864 continue; 00865 00866 if ( !$this->fileExists( $v_filename ) ) 00867 { 00868 $this->_warning("File '$v_filename' does not exist"); 00869 continue; 00870 } 00871 00872 // ----- Add the file or directory header 00873 if (!$this->_addFile($v_filename, $v_header, $p_add_dir, $p_remove_dir)) 00874 return false; 00875 00876 if ( $this->fileIsDirectory( $v_filename ) ) 00877 { 00878 if (!($p_hdir = opendir($v_filename))) 00879 { 00880 $this->_warning("Directory '$v_filename' can not be read"); 00881 continue; 00882 } 00883 while (false !== ($p_hitem = readdir($p_hdir))) { 00884 if ( $p_hitem == '.' || $p_hitem == '..' ) 00885 continue; 00886 00887 if ($v_filename != ".") 00888 $p_temp_list[0] = $v_filename.'/'.$p_hitem; 00889 else 00890 $p_temp_list[0] = $p_hitem; 00891 00892 $v_result = $this->_addList($p_temp_list, $p_add_dir, $p_remove_dir); 00893 } 00894 00895 unset($p_temp_list); 00896 unset($p_hdir); 00897 unset($p_hitem); 00898 } 00899 } 00900 00901 return $v_result; 00902 } 00903 // }}} 00904 00905 // {{{ _writeHeader() 00906 function _writeHeader($p_filename, $p_stored_filename) 00907 { 00908 if ($p_stored_filename == '') 00909 $p_stored_filename = $p_filename; 00910 $v_reduce_filename = $this->_pathReduction($p_stored_filename); 00911 00912 $v_info = $this->fileStatistics( $p_filename ); 00913 if (strlen($v_reduce_filename) > 99) { 00914 if (!$this->_writeLongHeader($v_reduce_filename)) 00915 return false; 00916 } 00917 00918 $v_info = stat($p_filename); 00919 $v_uid = sprintf("%6s ", DecOct($v_info[4])); 00920 $v_gid = sprintf("%6s ", DecOct($v_info[5])); 00921 $v_perms = sprintf("%6s ", DecOct(fileperms($p_filename))); 00922 00923 $v_mtime = sprintf("%11s", DecOct(filemtime($p_filename))); 00924 00925 if ( $this->fileIsDirectory( $p_filename )) 00926 { 00927 $v_typeflag = "5"; 00928 $v_size = sprintf("%11s ", DecOct(0)); 00929 } 00930 else 00931 { 00932 $v_typeflag = ''; 00933 clearstatcache(); 00934 $v_size = sprintf("%11s ", DecOct(filesize($p_filename))); 00935 } 00936 00937 $v_linkname = ''; 00938 00939 $v_magic = ''; 00940 00941 $v_version = ''; 00942 00943 $v_uname = ''; 00944 00945 $v_gname = ''; 00946 00947 $v_devmajor = ''; 00948 00949 $v_devminor = ''; 00950 00951 $v_prefix = ''; 00952 00953 $v_binary_data_first = pack("a100a8a8a8a12A12", $v_reduce_filename, $v_perms, $v_uid, $v_gid, $v_size, $v_mtime); 00954 $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12", $v_typeflag, $v_linkname, $v_magic, $v_version, $v_uname, $v_gname, $v_devmajor, $v_devminor, $v_prefix, ''); 00955 00956 // ----- Calculate the checksum 00957 $v_checksum = 0; 00958 // ..... First part of the header 00959 for ($i=0; $i<148; $i++) 00960 $v_checksum += ord(substr($v_binary_data_first,$i,1)); 00961 // ..... Ignore the checksum value and replace it by ' ' (space) 00962 for ($i=148; $i<156; $i++) 00963 $v_checksum += ord(' '); 00964 // ..... Last part of the header 00965 for ($i=156, $j=0; $i<512; $i++, $j++) 00966 $v_checksum += ord(substr($v_binary_data_last,$j,1)); 00967 00968 // ----- Write the first 148 bytes of the header in the archive 00969 // if ($this->_compress) 00970 // @gzputs($this->_file, $v_binary_data_first, 148); 00971 // else 00972 // @fputs($this->_file, $v_binary_data_first, 148); 00973 $this->fileWrite( $v_binary_data_first, 148 ); 00974 00975 // ----- Write the calculated checksum 00976 $v_checksum = sprintf("%6s ", DecOct($v_checksum)); 00977 $v_binary_data = pack("a8", $v_checksum); 00978 // if ($this->_compress) 00979 // @gzputs($this->_file, $v_binary_data, 8); 00980 // else 00981 // @fputs($this->_file, $v_binary_data, 8); 00982 $this->fileWrite( $v_binary_data, 8 ); 00983 00984 // ----- Write the last 356 bytes of the header in the archive 00985 // if ($this->_compress) 00986 // @gzputs($this->_file, $v_binary_data_last, 356); 00987 // else 00988 // @fputs($this->_file, $v_binary_data_last, 356); 00989 $this->fileWrite( $v_binary_data_last, 356 ); 00990 00991 return true; 00992 } 00993 // }}} 00994 00995 // {{{ _writeHeaderBlock() 00996 function _writeHeaderBlock($p_filename, $p_size, $p_mtime=0, $p_perms=0, $p_type='', $p_uid=0, $p_gid=0) 00997 { 00998 $p_filename = $this->_pathReduction($p_filename); 00999 01000 if (strlen($p_filename) > 99) { 01001 if (!$this->_writeLongHeader($p_filename)) 01002 return false; 01003 } 01004 01005 if ($p_type == "5") { 01006 $v_size = sprintf("%11s ", DecOct(0)); 01007 } else { 01008 $v_size = sprintf("%11s ", DecOct($p_size)); 01009 } 01010 01011 $v_uid = sprintf("%6s ", DecOct($p_uid)); 01012 $v_gid = sprintf("%6s ", DecOct($p_gid)); 01013 $v_perms = sprintf("%6s ", DecOct($p_perms)); 01014 01015 $v_mtime = sprintf("%11s", DecOct($p_mtime)); 01016 01017 $v_linkname = ''; 01018 01019 $v_magic = ''; 01020 01021 $v_version = ''; 01022 01023 $v_uname = ''; 01024 01025 $v_gname = ''; 01026 01027 $v_devmajor = ''; 01028 01029 $v_devminor = ''; 01030 01031 $v_prefix = ''; 01032 01033 $v_binary_data_first = pack("a100a8a8a8a12A12", $p_filename, $v_perms, $v_uid, $v_gid, $v_size, $v_mtime); 01034 $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12", $p_type, $v_linkname, $v_magic, $v_version, $v_uname, $v_gname, $v_devmajor, $v_devminor, $v_prefix, ''); 01035 01036 // ----- Calculate the checksum 01037 $v_checksum = 0; 01038 // ..... First part of the header 01039 for ($i=0; $i<148; $i++) 01040 $v_checksum += ord(substr($v_binary_data_first,$i,1)); 01041 // ..... Ignore the checksum value and replace it by ' ' (space) 01042 for ($i=148; $i<156; $i++) 01043 $v_checksum += ord(' '); 01044 // ..... Last part of the header 01045 for ($i=156, $j=0; $i<512; $i++, $j++) 01046 $v_checksum += ord(substr($v_binary_data_last,$j,1)); 01047 01048 // ----- Write the first 148 bytes of the header in the archive 01049 $this->_writeBlock($v_binary_data_first, 148); 01050 01051 // ----- Write the calculated checksum 01052 $v_checksum = sprintf("%6s ", DecOct($v_checksum)); 01053 $v_binary_data = pack("a8", $v_checksum); 01054 $this->_writeBlock($v_binary_data, 8); 01055 01056 // ----- Write the last 356 bytes of the header in the archive 01057 $this->_writeBlock($v_binary_data_last, 356); 01058 01059 return true; 01060 } 01061 // }}} 01062 01063 // {{{ _writeLongHeader() 01064 function _writeLongHeader($p_filename) 01065 { 01066 $v_size = sprintf("%11s ", DecOct(strlen($p_filename))); 01067 01068 $v_typeflag = 'L'; 01069 01070 $v_linkname = ''; 01071 01072 $v_magic = ''; 01073 01074 $v_version = ''; 01075 01076 $v_uname = ''; 01077 01078 $v_gname = ''; 01079 01080 $v_devmajor = ''; 01081 01082 $v_devminor = ''; 01083 01084 $v_prefix = ''; 01085 01086 $v_binary_data_first = pack("a100a8a8a8a12A12", '././@LongLink', 0, 0, 0, $v_size, 0); 01087 $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12", $v_typeflag, $v_linkname, $v_magic, $v_version, $v_uname, $v_gname, $v_devmajor, $v_devminor, $v_prefix, ''); 01088 01089 // ----- Calculate the checksum 01090 $v_checksum = 0; 01091 // ..... First part of the header 01092 for ($i=0; $i<148; $i++) 01093 $v_checksum += ord(substr($v_binary_data_first,$i,1)); 01094 // ..... Ignore the checksum value and replace it by ' ' (space) 01095 for ($i=148; $i<156; $i++) 01096 $v_checksum += ord(' '); 01097 // ..... Last part of the header 01098 for ($i=156, $j=0; $i<512; $i++, $j++) 01099 $v_checksum += ord(substr($v_binary_data_last,$j,1)); 01100 01101 // ----- Write the first 148 bytes of the header in the archive 01102 $this->_writeBlock($v_binary_data_first, 148); 01103 01104 // ----- Write the calculated checksum 01105 $v_checksum = sprintf("%6s ", DecOct($v_checksum)); 01106 $v_binary_data = pack("a8", $v_checksum); 01107 $this->_writeBlock($v_binary_data, 8); 01108 01109 // ----- Write the last 356 bytes of the header in the archive 01110 $this->_writeBlock($v_binary_data_last, 356); 01111 01112 // ----- Write the filename as content of the block 01113 $i=0; 01114 while (($v_buffer = substr($p_filename, (($i++)*512), 512)) != '') { 01115 $v_binary_data = pack("a512", "$v_buffer"); 01116 $this->_writeBlock($v_binary_data); 01117 } 01118 01119 return true; 01120 } 01121 // }}} 01122 01123 // {{{ _readHeader() 01124 function _readHeader($v_binary_data, &$v_header) 01125 { 01126 if (strlen($v_binary_data)==0) { 01127 $v_header['filename'] = ''; 01128 return true; 01129 } 01130 01131 if (strlen($v_binary_data) != 512) { 01132 $v_header['filename'] = ''; 01133 $this->_error('Invalid block size : '.strlen($v_binary_data)); 01134 return false; 01135 } 01136 01137 // ----- Calculate the checksum 01138 $v_checksum = 0; 01139 // ..... First part of the header 01140 for ($i=0; $i<148; $i++) 01141 $v_checksum+=ord(substr($v_binary_data,$i,1)); 01142 // ..... Ignore the checksum value and replace it by ' ' (space) 01143 for ($i=148; $i<156; $i++) 01144 $v_checksum += ord(' '); 01145 // ..... Last part of the header 01146 for ($i=156; $i<512; $i++) 01147 $v_checksum+=ord(substr($v_binary_data,$i,1)); 01148 01149 $v_data = unpack("a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/a8checksum/a1typeflag/a100link/a6magic/a2version/a32uname/a32gname/a8devmajor/a8devminor", $v_binary_data); 01150 01151 // ----- Extract the checksum 01152 $v_header['checksum'] = OctDec(trim($v_data['checksum'])); 01153 if ($v_header['checksum'] != $v_checksum) { 01154 $v_header['filename'] = ''; 01155 01156 // ----- Look for last block (empty block) 01157 if (($v_checksum == 256) && ($v_header['checksum'] == 0)) 01158 return true; 01159 01160 $this->_error('Invalid checksum for file "'.$v_data['filename'].'" : '.$v_checksum.' calculated, '.$v_header['checksum'].' expected'); 01161 return false; 01162 } 01163 01164 // ----- Extract the properties 01165 $v_header['filename'] = trim($v_data['filename']); 01166 $v_header['mode'] = OctDec(trim($v_data['mode'])); 01167 $v_header['uid'] = OctDec(trim($v_data['uid'])); 01168 $v_header['gid'] = OctDec(trim($v_data['gid'])); 01169 $v_header['size'] = OctDec(trim($v_data['size'])); 01170 $v_header['mtime'] = OctDec(trim($v_data['mtime'])); 01171 if (($v_header['typeflag'] = $v_data['typeflag']) == "5") { 01172 $v_header['size'] = 0; 01173 } 01174 /* ----- All these fields are removed form the header because they do not carry interesting info 01175 $v_header[link] = trim($v_data[link]); 01176 $v_header[magic] = trim($v_data[magic]); 01177 $v_header[version] = trim($v_data[version]); 01178 $v_header[uname] = trim($v_data[uname]); 01179 $v_header[gname] = trim($v_data[gname]); 01180 $v_header[devmajor] = trim($v_data[devmajor]); 01181 $v_header[devminor] = trim($v_data[devminor]); 01182 */ 01183 01184 return true; 01185 } 01186 // }}} 01187 01188 // {{{ _readLongHeader() 01189 function _readLongHeader(&$v_header) 01190 { 01191 $v_filename = ''; 01192 $n = floor($v_header['size']/512); 01193 for ($i=0; $i<$n; $i++) { 01194 $v_content = $this->_readBlock(); 01195 $v_filename .= $v_content; 01196 } 01197 if (($v_header['size'] % 512) != 0) { 01198 $v_content = $this->_readBlock(); 01199 $v_filename .= $v_content; 01200 } 01201 01202 // ----- Read the next header 01203 $v_binary_data = $this->_readBlock(); 01204 01205 if (!$this->_readHeader($v_binary_data, $v_header)) 01206 return false; 01207 01208 $v_header['filename'] = $v_filename; 01209 01210 return true; 01211 } 01212 // }}} 01213 01214 // {{{ _extractInString() 01215 /** 01216 * This method extract from the archive one file identified by $p_filename. 01217 * The return value is a string with the file content, or NULL on error. 01218 * @param string $p_filename The path of the file to extract in a string. 01219 * @return a string with the file content or NULL. 01220 * @access private 01221 */ 01222 function _extractInString($p_filename) 01223 { 01224 $v_result_str = ""; 01225 01226 While (strlen($v_binary_data = $this->_readBlock()) != 0) 01227 { 01228 if (!$this->_readHeader($v_binary_data, $v_header)) 01229 return NULL; 01230 01231 if ($v_header['filename'] == '') 01232 continue; 01233 01234 // ----- Look for long filename 01235 if ($v_header['typeflag'] == 'L') { 01236 if (!$this->_readLongHeader($v_header)) 01237 return NULL; 01238 } 01239 01240 if ($v_header['filename'] == $p_filename) { 01241 if ($v_header['typeflag'] == "5") { 01242 $this->_error('Unable to extract in string a directory entry {'.$v_header['filename'].'}'); 01243 return NULL; 01244 } else { 01245 $n = floor($v_header['size']/512); 01246 for ($i=0; $i<$n; $i++) { 01247 $v_result_str .= $this->_readBlock(); 01248 } 01249 if (($v_header['size'] % 512) != 0) { 01250 $v_content = $this->_readBlock(); 01251 $v_result_str .= substr($v_content, 0, ($v_header['size'] % 512)); 01252 } 01253 return $v_result_str; 01254 } 01255 } else { 01256 $this->_jumpBlock(ceil(($v_header['size']/512))); 01257 } 01258 } 01259 01260 return NULL; 01261 } 01262 // }}} 01263 01264 // {{{ _extractList() 01265 function _extractList($p_path, &$p_list_detail, $p_mode, $p_file_list, $p_remove_path) 01266 { 01267 $v_result=true; 01268 $v_nb = 0; 01269 $v_extract_all = true; 01270 $v_listing = false; 01271 01272 // ----- Look for removing the WINDOW '\' 01273 if ( eZSys::osType() == 'win32' && strpos($p_path, '\\')) 01274 { 01275 str_replace('\\', '/', $p_path); 01276 } 01277 01278 if ($p_path == '' || (substr($p_path, 0, 1) != '/' && substr($p_path, 0, 3) != "../" && !strpos($p_path, ':'))) { 01279 $p_path = "./".$p_path; 01280 } 01281 $p_remove_path = $this->_translateWinPath($p_remove_path); 01282 01283 // ----- Look for path to remove format (should end by /) 01284 if (($p_remove_path != '') && (substr($p_remove_path, -1) != '/')) 01285 $p_remove_path .= '/'; 01286 $p_remove_path_size = strlen($p_remove_path); 01287 01288 switch ($p_mode) { 01289 case "complete" : 01290 $v_extract_all = TRUE; 01291 $v_listing = FALSE; 01292 break; 01293 case "partial" : 01294 $v_extract_all = FALSE; 01295 $v_listing = FALSE; 01296 break; 01297 case "list" : 01298 $v_extract_all = FALSE; 01299 $v_listing = TRUE; 01300 break; 01301 default : 01302 $this->_error('Invalid extract mode ('.$p_mode.')'); 01303 return false; 01304 } 01305 01306 clearstatcache(); 01307 01308 // While (!($v_end_of_file = ($this->_compress?@gzeof($this->_file):@feof($this->_file)))) 01309 while (!($v_end_of_file = ($this->fileEOF()))) 01310 { 01311 $v_extract_file = FALSE; 01312 $v_extraction_stopped = 0; 01313 01314 // if ($this->_compress) 01315 // $v_binary_data = @gzread($this->_file, 512); 01316 // else 01317 // $v_binary_data = @fread($this->_file, 512); 01318 $v_binary_data = $this->fileRead( 512 ); 01319 01320 if (!$this->_readHeader($v_binary_data, $v_header)) 01321 return false; 01322 01323 if ($v_header['filename'] == '') 01324 continue; 01325 01326 // ----- Look for long filename 01327 if ($v_header['typeflag'] == 'L') { 01328 if (!$this->_readLongHeader($v_header)) 01329 return false; 01330 } 01331 01332 if ((!$v_extract_all) && (is_array($p_file_list))) { 01333 // ----- By default no unzip if the file is not found 01334 $v_extract_file = false; 01335 01336 for ($i=0; $i<sizeof($p_file_list); $i++) { 01337 // ----- Look if it is a directory 01338 if (substr($p_file_list[$i], -1) == '/') { 01339 // ----- Look if the directory is in the filename path 01340 if ((strlen($v_header['filename']) > strlen($p_file_list[$i])) && (substr($v_header['filename'], 0, strlen($p_file_list[$i])) == $p_file_list[$i])) { 01341 $v_extract_file = TRUE; 01342 break; 01343 } 01344 } 01345 01346 // ----- It is a file, so compare the file names 01347 elseif ($p_file_list[$i] == $v_header['filename']) { 01348 $v_extract_file = TRUE; 01349 break; 01350 } 01351 } 01352 } else { 01353 $v_extract_file = TRUE; 01354 } 01355 01356 // ----- Look if this file need to be extracted 01357 if (($v_extract_file) && (!$v_listing)) 01358 { 01359 if (($p_remove_path != '') 01360 && (substr($v_header['filename'], 0, $p_remove_path_size) == $p_remove_path)) 01361 $v_header['filename'] = substr($v_header['filename'], $p_remove_path_size); 01362 if (($p_path != './') && ($p_path != '/')) { 01363 while (substr($p_path, -1) == '/') 01364 $p_path = substr($p_path, 0, strlen($p_path)-1); 01365 01366 if (substr($v_header['filename'], 0, 1) == '/') 01367 $v_header['filename'] = $p_path.$v_header['filename']; 01368 else 01369 $v_header['filename'] = $p_path.'/'.$v_header['filename']; 01370 } 01371 if (file_exists($v_header['filename'])) { 01372 if ((@is_dir($v_header['filename'])) && ($v_header['typeflag'] == '')) { 01373 $this->_error('File '.$v_header['filename'].' already exists as a directory'); 01374 return false; 01375 } 01376 if ((is_file($v_header['filename'])) && ($v_header['typeflag'] == "5")) { 01377 $this->_error('Directory '.$v_header['filename'].' already exists as a file'); 01378 return false; 01379 } 01380 if (!is_writeable($v_header['filename'])) { 01381 $this->_error('File '.$v_header['filename'].' already exists and is write protected'); 01382 return false; 01383 } 01384 if (filemtime($v_header['filename']) > $v_header['mtime']) { 01385 // To be completed : An error or silent no replace ? 01386 } 01387 } 01388 01389 // ----- Check the directory availability and create it if necessary 01390 elseif (($v_result = $this->_dirCheck(($v_header['typeflag'] == "5"?$v_header['filename']:dirname($v_header['filename'])))) != 1) { 01391 $this->_error('Unable to create path for '.$v_header['filename']); 01392 return false; 01393 } 01394 01395 if ($v_extract_file) { 01396 if ($v_header['typeflag'] == "5") { 01397 if (!@file_exists($v_header['filename'])) { 01398 if (!@eZDir::mkdir($v_header['filename'] )) { 01399 $this->_error('Unable to create directory {'.$v_header['filename'].'}'); 01400 return false; 01401 } 01402 } 01403 } else { 01404 if (($v_dest_file = @fopen($v_header['filename'], "wb")) == 0) { 01405 $this->_error('Error while opening {'.$v_header['filename'].'} in write binary mode'); 01406 return false; 01407 } else { 01408 $n = floor($v_header['size']/512); 01409 for ($i=0; $i<$n; $i++) { 01410 // if ($this->_compress) 01411 // $v_content = @gzread($this->_file, 512); 01412 // else 01413 // $v_content = @fread($this->_file, 512); 01414 $v_content = $this->fileRead( 512 ); 01415 fwrite($v_dest_file, $v_content, 512); 01416 } 01417 if (($v_header['size'] % 512) != 0) { 01418 // if ($this->_compress) 01419 // $v_content = @gzread($this->_file, 512); 01420 // else 01421 // $v_content = @fread($this->_file, 512); 01422 $v_content = $this->fileRead( 512 ); 01423 fwrite($v_dest_file, $v_content, ($v_header['size'] % 512)); 01424 } 01425 01426 @fclose($v_dest_file); 01427 01428 // ----- Change the file mode, mtime 01429 @touch($v_header['filename'], $v_header['mtime']); 01430 if ($v_header['mode'] & 0111) { 01431 // make file executable, obey umask 01432 $mode = fileperms($v_header['filename']) | (~umask() & 0111); 01433 @chmod($v_header['filename'], $mode); 01434 } 01435 // If we don`t force this, we can never delete installed packages 01436 @chmod( $v_header['filename'], 01437 octdec( eZINI::instance()->variable( 'FileSettings', 'StorageFilePermissions' ) ) ); 01438 } 01439 01440 // ----- Check the file size 01441 clearstatcache(); 01442 if (filesize($v_header['filename']) != $v_header['size']) { 01443 $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.'); 01444 return false; 01445 } 01446 } 01447 } else { 01448 // ----- Jump to next file 01449 // if ($this->_compress) 01450 // @gzseek($this->_file, @gztell($this->_file)+(ceil(($v_header['size']/512))*512)); 01451 // else 01452 // @fseek($this->_file, @ftell($this->_file)+(ceil(($v_header['size']/512))*512)); 01453 $seekPosition = $this->fileTell() + ( ceil( ( $v_header['size'] / 512 ) ) * 512 ); 01454 $this->fileSeek( $seekPosition ); 01455 } 01456 } else { 01457 // ----- Jump to next file 01458 // if ($this->_compress) 01459 // @gzseek($this->_file, @gztell($this->_file)+(ceil(($v_header['size']/512))*512)); 01460 // else 01461 // @fseek($this->_file, @ftell($this->_file)+(ceil(($v_header['size']/512))*512)); 01462 $seekPosition = $this->fileTell() + ( ceil ( ( $v_header['size'] / 512 ) ) * 512 ); 01463 $this->fileSeek( $seekPosition ); 01464 } 01465 01466 // if ($this->_compress) 01467 // $v_end_of_file = @gzeof($this->_file); 01468 // else 01469 // $v_end_of_file = @feof($this->_file); 01470 $v_end_of_file = $this->fileEOF(); 01471 01472 if ($v_listing || $v_extract_file || $v_extraction_stopped) { 01473 // ----- Log extracted files 01474 if (($v_file_dir = dirname($v_header['filename'])) == $v_header['filename']) 01475 $v_file_dir = ''; 01476 if ((substr($v_header['filename'], 0, 1) == '/') && ($v_file_dir == '')) 01477 $v_file_dir = '/'; 01478 01479 $p_list_detail[$v_nb++] = $v_header; 01480 } 01481 } 01482 01483 return true; 01484 } 01485 // }}} 01486 01487 // {{{ _openAppend() 01488 function _openAppend() 01489 { 01490 if (filesize($this->_tarname) == 0) 01491 return $this->_openWrite(); 01492 01493 if ($this->_compress) 01494 { 01495 // Rename to temporary file. 01496 $this->fileClose(); 01497 $temporaryHandler =& $this->detachHandler(); 01498 $temporaryHandler->rename( $this->_tarname . '.tmp' ); 01499 if ( !$this->_openWrite() ) 01500 { 01501 $temporaryHandler->rename( $this->_tarname ); 01502 // @rename($this->_tarname.".tmp", $this->_tarname); 01503 return false; 01504 } 01505 $temporaryHandler->fileOpen( false, 'rb' ); 01506 01507 // $v_buffer = @gzread($v_temp_tar, 512); 01508 $v_buffer = $temporaryHandler->read( 512 ); 01509 01510 // ----- Read the following blocks but not the last one 01511 // if (!@gzeof($v_temp_tar)) { 01512 // do{ 01513 // $v_binary_data = pack("a512", "$v_buffer"); 01514 // @gzputs($this->_file, $v_binary_data); 01515 // $v_buffer = @gzread($v_temp_tar, 512); 01516 01517 //<<<<<<< .working 01518 // } while (!@gzeof($v_temp_tar)); 01519 // } 01520 if ( !$temporaryHandler->eof() ) 01521 { 01522 do 01523 { 01524 $v_binary_data = pack( 'a512', "$v_buffer" ); 01525 $this->fileWrite( $v_binary_data ); 01526 $v_buffer = $temporaryHandler->read( 512 ); 01527 } while( !$temporaryHandler->eof() ); 01528 } 01529 // elseif ($this->_compress_type == 'bz2') { 01530 // $v_buffered_lines = array(); 01531 // $v_buffered_lines[] = @bzread($v_temp_tar, 512); 01532 // 01533 // // ----- Read the following blocks but not the last one 01534 // while (strlen($v_buffered_lines[] = @bzread($v_temp_tar, 512)) > 0) { 01535 // $v_binary_data = pack("a512", array_shift($v_buffered_lines)); 01536 // $this->_writeBlock($v_binary_data); 01537 // } 01538 // @bzclose($v_temp_tar); 01539 // } 01540 01541 $this->_close(); 01542 01543 // if (!@unlink($this->_tarname.".tmp")) 01544 if ( !$temporaryHandler->unlink() ) 01545 { 01546 $this->_error('Error while deleting temporary file \''.$this->_tarname.'.tmp\''); 01547 } 01548 } 01549 else 01550 { 01551 // ----- For not compressed tar, just add files before the last 512 bytes block 01552 if (!$this->_openReadWrite()) 01553 return false; 01554 01555 clearstatcache(); 01556 $v_size = filesize($this->_tarname); 01557 // fseek($this->_file, $v_size-512); 01558 $this->fileSeek( $v_size - 512 ); 01559 01560 } 01561 01562 return true; 01563 } 01564 // }}} 01565 01566 // {{{ _append() 01567 function _append($p_filelist, $p_add_dir='', $p_remove_dir='') 01568 { 01569 if (!$this->_openAppend()) 01570 return false; 01571 01572 if ($this->_addList($p_filelist, $p_add_dir, $p_remove_dir)) 01573 $this->_writeFooter(); 01574 01575 $this->_close(); 01576 01577 return true; 01578 } 01579 // }}} 01580 01581 // {{{ _dirCheck() 01582 01583 /** 01584 * Check if a directory exists and create it (including parent 01585 * dirs) if not. 01586 * 01587 * @param string $p_dir directory to check 01588 * 01589 * @return bool TRUE if the directory exists or was created 01590 */ 01591 function _dirCheck($p_dir) 01592 { 01593 if ((@is_dir($p_dir)) || ($p_dir == '')) 01594 return true; 01595 01596 $p_parent_dir = dirname($p_dir); 01597 01598 if (($p_parent_dir != $p_dir) && 01599 ($p_parent_dir != '') && 01600 (!$this->_dirCheck($p_parent_dir))) 01601 return false; 01602 01603 if (!@eZDir::mkdir( $p_dir )) { 01604 $this->_error("Unable to create directory '$p_dir'"); 01605 return false; 01606 } 01607 01608 return true; 01609 } 01610 01611 // }}} 01612 01613 // {{{ _pathReduction() 01614 01615 /** 01616 * Compress path by changing for example "/dir/foo/../bar" to "/dir/bar", and 01617 * remove double slashes. 01618 * 01619 * @param string $p_dir path to reduce 01620 * 01621 * @return string reduced path 01622 * 01623 * @access private 01624 * 01625 */ 01626 function _pathReduction($p_dir) 01627 { 01628 $v_result = ''; 01629 01630 // ----- Look for not empty path 01631 if ($p_dir != '') { 01632 // ----- Explode path by directory names 01633 $v_list = explode('/', $p_dir); 01634 01635 // ----- Study directories from last to first 01636 for ($i=sizeof($v_list)-1; $i>=0; $i--) { 01637 // ----- Look for current path 01638 if ($v_list[$i] == ".") { 01639 // ----- Ignore this directory 01640 // Should be the first $i=0, but no check is done 01641 } 01642 else if ($v_list[$i] == "..") { 01643 // ----- Ignore it and ignore the $i-1 01644 $i--; 01645 } 01646 else if (($v_list[$i] == '') && ($i!=(sizeof($v_list)-1)) && ($i!=0)) { 01647 // ----- Ignore only the double '//' in path, 01648 // but not the first and last / 01649 } else { 01650 $v_result = $v_list[$i].($i!=(sizeof($v_list)-1)?'/'.$v_result:''); 01651 } 01652 } 01653 } 01654 $v_result = strtr($v_result, '\\', '/'); 01655 return $v_result; 01656 } 01657 01658 // }}} 01659 01660 // {{{ _translateWinPath() 01661 function _translateWinPath($p_path, $p_remove_disk_letter=true) 01662 { 01663 //if (OS_WINDOWS) { 01664 if ( eZSys::osType() == 'win32' ) 01665 { 01666 // ----- Look for potential disk letter 01667 if (($p_remove_disk_letter) && (($v_position = strpos($p_path, ':')) != false)) { 01668 $p_path = substr($p_path, $v_position+1); 01669 } 01670 // ----- Change potential windows directory separator 01671 if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0,1) == '\\')) { 01672 $p_path = strtr($p_path, '\\', '/'); 01673 } 01674 } 01675 return $p_path; 01676 } 01677 // }}} 01678 01679 } 01680 ?>