<?
ini_set('display_errors', 'Off');
ini_set('track_errors', 1);
ini_set('memory_limit','100M');
error_reporting(0);
set_time_limit(300);

register_shutdown_function('serval_shutdown_func');

Class Scanner{
	var $log = array(
		'scan'=>array(),
		'dir'=>array(),
		'file'=>array()
	);
	var $ext 			= false;
	var $exc 			= false;
	var $rootDir 	= '';
	var $dirId 		= 1;
	var $version 	= 1.6;
	var $maxDir		= 100;
	var $isTest		= false;
	
	function run($param = array()){
		if(!is_array($param) || empty($param['path'])){
			return array("status"=>'error','version'=>$this->version,'msg'=>"Ошибка передачи данных");
		}
		$param['path'] = $this->fixPath(($param['path'] === '.' ? $_SERVER['DOCUMENT_ROOT'] : $param['path']));
		if($param['dirMax']>0){
			$this->maxDir = $param['dirMax'];
		}
		if($param['is_test']=="yes"){
			$this->isTest = true;
		}
		
		if(is_dir($param['path'])){
			if(is_array($param['ext']) && count($param['ext'])>0){
				foreach($param['ext'] as $v){
					$v = trim($v);
					if(!empty($v)){
						$this->ext[] = $v;
					}
				}
			}
			$this->ext = (is_array($param['ext']) && count($param['ext'])>0) ? $param['ext'] : false;
			if(is_array($param['exc']) && count($param['exc'])>0){
				foreach($param['exc'] as $v){
					$v = trim($v);
					if(!empty($v)){
						$dir = $param['path'].'/'.$v.'/';
						$this->exc[] = $this->fixPath($dir,false);
					}
				}
			}
			
			$this->rootDir = $param['path'];
			if(is_array($param['listDir']) && count($param['listDir'])>0){
				foreach($param['listDir'] as $val){
					if(!empty($val)){
						$this->dirId++;
						$this->log['dir'][$this->dirId] = $val;
						$this->find($val['path'],$this->dirId,($val['level']+1));
					}
				}
			}else{
				$this->find($param['path'],$this->dirId);
			}
			return array("status"=>'ok','dirMax'=>$this->maxDir,'version'=>$this->version,'log'=>$this->log);
		}else{
			return array("status"=>'error','version'=>$this->version,'msg'=>"Ошибка! root папка не доступна!");
		}
	}
	
	function find($path,$dirId,$i=0){
		if(count($this->log['scan'])>=$this->maxDir) return false; /* Максимум который можно просканить */
		if($i>100) return false; /* Если большая вложеность */
		
		$path 		= $this->fixPath($path.'/');
		$fixPath 	= $this->fixPath($path.'/',false);
		
		$list = glob($path."{.*,*}",GLOB_BRACE);
		if(isset($this->log['dir'][$dirId])){
    	$this->log['scan'][$dirId] = $this->log['dir'][$dirId];
    }
    unset($this->log['dir'][$dirId]);
		if(count($list)>0){
			foreach($list as $val){
				$pathInfo = pathinfo($val);
				if($pathInfo['basename'] === '.' || $pathInfo['basename'] === '..' || is_link($val)) continue;
				if($this->exc && in_array($val.'/',$this->exc) ) continue;
				
				if(is_dir($val)){
				 	$PathName = $this->fixPath($pathInfo['dirname'].'/'.$pathInfo['basename'].'/',false); 
					if(empty($PathName)) continue;
					$this->dirId++;
					$this->log['dir'][$this->dirId] = array('path'=>$PathName,'level'=>$i);
					if(!$this->isTest){
						$this->find($val,$this->dirId,($i+1));
					}
				}
				
				if(is_file($val)){
					if(!$this->ext || in_array(".".$pathInfo['extension'],$this->ext)){
						$this->log['file'][] = array(
							'dirId'=>$dirId,
							'level'=>$i,
							'name'=>$pathInfo['basename'],
							'size'=>filesize($val),
							'hash'=>$this->hashFile($val),
						);
					}	
				}
				unset($pathInfo);
			}
		}
		unset($list);
	}
	
	function fixPath($val,$root = true){
		$val = $this->rootDir.'/'.str_replace($this->rootDir,"/",$val);
		if(!$root){ /* Удаляем рутовую директорию */
			$val = '/'.str_replace($this->rootDir,"/",$val);
		}
		return preg_replace('~[\/]+~u','/',$val);
	}
	
	function hashFile($file){
		$hash = false;
		if (function_exists('hash_file')) {
			$hash = @hash_file('md5', $file);
		} elseif(function_exists('md5_file')) {
		  $hash = @md5_file($file);
		} else {
			if($c = file_get_contents($file)){
				$hash = md5($c);
				unset($c);
			}
		}
		return $hash ? $hash : -1;
	}
	
}

