<?php
class PLTemplate
{
	private $arrayConfig = array();
	public $xingTemplate_Class_Lang = array(
																			' 模板文件不存在或读取失败',
																			' 模板文件大小超出限制',
																			' 模板文件没有正常加载',
																			'严重错误',
																			'程序警告',
																			'语法错误',
																			'文件名称',
																			'错误等级',
																			'错误所在',
																			'错误信息',
																			'缓存文件路径',
																			'错误源产生在',
																			'行'
																		);
	public function __construct($arrayConfig = array())
	{		
		$this->arrayConfig['classDir'] = dirname(str_replace('\\','/',__FILE__));
		
		$this->arrayConfig += $arrayConfig;
		$this->arrayConfig['ClassName'] = __CLASS__;
		global $_xingTemplate_Class_Lang;
		if (is_array($_xingTemplate_Class_Lang)) 
		{
			$this->xingTemplate_Class_Lang += $_xingTemplate_Class_Lang;
		}
		$Plugins = $this->get_Template_Plugins();
		if (is_array($Plugins))
		{
			foreach ($Plugins as $p_path){ include $p_path; }
		}
			
	}
	public function setConfig($key, $value = null)
	{
		if (is_array($key))
		{
			$this->arrayConfig += $key;
		}else{
			$this->arrayConfig[$key] = $value;
		}
	}
	public function getConfig($key = null)
	{
		if ($key)
		{
			return $this->arrayConfig[$key];
		}
		return $this->arrayConfig;
	}
	public function assign($key,$val = null)
	{
		if (empty($key)) return '';
		if (is_array($key))
		{
			foreach ($key as $k=>$v)
			{
				$this->arrayConfig['GLOBALS'][$k] = $v;
			}
		}else{
			$this->arrayConfig['GLOBALS'][$key] = $val;	
		}
	}
	private function & get_Value($key)
	{
		if (isset($this->arrayConfig['GLOBALS'][$key]))
		{
			return $this->arrayConfig['GLOBALS'][$key];
		}else{
			global $$key;
				if ($$key)
				{
					$this->assign($key,$$key);
				}
				return $$key;
		}
	}
	private function get_Template_Path($templateName)
	{
		return $this->arrayConfig['templateDir'][(empty($this->arrayConfig['template_Name']) ? 'default' : $this->arrayConfig['template_Name'])].'/'.$templateName.$this->arrayConfig['templateExt'];
	}
	
	private function get_Template_Compile_Path($templateName)
	{
		return $this->arrayConfig['classDir'].'/'.$this->arrayConfig['templateCompileDir'].'/'.md5($this->get_Template_Path($templateName)).$this->arrayConfig['templateCompileExt'];
	}
	private function get_Template_Cache_Path($templateName, $all = false)
	{
		if ($all)
		{
			if ($all === true)
			{
				$tmp_path = md5($templateName).'*';
			}else{
				$tmp_path = md5($templateName).$all;
			}
		}else{
			$tmp_path = md5($templateName).$this->arrayConfig['cacheId'];
			
		}
		return $this->arrayConfig['classDir'].'/'.$this->arrayConfig['templateCacheDir'].'/'.$tmp_path.$this->arrayConfig['templateCacheExt'];
	}
	private function get_Template_Plugins()
	{
		if (is_dir($this->arrayConfig['classDir'].'/'.$this->arrayConfig['templatePluginsDir'].'/'))
		{
			return glob($this->arrayConfig['classDir'].'/'.$this->arrayConfig['templatePluginsDir'].'/*.php');
		}
	}
	public function is_cached($templateName)
	{
		$_PATH = $this->get_Template_Cache_Path($templateName);
		if (!file_exists($_PATH))
		{
			return false;
		}elseif (filemtime($_PATH) + $this->arrayConfig['cache_time'] < time()){
			return false;
		}else{
			return true;
		}
	}
	private function template_Read($PATH)
	{
		if (function_exists('file_get_contents'))
		{
			return file_get_contents($PATH);
		}else{
			$fopen = fopen($PATH,'r');
			$template_Content = '';
			do {
				$data = fread($fopen,1024);
				if (strlen($data)===0) break;
				$template_Content .= $data;
			}while(1);
			fclose($fopen);
			
			return $template_Content;
		}
	}
	

