<?php
class CFACreator {
private $source;
private $pw;
public function __construct($source) {
if (!file_exists($source)) {
throw new Exception($source." not found.");
}
if (!is_dir($source)) {
throw new Exception("There is no need to pack a single file.");
}
if (substr($source, strlen($source)-1)!="\\" && substr($source, strlen($source)-1)!="/") $source.="/";
$this->source=$source;
}
public function setPassword($pw) {
$this->pw=$pw;
}
public function packTo($file, $crypt=false) {
$files=$this->listDir($this->source);
if ($crypt) {
$out_stream=tmpfile();
} else {
$out_stream=fopen($file, "w+");
fwrite($out_stream, "r");
}
foreach ($files as $name=>$size) {
$name=gzcompress($name);
fwrite($out_stream, $this->compress(strlen($name)));
fwrite($out_stream, chr(255));
fwrite($out_stream, $name);
fwrite($out_stream, $this->compress($size));
fwrite($out_stream, chr(255));
}
fwrite($out_stream, chr(255));
foreach ($files as $name=>$size) {
$fp=fopen($this->source.$name, "r+");
while ($size>=100) {
fwrite($out_stream, fread($fp, 100));
$size-=100;
}
if ($size!=0) fwrite($out_stream, fread($fp, $size));
}
if ($crypt) {
rewind($out_stream);
$tmp=$out_stream;
$out_stream=fopen($file, "w+");
fwrite($out_stream, "c");
$iv=$this->pw;
if (strlen($iv)>8) {
$iv=substr($iv, 0, 8);
} elseif (strlen($iv)<8) {
$num=round(8/strlen($iv))+1;
$iv=str_repeat($iv, $num);
$iv=substr($iv, 0, 8);
}
while (!feof($tmp)) {
$part=fread($tmp, 100);
$part=mcrypt_encrypt(MCRYPT_BLOWFISH, $this->pw, $part, "cbc", $iv);
$part=base64_encode($part);
fwrite($out_stream, $part);
}
fclose($tmp);
}
fclose($out_stream);
}
private function listDir($path, $is_root=true, $root=null) {
$files=array();
if (substr($path, strlen($path)-1)!="\\" && substr($path, strlen($path)-1)!="/") $path.="/";
if ($root==null && $is_root) $root=$path;
if ($dir=opendir($path)) {
while ($file=readdir($dir)) {
if ($file!=".." && $file!=".") {
if (is_dir($path.$file)) {
$ar=$this->listDir($path.$file, false, $root);
$files=array_merge($files, $ar);
} else {
if ($is_root) {
$name=$file;
} else {
$name=substr($path.$file, strlen($root));
}
$files[$name]=filesize($path.$file);
}
}
}
closedir($dir);
return $files;
} else {
throw new Exception("Could not open ".$path);
}
}
public static function compress($int) {
$comp="";
$full=0;
while ($int>=253) {
if ($full==253) {
$comp.=chr(253);
$full=0;
}
$full++;
$int-=253;
}
if ($full!=0) $comp.=chr($full);
$comp.=chr(254);
if ($int!=0) $comp.=chr($int);
return $comp;
}
}
class CFAExtractor {
private $path;
private $pw;
public function __construct($path) {
if (!file_exists($path)) {
throw new Exception($path." not found.");
}
$this->path=$path;
}
public function setPassword($pw) {
$this->pw=$pw;
}
public function extractTo($path) {
if (!file_exists($this->path)) {
throw new Exception($path." not found.");
}
if (substr($path, strlen($path)-1)!="\\" && substr($path, strlen($path)-1)!="/") $path.="/";
$in_stream=fopen($this->path, "r");
$mode=fread($in_stream, 1);
if ($mode!="c" && $mode!="r") {
fclose($in_stream);
throw new Exception("Invalid file given.");
}
if ($mode=="c") {
// crypted file
if ($this->pw==null) {
throw new Exception("File encrypted but no password given!");
}
$iv=$this->pw;
if (strlen($iv)>8) {
$iv=substr($iv, 0, 8);
} elseif (strlen($iv)<8) {
$num=round(8/strlen($iv))+1;
$iv=str_repeat($iv, $num);
$iv=substr($iv, 0, 8);
}
$tmp_file=tmpfile();
while (!feof($in_stream)) {
$part=fread($in_stream, 136);
$part=base64_decode($part);
$part=mcrypt_decrypt(MCRYPT_BLOWFISH, $this->pw, $part, "cbc", $iv);
fwrite($tmp_file, $part);
}
fclose($in_stream);
rewind($tmp_file);
$in_stream=$tmp_file;
}
$files=array();
$ci=ord(fread($in_stream, 1));
while ($ci!=255) {
$name_length="";
while ($ci!=255) {
$name_length.=chr($ci);
$ci=ord(fread($in_stream, 1));
}
$name_length=$this->uncompress($name_length);
$name=gzuncompress(fread($in_stream, $name_length));
$size="";
$ci=ord(fread($in_stream, 1));
while ($ci!=255) {
$size.=chr($ci);
$ci=ord(fread($in_stream, 1));
}
$size=$this->uncompress($size);
$files[$name]=$size;
$ci=ord(fread($in_stream, 1));
}
$this->mkdir($path);
foreach ($files as $name=>$size) {
$this->mkdir(dirname($path.$name));
$fp=fopen($path.$name, "w+");
if (!$fp) {
throw new Exception("Could not create ".$path.$name);
}
while ($size>=100) {
fwrite($fp, fread($in_stream, 100));
$size-=100;
}
if ($size!=0) fwrite($fp, fread($in_stream, $size));
fclose($fp);
}
fclose($in_stream);
}
public static function mkdir($path, $rights=0777) {
if (file_exists($path)) return;
$path=str_replace("\\", "/", $path);
if (substr($path, strlen($path)-1)=="/") $path=substr($path, 0, strlen($path)-1);
$prev=strrpos($path, "/");
$prev=substr($path, 0, $prev);
if (!file_exists($prev)) {
self::mkdir($prev, $rights);
}
mkdir($path);
}
public static function uncompress($bytes) {
$j=strlen($bytes)-1;
$full=0;
$c=-1;
$i=0;
$c=ord($bytes[0]);
while ($c!=254 && $i!=$j) {
$full+=$c;
$i++;
$c=ord($bytes[$i]);
}
$size=$full*253;
$i++;
while ($i<=$j) {
$c=$bytes[$i];
$size+=ord($c);
$i++;
}
return $size;
}
}
class CFAFile {
private $filename;
private $filelist=array();
private $passsword;
public function __construct($filename, $pw=null) {
$this->filename=$filename;
$this->password=$pw;
if (file_exists($filename)) {
$in_stream=fopen($filename, "r");
$mode=fread($in_stream, 1);
if ($mode=="c") {
} elseif ($mode!="r") {
throw new Exception("Invalid file given.");
}
$ci=ord(fread($in_stream, 1));
$pos=0;
$files=array();
$buffer_size=2;
while ($ci!=255) {
$name_length="";
while ($ci!=255) {
$name_length.=chr($ci);
$ci=ord(fread($in_stream, 1));
$buffer_size++;
}
$name_length=$this->uncompress($name_length);
$name=gzuncompress(fread($in_stream, $name_length));
$buffer_size+=$name_length;
$size="";
$ci=ord(fread($in_stream, 1));
$buffer_size++;
while ($ci!=255) {
$size.=chr($ci);
$ci=ord(fread($in_stream, 1));
$buffer_size++;
}
$size=$this->uncompress($size);
$files[]=array(
"name"=>$name,
"size"=>$size,
"pos"=>$pos
);
$pos+=$size;
$ci=ord(fread($in_stream, 1));
$buffer_size++;
}
fclose($in_stream);
foreach($files as $info) {
$this->filelist[]=new CFAEntry($info["name"], $filename, $info["size"], $info["pos"]+$buffer_size);
$buffer_size+=$info["size"];
}
}
}
public function getFileList() {
return $this->filelist;
}
public function remove($s_entry) {
$found=false;
foreach ($this->filelist as $k=>$entry) {
if ($entry===$s_entry) {
$found=true;
unset($this->filelist[$k]);
}
}
if ($found) $this->filelist=array_merge($this->filelist, array());
}
public function add($entry) {
if (!$entry instanceof CFAEntry) return;
$this->filelist[]=$entry;
}
public function flushToFile() {
if ($this->password!=null) {
$stream=tmpfile();
} else {
$stream=fopen($this->filename, "w+");
fwrite($stream, "r");
}
foreach ($this->filelist as $entry) {
$name=gzcompress($entry->getName());
fwrite($stream, $this->compress(strlen($name)));
fwrite($stream, chr(255));
fwrite($stream, $name);
fwrite($stream, $this->compress($entry->getSize()));
fwrite($stream, chr(255));
}
fwrite($stream, chr(255));
foreach ($this->filelist as $entry) {
$handle=$entry->getFileHandle();
$POS=ftell($handle);
rewind($handle);
while (!feof($handle)) {
fwrite($stream, fread($handle, 1));
}
fseek($handle, $POS);
}
}
public static function uncompress($bytes) {
$j=strlen($bytes)-1;
$full=0;
$c=-1;
$i=0;
$c=ord($bytes[0]);
while ($c!=254 && $i!=$j) {
$full+=$c;
$i++;
$c=ord($bytes[$i]);
}
$size=$full*253;
$i++;
while ($i<=$j) {
$c=$bytes[$i];
$size+=ord($c);
$i++;
}
return $size;
}
public static function compress($int) {
$comp="";
$full=0;
while ($int>=253) {
if ($full==253) {
$comp.=chr(253);
$full=0;
}
$full++;
$int-=253;
}
if ($full!=0) $comp.=chr($full);
$comp.=chr(254);
if ($int!=0) $comp.=chr($int);
return $comp;
}
}
class CFAEntry {
private $sourcefile="unknown";
private $filename;
private $size=-1;
private $start="unknown";
private $handle;
// 1 - Existiert, 2 - Muss erstellt werden
private $mode=-1;
public function __construct($name, $sourcefile=null, $size=null, $start=null) {
if ($sourcefile==null) {
$this->filename=$name;
$this->mode=2;
} else {
if (!file_exists($sourcefile)) {
throw new Exception($sourcefile." not found.");
}
$this->sourcefile=$sourcefile;
$this->filename=$name;
$this->size=$size;
$this->start=$start;
$this->mode=1;
}
}
public function __destruct() {
if ($this->handle!=null) fclose($this->handle);
}
public function getSize() {
if ($this->handle==null) {
if ($this->size!=-1) return $this->size;
return 0;
} else {
$info=fstat($this->handle);
return $info["size"];
}
}
public function getName() {
return $this->filename;
}
public function getSourcefile() {
return $this->sourcefile;
}
public function getFileHandle() {
if ($this->handle==null) {
$this->handle=tmpfile();
if ($this->mode==1) {
$nsize=(int) "".$this->size;
$sf_stream=fopen($this->sourcefile, "r");
fseek($sf_stream, $this->start);
while ($nsize>=100) {
fwrite($this->handle, fread($sf_stream, 100));
$nsize-=100;
}
if ($nsize!=0) fwrite($this->handle, fread($sf_stream, $nsize));
fclose($sf_stream);
rewind($this->handle);
}
}
return $this->handle;
}
}
?> |