summaryrefslogtreecommitdiff
path: root/includes/tar.class.php
diff options
context:
space:
mode:
Diffstat (limited to 'includes/tar.class.php')
-rw-r--r--includes/tar.class.php467
1 files changed, 467 insertions, 0 deletions
diff --git a/includes/tar.class.php b/includes/tar.class.php
new file mode 100644
index 0000000..c8070b6
--- /dev/null
+++ b/includes/tar.class.php
@@ -0,0 +1,467 @@
+<?php
+/*
+=======================================================================
+Name:
+ tar Class
+Author:
+ Josh Barger <joshb@npt.com>
+Description:
+ This class reads and writes Tape-Archive (TAR) Files and Gzip
+ compressed TAR files, which are mainly used on UNIX systems.
+ This class works on both windows AND unix systems, and does
+ NOT rely on external applications!! Woohoo!
+Usage:
+ Copyright (C) 2002 Josh Barger
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details at:
+ http://www.gnu.org/copyleft/lesser.html
+ If you use this script in your application/website, please
+ send me an e-mail letting me know about it :)
+Bugs:
+ Please report any bugs you might find to my e-mail address
+ at joshb@npt.com. If you have already created a fix/patch
+ for the bug, please do send it to me so I can incorporate it into my release.
+Version History:
+ 1.0 04/10/2002 - InitialRelease
+ 2.0 04/11/2002 - Merged both tarReader and tarWriter
+ classes into one
+ - Added support for gzipped tar files
+ Remember to name for .tar.gz or .tgz
+ if you use gzip compression!
+ :: THIS REQUIRES ZLIB EXTENSION ::
+ - Added additional comments to
+ functions to help users
+ - Added ability to remove files and
+ directories from archive
+ 2.1 04/12/2002 - Fixed serious bug in generating tar
+ - Created another example file
+ - Added check to make sure ZLIB is
+ installed before running GZIP
+ compression on TAR
+ 2.2 05/07/2002 - Added automatic detection of Gzipped
+ tar files (Thanks go to Jrgen Falch
+ for the idea)
+ - Changed "private" functions to have
+ special function names beginning with
+ two underscores
+=======================================================================
+*/
+class tar {
+ // Unprocessed Archive Information
+ public $filename;
+ public $isGzipped;
+ public $tar_file;
+ // Processed Archive Information
+ public $files;
+ public $directories;
+ public $numFiles = 0;
+ public $numDirectories = 0;
+ // Class Constructor -- Does nothing...
+ function tar() {
+ return true;
+ }
+ // Computes the unsigned Checksum of a file's header
+ // to try to ensure valid file
+ // PRIVATE ACCESS FUNCTION
+ function __computeUnsignedChecksum($bytestring) {
+ $unsigned_chksum=0;
+ for($i=0; $i<512; $i++)
+ $unsigned_chksum += ord($bytestring[$i]);
+ for($i=0; $i<8; $i++)
+ $unsigned_chksum -= ord($bytestring[148 + $i]);
+ $unsigned_chksum += ord(" ") * 8;
+ return $unsigned_chksum;
+ }
+ // Converts a NULL padded string to a non-NULL padded string
+ // PRIVATE ACCESS FUNCTION
+ function __parseNullPaddedString($string) {
+ $position = strpos($string,chr(0));
+ return substr($string,0,$position);
+ }
+ // This function parses the current TAR file
+ // PRIVATE ACCESS FUNCTION
+ function __parseTar() {
+ // Read Files from archive
+ $tar_length = strlen($this->tar_file);
+ $main_offset = 0;
+ while($main_offset < $tar_length) {
+ // If we read a block of 512 nulls, we are at the end of the archive
+ if(substr($this->tar_file,$main_offset,512) == str_repeat(chr(0),512))
+ break;
+ // Parse file name
+ $file_name = $this->__parseNullPaddedString(substr($this->tar_file,$main_offset,100));
+ // Parse the file mode
+ $file_mode = substr($this->tar_file,$main_offset + 100,8);
+ // Parse the file user ID
+ $file_uid = octdec(substr($this->tar_file,$main_offset + 108,8));
+ // Parse the file group ID
+ $file_gid = octdec(substr($this->tar_file,$main_offset + 116,8));
+ // Parse the file size
+ $file_size = octdec(substr($this->tar_file,$main_offset + 124,12));
+ // Parse the file update time - unix timestamp format
+ $file_time = octdec(substr($this->tar_file,$main_offset + 136,12));
+ // Parse Checksum
+ $file_chksum = octdec(substr($this->tar_file,$main_offset + 148,6));
+ // Parse user name
+ $file_uname = $this->__parseNullPaddedString(substr($this->tar_file,$main_offset + 265,32));
+ // Parse Group name
+ $file_gname = $this->__parseNullPaddedString(substr($this->tar_file,$main_offset + 297,32));
+ // Make sure our file is valid
+ if($this->__computeUnsignedChecksum(substr($this->tar_file,$main_offset,512)) != $file_chksum)
+ return false;
+ // Parse File Contents
+ $file_contents = substr($this->tar_file,$main_offset + 512,$file_size);
+ /* ### Unused Header Information ###
+ $activeFile["typeflag"] = substr($this->tar_file,$main_offset + 156,1);
+ $activeFile["linkname"] = substr($this->tar_file,$main_offset + 157,100);
+ $activeFile["magic"] = substr($this->tar_file,$main_offset + 257,6);
+ $activeFile["version"] = substr($this->tar_file,$main_offset + 263,2);
+ $activeFile["devmajor"] = substr($this->tar_file,$main_offset + 329,8);
+ $activeFile["devminor"] = substr($this->tar_file,$main_offset + 337,8);
+ $activeFile["prefix"] = substr($this->tar_file,$main_offset + 345,155);
+ $activeFile["endheader"] = substr($this->tar_file,$main_offset + 500,12);
+ */
+ if($file_size > 0) {
+ // Increment number of files
+ $this->numFiles++;
+ // Create us a new file in our array
+ $activeFile = &$this->files[];
+ // Asign Values
+ $activeFile["name"] = $file_name;
+ $activeFile["mode"] = $file_mode;
+ $activeFile["size"] = $file_size;
+ $activeFile["time"] = $file_time;
+ $activeFile["user_id"] = $file_uid;
+ $activeFile["group_id"] = $file_gid;
+ $activeFile["user_name"] = $file_uname;
+ $activeFile["group_name"] = $file_gname;
+ $activeFile["checksum"] = $file_chksum;
+ $activeFile["file"] = $file_contents;
+ } else {
+ // Increment number of directories
+ $this->numDirectories++;
+ // Create a new directory in our array
+ $activeDir = &$this->directories[];
+ // Assign values
+ $activeDir["name"] = $file_name;
+ $activeDir["mode"] = $file_mode;
+ $activeDir["time"] = $file_time;
+ $activeDir["user_id"] = $file_uid;
+ $activeDir["group_id"] = $file_gid;
+ $activeDir["user_name"] = $file_uname;
+ $activeDir["group_name"] = $file_gname;
+ $activeDir["checksum"] = $file_chksum;
+ }
+ // Move our offset the number of blocks we have processed
+ $main_offset += 512 + (ceil($file_size / 512) * 512);
+ }
+ return true;
+ }
+ // Read a non gzipped tar file in for processing
+ // PRIVATE ACCESS FUNCTION
+ function __readTar($filename='') {
+ // Set the filename to load
+ if(!$filename)
+ $filename = $this->filename;
+ // Read in the TAR file
+ $fp = fopen($filename,"rb");
+ $this->tar_file = fread($fp,filesize($filename));
+ fclose($fp);
+ if($this->tar_file[0] == chr(31) && $this->tar_file[1] == chr(139) && $this->tar_file[2] == chr(8)) {
+ if(!function_exists("gzinflate"))
+ return false;
+ $this->isGzipped = TRUE;
+ $this->tar_file = gzinflate(substr($this->tar_file,10,-4));
+ }
+ // Parse the TAR file
+ $this->__parseTar();
+ return true;
+ }
+ // Generates a TAR file from the processed data
+ // PRIVATE ACCESS FUNCTION
+ function __generateTAR() {
+ // Clear any data currently in $this->tar_file
+ unset($this->tar_file);
+ $this->tar_file='';
+ // Generate Records for each directory, if we have directories
+ if($this->numDirectories > 0) {
+ foreach($this->directories as $key => $information) {
+ unset($header);
+ // Generate tar header for this directory
+ // Filename, Permissions, UID, GID, size, Time, checksum, typeflag, linkname, magic, version, user name, group name, devmajor, devminor, prefix, end
+ $header .= str_pad($information["name"],100,chr(0));
+ $header .= str_pad(decoct($information["mode"]),7,"0",STR_PAD_LEFT) . chr(0);
+ $header .= str_pad(decoct($information["user_id"]),7,"0",STR_PAD_LEFT) . chr(0);
+ $header .= str_pad(decoct($information["group_id"]),7,"0",STR_PAD_LEFT) . chr(0);
+ $header .= str_pad(decoct(0),11,"0",STR_PAD_LEFT) . chr(0);
+ $header .= str_pad(decoct($information["time"]),11,"0",STR_PAD_LEFT) . chr(0);
+ $header .= str_repeat(" ",8);
+ $header .= "5";
+ $header .= str_repeat(chr(0),100);
+ $header .= str_pad("ustar",6,chr(32));
+ $header .= chr(32) . chr(0);
+ $header .= str_pad("",32,chr(0));
+ $header .= str_pad("",32,chr(0));
+ $header .= str_repeat(chr(0),8);
+ $header .= str_repeat(chr(0),8);
+ $header .= str_repeat(chr(0),155);
+ $header .= str_repeat(chr(0),12);
+ // Compute header checksum
+ $checksum = str_pad(decoct($this->__computeUnsignedChecksum($header)),6,"0",STR_PAD_LEFT);
+ for($i=0; $i<6; $i++) {
+ $header[(148 + $i)] = substr($checksum,$i,1);
+ }
+ $header[154] = chr(0);
+ $header[155] = chr(32);
+ // Add new tar formatted data to tar file contents
+ $this->tar_file .= $header;
+ }
+ }
+ // Generate Records for each file, if we have files (We should...)
+ if($this->numFiles > 0) {
+ foreach($this->files as $key => $information) {
+ unset($header);
+ $header='';
+ // Generate the TAR header for this file
+ // Filename, Permissions, UID, GID, size, Time, checksum, typeflag, linkname, magic, version, user name, group name, devmajor, devminor, prefix, end
+ $header .= str_pad($information["name"],100,chr(0));
+ $header .= str_pad(decoct($information["mode"]),7,"0",STR_PAD_LEFT) . chr(0);
+ $header .= str_pad(decoct($information["user_id"]),7,"0",STR_PAD_LEFT) . chr(0);
+ $header .= str_pad(decoct($information["group_id"]),7,"0",STR_PAD_LEFT) . chr(0);
+ $header .= str_pad(decoct($information["size"]),11,"0",STR_PAD_LEFT) . chr(0);
+ $header .= str_pad(decoct($information["time"]),11,"0",STR_PAD_LEFT) . chr(0);
+ $header .= str_repeat(" ",8);
+ $header .= "0";
+ $header .= str_repeat(chr(0),100);
+ $header .= str_pad("ustar",6,chr(32));
+ $header .= chr(32) . chr(0);
+ $header .= str_pad($information["user_name"],32,chr(0)); // How do I get a file's user name from PHP?
+ $header .= str_pad($information["group_name"],32,chr(0)); // How do I get a file's group name from PHP?
+ $header .= str_repeat(chr(0),8);
+ $header .= str_repeat(chr(0),8);
+ $header .= str_repeat(chr(0),155);
+ $header .= str_repeat(chr(0),12);
+ // Compute header checksum
+ $checksum = str_pad(decoct($this->__computeUnsignedChecksum($header)),6,"0",STR_PAD_LEFT);
+ for($i=0; $i<6; $i++) {
+ $header[(148 + $i)] = substr($checksum,$i,1);
+ }
+ $header[154] = chr(0);
+ $header[155] = chr(32);
+ // Pad file contents to byte count divisible by 512
+ $file_contents = str_pad($information["file"],(ceil($information["size"] / 512) * 512),chr(0));
+ // Add new tar formatted data to tar file contents
+ $this->tar_file .= $header . $file_contents;
+ }
+ }
+ // Add 512 bytes of NULLs to designate EOF
+ $this->tar_file .= str_repeat(chr(0),512);
+ return true;
+ }
+ // Open a TAR file
+ function openTAR($filename) {
+ // Clear any values from previous tar archives
+ //unset($this->filename);
+ $this->filename='';
+ //unset($this->isGzipped);
+ $this->isGzipped=0;
+ //unset($this->tar_file);
+ $this->tar_file=0;
+ //unset($this->files);
+ $this->files='';
+ //unset($this->directories);
+ //unset($this->numFiles);
+ //unset($this->numDirectories);
+ $this->directories='';
+ $this->numFiles=0;
+ $this->numDirectories=0;
+ // If the tar file doesn't exist...
+ if(!file_exists($filename))
+ return false;
+ $this->filename = $filename;
+ // Parse this file
+ $this->__readTar();
+ return true;
+ }
+ // Appends a tar file to the end of the currently opened tar file
+ function appendTar($filename) {
+ // If the tar file doesn't exist...
+ if(!file_exists($filename))
+ return false;
+ $this->__readTar($filename);
+ return true;
+ }
+ // Retrieves information about a file in the current tar archive
+ function getFile($filename) {
+ if($this->numFiles > 0) {
+ foreach($this->files as $key => $information) {
+ if($information["name"] == $filename)
+ return $information;
+ }
+ }
+ return false;
+ }
+ // Retrieves information about a directory in the current tar archive
+ function getDirectory($dirname) {
+ if($this->numDirectories > 0) {
+ foreach($this->directories as $key => $information) {
+ if($information["name"] == $dirname)
+ return $information;
+ }
+ }
+ return false;
+ }
+ // Check if this tar archive contains a specific file
+ function containsFile($filename) {
+ if($this->numFiles > 0) {
+ foreach($this->files as $key => $information) {
+ if($information["name"] == $filename)
+ return true;
+ }
+ }
+ return false;
+ }
+ // Check if this tar archive contains a specific directory
+ function containsDirectory($dirname) {
+ if($this->numDirectories > 0) {
+ foreach($this->directories as $key => $information) {
+ if($information["name"] == $dirname)
+ return true;
+ }
+ }
+ return false;
+ }
+ // Add a directory to this tar archive
+ function addDirectory($dirname) {
+ if(!file_exists($dirname))
+ return false;
+ // Get directory information
+ $file_information = stat($dirname);
+ // Add directory to processed data
+ $this->numDirectories++;
+ $activeDir = &$this->directories[];
+ $activeDir["name"] = $dirname;
+ $activeDir["mode"] = $file_information["mode"];
+ $activeDir["time"] = $file_information["time"];
+ $activeDir["user_id"] = $file_information["uid"];
+ $activeDir["group_id"] = $file_information["gid"];
+ $activeDir["checksum"] = $checksum;
+ return true;
+ }
+ // Add a file to the tar archive
+ function addFile($filename) {
+ // Make sure the file we are adding exists!
+ if(!file_exists($filename))
+ return false;
+ // Make sure there are no other files in the archive that have this same filename
+ if($this->containsFile($filename))
+ return false;
+ // Get file information
+ $file_information = stat($filename);
+ // Read in the file's contents
+ $fp = fopen($filename,"rb");
+ $file_contents = fread($fp,filesize($filename));
+ fclose($fp);
+ // Add file to processed data
+ $this->numFiles++;
+ $activeFile = &$this->files[];
+ $activeFile["name"] = $filename;
+ $activeFile["mode"] = $file_information["mode"];
+ $activeFile["user_id"] = $file_information["uid"];
+ $activeFile["group_id"] = $file_information["gid"];
+ $activeFile["size"] = $file_information["size"];
+ $activeFile["time"] = $file_information["mtime"];
+ $activeFile["checksum"] = $checksum;
+ $activeFile["user_name"] = "";
+ $activeFile["group_name"] = "";
+ $activeFile["file"] = $file_contents;
+ return true;
+ }
+ // Add a file to the tar archive
+ function addData($filename,$data,$time=0) {
+ global $gBitSystem;
+ // Make sure there are no other files in the archive that have this same filename
+ if($this->containsFile($filename))
+ return false;
+ if (!$time) $time=$gBitSystem->getUTCTime();
+ // Read in the file's contents
+ $file_contents = $data;
+ // Add file to processed data
+ $this->numFiles++;
+ $activeFile = &$this->files[];
+ $activeFile["name"] = $filename;
+ $activeFile["mode"] = octdec("666");
+ $activeFile["user_id"] = "";
+ $activeFile["group_id"] = "";
+ $activeFile["size"] = strlen($data);
+ $activeFile["time"] = $time;
+ if(!isset($checksum)) $checksum=0;
+ $activeFile["checksum"] = $checksum;
+ $activeFile["user_name"] = "";
+ $activeFile["group_name"] = "";
+ $activeFile["file"] = $file_contents;
+ return true;
+ }
+ // Remove a file from the tar archive
+ function removeFile($filename) {
+ if($this->numFiles > 0) {
+ foreach($this->files as $key => $information) {
+ if($information["name"] == $filename) {
+ $this->numFiles--;
+ unset($this->files[$key]);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ // Remove a directory from the tar archive
+ function removeDirectory($dirname) {
+ if($this->numDirectories > 0) {
+ foreach($this->directories as $key => $information) {
+ if($information["name"] == $dirname) {
+ $this->numDirectories--;
+ unset($this->directories[$key]);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ // Write the currently loaded tar archive to disk
+ function saveTar() {
+ if(!$this->filename)
+ return false;
+ // Write tar to current file using specified gzip compression
+ $this->toTar($this->filename,$this->isGzipped);
+ return true;
+ }
+ // Saves tar archive to a different file than the current file
+ function toTar($filename,$useGzip) {
+ if(!$filename)
+ return false;
+ // Encode processed files into TAR file format
+ $this->__generateTar();
+ // GZ Compress the data if we need to
+ if($useGzip) {
+ // Make sure we have gzip support
+ if(!function_exists("gzencode"))
+ return false;
+ $file = gzencode($this->tar_file);
+ } else {
+ $file = $this->tar_file;
+ }
+ // Write the TAR file
+ $fp = fopen($filename,"wb");
+ fwrite($fp,$file);
+ fclose($fp);
+ return true;
+ }
+}
+?>