Class BritCrypt{
	var $key 					= null;
	var $encodingIn 	= 'UTF-8';
	var $encodingOut 	= 'CP866';
	var $stb					= 63;
	var $type					= 'default';
		
	function encrypt($string=''){
		if(empty($this->key)) return false;
		if($this->type=="lite"){
			return $this->crypt_lite($string);
		}else{
			$keyw = $this->calculateKeyw($string);
			$Len = mb_strlen($string, $this->encodingIn);
			
			$result = '';
	    for ($i = 0; $i < $Len; $i++) {
		    $char = mb_substr($string, $i, 1, $this->encodingIn);
		    $ord = ord(iconv($this->encodingIn, $this->encodingOut, $char));
		    $char = chr(($ord - $this->stb) ^ $keyw[$i]);   
		    $result.= iconv($this->encodingOut, $this->encodingIn, $char);
	    }
	    unset($string);
			return $result;
		}
	}
	
  function calculateKeyw($pass){
	    $keyw = array();
	    $lenPass = mb_strlen($pass, $this->encodingIn);
	    $lenKey = mb_strlen($this->key, $this->encodingIn);
	    for ($i = 1; $i <= $lenPass; $i++) {
	        if ($lenKey < $lenPass) {
	            $j = $i % $lenKey;
	            if ($j === 0) {
	                $j = $lenKey;
	            }
	        } else {
	            $j = $i;
	        }
	
	        $keyw[] = ord(mb_substr($this->key, $j - 1, 1, $this->encodingIn));
	    }
	    return $keyw;
  }
  
	function decrypt($string=''){   
		if(empty($this->key)) return false;
		if($this->type=="lite"){
				return $this->crypt_lite($string);
		}else{
				$keyw = $this->calculateKeyw($string);
				$Len = mb_strlen($string, $this->encodingIn);
				$result = '';
				for ($i = 0; $i < $Len; $i++) {
					$char = mb_substr($string, $i, 1, $this->encodingIn);
					$ord = ord(iconv($this->encodingIn, $this->encodingOut, $char));
					$ord = $ord ^ $keyw[$i];
					$result .=iconv($this->encodingOut, $this->encodingIn, chr($ord + $this->stb));
				}
				unset($string);      
				return $result;
		}
	}
	
	function crypt_lite($string){
		if(empty($this->key)) return false;
		for($i=0;$i<mb_strlen($string,'utf-8');){
			for($j=0;$j<mb_strlen($this->key,'utf-8');$j++, $i++){
				$outText .= $string{$i} ^ $this->key{$j};
			}
		}
		unset($string);
		return $outText;
	}
	
}

$_POST['_scan_isOk'] = false;
if(isset($_POST['run']) && $_POST['run']=="DoCheckThis"){
	$sCode  			= "{[sCODE]}";
	$_crypt 			= new BritCrypt;
	$_crypt->key 	= $sCode;  
	$_crypt->type = $_POST['crypt_type'];
	$data					= unserialize($_crypt->decrypt(base64_decode($_POST['data'])));
	unset($_POST['data']);
	$scan 		= new Scanner();
	$result 	= $scan->run($data);
	unset($data);
	echo $_crypt->encrypt(base64_encode(serialize($result)));
	$_POST['_scan_isOk'] = true;
}

function serval_shutdown_func(){
	if(!$_POST['_scan_isOk']){
		$error  			= error_get_last();
		$sCode  			= "8ef0ae4e3d4625f8f14b84c6c4be7f6d";
		$_crypt 			= new BritCrypt($sCode);
		$_crypt->type = $_POST['crypt_type'];
		$result 			= array('status'=>'error','msg'=>"Error: ".$error['message']);
		echo $_crypt->encrypt(serialize($result));
		die();
	}
}
?>