	private function template_Write($PATH,$String)
	{

		$this->template_CreateDir(dirname($PATH));


			$fopen = fopen($PATH,'w');
				flock($fopen, LOCK_EX + LOCK_NB);
				$fwrite = fwrite($fopen,$String);
	
					if (!$fwrite) $fwrite = fwrite($fopen,$String);
				flock($fopen, LOCK_UN + LOCK_NB);
			fclose($fopen);

		return $fwrite;
	}
	
	private function template_CreateDir($Dir)
	{
		if (is_dir($Dir))
		 return true;
		 
		if (mkdir($Dir, $this->arrayConfig['dir_mode']))
			return true;
		
		if (!$this->template_CreateDir(dirname($Dir)))
		 return false;
		
		return mkdir($Dir, $this->arrayConfig['dir_mode']);
	}
	

	public function getMicrotime()
	{
		list($microtime_1,$microtime_2) = explode(' ',microtime());
		return $microtime_1 + $microtime_2;
	}

	public function display($templateName, $key = '',$Clean = 0)
	{
		$this->xingTemplate_Display($templateName,$Clean,'display',$key);
	}
	
	public function fetch($templateName, $key = '')
	{
		return $this->xingTemplate_Display($templateName,$Clean,'output',$key);
	}

	private function xingTemplate_Display($templateName,$Clean = 0,$display = '',$key = '')
	{

		if (!$this->arrayConfig['error_reporting'])
		{
			$xingTemplate_old_err = error_reporting();
				error_reporting(E_ERROR | E_WARNING | E_PARSE);
		}

		if ($key)
		{
			$tmp_key = $this->arrayConfig['template_Name'];
			$this->arrayConfig['template_Name'] = $key;
		}
		
		$this->arrayConfig['Runtime'] = $this->getMicrotime();
		
		if ($this->arrayConfig['cache_is'])
			$_PATH = $this->get_Template_Cache_Path($templateName);
		
		if (!$this->is_cached($templateName) || $Clean)
		{	
			if ($this->arrayConfig['compatible'])
			{
				ob_start();
			}else{

				$class_debug = new xingTemplate_debug($this);
				
				ob_start(array($class_debug,'xingTemplate_xError'));
			}
					include $this->xingTemplate_compile($templateName,$Clean);
					
					$xingTemplate_Content = ob_get_contents();
				ob_end_clean();

		}else{
			$xingTemplate_Content = $this->template_Read($_PATH);
		}

			if ($this->arrayConfig['cache_is'])
			{
	
				if (!$this->is_cached($templateName))
					$this->template_write($_PATH,$xingTemplate_Content);
			}
		
			if ($this->arrayConfig['debug'])
			{
				unset($this->arrayConfig['GLOBALS'][$this->arrayConfig['ClassName']]);
				ob_start(); print_r($this->arrayConfig); $debug = ob_get_contents(); ob_end_clean();
				$xingTemplate_Content .= '<div id="Me" style="display:none;">'.highlight_string($debug,1).'</div>'.'<script type="text/javascript">var code=document.getElementById("Me").innerHTML;var newwin=window.open("","","height=600 ,width=500,scrollbars=yes");  newwin.opener = null ;newwin.document.write(code); newwin.document.close();</script>';		
			}
			
			switch ($display)
			{
				case 'display':
						echo $xingTemplate_Content;
						
						$xingTemplate_Content = null;
				break;
			}
			
			/* 返回执行时间 */
		$this->template_Runtime();
		
		if (isset($tmp_key)) $this->arrayConfig['template_Name'] = $tmp_key;

		if ($this->arrayConfig['gzip_off'] && ereg('gzip',$_SERVER['HTTP_ACCEPT_ENCODING']))
		{
			ob_start('ob_gzhandler');
		}
		
		/* 定义错误信息 */
		if (!$this->arrayConfig['error_reporting'])
			error_reporting($xingTemplate_old_err);
		
		return $xingTemplate_Content;
	}
	

