- Sync with pear/Archive_Tar/Archive/Tar.php CVS 1.11

- Support for bz2 compression
- Add new methods AddString() and extractInString()
This commit is contained in:
Vincent Blavet 2003-05-28 06:01:04 +00:00
parent 4a240c6a50
commit 534ab0b542

View File

@ -39,6 +39,11 @@ class Archive_Tar extends PEAR
*/
var $_compress=false;
/**
* @var string Type of compression : 'none', 'gz' or 'bz2'
*/
var $_compress_type='none';
/**
* @var file descriptor
*/
@ -64,41 +69,61 @@ class Archive_Tar extends PEAR
function Archive_Tar($p_tarname, $p_compress = null)
{
$this->PEAR();
$this->_compress = false;
$this->_compress_type = 'none';
if ($p_compress === null) {
if (@file_exists($p_tarname)) {
if ($fp = @fopen($p_tarname, "r")) {
if ($fp = @fopen($p_tarname, "rb")) {
// look for gzip magic cookie
$data = fread($fp, 2);
fclose($fp);
if ($data == "\37\213") {
$p_compress = true;
$this->_compress = true;
$this->_compress_type = 'gz';
// No sure it's enought for a magic code ....
} elseif ($data == "BZ") {
$this->_compress = true;
$this->_compress_type = 'bz2';
}
}
} else {
// probably a remote file or some file accessible
// through a stream interface
if (substr($p_tarname, -2) == 'gz') {
$p_compress = true;
$this->_compress = true;
$this->_compress_type = 'gz';
} elseif ((substr($p_tarname, -3) == 'bz2') ||
(substr($p_tarname, -2) == 'bz')) {
$this->_compress = true;
$this->_compress_type = 'bz2';
}
}
} else {
if ($p_compress == 'gz') {
$this->_compress = true;
$this->_compress_type = 'gz';
} else if ($p_compress == 'bz2') {
$this->_compress = true;
$this->_compress_type = 'bz2';
}
}
$this->_tarname = $p_tarname;
if ($p_compress) { // assert zlib extension support
$extname = 'zlib';
if ($this->_compress) { // assert zlib or bz2 extension support
if ($this->_compress_type == 'gz')
$extname = 'zlib';
else if ($this->_compress_type == 'bz2')
$extname = 'bz2';
if (!extension_loaded($extname)) {
if (OS_WINDOWS) {
@dl("php_$extname.dll");
} else {
@dl("$extname.so");
}
PEAR::loadExtension($extname);
}
if (!extension_loaded($extname)) {
die("The extension '$extname' couldn't be found.\n".
"Please make sure your version of PHP was built".
"Please make sure your version of PHP was built ".
"with '$extname' support.\n");
return false;
}
}
$this->_compress = (bool)$p_compress;
}
// }}}
@ -311,6 +336,43 @@ class Archive_Tar extends PEAR
}
// }}}
// {{{ addString()
/**
* This method add a single string as a file at the
* end of the existing archive. If the archive does not yet exists it
* is created.
*
* @param string $p_filename A string which contains the full filename path
* that will be associated with the string.
* @param string $p_string The content of the file added in the archive.
* @return true on success, false on error.
* @access public
*/
function addString($p_filename, $p_string)
{
$v_result = true;
if (!@is_file($this->_tarname)) {
if (!$this->_openWrite()) {
return false;
}
$this->_close();
}
if (!$this->_openAppend())
return false;
// Need to check the get back to the temporary file ? ....
$v_result = $this->_addString($p_filename, $p_string);
$this->_writeFooter();
$this->_close();
return $v_result;
}
// }}}
// {{{ extractModify()
/**
* This method extract all the content of the archive in the directory
@ -358,6 +420,27 @@ class Archive_Tar extends PEAR
}
// }}}
// {{{ extractInString()
/**
* This method extract from the archive one file identified by $p_filename.
* The return value is a string with the file content, or NULL on error.
* @param string $p_filename The path of the file to extract in a string.
* @return a string with the file content or NULL.
* @access public
*/
function extractInString($p_filename)
{
if ($this->_openRead()) {
$v_result = $this->_extractInString($p_filename);
$this->_close();
} else {
$v_result = NULL;
}
return $v_result;
}
// }}}
// {{{ extractList()
/**
* This method extract from the archive only the files indicated in the
@ -417,10 +500,14 @@ class Archive_Tar extends PEAR
// {{{ _openWrite()
function _openWrite()
{
if ($this->_compress)
$this->_file = @gzopen($this->_tarname, "w");
if ($this->_compress_type == 'gz')
$this->_file = @gzopen($this->_tarname, "wb");
else if ($this->_compress_type == 'bz2')
$this->_file = @bzopen($this->_tarname, "wb");
else if ($this->_compress_type == 'none')
$this->_file = @fopen($this->_tarname, "wb");
else
$this->_file = @fopen($this->_tarname, "w");
$this->_error('Unknown or missing compression type ('.$this->_compress_type.')');
if ($this->_file == 0) {
$this->_error('Unable to open in write mode \''.$this->_tarname.'\'');
@ -462,10 +549,14 @@ class Archive_Tar extends PEAR
// ----- File to open if the normal Tar file
$v_filename = $this->_tarname;
if ($this->_compress)
if ($this->_compress_type == 'gz')
$this->_file = @gzopen($v_filename, "rb");
else
else if ($this->_compress_type == 'bz2')
$this->_file = @bzopen($v_filename, "rb");
else if ($this->_compress_type == 'none')
$this->_file = @fopen($v_filename, "rb");
else
$this->_error('Unknown or missing compression type ('.$this->_compress_type.')');
if ($this->_file == 0) {
$this->_error('Unable to open in read mode \''.$v_filename.'\'');
@ -479,10 +570,14 @@ class Archive_Tar extends PEAR
// {{{ _openReadWrite()
function _openReadWrite()
{
if ($this->_compress)
if ($this->_compress_type == 'gz')
$this->_file = @gzopen($this->_tarname, "r+b");
else
else if ($this->_compress_type == 'bz2')
$this->_file = @bzopen($this->_tarname, "r+b");
else if ($this->_compress_type == 'none')
$this->_file = @fopen($this->_tarname, "r+b");
else
$this->_error('Unknown or missing compression type ('.$this->_compress_type.')');
if ($this->_file == 0) {
$this->_error('Unable to open in read/write mode \''.$this->_tarname.'\'');
@ -497,10 +592,14 @@ class Archive_Tar extends PEAR
function _close()
{
if (isset($this->_file)) {
if ($this->_compress)
if ($this->_compress_type == 'gz')
@gzclose($this->_file);
else
else if ($this->_compress_type == 'bz2')
@bzclose($this->_file);
else if ($this->_compress_type == 'none')
@fclose($this->_file);
else
$this->_error('Unknown or missing compression type ('.$this->_compress_type.')');
$this->_file = 0;
}
@ -536,16 +635,87 @@ class Archive_Tar extends PEAR
}
// }}}
// {{{ _writeBlock()
function _writeBlock($p_binary_data, $p_len=null)
{
if ($this->_file) {
if ($p_len === null) {
if ($this->_compress_type == 'gz')
@gzputs($this->_file, $p_binary_data);
else if ($this->_compress_type == 'bz2')
@bzwrite($this->_file, $p_binary_data);
else if ($this->_compress_type == 'none')
@fputs($this->_file, $p_binary_data);
else
$this->_error('Unknown or missing compression type ('.$this->_compress_type.')');
} else {
if ($this->_compress_type == 'gz')
@gzputs($this->_file, $p_binary_data, $p_len);
else if ($this->_compress_type == 'bz2')
@bzwrite($this->_file, $p_binary_data, $p_len);
else if ($this->_compress_type == 'none')
@fputs($this->_file, $p_binary_data, $p_len);
else
$this->_error('Unknown or missing compression type ('.$this->_compress_type.')');
}
}
return true;
}
// }}}
// {{{ _readBlock()
function _readBlock($p_len=null)
{
$v_block = null;
if ($this->_file) {
if ($p_len === null)
$p_len = 512;
if ($this->_compress_type == 'gz')
$v_block = @gzread($this->_file, 512);
else if ($this->_compress_type == 'bz2')
$v_block = @bzread($this->_file, 512);
else if ($this->_compress_type == 'none')
$v_block = @fread($this->_file, 512);
else
$this->_error('Unknown or missing compression type ('.$this->_compress_type.')');
}
return $v_block;
}
// }}}
// {{{ _jumpBlock()
function _jumpBlock($p_len=null)
{
if ($this->_file) {
if ($p_len === null)
$p_len = 1;
if ($this->_compress_type == 'gz')
@gzseek($this->_file, @gztell($this->_file)+($p_len*512));
else if ($this->_compress_type == 'bz2') {
// ----- Replace missing bztell() and bzseek()
for ($i=0; $i<$p_len; $i++)
$this->_readBlock();
} else if ($this->_compress_type == 'none')
@fseek($this->_file, @ftell($this->_file)+($p_len*512));
else
$this->_error('Unknown or missing compression type ('.$this->_compress_type.')');
}
return true;
}
// }}}
// {{{ _writeFooter()
function _writeFooter()
{
if ($this->_file) {
// ----- Write the last 0 filled block for end of archive
$v_binary_data = pack("a512", '');
if ($this->_compress)
@gzputs($this->_file, $v_binary_data);
else
@fputs($this->_file, $v_binary_data);
$this->_writeBlock($v_binary_data);
}
return true;
}
@ -661,10 +831,7 @@ class Archive_Tar extends PEAR
while (($v_buffer = fread($v_file, 512)) != '') {
$v_binary_data = pack("a512", "$v_buffer");
if ($this->_compress)
@gzputs($this->_file, $v_binary_data);
else
@fputs($this->_file, $v_binary_data);
$this->_writeBlock($v_binary_data);
}
fclose($v_file);
@ -679,6 +846,35 @@ class Archive_Tar extends PEAR
}
// }}}
// {{{ _addString()
function _addString($p_filename, $p_string)
{
if (!$this->_file) {
$this->_error('Invalid file descriptor');
return false;
}
if ($p_filename == '') {
$this->_error('Invalid file name');
return false;
}
// ----- Calculate the stored filename
$p_filename = $this->_translateWinPath($p_filename, false);;
if (!$this->_writeHeaderBlock($p_filename, strlen($p_string), 0, 0, "", 0, 0))
return false;
$i=0;
while (($v_buffer = substr($p_string, (($i++)*512), 512)) != '') {
$v_binary_data = pack("a512", $v_buffer);
$this->_writeBlock($v_binary_data);
}
return true;
}
// }}}
// {{{ _writeHeader()
function _writeHeader($p_filename, $p_stored_filename)
{
@ -687,7 +883,7 @@ class Archive_Tar extends PEAR
$v_reduce_filename = $this->_pathReduction($p_stored_filename);
if (strlen($v_reduce_filename) > 99) {
if (!$this->_writeLongHeader($p_stored_filename))
if (!$this->_writeLongHeader($v_reduce_filename))
return false;
}
@ -739,24 +935,83 @@ class Archive_Tar extends PEAR
$v_checksum += ord(substr($v_binary_data_last,$j,1));
// ----- Write the first 148 bytes of the header in the archive
if ($this->_compress)
@gzputs($this->_file, $v_binary_data_first, 148);
else
@fputs($this->_file, $v_binary_data_first, 148);
$this->_writeBlock($v_binary_data_first, 148);
// ----- Write the calculated checksum
$v_checksum = sprintf("%6s ", DecOct($v_checksum));
$v_binary_data = pack("a8", $v_checksum);
if ($this->_compress)
@gzputs($this->_file, $v_binary_data, 8);
else
@fputs($this->_file, $v_binary_data, 8);
$this->_writeBlock($v_binary_data, 8);
// ----- Write the last 356 bytes of the header in the archive
if ($this->_compress)
@gzputs($this->_file, $v_binary_data_last, 356);
else
@fputs($this->_file, $v_binary_data_last, 356);
$this->_writeBlock($v_binary_data_last, 356);
return true;
}
// }}}
// {{{ _writeHeaderBlock()
function _writeHeaderBlock($p_filename, $p_size, $p_mtime=0, $p_perms=0, $p_type='', $p_uid=0, $p_gid=0)
{
$p_filename = $this->_pathReduction($p_filename);
if (strlen($p_filename) > 99) {
if (!$this->_writeLongHeader($p_filename))
return false;
}
if ($p_type == "5") {
$v_size = sprintf("%11s ", DecOct(0));
} else {
$v_size = sprintf("%11s ", DecOct($p_size));
}
$v_uid = sprintf("%6s ", DecOct($p_uid));
$v_gid = sprintf("%6s ", DecOct($p_gid));
$v_perms = sprintf("%6s ", DecOct($p_perms));
$v_mtime = sprintf("%11s", DecOct($p_mtime));
$v_linkname = '';
$v_magic = '';
$v_version = '';
$v_uname = '';
$v_gname = '';
$v_devmajor = '';
$v_devminor = '';
$v_prefix = '';
$v_binary_data_first = pack("a100a8a8a8a12A12", $p_filename, $v_perms, $v_uid, $v_gid, $v_size, $v_mtime);
$v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12", $p_type, $v_linkname, $v_magic, $v_version, $v_uname, $v_gname, $v_devmajor, $v_devminor, $v_prefix, '');
// ----- Calculate the checksum
$v_checksum = 0;
// ..... First part of the header
for ($i=0; $i<148; $i++)
$v_checksum += ord(substr($v_binary_data_first,$i,1));
// ..... Ignore the checksum value and replace it by ' ' (space)
for ($i=148; $i<156; $i++)
$v_checksum += ord(' ');
// ..... Last part of the header
for ($i=156, $j=0; $i<512; $i++, $j++)
$v_checksum += ord(substr($v_binary_data_last,$j,1));
// ----- Write the first 148 bytes of the header in the archive
$this->_writeBlock($v_binary_data_first, 148);
// ----- Write the calculated checksum
$v_checksum = sprintf("%6s ", DecOct($v_checksum));
$v_binary_data = pack("a8", $v_checksum);
$this->_writeBlock($v_binary_data, 8);
// ----- Write the last 356 bytes of the header in the archive
$this->_writeBlock($v_binary_data_last, 356);
return true;
}
@ -801,33 +1056,21 @@ class Archive_Tar extends PEAR
$v_checksum += ord(substr($v_binary_data_last,$j,1));
// ----- Write the first 148 bytes of the header in the archive
if ($this->_compress)
@gzputs($this->_file, $v_binary_data_first, 148);
else
@fputs($this->_file, $v_binary_data_first, 148);
$this->_writeBlock($v_binary_data_first, 148);
// ----- Write the calculated checksum
$v_checksum = sprintf("%6s ", DecOct($v_checksum));
$v_binary_data = pack("a8", $v_checksum);
if ($this->_compress)
@gzputs($this->_file, $v_binary_data, 8);
else
@fputs($this->_file, $v_binary_data, 8);
$this->_writeBlock($v_binary_data, 8);
// ----- Write the last 356 bytes of the header in the archive
if ($this->_compress)
@gzputs($this->_file, $v_binary_data_last, 356);
else
@fputs($this->_file, $v_binary_data_last, 356);
$this->_writeBlock($v_binary_data_last, 356);
// ----- Write the filename as content of the block
$i=0;
while (($v_buffer = substr($p_filename, (($i++)*512), 512)) != '') {
$v_binary_data = pack("a512", "$v_buffer");
if ($this->_compress)
@gzputs($this->_file, $v_binary_data);
else
@fputs($this->_file, $v_binary_data);
$this->_writeBlock($v_binary_data);
}
return true;
@ -871,7 +1114,7 @@ class Archive_Tar extends PEAR
if (($v_checksum == 256) && ($v_header['checksum'] == 0))
return true;
$this->_error('Invalid checksum : '.$v_checksum.' calculated, '.$v_header['checksum'].' expected');
$this->_error('Invalid checksum for file "'.$v_data['filename'].'" : '.$v_checksum.' calculated, '.$v_header['checksum'].' expected');
return false;
}
@ -905,25 +1148,16 @@ class Archive_Tar extends PEAR
$v_filename = '';
$n = floor($v_header['size']/512);
for ($i=0; $i<$n; $i++) {
if ($this->_compress)
$v_content = @gzread($this->_file, 512);
else
$v_content = @fread($this->_file, 512);
$v_content = $this->_readBlock();
$v_filename .= $v_content;
}
if (($v_header['size'] % 512) != 0) {
if ($this->_compress)
$v_content = @gzread($this->_file, 512);
else
$v_content = @fread($this->_file, 512);
$v_content = $this->_readBlock();
$v_filename .= $v_content;
}
// ----- Read the next header
if ($this->_compress)
$v_binary_data = @gzread($this->_file, 512);
else
$v_binary_data = @fread($this->_file, 512);
$v_binary_data = $this->_readBlock();
if (!$this->_readHeader($v_binary_data, $v_header))
return false;
@ -934,6 +1168,56 @@ class Archive_Tar extends PEAR
}
// }}}
// {{{ _extractInString()
/**
* This method extract from the archive one file identified by $p_filename.
* The return value is a string with the file content, or NULL on error.
* @param string $p_filename The path of the file to extract in a string.
* @return a string with the file content or NULL.
* @access private
*/
function _extractInString($p_filename)
{
$v_result_str = "";
While (strlen($v_binary_data = $this->_readBlock()) != 0)
{
if (!$this->_readHeader($v_binary_data, $v_header))
return NULL;
if ($v_header['filename'] == '')
continue;
// ----- Look for long filename
if ($v_header['typeflag'] == 'L') {
if (!$this->_readLongHeader($v_header))
return NULL;
}
if ($v_header['filename'] == $p_filename) {
if ($v_header['typeflag'] == "5") {
$this->_error('Unable to extract in string a directory entry {'.$v_header['filename'].'}');
return NULL;
} else {
$n = floor($v_header['size']/512);
for ($i=0; $i<$n; $i++) {
$v_result_str .= $this->_readBlock();
}
if (($v_header['size'] % 512) != 0) {
$v_content = $this->_readBlock();
$v_result_str .= substr($v_content, 0, ($v_header['size'] % 512));
}
return $v_result_str;
}
} else {
$this->_jumpBlock(ceil(($v_header['size']/512)));
}
}
return NULL;
}
// }}}
// {{{ _extractList()
function _extractList($p_path, &$p_list_detail, $p_mode, $p_file_list, $p_remove_path)
{
@ -973,16 +1257,11 @@ class Archive_Tar extends PEAR
clearstatcache();
While (!($v_end_of_file = ($this->_compress?@gzeof($this->_file):@feof($this->_file))))
While (strlen($v_binary_data = $this->_readBlock()) != 0)
{
$v_extract_file = FALSE;
$v_extraction_stopped = 0;
if ($this->_compress)
$v_binary_data = @gzread($this->_file, 512);
else
$v_binary_data = @fread($this->_file, 512);
if (!$this->_readHeader($v_binary_data, $v_header))
return false;
@ -1073,17 +1352,11 @@ class Archive_Tar extends PEAR
} else {
$n = floor($v_header['size']/512);
for ($i=0; $i<$n; $i++) {
if ($this->_compress)
$v_content = @gzread($this->_file, 512);
else
$v_content = @fread($this->_file, 512);
$v_content = $this->_readBlock();
fwrite($v_dest_file, $v_content, 512);
}
if (($v_header['size'] % 512) != 0) {
if ($this->_compress)
$v_content = @gzread($this->_file, 512);
else
$v_content = @fread($this->_file, 512);
$v_content = $this->_readBlock();
fwrite($v_dest_file, $v_content, ($v_header['size'] % 512));
}
@ -1103,24 +1376,18 @@ class Archive_Tar extends PEAR
}
}
} else {
// ----- Jump to next file
if ($this->_compress)
@gzseek($this->_file, @gztell($this->_file)+(ceil(($v_header['size']/512))*512));
else
@fseek($this->_file, @ftell($this->_file)+(ceil(($v_header['size']/512))*512));
$this->_jumpBlock(ceil(($v_header['size']/512)));
}
} else {
// ----- Jump to next file
if ($this->_compress)
@gzseek($this->_file, @gztell($this->_file)+(ceil(($v_header['size']/512))*512));
else
@fseek($this->_file, @ftell($this->_file)+(ceil(($v_header['size']/512))*512));
$this->_jumpBlock(ceil(($v_header['size']/512)));
}
/* TBC : Seems to be unused ...
if ($this->_compress)
$v_end_of_file = @gzeof($this->_file);
else
$v_end_of_file = @feof($this->_file);
*/
if ($v_listing || $v_extract_file || $v_extraction_stopped) {
// ----- Log extracted files
@ -1137,9 +1404,12 @@ class Archive_Tar extends PEAR
}
// }}}
// {{{ _append()
function _append($p_filelist, $p_add_dir='', $p_remove_dir='')
// {{{ _openAppend()
function _openAppend()
{
if (filesize($this->_tarname) == 0)
return $this->_openWrite();
if ($this->_compress) {
$this->_close();
@ -1148,7 +1418,12 @@ class Archive_Tar extends PEAR
return false;
}
if (($v_temp_tar = @gzopen($this->_tarname.".tmp", "rb")) == 0) {
if ($this->_compress_type == 'gz')
$v_temp_tar = @gzopen($this->_tarname.".tmp", "rb");
elseif ($this->_compress_type == 'bz2')
$v_temp_tar = @bzopen($this->_tarname.".tmp", "rb");
if ($v_temp_tar == 0) {
$this->_error('Unable to open file \''.$this->_tarname.'.tmp\' in binary read mode');
@rename($this->_tarname.".tmp", $this->_tarname);
return false;
@ -1159,39 +1434,58 @@ class Archive_Tar extends PEAR
return false;
}
$v_buffer = @gzread($v_temp_tar, 512);
if ($this->_compress_type == 'gz') {
$v_buffer = @gzread($v_temp_tar, 512);
// ----- Read the following blocks but not the last one
if (!@gzeof($v_temp_tar)) {
do{
$v_binary_data = pack("a512", "$v_buffer");
@gzputs($this->_file, $v_binary_data);
$v_buffer = @gzread($v_temp_tar, 512);
// ----- Read the following blocks but not the last one
if (!@gzeof($v_temp_tar)) {
do{
$v_binary_data = pack("a512", $v_buffer);
$this->_writeBlock($v_binary_data);
$v_buffer = @gzread($v_temp_tar, 512);
} while (!@gzeof($v_temp_tar));
} while (!@gzeof($v_temp_tar));
}
@gzclose($v_temp_tar);
}
elseif ($this->_compress_type == 'bz2') {
$v_buffered_lines = array();
$v_buffered_lines[] = @bzread($v_temp_tar, 512);
if ($this->_addList($p_filelist, $p_add_dir, $p_remove_dir))
$this->_writeFooter();
// ----- Read the following blocks but not the last one
while (strlen($v_buffered_lines[] = @bzread($v_temp_tar, 512)) > 0) {
$v_binary_data = pack("a512", array_shift($v_buffered_lines));
$this->_writeBlock($v_binary_data);
}
$this->_close();
@gzclose($v_temp_tar);
@bzclose($v_temp_tar);
}
if (!@unlink($this->_tarname.".tmp")) {
$this->_error('Error while deleting temporary file \''.$this->_tarname.'.tmp\'');
}
return true;
} else {
// ----- For not compressed tar, just add files before the last 512 bytes block
if (!$this->_openReadWrite())
return false;
clearstatcache();
$v_size = filesize($this->_tarname);
fseek($this->_file, $v_size-512);
}
// ----- For not compressed tar, just add files before the last 512 bytes block
if (!$this->_openReadWrite())
return false;
clearstatcache();
$v_size = filesize($this->_tarname);
fseek($this->_file, $v_size-512);
return true;
}
// }}}
// {{{ _append()
function _append($p_filelist, $p_add_dir='', $p_remove_dir='')
{
if (!$this->_openAppend())
return false;
if ($this->_addList($p_filelist, $p_add_dir, $p_remove_dir))
$this->_writeFooter();
@ -1298,4 +1592,4 @@ class Archive_Tar extends PEAR
// }}}
}
?>
?>