/** * TAR file functions (compress / extract) * * up to now only for tar files that can be load compleat in the ram */ class Tar { private $tar_file = ""; private $fp = null; public $err = ""; /** * Set name of TAR file * * @param string $archive Path to TAR archive to extract */ public function __construct ($archive="") { $this->tar_file = $archive; } private function out ($data) { if ($this->fp) { fputs ($this->fp, $data); } else { print ($data); ob_flush (); flush (); } } /** * Compress the given path to a TAR compressed file * * @param string $path Path of files to compress or array with files */ public function compress ($path='.', $recursive=true) { if ($this->tar_file && !($this->fp = fopen ($this->tar_file, "wb"))) { $this->err = "Error: Can't open output file"; return $this->err; } $tree = is_array ($path) ? $path : $this->build_tree ($path, $recursive); if (!$this->process_tree ($tree)) { return $this->err; } $this->out (pack ("a512", "")); if ($this->fp) { fclose ($this->fp); } return false; } private function build_tree ($dir='.', $recursive=true) { $output = array (); $handle = opendir ($dir); while (false !== ($readdir = readdir ($handle))){ if ($readdir != '.' && $readdir != '..'){ $path = $dir.'/'.$readdir; if (is_file ($path)) { $output[] = preg_replace ("/^\.\//", "", $path); } elseif (is_dir ($path) && $recursive) { $output[] = preg_replace ("/^\.\//", "", $path).'/'; $output = array_merge ($output, $this->build_tree ($path, $recursive)); } } } closedir ($handle); return $output; } private function process_tree ($tree) { foreach ($tree as $pathfile) { if (substr ($pathfile, -1, 1) == '/') { if (!($header = $this->build_header ($pathfile))) { return false; } $this->out ($header); } elseif ($pathfile != $this->tar_file) { $filesize = filesize ($pathfile); $block_len = 512 * ceil ($filesize/512) - $filesize; if (!($header = $this->build_header ($pathfile))) { return false; } $this->out ($header); $this->out (file_get_contents ($pathfile)); $this->out (pack ("a".$block_len, "")); } } return true; } private function build_header ($pathfile) { if (strlen ($pathfile) > 99) { $this->err = "File name/path to long"; return false; } $info = stat ($pathfile); if (is_dir ($pathfile)) $info[7] = 0; $header = pack ("a100a8a8a8a12A12a8a1a100a255", $pathfile, sprintf ("%6s ", decoct ($info[2])), sprintf ("%6s ", decoct ($info[4])), sprintf ("%6s ", decoct ($info[5])), sprintf ("%11s ",decoct ($info[7])), sprintf ("%11s", decoct ($info[9])), sprintf ("%8s", " "), (is_dir ($pathfile) ? "5" : "0"), "", "" ); clearstatcache (); $checksum = 0; for ($i=0; $i<512; $i++) { $checksum += ord (substr ($header,$i,1)); } $checksum_data = pack ( "a8", sprintf ("%6s ", decoct($checksum)) ); for ($i=0, $j=148; $i<7; $i++, $j++) { $header[$j] = $checksum_data[$i]; } return $header; } /** * Extract a TAR compressed file to the given path * * @param string $destination Path to extract archive into */ public function extract ($destination='.') { // Initialize variables $_data = null; $_metadata = null; if (! ($_data = file_get_contents ($this->tar_file))) { $this->err = "Can't open input file"; return $this->err; } if (!($_metadata = $this->getTarInfo ($_data))) { return $this->err; } for ($i=0,$n=count($_metadata);$i<$n;$i++) { if ($_metadata[$i]['type'] == 0x30) { $buffer = $_metadata[$i]['data']; $path = $destination."/".$_metadata[$i]['name']; // Make sure the destination folder exists if (!is_dir (dirname ($path)) && !mkdir (dirname ($path))) { $this->err = "Unable to create destination dir"; return $this->err; } if ($fp = fopen ($path, "wb")) { fputs ($fp, $buffer); fclose ($fp); } else { $this->err = "Unable to write file"; return $this->err; } } } return false; } /** * Get the list of files/data from a Tar archive buffer. * * @access private * @param string $data The Tar archive buffer. * @return array Archive metadata array *
* KEY: Position in the array * VALUES: 'attr' -- File attributes * 'data' -- Raw file contents * 'date' -- File modification time * 'name' -- Filename * 'size' -- Original file size * 'type' -- File type ** @since 1.5 */ private function getTarInfo (& $data) { $position = 0; $return_array = array (); while ($position < strlen ($data)) { if (! ($info = @ unpack ("a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/a8checksum/Ctypeflag/a100link/a6magic/a2version/a32uname/a32gname/a8devmajor/a8devminor", substr ($data, $position)))) { $this->err = "Unable to decompress input file"; return false; } $position += 512; $contents = substr ($data, $position, octdec ($info['size'])); $position += ceil (octdec ($info['size']) / 512) * 512; if ($info['filename']) { $file = array ( 'attr' => null, 'data' => null, 'date' => octdec($info['mtime']), 'name' => trim($info['filename']), 'size' => octdec($info['size']), 'type' => $info['typeflag'] ); if (($info['typeflag'] == 0) || ($info['typeflag'] == 0x30) || ($info['typeflag'] == 0x35)) { /* File or folder. */ $file['data'] = $contents; $mode = hexdec(substr($info['mode'], 4, 3)); $file['attr'] = (($info['typeflag'] == 0x35) ? 'd' : '-') . (($mode & 0x400) ? 'r' : '-') . (($mode & 0x200) ? 'w' : '-') . (($mode & 0x100) ? 'x' : '-') . (($mode & 0x040) ? 'r' : '-') . (($mode & 0x020) ? 'w' : '-') . (($mode & 0x010) ? 'x' : '-') . (($mode & 0x004) ? 'r' : '-') . (($mode & 0x002) ? 'w' : '-') . (($mode & 0x001) ? 'x' : '-'); } else { /* Some other type. */ } $return_array[] = $file; } } return $return_array; } } ?>