	private function ConverTag($Tag)
	{
		$_count = strlen($Tag);
		$new_array = array('{','}','[',']','$','(',')','*','+','.','?','\\','^','|');
		$Tag_ = '';
		for ($i=0;$i<$_count;$i++)
		{
			$Tag_ .= (in_array($Tag[$i],$new_array)?'\\':'').$Tag[$i];
		}
		return $Tag_;
	}


	private function xingTemplate_compile($templateName,$Clean = 0)
	{
		$_PATH = array();


		$_PATH['From'] =  $this->get_Template_Path($templateName);
		$_PATH['Save'] =  $this->get_Template_Compile_Path($templateName);
		
	
		if (!file_exists($_PATH['From'])) return $_PATH['From'].' {'.$templateName.$this->xingTemplate_Class_Lang[0].'}';


		if ($this->arrayConfig['force_compile']) $Clean = 1;
		
		if (!$Clean)
		{
			if (file_exists($_PATH['From']))
				$_fromt = filemtime($_PATH['From']);
			if (file_exists($_PATH['Save']))
				$_savet = filemtime($_PATH['Save']);

			if ($_fromt <= $_savet)
			{
				return $_PATH['Save'];
			}
		}
		

		if (filesize($_PATH['From']) > $this->arrayConfig['file_max'] * 1024 * 1024) return $this->xingTemplate_Error($templateName.$this->xingTemplate_Class_Lang[1].' ('.$this->arrayConfig['file_max'].' M)');
		

		$_Left = '(?<!!)'.$this->ConverTag($this->arrayConfig['left_tag']);
		$_Right = '((?<![!]))'.$this->ConverTag($this->arrayConfig['right_tag']);
		
	
		$xingTemplate_Conver = $this->template_read($_PATH['From']);

		if (empty($xingTemplate_Conver))
		{
			$this->template_Write($_PATH['Save'],$xingTemplate_Conver);
			return $_PATH['Save'];
		}
		
		$xingTemplate_Conver = trim($xingTemplate_Conver);
		
		preg_match_all('/'.$_Left.'载入模板"(([\w|-|\/]{1,})|(\$([_a-zA-Z][\w]+)))"'.$_Right.'/',$xingTemplate_Conver,$Include_);
		$Include_count = count($Include_[0]);
		

		for ($i=0;$i< $Include_count;$i++)
		{
			$xingTemplate_Conver = str_replace($Include_[0][$i],$this->arrayConfig['left_tag'].'eval include $this->xingTemplate_compile("'.$Include_[1][$i].'")'.$this->arrayConfig['right_tag'],$xingTemplate_Conver);
		
		}
		unset($Include_);

		preg_match_all('/\$([_a-zA-Z][\w]+)/',$xingTemplate_Conver,$Global_var);

		if (is_array($Global_var[1]))
		{	
			$Global_var[1] = array_unique($Global_var[1]);

			$Global_var_Im = array('this','_GET','_POST','_COOKIE','_SERVER','_SESSION','_FILES','_ENV');
			$Global_var_out = '';

			foreach ($Global_var[1] as $val)
			{
				if (!in_array($val,$Global_var_Im))
				{
					$Global_var_out .= '$'.$val.' =& $this->get_Value(\''.$val.'\'); ';

				}
			}
		}

		$Template_preg = array();
		$Template_Replace = array();


		if ($this->arrayConfig['PHP_off'] === false)
		{
			$xingTemplate_Preg[] = '/<\?(=|php|)(.+?)\?>/is';
			
			$xingTemplate_Replace[] = '&lt;?\\1\\2?&gt;';
		}


	
 
		$xingTemplate_Preg[] = '/'.$_Left."(eval|_)( |[\r\n])(.*?)".$_Right.'/is';
		$xingTemplate_Preg[] = '/'.$_Left.'输出:(.*?)'.$_Right.'/is';
		$xingTemplate_Preg[] = '/<!--'.$_Left.'php (.*?)'.$_Right.'-->/is';
		$xingTemplate_Preg[] = '/'.$_Left.'php (.*?)'.$_Right.'/is';
		$xingTemplate_Preg[] = '/'.$_Left.'打印数组:(.*?)'.$_Right.'/i';
		$xingTemplate_Preg[] = '/'.$_Left.'\/(if|show|for|foreach|eval|while)'.$_Right.'/i'; 
		$xingTemplate_Preg[] = '/'.$_Left.'((( *(\+\+|--) *)*?(([_a-zA-Z][\w]*\(.*?\))|\$((\w+)((\[|\()(\'|")?\$*\w*(\'|")?(\)|\]))*((->)?\$?(\w*)(\((\'|")?(.*?)(\'|")?\)|))){0,})( *\.?[^ \.]*? *)*?){1,})'.$_Right.'/i'; 
		$xingTemplate_Preg[] = "/(	| ){0,}(\r\n){1,}\";/"; 
		$xingTemplate_Preg[] = '/<模板注释:"(.*?)">/';
		$xingTemplate_Preg[] = '/<!:"(.*?)">/'; 
		$xingTemplate_Preg[] = '/'.$_Left.'\%([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)'.$_Right.'/';
		$xingTemplate_Preg[] = '/'.$_Left.'循环\s+(\S+)\s+(\S+)'.$_Right.'/';
		$xingTemplate_Preg[] = '/'.$_Left.'循环\s+(\S+)\s+(\S+)\s+(\S+)'.$_Right.'/';
		$xingTemplate_Preg[] = '/'.$_Left.'\/循环'.$_Right.'/';
		$xingTemplate_Preg[] = '/'.$_Left.'假设\s+(.*?)'.$_Right.'/i';
		$xingTemplate_Preg[] = '/'.$_Left.'\/假设'.$_Right.'/i';
		$xingTemplate_Preg[] = '/#读取循环数据/i';
		$xingTemplate_Preg[] = '/#读取单个数据/i';
		$xingTemplate_Preg[] = '/#读取缓存数据/i';
		$xingTemplate_Preg[] = '/#分类名称/i';
		$xingTemplate_Preg[] = '/'.$_Left.'否则'.$_Right.'/i';
		$xingTemplate_Preg[] = '/'.$_Left.'(否则 假设|否则假设) (.*?)'.$_Right.'/i';
		$xingTemplate_Preg[] = '/'.$_Left.'因为 (.*?)'.$_Right.'/i';
		$xingTemplate_Preg[] = '/'.$_Left.'当循环 (.*?)'.$_Right.'/i';
		$xingTemplate_Preg[] = '/#频道路径/i';
		$xingTemplate_Preg[] = '/#风格路径/i';
		$xingTemplate_Preg[] = '/#网址/i';
		$xingTemplate_Preg[] = '/'.$_Left.'list\s+(\S+)\s+(\S+)'.$_Right.'/';
		$xingTemplate_Preg[] = '/'.$_Left.'list\s+(\S+)\s+(\S+)\s+(\S+)'.$_Right.'/';
		$xingTemplate_Preg[] = '/'.$_Left.'\/list'.$_Right.'/';
		$xingTemplate_Preg[] = '/'.$_Left.'show\s+(\S+)'.$_Right.'/i';
		$xingTemplate_Preg[] = '/'.$_Left.'if (.*?)'.$_Right.'/i'; 
		$xingTemplate_Preg[] = '/'.$_Left.'else'.$_Right.'/i';
		$xingTemplate_Preg[] = '/'.$_Left.'->(.*?)'.$_Right.'/is';
	
		
		
         
		$xingTemplate_Replace[] = '<?php \\3; ?>';
		$xingTemplate_Replace[] = '<?php echo \\1; ?>';
		$xingTemplate_Replace[] = '<?php \\1; ?>';
		$xingTemplate_Replace[] = '<?php \\1; ?>';
		$xingTemplate_Replace[] = '<?php print_r(\\1); ?>';
		$xingTemplate_Replace[] = '<?php } ?>';
		$xingTemplate_Replace[] = '<?php echo \\1;?>';
		$xingTemplate_Replace[] = '';
		$xingTemplate_Replace[] = '';
		$xingTemplate_Replace[] = '';
		$xingTemplate_Replace[] = '<?php echo $this->lang_array[\'\\1\'];?>';
		$xingTemplate_Replace[] = '<?php if(is_array(\\1)) { foreach(\\1 as \\2) { ?>';
		$xingTemplate_Replace[] = '<?php if(is_array(\\1)) { foreach(\\1 as \\2 => \\3) { ?>';
		$xingTemplate_Replace[] = '<?php } } ?>';
		$xingTemplate_Replace[] = '<?php if (\\1){ ?>';
		$xingTemplate_Replace[] = '<?php } ?>';
		$xingTemplate_Replace[] = 'sql_list';
		$xingTemplate_Replace[] = 'sql_show';
		$xingTemplate_Replace[] = 'cache_read';
		$xingTemplate_Replace[] = 'catname';
		$xingTemplate_Replace[] = '<?php }else{ ?>';
		$xingTemplate_Replace[] = '<?php }else if (\\2){ ?>';
		$xingTemplate_Replace[] = '<?php for (\\1) { ?>';
		$xingTemplate_Replace[] = '<?php while (\\1) { ?>';
		$xingTemplate_Replace[] = 'modurl';
		$xingTemplate_Replace[] = 'PL_SKIN';
		$xingTemplate_Replace[] = 'PL_URL';
		$xingTemplate_Replace[] = '<?php if(is_array(\\1)) { foreach(\\1 as \\2) { ?>';
		$xingTemplate_Replace[] = '<?php if(is_array(\\1)) { foreach(\\1 as \\2 => \\3) { ?>';
		$xingTemplate_Replace[] = '<?php } } ?>';
		$xingTemplate_Replace[] = '<?php if (\\1){ ?>';
		$xingTemplate_Replace[] = '<?php if (\\1){ ?>';
		$xingTemplate_Replace[] = '<?php }else{ ?>';
		$xingTemplate_Replace[] = '<?php echo \\1; ?>';

		
		
		  /* 在有必要时 开启 */  
		//ksort($xingTemplate_Preg);
		//ksort($xingTemplate_Replace);
				

		$xingTemplate_Conver=preg_replace($xingTemplate_Preg,$xingTemplate_Replace,$xingTemplate_Conver);

		$xingTemplate_Conver = str_replace(array('!'.$this->arrayConfig['right_tag'],'!'.$this->arrayConfig['left_tag'],'?><?php'),array($this->arrayConfig['right_tag'],$this->arrayConfig['left_tag'],''),$xingTemplate_Conver);

		if ($Global_var_out)
		{
			$xingTemplate_Conver = "<?php $Global_var_out ?>\r\n".$xingTemplate_Conver;
		}
		
		$this->template_write($_PATH['Save'],$xingTemplate_Conver);
		
		
		return $_PATH['Save'];

	}



