addfile($data,$filename,$flags); | -data - file contents | -filename - name of file to be put in archive | -flags (all flags are optional) | -flags (tar) [array]: -same flags as tarfile() | -flags (gzip) [string]: -comment to add to archive | -flags (zip) [array] -time - last modification time | | $example->addfiles($filelist); | -filelist - array of file names relative to CWD | | $example->adddirectories($dirlist); | -dirlist - array of directory names relative to CWD +------------------------------------------------------------*/ /*------------------------------------------------------------ | To output files: | $example->getdata(); | -returns file contents | | $example->filedownload($filename); | -filename - the name to give the file that is being sent | | $example->filewrite($filename,$perms); // perms optional | -filename - the name (including path) of the file to write | -perms - permissions to give the file after it is written +------------------------------------------------------------*/ /*------------------------------------------------------------ | To extract files (tar and gzip) | $example->extract($data); | -data - data to extract files from | -returns an array containing file attributes and contents | | $example->extractfile($filename); | -filename - the name (including path) of the file to use | -returns an array containing file attributes and contents | | Both functions will return a string containing any errors +------------------------------------------------------------*/ class tarfile extends archive { var $cwd = "./"; var $tardata = ""; var $defaultflags = array( 'mode' => 0, 'uid' => 0, 'gid' => 0, 'time' => 0, 'type' => 0, 'link' => "", 'path' => "", ); var $replacestats = array(); var $recursesd = 1; var $storepath = 1; function tarfile($cwd="./",$flags=array()) { $this->cwd = $cwd; $this->defaultflags['mode'] = decoct(0x8000 | 0x0100 | 0x0080 | 0x0020 | 0x0004); $this->defaultflags['time'] = time(); if(isset($flags['recursesd'])) $this->recursesd = $flags['recursesd']; if(isset($flags['storepath'])) $this->storepath = $flags['storepath']; if(isset($flags['replacestats'])) { if(is_array($flags['replacestats'])) { if(isset($flags['replacestats']['mode'])) $this->replacestats['mode'] = $flags['replacestats']['mode']; if(isset($flags['replacestats']['time'])) $this->replacestats['time'] = $flags['replacestats']['time']; } else if($flags['replacestats'] == 1) { $this->replacestats['mode'] = $this->defaultflags['mode']; $this->replacestats['time'] = $this->defaultflags['time']; } } $this->archive($flags); } function addfile($data,$filename,$flags=array()) { if(strlen($filename) > 99) return; $flags['mode'] = isset($this->replacestats['mode'])? $this->replacestats['mode'] : (isset($flags['mode'])? $flags['mode'] : $this->defaultflags['mode']); $flags['uid'] = isset($flags['uid'])? $flags['uid'] : $this->defaultflags['uid']; $flags['gid'] = isset($flags['gid'])? $flags['gid'] : $this->defaultflags['gid']; $flags['time'] = isset($this->replacestats['time'])? $this->replacestats['time'] : (isset($flags['time'])? $flags['time'] : $this->defaultflags['time']); $flags['type'] = isset($flags['type'])? $flags['type'] : $this->defaultflags['type']; $flags['link'] = isset($flags['link'])? $flags['link'] : $this->defaultflags['link']; $flags['path'] = isset($flags['path'])? $flags['path'] : $this->defaultflags['path']; $flags['size'] = isset($flags['size'])? $flags['size'] : strlen($data); if($this->storepath != 1) { $filename = strstr($filename,"/")? substr($filename,strrpos($filename,"/")+1) : $filename; $flags['path'] = ""; } else $filename = preg_replace("/^(\.{1,2}(\/|\\\))+/","",$filename); $blockbeg = pack("a100a8a8a8a12a12",$filename,$flags['mode'],sprintf("%6s ",decoct($flags['uid'])),sprintf("%6s ",decoct($flags['gid'])),sprintf("%11s ",decoct($flags['size'])),sprintf("%11s ",decoct($flags['time']))); $blockend = pack("a1a100a6a2a32a32a8a8a155",$flags['type'],$flags['link'],"ustar","00","Unknown","Unknown","","",$flags['path']); $checksum = 0; for($i = 0; $i < 148; $i++) $checksum += ord(substr($blockbeg,$i,1)); for($i = 148; $i < 156; $i++) $checksum += ord(" "); for($i = 156; $i < 512; $i++) $checksum += ord(substr($blockend,$i-156,1)); $checksum = pack("a8",sprintf("%6s ",decoct($checksum))); if($flags['size'] % 512 > 0) $data .= $this->nullpad(512 - $flags['size'] % 512); $this->tardata .= $blockbeg . $checksum . $blockend . pack("a12","") . $data; } function addfiles($filelist) { $pwd = getcwd(); @chdir($this->cwd); foreach($filelist as $current) { $file = array(); if($this->storepath != 1) $file['name'] = strstr($current,"/")? substr($current,strrpos($current,"/")+1) : $current; else $file['name'] = preg_replace("/^(\.{1,2}(\/|\\\))+/","",$current); $file['mode'] = @fileperms($current); if($file['mode'] & 0x4000) $file['type'] = 5; // Directory else if($file['mode'] & 0x8000) $file['type'] = 0; // Regular else if($file['mode'] & 0xA000) $file['type'] = 1; // Link else $file['type'] = 9; // Unknown $file['mode'] = decoct($file['mode']); if($file['type'] == 0 && !@file_exists($current)) return; else if(strlen($file['name']) > 99) { $offset = strrpos($file['name'],"/") + 1; $file['path'] = substr($file['name'],0,$offset); $file['name'] = substr($file['name'],$offset); if(strlen($file['name']) > 99 || strlen($file['path']) > 154) return; } else $file['path'] = ""; $stat = stat($current); if(($file['type'] == 0 || $file['type'] == 1) && $fp = @fopen($current,"rb")) { $data = fread($fp,$stat[7]); fclose($fp); } else $data = ""; $flags = array( 'mode' => $file['mode'], 'uid' => $stat[4], 'gid' => $stat[5], 'size' => $stat[7], 'time' => $stat[9], 'type' => $file['type'], 'link' => $file['type'] == 1? @readlink($current) : "", 'path' => $file['path'], ); $this->addfile($data,$file['name'],$flags); } @chdir($pwd); } function extract($data) { $return = array(); $blocks = strlen($data)/512 - 1; $offset = 0; while($offset < $blocks) { $header = substr($data,512*$offset,512); $current = unpack("a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/a8checksum/a1type/a100linkname/a6magic/a2version/a32uname/a32gname/a8devmajor/a8devminor/a155path",$header); foreach($current as $k => $v) $current[$k] = trim($v); $current['mode'] = octdec($current['mode']); $current['uid'] = octdec($current['uid']); $current['gid'] = octdec($current['gid']); $current['size'] = octdec($current['size']); $current['mtime'] = octdec($current['mtime']); $current['checksum'] = octdec($current['checksum']); $current['type'] = octdec($current['type']); if($this->storepaths != 1) $current['filename'] = substr($current['filename'],strrpos($current['filename'],"/")+1); $current['filename'] = preg_replace("/\W+/","",$current['filename']); $checksum = 0; for($i = 0; $i < 148; $i++) $checksum += ord(substr($header,$i,1)); for($i = 148; $i < 156; $i++) $checksum += ord(" "); for($i = 156; $i < 512; $i++) $checksum += ord(substr($header,$i,1)); if($current['checksum'] != $checksum) return "CHECKSUM"; $size = ceil($current['size']/512); $current['data'] = substr($data,512*($offset++),$current['size']); $offset += $size; $return[] = $current; } return $return; } function getdata() { return $this->tardata . pack("a512",""); } function filedownload($filename) { @header("Content-type: application/x-tar"); @header("Content-disposition: attachment; filename=$filename"); print($this->getdata()); } function nullpad($bytes) { $return = ""; for($i = 0; $i < $bytes; ++$i) $return .= "\0"; return $return; } } class gzfile extends archive { var $gzdata = ""; function addfile($data,$filename=null,$comment=null) { $flags = bindec("000".(!empty($comment)? "1" : "0").(!empty($filename)? "1" : "0")."000"); $this->gzdata .= pack("C1C1C1C1VC1C1",0x1f,0x8b,8,$flags,time(),2,0xFF); if(!empty($filename)) $this->gzdata .= "$filename\0"; if(!empty($comment)) $this->gzdata .= "$comment\0"; $this->gzdata .= gzdeflate($data); $this->gzdata .= pack("VV",crc32($data),strlen($data)); } function extract($data) { $id = unpack("H2id1/H2id2",substr($data,0,2)); if($id['id1'] != "1f" || $id['id2'] != "8b") die("Not valid gzip data."); $temp = unpack("Cflags",substr($data,2,1)); $temp = decbin($temp['flags']); if($temp & 0x8) $flags['name'] = 1; if($temp & 0x4) $flags['comment'] = 1; $offset = 10; $filename = ""; while(!empty($flags['name'])) { $char = substr($data,$offset,1); $offset++; if($char == "\0") break; $filename .= $char; } if($filename == "") $filename = "file"; $comment = ""; while(!empty($flags['comment'])) { $char = substr($data,$offset,1); $offset++; if($char == "\0") break; $comment .= $char; } $temp = unpack("Vcrc32/Visize",substr($data,strlen($data)-8,8)); $crc32 = $temp['crc32']; $isize = $temp['isize']; $data = gzinflate(substr($data,$offset,strlen($data)-8-$offset)); if($crc32 != crc32($data)) return "CRC"; return array('filename'=>$filename,'comment'=>$comment,'size'=>$isize,'data'=>$data); } function getdata() { return $this->gzdata; } function filedownload($filename) { @header("Content-type: application/x-gzip"); @header("Content-disposition: attachment; filename=$filename"); print($this->getdata()); } } class zipfile extends archive { var $cwd = "./"; var $comment = ""; var $level = 9; var $offset = 0; var $recursesd = 1; var $storepath = 1; var $replacetime = 0; var $central = array(); var $zipdata = array(); function zipfile($cwd="./",$flags=array()) { $this->cwd = $cwd; if(isset($flags['time'])) $this->replacetime = $flags['time']; if(isset($flags['recursesd'])) $this->recursesd = $flags['recursesd']; if(isset($flags['storepath'])) $this->storepath = $flags['storepath']; if(isset($flags['level'])) $this->level = $flags['level']; if(isset($flags['comment'])) $this->comment = $flags['comment']; $this->archive($flags); } function addfile($data,$filename,$flags=array()) { if($this->storepath != 1) $filename = strstr($filename,"/")? substr($filename,strrpos($filename,"/")+1) : $filename; else $filename = preg_replace("/^(\.{1,2}(\/|\\\))+/","",$filename); $mtime = !empty($this->replacetime)? getdate($this->replacetime) : (isset($flags['time'])? getdate($flags['time']) : getdate()); $mtime = preg_replace("/(..){1}(..){1}(..){1}(..){1}/","\\x\\4\\x\\3\\x\\2\\x\\1",dechex(($mtime['year']-1980<<25)|($mtime['mon']<<21)|($mtime['mday']<<16)|($mtime['hours']<<11)|($mtime['minutes']<<5)|($mtime['seconds']>>1))); eval('$mtime = "'.$mtime.'";'); $crc32 = crc32($data); $normlength = strlen($data); $data = gzcompress($data,$this->level); $data = substr($data,2,strlen($data)-6); $complength = strlen($data); $this->zipdata[] = "\x50\x4b\x03\x04\x14\x00\x00\x00\x08\x00".$mtime.pack("VVVvv",$crc32,$complength,$normlength,strlen($filename),0x00).$filename.$data.pack("VVV",$crc32,$complength,$normlength); $this->central[] = "\x50\x4b\x01\x02\x00\x00\x14\x00\x00\x00\x08\x00".$mtime.pack("VVVvvvvvVV",$crc32,$complength,$normlength,strlen($filename),0x00,0x00,0x00,0x00,0x0000,$this->offset).$filename; $this->offset = strlen(implode("",$this->zipdata)); } function addfiles($filelist) { $pwd = getcwd(); @chdir($this->cwd); foreach($filelist as $current) { if(!@file_exists($current)) continue; $stat = stat($current); if($fp = @fopen($current,"rb")) { $data = fread($fp,$stat[7]); fclose($fp); } else $data = ""; $flags = array('time'=>$stat[9]); $this->addfile($data,$current,$flags); } @chdir($pwd); } function getdata() { $central = implode("",$this->central); $zipdata = implode("",$this->zipdata); return $zipdata.$central."\x50\x4b\x05\x06\x00\x00\x00\x00".pack("vvVVv",sizeof($this->central),sizeof($this->central),strlen($central),strlen($zipdata),strlen($this->comment)).$this->comment; } function filedownload($filename) { @header("Content-type: application/zip"); @header("Content-disposition: attachment; filename=$filename"); print($this->getdata()); } } class archive { var $overwrite = 0; var $defaultperms = 0644; function archive($flags=array()) { if(isset($flags['overwrite'])) $this->overwrite = $flags['overwrite']; if(isset($flags['defaultperms'])) $this->defaultperms = $flags['defaultperms']; } function adddirectories($dirlist) { $pwd = getcwd(); @chdir($this->cwd); $filelist = array(); foreach($dirlist as $current) { if(@is_dir($current)) { $temp = $this->parsedirectories($current); foreach($temp as $filename) $filelist[] = $filename; } else if(@file_exists($current)) $filelist[] = $current; } @chdir($pwd); $this->addfiles($filelist); } function parsedirectories($dirname) { $filelist = array(); $dir = @opendir($dirname); while($file = @readdir($dir)) { if($file == "." || $file == "..") continue; else if(@is_dir($dirname."/".$file)) { if($this->recursesd != 1) continue; $temp = $this->parsedirectories($dirname."/".$file); foreach($temp as $file2) $filelist[] = $file2; } else if(@file_exists($dirname."/".$file)) $filelist[] = $dirname."/".$file; } @closedir($dir); return $filelist; } function filewrite($filename,$perms=null) { if($this->overwrite != 1 && @file_exists($filename)) die("File $filename already exists."); if(@file_exists($filename)) @unlink($filename); $fp = @fopen($filename,"wb"); if(!fwrite($fp,$this->getdata())) die("Could not write data to $filename."); @fclose($fp); if(!isset($perms)) $perms = $this->defaultperms; @chmod($filename,$perms); } function extractfile($filename) { if($fp = @fopen($filename,"rb")) { return $this->extract(fread($fp,filesize($filename))); @fclose($fp); } else die("Could not open $filename."); } } ?>