Source for file class.tar.php
Documentation is available at class.tar.php
// $Id: class.tar.php 2 2005-11-02 18:23:29Z skalpa $
php-downloader v1.0 - www.ipunkt.biz
(c) 2002 - www.ipunkt.biz (rok)
=======================================================================
Josh Barger <joshb@npt.com>
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!
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 :)
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.
1.0 04/10/2002 - InitialRelease
2.0 04/11/2002 - Merged both tarReader and tarWriter
- 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
- Added ability to remove files and
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
2.2 05/07/2002 - Added automatic detection of Gzipped
tar files (Thanks go to Jidgen Falch
- Changed "private" functions to have
special function names beginning with
=======================================================================
XOOPS changes onokazu <webmaster@xoops.org>
12/25/2002 - Added flag to addFile() function for binary files
=======================================================================
* 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!
* @author Josh Barger <joshb@npt.com>
* @copyright Copyright (C) 2002 Josh Barger
* Unprocessed Archive Information
* Processed Archive Information
* Class Constructor -- Does nothing...
* Computes the unsigned Checksum of a file's header
* to try to ensure valid file
* @param string $bytestring
function __computeUnsignedChecksum($bytestring)
$unsigned_chksum += ord($bytestring[$i]);
$unsigned_chksum -= ord($bytestring[148 + $i]);
$unsigned_chksum += ord(" ") * 8;
* Converts a NULL padded string to a non-NULL padded string
function __parseNullPaddedString($string)
return substr($string,0,$position);
* This function parses the current TAR file
* @return bool always TRUE
// Read Files from archive
while ( $main_offset < $tar_length ) {
// If we read a block of 512 nulls, we are at the end of the archive
$file_name = $this->__parseNullPaddedString(substr($this->tar_file,$main_offset,100));
// Parse the file user ID
// Parse the file group ID
// Parse the file update time - unix timestamp format
$file_uname = $this->__parseNullPaddedString(substr($this->tar_file,$main_offset + 265,32));
$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)
$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);
// Increment number of files
// Create us a new file in our array
$activeFile = &$this->files[];
$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;
// Increment number of directories
// Create a new directory in our array
$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);
* Read a non gzipped tar file in for processing.
* @param string $filename full filename
* @return bool always TRUE
function __readTar($filename= '')
// Set the filename to load
$fp = fopen($filename,"rb");
* Generates a TAR file from the processed data
* @return bool always TRUE
// Clear any data currently in $this->tar_file
// Generate Records for each directory, if we have directories
// 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["user_id"]),7,"0",STR_PAD_LEFT) . chr(0);
$header .= str_pad(decoct($information["group_id"]),7,"0",STR_PAD_LEFT) . chr(0);
// Compute header checksum
$checksum = str_pad(decoct($this->__computeUnsignedChecksum($header)),6,"0",STR_PAD_LEFT);
$header[(148 + $i)] = substr($checksum,$i,1);
// Add new tar formatted data to tar file contents
// Generate Records for each file, if we have files (We should...)
foreach($this->files as $key => $information) {
// 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["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($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?
// Compute header checksum
$checksum = str_pad(decoct($this->__computeUnsignedChecksum($header)),6,"0",STR_PAD_LEFT);
$header[(148 + $i)] = substr($checksum,$i,1);
// 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
* @param string $filename
// Clear any values from previous tar archives
// If the tar file doesn't exist...
* Appends a tar file to the end of the currently opened tar file.
* @param string $filename
// If the tar file doesn't exist...
$this->__readTar($filename);
* Retrieves information about a file in the current tar archive
* @param string $filename
* @return string FALSE on fail
foreach($this->files as $key => $information) {
if($information["name"] == $filename)
* Retrieves information about a directory in the current tar archive
* @return string FALSE on fail
if($information["name"] == $dirname)
* Check if this tar archive contains a specific file
* @param string $filename
foreach($this->files as $key => $information) {
if($information["name"] == $filename)
* Check if this tar archive contains a specific directory
foreach ( $this->directories as $key => $information ) {
if ( $information["name"] == $dirname ) {
* Add a directory to this tar archive
// Get directory information
$file_information = stat($dirname);
// Add directory to processed data
$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;
* Add a file to the tar archive
* @param string $filename
* @param boolean $binary Binary file?
function addFile($filename, $binary = false)
// Make sure the file we are adding exists!
// Make sure there are no other files in the archive that have this same filename
$file_information = stat($filename);
// Read in the file's contents
$fp = fopen($filename, "r");
$fp = fopen($filename, "rb");
// Add file to processed data
$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"] = isset ($checksum) ? $checksum : '';
$activeFile["user_name"] = "";
$activeFile["group_name"] = "";
$activeFile["file"] = trim($file_contents);
* Remove a file from the tar archive
* @param string $filename
foreach ( $this->files as $key => $information ) {
if ( $information["name"] == $filename ) {
unset ($this->files[$key]);
* Remove a directory from the tar archive
foreach ( $this->directories as $key => $information ) {
if ( $information["name"] == $dirname ) {
* Write the currently loaded tar archive to disk
// Write tar to current file using specified gzip compression
* Saves tar archive to a different file than the current file
* @param string $filename
* @param bool $useGzip Use GZ compression?
function toTar($filename,$useGzip)
// Encode processed files into TAR file format
// GZ Compress the data if we need to
// Make sure we have gzip support
$fp = fopen($filename,"wb");
* Sends tar archive to stdout
* @param string $filename
* @param bool $useGzip Use GZ compression?
// Encode processed files into TAR file format
// GZ Compress the data if we need to
// Make sure we have gzip support
|