	private function xingTemplate_Error($Msg)
	{
		echo $Msg;
		
		/*exit;*/
	}
	

	
	/* 清理缓存输出 或缓存 */
	public function xingTemplate_clean($type = 'cache')
	{
		
		switch ($type)
		{
			/* 判断是否是输出缓存 */
			case 'cache':
				$_PATH = dirname($this->get_Template_Cache_Path('_'));
				$_END = $this->arrayConfig['templateCacheExt'];
			
				$_PATH_ = glob($_PATH.'/*'.$_END);
			break;
			
			/* 判断是否是模板缓存 */
			case 'compile':
				$_PATH = dirname($this->get_Template_Compile_Path('_'));
				$_END = $this->arrayConfig['templateCompileExt'];
			
				$_PATH_ = glob($_PATH.'/*'.$_END);
			break;
		}
		
		 /* 判断是否是输出缓存 */
		if (!empty($type) && empty($_PATH))
		{
			echo $_PATH = $this->get_Template_Cache_Path($type, true);
			
			$_PATH_ = glob($_PATH);
		}
		
		if ($_PATH_)
		{
			
			if (is_array($_PATH_))
			{
				$j = 0;
				foreach ($_PATH_ as $val)
				{
					if (file_exists($val))
					{
						unlink($val);
						$j ++;
					}
				}
				return $j;
			}else{
				return false;
			}
		}
		
		return false;
	}
	
	/* 获取实时模板引擎运行时间 */
	public function template_Runtime()
	{
		/* 返回执行时间 */
		return $this->arrayConfig['Runtime'] = round($this->getMicrotime() - $this->arrayConfig['Runtime'],5);
	}

  /* 释放资源 */ 
	public function __destruct()
	{
		$this->arrayConfig = null;
	}
	
	//类结束

}




?>