<?php
class xingTemplate
{
	// 引擎选项
	private $arrayConfig = array();
	// 类实例化 (进行数组设置)
	public function __construct($arrayConfig = array())
	{		
		$this->arrayConfig = $arrayConfig;
	}
	/* 取得模板路径 */
	private function get_Template_Path($templateName)
	{
		return $this->arrayConfig['templateDir'].'/'.$templateName.$this->arrayConfig['templateExt'];
	}
	/* 获取模板编译路径 */
	private function get_Template_Compile_Path($templateName)
	{
		return $this->arrayConfig['templateCompileDir'].'/'.md5($this->get_Template_Path($templateName)).$this->arrayConfig['templateCompileExt'];
	}
	/* 向模板引擎中注入变量 */
	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 template_Read($PATH)
	{
		return file_get_contents($PATH);
	}
	/* 写入文件 */
	private function template_Write($PATH,$String)
	{
		/* 调用递归创建目录  */
		$this->template_CreateDir(dirname($PATH));
			/* 以写入方式打开文件句柄,开启 flock  */
			$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, 0777))
			return true;
		if (!$this->template_CreateDir(dirname($Dir)))
		 return false;
		return mkdir($Dir, 0777);
	}
	/* 输出模板 */
	public function display($templateName)
	{
		$this->xingTemplate_Display($templateName,'display');
	}
	/* 返回输出模板 */
	public function fetch($templateName)
	{
		return $this->xingTemplate_Display($templateName,'output');
	}
	/* 输出模板 */
	private function xingTemplate_Display($templateName,$display = '')
	{
		ob_start();
		include $this->xingTemplate_compile($templateName);
		$xingTemplate_Content = ob_get_contents();
		ob_end_clean();
		if($display=='display') {
			echo $xingTemplate_Content;
			$xingTemplate_Content = null;
			return null;
		}else{
			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.' 模板文件不存在！}';
		/* 判断模板缓存文件是否需要更新  */
		if ($this->arrayConfig['force_compile']) $Clean = 1;
		if (!$Clean)
		{
			if (file_exists($_PATH['From']))
				$_fromtime = filemtime($_PATH['From']);
			if (file_exists($_PATH['Save'])) {
				$_savetime = filemtime($_PATH['Save']);
			}else{
				$_savetime=0;
			}
			if ($_fromtime <= $_savetime)
			{
				return $_PATH['Save'];
			}
		}
		/* 【【【【【模板进行相关编译起始】】】】】 */
		/* 取得有效标示  */
		$_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.'xingTemplate (([\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();
		 /* 判断是否允许插入PHP  */
		if ($this->arrayConfig['PHP_off'] === false)
		{
			$xingTemplate_Preg[] = '/<\?(=|php|)(.+?)\?>/is';
			$xingTemplate_Replace[] = '&lt;?\\1\\2?&gt;';
		}
		$xingTemplate_Preg[] = '/'.$_Left.'(else if|elseif) (.*?)'.$_Right.'/i'; 
		$xingTemplate_Preg[] = '/'.$_Left.'for (.*?)'.$_Right.'/i'; 
		$xingTemplate_Preg[] = '/'.$_Left.'while (.*?)'.$_Right.'/i'; 
		$xingTemplate_Preg[] = '/'.$_Left.'(loop|foreach) (.*?)'.$_Right.'/i'; 
		$xingTemplate_Preg[] = '/'.$_Left.'if (.*?)'.$_Right.'/i'; 
		$xingTemplate_Preg[] = '/'.$_Left.'else'.$_Right.'/i'; 
		$xingTemplate_Preg[] = '/'.$_Left."(eval|_)( |[\r\n])(.*?)".$_Right.'/is';
		$xingTemplate_Preg[] = '/'.$_Left.'_e (.*?)'.$_Right.'/is';
		$xingTemplate_Preg[] = '/'.$_Left.'_p (.*?)'.$_Right.'/i';
		$xingTemplate_Preg[] = '/'.$_Left.'\/(if|for|loop|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[] = '/'.$_Left.'(\#|\*)(.*?)(\#|\*)'.$_Right.'/'; 

			/* 编译为相应的PHP文件语法 _所产生错误在运行时提示  */
		$xingTemplate_Replace[] = '<?php }else if (\\2){ ?>';
		$xingTemplate_Replace[] = '<?php for (\\1) { ?>';
		$xingTemplate_Replace[] = '<?php while (\\1) { ?>';
		$xingTemplate_Replace[] = '<?php foreach ((array)\\2) { ?>';
		$xingTemplate_Replace[] = '<?php if (\\1){ ?>';
		$xingTemplate_Replace[] = '<?php }else{ ?>';
		$xingTemplate_Replace[] = '<?php \\3; ?>';
		$xingTemplate_Replace[] = '<?php echo \\1; ?>';
		$xingTemplate_Replace[] = '<?php print_r(\\1); ?>';
		$xingTemplate_Replace[] = '<?php } ?>';
		$xingTemplate_Replace[] = '<?php echo \\1;?>';
		$xingTemplate_Replace[] = '';
		$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'];
	}
	/* 释放资源 */ 
	public function __destruct()
	{
		$this->arrayConfig = null;
	}
}
?>