openrat-cms

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

ArchiveTar.class.php (12341B)


      1 <?php
      2 /*
      3 =======================================================================
      4 Name:
      5 	tar Class
      6 
      7 Author:
      8 	Josh Barger <joshb@npt.com>
      9 
     10 Description:
     11 	This class reads and writes Tape-Archive (TAR) Files and Gzip
     12 	compressed TAR files, which are mainly used on UNIX systems.
     13 	This class works on both windows AND unix systems, and does
     14 	NOT rely on external applications!! Woohoo!
     15 
     16 Usage:
     17 	Copyright (C) 2002  Josh Barger
     18 
     19 	This library is free software; you can redistribute it and/or
     20 	modify it under the terms of the GNU Lesser General Public
     21 	License as published by the Free Software Foundation; either
     22 	version 2.1 of the License, or (at your option) any later version.
     23 
     24 	This library is distributed in the hope that it will be useful,
     25 	but WITHOUT ANY WARRANTY; without even the implied warranty of
     26 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     27 	Lesser General Public License for more details at:
     28 		http://www.gnu.org/copyleft/lesser.html
     29 
     30 	If you use this script in your application/website, please
     31 	send me an e-mail letting me know about it :)
     32 
     33 Bugs:
     34 	Please report any bugs you might find to my e-mail address
     35 	at joshb@npt.com.  If you have already created a fix/patch
     36 	for the bug, please do send it to me so I can incorporate it into my release.
     37 
     38 Version History:
     39 	1.0	04/10/2002	- InitialRelease
     40 
     41 	2.0	04/11/2002	- Merged both tarReader and tarWriter
     42 				  classes into one
     43 				- Added support for gzipped tar files
     44 				  Remember to name for .tar.gz or .tgz
     45 				  if you use gzip compression!
     46 				  :: THIS REQUIRES ZLIB EXTENSION ::
     47 				- Added additional comments to
     48 				  functions to help users
     49 				- Added ability to remove files and
     50 				  directories from archive
     51 	2.1	04/12/2002	- Fixed serious bug in generating tar
     52 				- Created another example file
     53 				- Added check to make sure ZLIB is
     54 				  installed before running GZIP
     55 				  compression on TAR
     56 	2.2	05/07/2002	- Added automatic detection of Gzipped
     57 				  tar files (Thanks go to J�rgen Falch
     58 				  for the idea)
     59 				- Changed "private" functions to have
     60 				  special function names beginning with
     61 				  two underscores
     62 =======================================================================
     63 */
     64 
     65 
     66 namespace util;
     67 class ArchiveTar
     68 {
     69 	// Unprocessed Archive Information
     70 	var $filename;
     71 	var $isGzipped;
     72 	var $tar_file;
     73 
     74 	// Processed Archive Information
     75 	var $files;
     76 	var $directories;
     77 	var $numFiles;
     78 	var $numDirectories;
     79 
     80 
     81 	// Class Constructor -- Does nothing...
     82 	function tar()
     83 	{
     84 		return true;
     85 	}
     86 
     87 
     88 	// Computes the unsigned Checksum of a file's header
     89 	// to try to ensure valid file
     90 	// PRIVATE ACCESS FUNCTION
     91 	function __computeUnsignedChecksum($bytestring)
     92 	{
     93 		$unsigned_chksum = 0;
     94 		for ($i = 0; $i < 512; $i++)
     95 			$unsigned_chksum += ord($bytestring[$i]);
     96 		for ($i = 0; $i < 8; $i++)
     97 			$unsigned_chksum -= ord($bytestring[148 + $i]);
     98 		$unsigned_chksum += ord(" ") * 8;
     99 
    100 		return $unsigned_chksum;
    101 	}
    102 
    103 
    104 	// Converts a NULL padded string to a non-NULL padded string
    105 	// PRIVATE ACCESS FUNCTION
    106 	function __parseNullPaddedString($string)
    107 	{
    108 		$position = strpos($string, chr(0));
    109 		return substr($string, 0, $position);
    110 	}
    111 
    112 
    113 	// This function parses the current TAR file
    114 	// PRIVATE ACCESS FUNCTION
    115 	function __parseTar()
    116 	{
    117 		// Read Files from archive
    118 		$this->numFiles = 0;
    119 		$tar_length = strlen($this->tar_file);
    120 		$main_offset = 0;
    121 		while ($main_offset < $tar_length) {
    122 			// If we read a block of 512 nulls, we are at the end of the archive
    123 			if (substr($this->tar_file, $main_offset, 512) == str_repeat(chr(0), 512))
    124 				break;
    125 
    126 			// Parse file name
    127 			$file_name = $this->__parseNullPaddedString(substr($this->tar_file, $main_offset, 100));
    128 
    129 			// Parse the file mode
    130 			$file_mode = substr($this->tar_file, $main_offset + 100, 8);
    131 
    132 			// Parse the file user ID
    133 			$file_uid = octdec(substr($this->tar_file, $main_offset + 108, 8));
    134 
    135 			// Parse the file group ID
    136 			$file_gid = octdec(substr($this->tar_file, $main_offset + 116, 8));
    137 
    138 			// Parse the file size
    139 			$file_size = octdec(substr($this->tar_file, $main_offset + 124, 12));
    140 
    141 			// Parse the file update time - unix timestamp format
    142 			$file_time = octdec(substr($this->tar_file, $main_offset + 136, 12));
    143 
    144 			// Parse Checksum
    145 			$file_chksum = octdec(substr($this->tar_file, $main_offset + 148, 6));
    146 
    147 			// Parse user name
    148 			$file_uname = $this->__parseNullPaddedString(substr($this->tar_file, $main_offset + 265, 32));
    149 
    150 			// Parse Group name
    151 			$file_gname = $this->__parseNullPaddedString(substr($this->tar_file, $main_offset + 297, 32));
    152 
    153 			// Make sure our file is valid
    154 			if ($this->__computeUnsignedChecksum(substr($this->tar_file, $main_offset, 512)) != $file_chksum)
    155 				return false;
    156 
    157 			// Parse File Contents
    158 			$file_contents = substr($this->tar_file, $main_offset + 512, $file_size);
    159 
    160 			/*	### Unused Header Information ###
    161 				$activeFile["typeflag"]		= substr($this->tar_file,$main_offset + 156,1);
    162 				$activeFile["linkname"]		= substr($this->tar_file,$main_offset + 157,100);
    163 				$activeFile["magic"]		= substr($this->tar_file,$main_offset + 257,6);
    164 				$activeFile["version"]		= substr($this->tar_file,$main_offset + 263,2);
    165 				$activeFile["devmajor"]		= substr($this->tar_file,$main_offset + 329,8);
    166 				$activeFile["devminor"]		= substr($this->tar_file,$main_offset + 337,8);
    167 				$activeFile["prefix"]		= substr($this->tar_file,$main_offset + 345,155);
    168 				$activeFile["endheader"]	= substr($this->tar_file,$main_offset + 500,12);
    169 			*/
    170 
    171 			if ($file_size > 0) {
    172 				// Increment number of files
    173 				$this->numFiles++;
    174 
    175 				// Create us a new file in our array
    176 				$activeFile = &$this->files[];
    177 
    178 				// Asign Values
    179 				$activeFile["name"] = $file_name;
    180 				$activeFile["mode"] = $file_mode;
    181 				$activeFile["size"] = $file_size;
    182 				$activeFile["time"] = $file_time;
    183 				$activeFile["user_id"] = $file_uid;
    184 				$activeFile["group_id"] = $file_gid;
    185 				$activeFile["user_name"] = $file_uname;
    186 				$activeFile["group_name"] = $file_gname;
    187 				$activeFile["checksum"] = $file_chksum;
    188 				$activeFile["file"] = $file_contents;
    189 
    190 			} else {
    191 				// Increment number of directories
    192 				$this->numDirectories++;
    193 
    194 				// Create a new directory in our array
    195 				$activeDir = &$this->directories[];
    196 
    197 				// Assign values
    198 				$activeDir["name"] = $file_name;
    199 				$activeDir["mode"] = $file_mode;
    200 				$activeDir["time"] = $file_time;
    201 				$activeDir["user_id"] = $file_uid;
    202 				$activeDir["group_id"] = $file_gid;
    203 				$activeDir["user_name"] = $file_uname;
    204 				$activeDir["group_name"] = $file_gname;
    205 				$activeDir["checksum"] = $file_chksum;
    206 			}
    207 
    208 			// Move our offset the number of blocks we have processed
    209 			$main_offset += 512 + (ceil($file_size / 512) * 512);
    210 		}
    211 
    212 		return true;
    213 	}
    214 
    215 
    216 	// Read a non gzipped tar file in for processing
    217 	// PRIVATE ACCESS FUNCTION
    218 	function __readTar($filename = '')
    219 	{
    220 		// Set the filename to load
    221 		// Read in the TAR file
    222 
    223 		if ($this->tar_file[0] == chr(31) && $this->tar_file[1] == chr(139) && $this->tar_file[2] == chr(8)) {
    224 			if (!function_exists("gzinflate"))
    225 				return false;
    226 
    227 			$this->isGzipped = TRUE;
    228 
    229 			$this->tar_file = gzinflate(substr($this->tar_file, 10, -4));
    230 		}
    231 
    232 		// Parse the TAR file
    233 		$this->__parseTar();
    234 
    235 		return true;
    236 	}
    237 
    238 
    239 	// Generates a TAR file from the processed data
    240 	// PRIVATE ACCESS FUNCTION
    241 	function __generateTAR()
    242 	{
    243 		// Clear any data currently in $this->tar_file	
    244 		unset($this->tar_file);
    245 
    246 		// Generate Records for each directory, if we have directories
    247 		if ($this->numDirectories > 0) {
    248 			foreach ($this->directories as $key => $information) {
    249 				unset($header);
    250 
    251 				// Generate tar header for this directory
    252 				// Filename, Permissions, UID, GID, size, Time, checksum, typeflag, linkname, magic, version, user name, group name, devmajor, devminor, prefix, end
    253 				$header .= str_pad($information["name"], 100, chr(0));
    254 				$header .= str_pad(decoct($information["mode"]), 7, "0", STR_PAD_LEFT) . chr(0);
    255 				$header .= str_pad(decoct($information["user_id"]), 7, "0", STR_PAD_LEFT) . chr(0);
    256 				$header .= str_pad(decoct($information["group_id"]), 7, "0", STR_PAD_LEFT) . chr(0);
    257 				$header .= str_pad(decoct(0), 11, "0", STR_PAD_LEFT) . chr(0);
    258 				$header .= str_pad(decoct($information["time"]), 11, "0", STR_PAD_LEFT) . chr(0);
    259 				$header .= str_repeat(" ", 8);
    260 				$header .= "5";
    261 				$header .= str_repeat(chr(0), 100);
    262 				$header .= str_pad("ustar", 6, chr(32));
    263 				$header .= chr(32) . chr(0);
    264 				$header .= str_pad("", 32, chr(0));
    265 				$header .= str_pad("", 32, chr(0));
    266 				$header .= str_repeat(chr(0), 8);
    267 				$header .= str_repeat(chr(0), 8);
    268 				$header .= str_repeat(chr(0), 155);
    269 				$header .= str_repeat(chr(0), 12);
    270 
    271 				// Compute header checksum
    272 				$checksum = str_pad(decoct($this->__computeUnsignedChecksum($header)), 6, "0", STR_PAD_LEFT);
    273 				for ($i = 0; $i < 6; $i++) {
    274 					$header[(148 + $i)] = substr($checksum, $i, 1);
    275 				}
    276 				$header[154] = chr(0);
    277 				$header[155] = chr(32);
    278 
    279 				// Add new tar formatted data to tar file contents
    280 				$this->tar_file .= $header;
    281 			}
    282 		}
    283 
    284 		// Generate Records for each file, if we have files (We should...)
    285 		if ($this->numFiles > 0) {
    286 			foreach ($this->files as $key => $information) {
    287 				unset($header);
    288 				$header = '';
    289 
    290 				// Generate the TAR header for this file
    291 				// Filename, Permissions, UID, GID, size, Time, checksum, typeflag, linkname, magic, version, user name, group name, devmajor, devminor, prefix, end
    292 				$header .= str_pad($information["name"], 100, chr(0));
    293 				$header .= str_pad(decoct($information["mode"]), 7, "0", STR_PAD_LEFT) . chr(0);
    294 				$header .= str_pad(decoct($information["user_id"]), 7, "0", STR_PAD_LEFT) . chr(0);
    295 				$header .= str_pad(decoct($information["group_id"]), 7, "0", STR_PAD_LEFT) . chr(0);
    296 				$header .= str_pad(decoct($information["size"]), 11, "0", STR_PAD_LEFT) . chr(0);
    297 				$header .= str_pad(decoct($information["time"]), 11, "0", STR_PAD_LEFT) . chr(0);
    298 				$header .= str_repeat(" ", 8);
    299 				$header .= "0";
    300 				$header .= str_repeat(chr(0), 100);
    301 				$header .= str_pad("ustar", 6, chr(32));
    302 				$header .= chr(32) . chr(0);
    303 				$header .= str_pad($information["user_name"], 32, chr(0));    // How do I get a file's user name from PHP?
    304 				$header .= str_pad($information["group_name"], 32, chr(0));    // How do I get a file's group name from PHP?
    305 				$header .= str_repeat(chr(0), 8);
    306 				$header .= str_repeat(chr(0), 8);
    307 				$header .= str_repeat(chr(0), 155);
    308 				$header .= str_repeat(chr(0), 12);
    309 
    310 				// Compute header checksum
    311 				$checksum = str_pad(decoct($this->__computeUnsignedChecksum($header)), 6, "0", STR_PAD_LEFT);
    312 				for ($i = 0; $i < 6; $i++) {
    313 					$header[(148 + $i)] = substr($checksum, $i, 1);
    314 				}
    315 				$header[154] = chr(0);
    316 				$header[155] = chr(32);
    317 
    318 				// Pad file contents to byte count divisible by 512
    319 				$file_contents = str_pad($information["file"], (ceil($information["size"] / 512) * 512), chr(0));
    320 
    321 				// Add new tar formatted data to tar file contents
    322 				$this->tar_file .= $header . $file_contents;
    323 			}
    324 		}
    325 
    326 		// Add 512 bytes of NULLs to designate EOF
    327 		$this->tar_file .= str_repeat(chr(0), 512);
    328 
    329 		return true;
    330 	}
    331 
    332 
    333 	// Open a TAR file
    334 	function openTAR($value)
    335 	{
    336 		// Clear any values from previous tar archives
    337 		unset($this->filename);
    338 		unset($this->isGzipped);
    339 		unset($this->tar_file);
    340 		unset($this->files);
    341 		unset($this->directories);
    342 		unset($this->numFiles);
    343 		unset($this->numDirectories);
    344 
    345 		$this->filename = 'none';
    346 		$this->tar_file = $value;
    347 		// Parse this file
    348 		$this->__readTar();
    349 
    350 		return true;
    351 	}
    352 
    353 
    354 	// Write the currently loaded tar archive to disk
    355 	function saveTar()
    356 	{
    357 		if (!$this->filename)
    358 			return false;
    359 
    360 		// Write tar to current file using specified gzip compression
    361 		$this->toTar($this->filename, $this->isGzipped);
    362 
    363 		return true;
    364 	}
    365 
    366 
    367 	// Saves tar archive to a different file than the current file
    368 	function toTar($filename, $useGzip)
    369 	{
    370 		if (!$filename)
    371 			return false;
    372 
    373 		// Encode processed files into TAR file format
    374 		$this->__generateTar();
    375 
    376 		// GZ Compress the data if we need to
    377 		if ($useGzip) {
    378 			// Make sure we have gzip support
    379 			if (!function_exists("gzencode"))
    380 				return false;
    381 
    382 			$file = gzencode($this->tar_file);
    383 		} else {
    384 			$file = $this->tar_file;
    385 		}
    386 
    387 		// Write the TAR file
    388 		$fp = fopen($filename, "wb");
    389 		fwrite($fp, $file);
    390 		fclose($fp);
    391 
    392 		return true;
    393 	}
    394 }
    395 
    396 ?>