View file pckii.php

File size: 6.41Kb
#!/usr/bin/php
<?php
/**** *** 
 *  *** ***
 *  Pckii
 *  Packer by Im Ieee :)
 *  v 1.1.0 - 2012
 *  ieee[[at]]bk.ru
 *  http://wapsait.pp.ru 
 *  * * * *
*/
/*default output file*/
define('DEF_OUT', 'pckii_compr.php');
/*zlib library was not found :(*/
define('NO_ZLIB', "I need zlib!\n");
/*no -d argument*/
define('SPECIFY_DIR', "Please, specify dir, which I should pack.\n");
/*can not read something*/
define('NOT_RDBL', "Could not read '%s'.\n");
/*output file can not be opened*/
define('CANT_OP_OUT', "Could not open output file: %s.\n");
/*writing something*/
define('WR_DIR', "Writing directory %s.\n");
define('WR_FIL', "Writing file %s.\n");
/*final message*/
define('OK', "Created file %s, contains %u dirs, %u files. Compression: %.2f%%.\n");

define('HELP',
'
  Pckii archiver tool v1.1.0
  creates self-unpacking php scripts
  usage pckii -d[irectory] DIRECTORY
  other options:
  -o[utput] FILE specifies an output file (default: '.DEF_OUT.')
  -b[egin] FILE includes a file at the beginning of the script
  -e[nd] FILE includes a file at the end of the script
  -r[oot] DIR specifies a directory, which will contain packed files
  -c[ompat] enable compatibility with php 5.0 (default - with php 5.1) 
  -v[erbose] write file and directory names (turned off by default)
  -h[elp] show this help
  (c) Im ieee, 2011-2012
'
);
/*can not create something*/
define('CANT_CREATE_DIR','Could not create directory:');
define('CANT_CREATE_FILE','Could not create file:');
/*parsing options*/
$argv[]=$begin=$end=$r_start=$r_end='';
$cmp=false;
for($i=0; $i<$argc; $i++){
	switch($argv[$i]){
	case '-b': case '-begin': 
		(is_readable($argv[++$i])&&is_file($argv[$i])) || die(sprintf(NOT_RDBL, $argv[$i]));
		$begin=file_get_contents($argv[$i]); break;
	case '-e': case '-end':
		(is_readable($argv[++$i])&&is_file($argv[$i])) || die(sprintf(NOT_RDBL, $argv[$i]));
		$end=file_get_contents($argv[$i]); break;
	case '-d': case '-directory':
		(is_readable($argv[++$i])&&is_dir($argv[$i])) || die(sprintf(NOT_RDBL, $argv[$i]));
		$start_dir=rtrim($argv[$i], '/\\'); break;
		case '-r': case '-root':
			$r_start=str_replace('\\', '', rtrim($argv[++$i], '/\\')).'\\'; 
			$r_end='\\'; break;
		case '-c': case '-compat':
			$cmp=true; break;
	case '-o': case '-output':
		$out_f=$argv[++$i]; break;
	case '-h': case '-help': die(HELP);
	case '-v': case '-verbose': $verb=true; break;
	}
}
/*some checks*/
function_exists('gzeof') || die(NO_ZLIB);
isset($start_dir) || die(SPECIFY_DIR);
isset($out_f) || $out_f=DEF_OUT; 
(@$fp_out=fopen($out_f, 'wb')) || die(sprintf(CANT_OP_OUT, $out_f));
/*main unpacking code*/
$main_code=str_replace(array("\n", "\r"), array('',''),'
$s=DIRECTORY_SEPARATOR;
$f=$p=""; 
while(!feof($g))
{
if(($c=fgetc($g))=="\\\\")
{
if($f!="")
{
@mkdir($p.=$f.$s)||print"'.addcslashes(CANT_CREATE_DIR, '$"\\').'".$p.PHP_EOL;
$f="";
}
else
$p=($b=strrpos(rtrim($p,"\\/"),$s))?substr($p,0,$b+1):"";
}
elseif($c=="/")
{
@(file_put_contents($p.$f,($c=fgetc($g))?fread($g,array_pop(unpack("V",fread($g,$c)."\\0\\0\\0"))):"")!==false)||print"'.addcslashes(CANT_CREATE_FILE, '$\\"').'".$p.PHP_EOL;
$f="";
}
else
$f.=$c;
}
');
/*gzip check and the end of php code ($off,$q - in $archive)*/
fwrite($fp_out,'<?php function_exists("gzeof")||die("'.addcslashes(NO_ZLIB,'$"\\').'");$q=');
$off=ftell($fp_out);
if($cmp){
	/*we need to create a temporary file*/
	$temp_f=tempnam('', 'pck');
	$fp_write=gzopen($temp_f, 'wb9');
} else {
	/*writing header*/
	$main_code=';eval(gzinflate(\''.
	addcslashes(gzdeflate($begin.
	'fseek($g=fopen($_SERVER["SCRIPT_FILENAME"],"rb"),$q);stream_filter_append($g,"zlib.inflate",STREAM_FILTER_READ,9);'.$main_code.$end,9),"'\\")
	.'\'));__halt_compiler();';
	/*oh yes, i could use CHO there but it is 24 bytes long :(*/
	$off+=strlen($main_code);
	$t=strlen($off);
	$off+=$t;
	(strlen($off)==$t) || $off++;
	fwrite($fp_out, $off.$main_code); 
	$fp_write=&$fp_out;
	stream_filter_append($fp_write,"zlib.deflate",STREAM_FILTER_WRITE,9);
}
$dir_c=$tot_size=$file_c=0;
/*it is called recursively, so it is function*/
function pack_dir($path, $dir, $start=false){
	global $fp_write, $dir_c, $file_c, $verb, $tot_size, $r_start, $r_end;
	/*root directory*/
	fwrite($fp_write, ($start)?$r_start:$dir.'\\');
	$dir=$path.$dir.DIRECTORY_SEPARATOR;
	($verb) && printf(WR_DIR, $dir);
	$dir_arr=scandir($dir);
	foreach($dir_arr as $node){
		if($node=='.'||$node=='..'){
		continue;
		}else if(!is_readable($dir.$node)){
		printf(NOT_RDBL, $dir.$node);
		continue;
		}else{
		$node=str_replace('\\', '', $node);
		if(is_file($dir.$node)){
		$file_c++;
				($verb) && printf(WR_FIL, $dir.$node);
				$size=filesize($dir.$node);
				$tot_size+=$size;
				/*size is packed as unsigned long, little endian*/
		$pck=rtrim(pack('V',$size), chr(0));
		fwrite($fp_write,$node.'/'.strlen($pck).$pck.file_get_contents($dir.$node));
		}else{
		$dir_c++;
		pack_dir($dir, $node);
		}
	}
	 }
	 fwrite($fp_write, ($start)?$r_end:'\\');
}
pack_dir($start_dir, '', true);
fclose($fp_write);
if($cmp){
	$fp_write=fopen($temp_f, 'r+');
	/*looking for <? and <% and replacing them with #? and #%*/
	define('BUF_SIZE', 4096);
	/*contains positions of < symbols*/
	$mtcs=array();
	$last=0;
	do{
		$buf=preg_split('/\<(?=\?|%|$)/i', fread($fp_write, BUF_SIZE));
		$not_end=!feof($fp_write);
		$len=sizeof($buf)-1;
		for($i=0; $i<$len; $i++){
			$mtcs[]=strlen($buf[$i])+$last;
			$last=0;
		}
		$last+=strlen($buf[$len]);
		$buf=join('#', $buf);
		fseek($fp_write, -strlen($buf), SEEK_CUR);
		fwrite($fp_write, $buf);
		/*we can not use feof there, because we're in the "write mode" :(*/
	}while($not_end);
	/*code that replaces #? with <?*/
	$repl_code=(sizeof($mtcs))?
	'foreach(array('.join(',',$mtcs).') as $b){stream_copy_to_stream($f,$g,$b,$q);$q+=$b+1;fputs($g,"<");}'.(($last)?'stream_copy_to_stream($f,$g,-1,$q);':''):
	'stream_copy_to_stream($f,$g);';
	$main_code=';eval(gzinflate(\''.
	addcslashes(gzdeflate($begin.
	'fseek($f=fopen($_SERVER["SCRIPT_FILENAME"],"rb"),$q);$g=fopen($n=tempnam("","pck"),"wb");'.$repl_code.'fclose($g);$g=gzopen($n,"rb");'.$main_code.'fclose($g);unlink($n);'.$end,9),"'\\")
	.'\'));die?>';
	/*we need to determine the end of php code in archive ($q)*/
	$off+=strlen($main_code);
	$t=strlen($off);
	$off+=$t;
	(strlen($off)==$t) || $off++;
	fwrite($fp_out, $off.$main_code);
	/*copying data from the temporary file*/
	fseek($fp_write, 0);
	stream_copy_to_stream($fp_write, $fp_out);
	fclose($fp_out);
	fclose($fp_write);
	unlink($temp_f);
}
printf(OK, $out_f, $dir_c, $file_c, ($tot_size/filesize($out_f)-1)*100);
?>