PHP Classes

File: MakeCAB.class

Recommend this page to a friend!
  Classes of Sam S   MakeCAB   MakeCAB.class   Download  
File: MakeCAB.class
Role: Class source
Content type: text/plain
Description: Primary Class file
Class: MakeCAB
Create CAB archives from lists of files
Author: By
Last change: Updated comments
Date: 15 years ago
Size: 14,376 bytes
 

Contents

Class file image Download
<?php /** * @package MakeCAB * @example /examplecab.php Example usage of this class. * @category File Formats * @author Sam Shull <samshull@samshull.com> * @copyright Copyright (c) 2007, Sam Shull * @license http://www.samshull.com/bsdlicense.txt BSD License * @link http://samshull.com/examplecab.php * @version 0.9 * @access public */ class MakeCAB{ /** * Absolute / Relative Path to cab file * * @var string * @access protected */ var $cabfile; /** * Array of files to be added to archive * * @var array * @access protected */ var $cabfiles = array(); /** * Array of data for CAB folder * * @var array * @access protected */ var $cabfolder = array('offset' => 44, ## offset of data 'numblocks' => 0, ## number of blocks 'typecmp' => 1, ## 0 = no compression; 1 = MSZIP; LZX 'fileoffset' => 0 ); /** * Array of data for CAB Header * * @var array * @access protected */ var $cabheader = array('sig' => "MSCF", ## signature 'res1' => 0, ## reserved space 'size' => 44, ## total size of cab file 'res2' => 0, 'offset' => 44, ## offset of first data block 'res3' => 0, 'vmaj' => 1, ## cab file format major version number 1 'vmin' => 3, ## cab file format minor version number 3 'numfolders' => 1, ## must have at least one folder NewCABFolder() 'numfiles' => 0, ## number of files in cab file 'flags' => 0, ## not supported 'setid' => 1234, ## set ID (not supported) 'cabid' => 0, ##cab id not supported ); /** * Max data block size * * @var integer * @access protected */ var $BLOCKSIZE = 32768; /** * Linux Seperator * * @var string * @access protected */ var $LINSEP = '/'; /** * Windows Seperator * * @var string * @access protected */ var $WINSEP = '\\'; /** * Method: MakeCAB __construct * Construct * @param string $file - file that will be written to * @param int $typecmp - level of compression */ function MakeCAB($file,$typecmp=1){ $this->cabfile = $file; $this->cabfolder['typecmp'] = ($typecmp > 0 && extension_loaded('zlib')) ? $typecmp : 0; } /** * Method: WriteCab * Write the data to a file */ function WriteCAB(){ $this->cabfolder['numblocks'] = ceil($this->cabfolder['fileoffset']/$this->BLOCKSIZE); $this->cabheader['size'] += ($this->cabfolder['numblocks'] * 8); if(false !== ($res = fopen( $this->cabfile, "w+b" ))){ $this->WriteHeader($res); $this->WriteFolder($res); $this->WriteFiles($res); $this->WriteData($res); $this->UpdateCABsize($res); fclose( $res ); } else { die("Failed to open ".$this->cabfile); } } //Update the file size in the header (occassional errors with filesize caused by compression & using strlen as a byte counter) function UpdateCABsize($res){ $t = ftell($res); fseek($res,8); $this->WriteDword( $res, $t ); } /** * Method: addfile * Add a local file system file to your cab file * @param string $file - path preferably absolute path * @param bool|string $strip - if string is used parser will leave on the path what it is told to * e.g.: $file="/usr/path/data/file" $strip="/path" will result in an archive entry="/path/data/file" * a strip value of (bool) false then would result in archive entry= "/usr/path/data/file" * @param int $atribs - e.g hidden, read-only - see sdk */ function addfile($file,$strip=true,$atribs=32){ $filename = $strip==false ? $this->MakeWinPath( $file ) : $this->StripPath($file,$strip); $m=stat($file); $newcabfile = array('ucomp' => $m['size'], 'offset' => $this->cabfolder['fileoffset'], 'date' => $this->MakeCabFileDate($m['mtime']), 'time' => $this->MakeCabFileTime($m['mtime']), 'atribs' => $atribs, 'name' => $this->MakeWinPath($filename)."\0", 'path' => $file, 'size' => $m['size'] ); $this->cabfolder['fileoffset'] += $m['size']; $this->cabfolder['offset'] += 17 + strlen( $filename ); $this->cabheader['size'] += 17 + strlen( $filename ) + $m['size']; $this->cabheader['numfiles']++; $this->cabfiles[]=$newcabfile; clearstatcache(); } /** * Method: addurl * Add a file from a url using any stream that can be handled by PHP * for parameter descriptions see addfile descriptions * @param string $file * @param bool|string $strip * @param int $atribs */ function addurl($file,$strip=true,$atribs=32){ $x = file_get_contents($file); $filename = $strip==false ? $this->MakeWinPath( preg_replace("@^.*://@","/",$file) ) : $this->StripPath($file,$strip); $filen = dirname(__FILE__).$this->StripPath($file,true).".cabtemp"; file_put_contents($filen,$x); $m=stat($filen); $newcabfile = array('ucomp' => $m['size'], 'offset' => $this->cabfolder['fileoffset'], 'date' => $this->MakeCabFileDate($m['mtime']), 'time' => $this->MakeCabFileTime($m['mtime']), 'atribs' => $atribs, 'name' => $this->MakeWinPath($filename)."\0", 'path' => $filen, 'size' => $m['size'] ); $this->cabfolder['fileoffset'] += $m['size']; $this->cabfolder['offset'] += 17 + strlen( $filename ); $this->cabheader['size'] += 17 + strlen( $filename ) + $m['size']; $this->cabheader['numfiles']++; $this->cabfiles[]=$newcabfile; clearstatcache(); } /** * Method: adddir * Add an entire file system directory to your cab file * for parameter descriptions see addfile descriptions * @param string $dir * @param bool|string $strip * @param int $atribs */ function adddir($dir,$strip=true,$atribs=32){ $dir = preg_match("/(\/|\\\\)$/",$dir) ? $dir : $dir.$this->LINSEP; if($d = opendir($dir) ){ while(false !== ($file = readdir($d)) ){ if(is_file($dir.$file)){ $filename = $strip==false ? $this->MakeWinPath( $dir.$file ) : $this->StripPath($dir.$file,$strip); $m=stat($dir.$file); $newcabfile = array('ucomp' => $m['size'], 'offset' => $this->cabfolder['fileoffset'], 'date' => $this->MakeCabFileDate($m['mtime']), 'time' => $this->MakeCabFileTime($m['mtime']), 'atribs' => $atribs, 'name' => $this->MakeWinPath($filename)."\0", 'path' => $dir.$file, 'size' => $m['size'] ); $this->cabfolder['fileoffset'] += $m['size']; $this->cabfolder['offset'] += 17 + strlen( $filename ); $this->cabheader['size'] += 17 + strlen( $filename ) + $m['size']; ## + 1 for \0 ! $this->cabheader['numfiles']++; $this->cabfiles[]=$newcabfile; }//end if clearstatcache(); }//end while closedir($d); } } ## strip the path function StripPath($path,$strip){ $one = preg_match("@".$this->LINSEP."@x", $path) ? 1 : 0; $path = $strip === true ? substr($path,strrpos($path,$this->LINSEP)+$one) : ($strip != false ? substr($path,strpos($path,$strip)) : $path); return $path; } ## make win path function MakeWinPath ($path){ if(preg_match("@".$this->LINSEP."@x", $path) ) $path = preg_replace("'".$this->LINSEP."'s", $this->WINSEP, $path); return $path; } ## make cabinet file date from certain file function MakeCabFileDate($seconds){ $s = localtime($seconds, true); $res = ( ($s['tm_year'] - 80 ) << 9 ) + ( ($s['tm_mon']+1) << 5 ) + $s['tm_mday']; return $res; } ## make cabinet file date function MakeCabFileTime($seconds){ $s = localtime($seconds, true); $res = ( $s['tm_hour'] << 11 ) + ( $s['tm_min'] << 5 ) + ( $s['tm_sec'] / 2 ); return $res; } ################# WRITING ################# ## write the header function WriteHeader($res){ $this->WriteByteBuffer( $res, $this->cabheader['sig'] ); $this->WriteDword( $res, $this->cabheader['res1'] ); $this->WriteDword( $res, $this->cabheader['size'] ); $this->WriteDword( $res, $this->cabheader['res2'] ); $this->WriteDword( $res, $this->cabheader['offset'] ); $this->WriteDword( $res, $this->cabheader['res3'] ); $this->WriteByte( $res, $this->cabheader['vmin'] ); $this->WriteByte( $res, $this->cabheader['vmaj'] ); $this->WriteWord( $res, $this->cabheader['numfolders'] ); $this->WriteWord( $res, $this->cabheader['numfiles'] ); $this->WriteWord( $res, $this->cabheader['flags'] ); $this->WriteWord( $res, $this->cabheader['setid'] ); $this->WriteWord( $res, $this->cabheader['cabid'] ); } function WriteByteBuffer($res, $scalar){ fwrite( $res, $scalar ); } ## write (unsigned long int) dword; function WriteDword($res, $scalar){ if( preg_match("/[ \/a-zA-Z]/", $scalar) ) { $f = array(); for($i=0; $i<strlen($scalar); ++$i ) { $f[$i] = ord( substr($scalar,$i,1) ); } $fmt = "L".strlen($scalar); fwrite( $res, pack( "$fmt", $f ) ); return; } fwrite( $res, pack("L",$scalar) ); } ## write (unsigned char) single byte with pack; function WriteByte($res, $scalar){ fwrite( $res, pack("C",$scalar) ); } ## write (unsigned short int) word; function WriteWord($res, $scalar){ if( preg_match("/[ \/a-zA-Z]/", $scalar) ) { $f = array(); for($i=0; $i<strlen($scalar); ++$i ) { $f[$i] = ord( substr($scalar,$i,1) ); } $fmt = "S".strlen($scalar); fwrite( $res, pack( "$fmt", $f ) ); return; } fwrite( $res, pack("S",$scalar) ); } ## write the folder function WriteFolder($res){ $this->WriteDword( $res, $this->cabfolder['offset'] ); $this->WriteWord( $res, $this->cabfolder['numblocks'] ); $this->WriteWord( $res, $this->cabfolder['typecmp'] ); } ## write the files function WriteFiles($res){ foreach ( $this->cabfiles as $file ) { $this->WriteDword( $res, $file['ucomp'] ); $this->WriteDword( $res, $file['offset'] ); $this->WriteWord( $res, $file['index'] ); $this->WriteWord( $res, $file['date'] ); $this->WriteWord( $res, $file['time'] ); $this->WriteWord( $res, $file['fileattr'] ); $this->WriteByteBuffer( $res, $file['name'] ); } } function WriteData($res){ $datasize = $this->cabfolder['fileoffset']; $blocksize = $datasize > $this->BLOCKSIZE ? $this->BLOCKSIZE : $datasize; $block = $blocksize; $newblock = false; foreach ( $this->cabfiles as $file ){ if(false !== ($res1 = @fopen( $file['path'], "rb" ))){ $read_this_time = 0; $read_last_time = 0; while(!feof($res1)){ $buffer .= fread($res1,$block); $read = ftell($res1); $read_this_time = $read - $read_last_time; $read_last_time = $read; $datasize -= $read_this_time; if($read_this_time == $blocksize){ $block = $this->BLOCKSIZE; $newblock = true; } else { $block -= $read_this_time; $newblock = false; if($block <= 0){ $block = $this->BLOCKSIZE; $newblock = true; } } if( $newblock ){ $data = $this->cabfolder['typecmp'] == 1 ? $this->compressdata($buffer) : array('cbytes'=>$blocksize,'data'=>$buffer); $this->WriteDword( $res, 0 ); $this->WriteWord( $res, $data['cbytes'] ); $this->WriteWord( $res, $blocksize ); $this->WriteByteBuffer( $res, $data['data'] ); $blocksize = $datasize > $this->BLOCKSIZE ? $this->BLOCKSIZE : $datasize; $buffer = ""; } } ## close input file fclose( $res1 ); if(preg_match("'\.cabtemp$'",$file['path'])) unlink($file['path']); } else { die("Failed to open ".$file); } } } //*/ function compressdata($buffer){ $data['data'] = pack("C",0x43) . pack("C", 0x4B) . gzdeflate($buffer,$this->cabfolder['typecmp']); $data['cbytes']=$this->bytelen($data['data']); return $data; } function bytelen($data) { return strlen($data."A") - 1; } /* An unused method to compute the csum, not finished function CSUMCompute($pv, $cb, $seed=0){ //$csumpartial = $this->CSUMCompute(0,$data['cbytes'],0); //$csum = $this->CSUMCompute($data['cbytes'],sizeof(CFDATA) sizeof($csum),$csumpartial); //int cUlong; // Number of ULONGs in block //CHECKSUM csum; // Checksum accumulator //BYTE *pb; //ULONG ul; $cUlong = $cb / 4; // Number of ULONGs $csum = $seed; // Init checksum $pb = $pv; // Start at front of data block //** Checksum integral multiple of ULONGs while ($cUlong-- > 0) { //** NOTE: Build ULONG in big/little-endian independent manner $ul = $pb++; // Get low-order byte $ul |= (($pb++) << 8); // Add 2nd byte $ul |= (($pb++) << 16); // Add 3nd byte $ul |= (($pb++) << 24); // Add 4th byte $csum ^= $ul; // Update checksum } //** Checksum remainder bytes $ul = 0; switch ($cb % 4) { case 3: $ul |= (($pb++) << 16); // Add 3nd byte case 2: $ul |= (($pb++) << 8); // Add 2nd byte case 1: $ul |= $pb++; // Get low-order byte default: break; } $csum ^= $ul; // Update checksum //** Return computed checksum return $csum; } //*/ } ?>