<?php

/*
  PHP version 5
  Copyright (c) 2002-2018 ECISP.CN、EarcLink.COM
  警告：这不是一个免费的软件，请在许可范围内使用，请尊重知识产权，侵权必究，举报有奖
  作者：黄祥云 E-mail:6326420@qq.com  QQ:6326420 TEL:18665655030
  ESPCMS官网介绍：http://www.ecisp.cn	企业建站：http://www.earclink.cn
 */

class ESPCMS_Templates_Parser {

	private $template_content;
	private $list_hash = '6623ef97c6f6ccf2fb032e800d2edda9';
	private $link_hash = '885BA145EFC8431D34F5CC06D142F143';
	private $get_hash = '214adb21252b0af7b03s214s9';
	private $get_table_hash = '60af7b03s21fs';
	private $find_hash = '4adb4912cd04e6fd3';
	private $pack_hash = 'E843B7A28BF9F9FC6D55A5A8EAE72F36';
	private $code_spc = false;

	public function compile($fetch_filename, $templates_path_dir, $templates_themss_dirname, $html_compile_dir, $left_delimiter, $right_delimiter) {
		$this->fetch_filename = $fetch_filename;
		$this->templates_themss_dirname = $templates_themss_dirname;
		$this->left_delimiter = preg_quote($left_delimiter);
		$this->right_delimiter = preg_quote($right_delimiter);
		$templates_filename = $templates_path_dir . $fetch_filename;
		$parsed_file = $html_compile_dir . md5($templates_filename) . '.php';
		if (!file_exists($templates_filename)) {
			espcms_message_err('public_pack-espcms_templates_filename_err', array($fetch_filename));
		}
		$fp = fopen($templates_filename, 'r');
		if (!$fp) {
			espcms_message_err('public_pack-espcms_templates_filename_fp_err', array($fetch_filename));
		}
		if (filesize($templates_filename)) {
			$this->template_content = fread($fp, filesize($templates_filename));
		} else {
			espcms_message_err('public_pack-espcms_templates_filename_size_err', array($fetch_filename));
		}
		fclose($fp);
		$this->_parse_common();
		$this->_parse_var();
		$this->_parse_for();
		$this->_parse_if();
		$this->_parse_fun();
		$this->_parse_link();
		$this->_parse_pack();
		$this->_parse_find();
		$this->_parse_class();
		$this->_parse_get();
		$this->_parse_list();
		$this->_parse_echo();
		if ($this->code_spc) {
			$this->template_content = $this->str_space($this->template_content);
		}
		$fp = fopen($parsed_file, 'w');
		fwrite($fp, $this->template_content);
		fclose($fp);
	}

	private function str_space($str) {
		if (!$str) {
			return false;
		}
		$str = preg_replace("/[\t]+/is", '', $str);
		$str = preg_replace("/([\s]{2,})/", '', $str);
		return $str;
	}

	private function _parse_common() {
		if (preg_match('/' . $this->left_delimiter . '\s*#\s*' . $this->right_delimiter . '/', $this->template_content)) {
			$patten = '/' . $this->left_delimiter . '\s*#\s*' . $this->right_delimiter . '\s*([^' . $this->left_delimiter . ']*)\s*' . $this->left_delimiter . '\s*#\s*' . $this->right_delimiter . '/';
			$this->template_content = preg_replace($patten, '<?php /* $1 */ ?>', $this->template_content);
		}
		return true;
	}

	private function _parse_var() {
		if (preg_match('/' . $this->left_delimiter . '\s*\\$[a-zA-Z0-9_]{1,}|$[a-zA-Z0-9_]{1,}\s*\|\s*([a-zA-Z_]+)\[([^]]+)\]\s*' . $this->right_delimiter . '/', $this->template_content)) {
			$patten = '/\$([A-Za-z]+[\w]+)/';
			$this->template_content = preg_replace($patten, "\$this->_tpl_vars['$1']", $this->template_content);
			$patten = '/(\$this->_tpl_vars\[\'[\w]+\'\])\.([\w]+)/';
			$this->template_content = preg_replace($patten, "\$1['$2']", $this->template_content);
		}
	}

	private function _parse_get() {
		if (preg_match('/' . $this->left_delimiter . '\s*get\s*name\s*=\s*[0-9a-zA-Z_]+/', $this->template_content)) {
			preg_match_all('/' . $this->left_delimiter . '\s*get[^\f]*?\/get' . $this->right_delimiter . '/', $this->template_content, $getarray);
			foreach ($getarray[0] as $key => $variable) {
				$bearkarray = array();
				preg_match_all('/' . $this->left_delimiter . '\s*get\s*name\s*=\s*([0-9a-zA-Z_]+)\s*(iscache=\s*([0-9]{1})|)\s*(cachefile=\s*([^\s]+)|)\s*(class=\s*([^%]+)|)*\s*' . $this->right_delimiter . '/', $variable, $bearkarray);
				$newbearkText = $this->_parse_array__get($bearkarray, $this->left_delimiter, $this->right_delimiter);
				$getout = str_replace($bearkarray[0][0], $newbearkText, $variable);
				$value_strget = '/' . $this->left_delimiter . '\s*get\s*name\s*=\s*([0-9a-zA-Z_]+)\s*(iscache=\s*([0-9]{1})|)\s*(cachefile=\s*([0-9a-zA-Z_,<\?\>\=\$\[\]\'\s-]+)|)\s*(class=\s*([^%]+)|)' . $this->right_delimiter . '/';
				$value_endget = '/' . $this->left_delimiter . '\s*\/get\s*' . $this->right_delimiter . '/';
				$getout = preg_replace($value_strget, $this->get_hash . '$1|$7|$3|$5|' . $this->get_table_hash, $getout);
				$getout = preg_replace($value_endget, $this->get_hash, $getout);
				$rec_book = '/' . preg_quote($bearkarray[0][0]) . '[^\f]*?' . $this->left_delimiter . '\s*\/get\s*' . $this->right_delimiter . '/';
				$this->template_content = preg_replace($rec_book, $getout, $this->template_content);
			}
		}
	}

	private function _parse_list() {
		if (strrchr($this->fetch_filename, '.') == '.lbi') {
			$this->template_content = preg_replace('/<meta\shttp-equiv=["|\']Content-Type["|\']\scontent=["|\']text\/html;\scharset=(?:.*?)["|\']>\r?\n?/i', '', $this->template_content);
		}
		if (preg_match('/' . $this->left_delimiter . '\s*list\s*name\s*=\s*[0-9a-zA-Z_]+/', $this->template_content)) {
			preg_match_all('/' . $this->left_delimiter . '\s*list\s*name\s*=\s*([0-9a-zA-Z_]+)\s*(file=\s*([0-9a-zA-Z_,]+)|)\s*(iscache=\s*([0-9]{1})|)\s*(cachefile=\s*([^\s]+)|)\s*(libdir=\s*([0-9a-zA-Z_,]+)|)\s*(class=\s*([^%]+)|)' . $this->right_delimiter . '/', $this->template_content, $bearkarray);
			foreach ($bearkarray[0] as $key => $variable) {
				if (!empty($bearkarray[11][$key])) {
					$textarray = array($bearkarray[0][$key], $bearkarray[1][$key], $bearkarray[2][$key], $bearkarray[3][$key], $bearkarray[4][$key], $bearkarray[5][$key], $bearkarray[6][$key], $bearkarray[7][$key], $bearkarray[8][$key], $bearkarray[9][$key], $bearkarray[10][$key], $bearkarray[11][$key]);
					$newbearkText = $this->_parse_array__list($textarray, $this->left_delimiter, $this->right_delimiter);
					$this->template_content = str_replace($variable, $newbearkText, $this->template_content);
				}
			}
			$value_beark = '/' . $this->left_delimiter . '\s*list\s*name\s*=\s*([0-9a-zA-Z_]+)\s*(file=\s*([0-9a-zA-Z_,]+)|)\s*(iscache=\s*([0-9]{1})|)\s*(cachefile=\s*([^\s]+)|)\s*(libdir=\s*([0-9a-zA-Z_,]+)|)\s*(class=\s*([^%]+)|)' . $this->right_delimiter . '/';
			$this->template_content = preg_replace($value_beark, $this->list_hash . '$1|$11|$3|$5|$7|$9|' . $this->list_hash, $this->template_content);
		}
	}

	private function _parse_for() {
		if (preg_match('/' . $this->left_delimiter . '\s*forlist[^\n]+' . $this->right_delimiter . '/', $this->template_content)) {
			if (preg_match('/' . $this->left_delimiter . '\s*\/forlist\s*' . $this->right_delimiter . '/', $this->template_content)) {
				preg_match_all('/\$this->_tpl_vars\[[\w\']+\]\[[\w]+\]\.[\w\[\]\.\\(\)\']+/', $this->template_content, $valueAt);
				foreach ($valueAt[0] as $key => $variable) {
					$arraylistNew = $this->_parse_value_preg($variable);
					$this->template_content = preg_replace('/' . preg_quote($variable) . '/', $arraylistNew, $this->template_content, 1);
				}
				preg_match_all('/' . $this->left_delimiter . '\s*forlist\s*([$\w-\>\=.\s\[\]\']+)\s*' . $this->right_delimiter . '/', $this->template_content, $forlistarray);
				for ($i = 0; $i < count($forlistarray[0]); $i++) {
					$tag_args = $forlistarray[0][$i];
					$attrs = $this->_parse_array_tag($tag_args);
					if (empty($attrs['key']))
						trigger_error('错误：FORLIST语句未设置key参数', E_USER_ERROR);
					if (empty($attrs['from']))
						trigger_error('错误：FORLIST语句未设置FROM参数', E_USER_ERROR);
					$value_forlist = '/key=>([\w]*)/';
					$this->template_content = preg_replace($value_forlist, "$$1+1", $this->template_content);
					$value_forlist = '/list=>([\w]*)/';
					$this->template_content = preg_replace($value_forlist, "$$1", $this->template_content);
					$value_forlist = '/' . $this->left_delimiter . '\s*div=>([\w]+)=([\w]+)\s*' . $this->right_delimiter . '/';
					if (preg_match($value_forlist, $this->template_content)) {
						if (preg_match('/' . $this->left_delimiter . '\s*\/div=>([\w]+)\s*' . $this->right_delimiter . '/', $this->template_content)) {
							$this->template_content = preg_replace($value_forlist, "<?php if(\$divid_$1==$2){ ?>", $this->template_content);
							$value_forlist = '/' . $this->left_delimiter . '\s*\/div=>([\w]+)\s*' . $this->right_delimiter . '/';
							$this->template_content = preg_replace($value_forlist, "<?php \$divid_$1=0;}\$divid_$1++;?>", $this->template_content);
						} else {
							trigger_error('错误：div语句没有封闭', E_USER_ERROR);
						}
					}
					$value_forlist = '/(\$this->_tpl_vars[^=]+)=>([\w]+)/';
					$this->template_content = preg_replace($value_forlist, "$1[$$2]", $this->template_content);
					$forlist_max = !empty($attrs['max']) ? $attrs['max'] : "count(" . $attrs['from'] . ")";
					$patten_forlist = $attrs['from'];
					$patten_forlist = '/' . $this->left_delimiter . '\s*forlist\s*' . preg_quote($forlistarray[1][$i]) . '\s*' . $this->right_delimiter . '/';
					$this->template_content = preg_replace($patten_forlist, "<?php if (count(" . $attrs['from'] . ")>0){\$divid_" . $attrs['key'] . "=1;for(\$" . $attrs['key'] . "=0;\$" . $attrs['key'] . "<" . $forlist_max . "; \$" . $attrs['key'] . "++){?>", $this->template_content);
				}
				$end_forlist = '/' . $this->left_delimiter . '\s*\/forlist\s*' . $this->right_delimiter . '/';
				$this->template_content = preg_replace($end_forlist, '<?php }} ?>', $this->template_content);
			} else {
				trigger_error('错误：语法错误,没有封闭FORLIST条件语句', E_USER_ERROR);
			}
		}
	}

	private function _parse_link() {
		if (preg_match("/" . $this->left_delimiter . "\s*link\s*file=[\'|\"]([^%]+)[\'|\"]\s*" . $this->right_delimiter . "/", $this->template_content, $file)) {
			if (trim($file[1]) == '')
				exit('错误：包含文件不能为空');
			$include_patten = '/' . $this->left_delimiter . '\s*link\s*file=[\'|\"]([^%]+)[\'|\"]\s*' . $this->right_delimiter . '/';
			$this->template_content = preg_replace($include_patten, $this->link_hash . $this->templates_themss_dirname . '$1|' . $this->link_hash, $this->template_content);
		}
		return true;
	}

	private function _parse_pack() {
		if (preg_match('/' . $this->left_delimiter . '\s*pack:[0-9a-zA-Z_-]+\s*/', $this->template_content)) {
			preg_match_all('/' . $this->left_delimiter . '\s*pack:[0-9a-zA-Z_-]+\s*(class=[^\s]+\s*|)' . $this->right_delimiter . '/', $this->template_content, $getarray);
			foreach ($getarray[0] as $key => $variable) {
				$packarray = array();
				$pack_class_str = null;
				preg_match_all('/' . $this->left_delimiter . '\s*pack:([0-9a-zA-Z_-]+)\s*(class=([^\s]+)\s*|)' . $this->right_delimiter . '/', $variable, $packarray);
				if ($packarray[3][0]) {
					$pack_class_str = $this->_parse_array_pack($packarray[3][0]);
				}
				$this->template_content = str_replace($packarray[0][0], $this->pack_hash . $packarray[1][0] . '|' . $pack_class_str . $this->pack_hash, $this->template_content);
			}
		}
	}

	private function _parse_array_pack($bearkarray) {
		$classvar = explode(',', $bearkarray);
		$newarray = array();
		foreach ($classvar as $key => $variable) {
			if (strstr($variable, '$this->_tpl_vars')) {
				$echo_patten = '/(\$this->[^\,]+])/';
				$newarray[$key] = preg_replace($echo_patten, "<?php echo $1 ?>", $variable);
			} else {
				$newarray[$key] = $variable;
			}
		}
		if (is_array($newarray)) {
			$newText = implode(',', $newarray);
		} else {
			$newText = false;
		}
		return $newText;
	}

	private function _parse_find() {
		if (preg_match('/' . $this->left_delimiter . '\s*find:[0-9a-zA-Z_]+\s*class*=\s*/', $this->template_content)) {
			preg_match_all('/' . $this->left_delimiter . '\s*find:[0-9a-zA-Z_]+\s*class=[^\s]+\s*out=[^%]+\s*' . $this->right_delimiter . '/', $this->template_content, $getarray);
			foreach ($getarray[0] as $key => $variable) {
				$bearkarray = array();
				preg_match_all('/' . $this->left_delimiter . '\s*find:([0-9a-zA-Z_]+)\s*class=([^\s]+)\s*out=([^%]+)\s*' . $this->right_delimiter . '/', $variable, $bearkarray);
				$this->_parse_array_find($bearkarray);
			}
		}
	}

	private function _parse_array_find($bearkarray) {
		if (strstr($bearkarray[2][0], '$this->_tpl_vars')) {
			$bearkarray[4][0] = str_replace($bearkarray[2][0], "<?php echo " . $bearkarray[2][0] . "?>", $bearkarray[2][0]);
		} else {
			$bearkarray[4][0] = $bearkarray[2][0];
		}
		$this->template_content = str_replace($bearkarray[0][0], $this->find_hash . $bearkarray[1][0] . '|' . $bearkarray[4][0] . '|' . $bearkarray[3][0] . $this->find_hash, $this->template_content);
	}

	private function _parse_class() {
		if (preg_match('/' . $this->left_delimiter . '\s*class\s*=>\s*[^%]+\s*' . $this->right_delimiter . '/', $this->template_content)) {
			$fun_patten = '/class\s*=>\s*([^\)]+\))/';
			$this->template_content = preg_replace($fun_patten, "\$this->$1", $this->template_content);
		}
		return true;
	}

	private function _parse_if() {
		if (preg_match('/' . $this->left_delimiter . '\s*if\s*[^%]+\s*' . $this->right_delimiter . '/', $this->template_content)) {
			if (preg_match('/' . $this->left_delimiter . '\s*\/if\s*' . $this->right_delimiter . '/', $this->template_content)) {
				$if_patten = '/' . $this->left_delimiter . '\s*if\s*([^%]+)\s*' . $this->right_delimiter . '/';
				$elseif_patten = '/' . $this->left_delimiter . '\s*elseif\s*([^%]+)\s*' . $this->right_delimiter . '/';
				preg_match_all($if_patten, $this->template_content, $forlistarray);
				$else_patten = '/' . $this->left_delimiter . '\s*else\s*' . $this->right_delimiter . '/';
				$ef_patten = '/' . $this->left_delimiter . '\s*\/if\s*' . $this->right_delimiter . '/';
				$this->template_content = preg_replace($if_patten, "<?php if($1){ ?>", $this->template_content);
				$this->template_content = preg_replace($elseif_patten, "<?php } elseif($1){ ?>", $this->template_content);
				$this->template_content = preg_replace($else_patten, '<?php }else{ ?>', $this->template_content);
				$this->template_content = preg_replace($ef_patten, '<?php } ?>', $this->template_content);
			} else {
				exit('错误：语法错误,没有封闭IF条件语句');
			}
		}
		return true;
	}

	private function _parse_fun() {
		if (preg_match('/\$this->_tpl_vars[\'\w\$\[\]]*\|[^%]*/', $this->template_content)) {
			$fun_patten = '/(\$this->_tpl_vars[\'\w\$\[\]]*)\|([\w]*)\(([^\)]*)\)/';
			$this->template_content = preg_replace($fun_patten, "\$2($1,$3)", $this->template_content);
		}
		if (preg_match('/\$this->_tpl_vars[\'\w\$\[\]]*\|[^%]*/', $this->template_content)) {
			$fun_patten = '/(\$this->_tpl_vars[\'\w\$\[\]]*)\|([\w]*)/';
			$this->template_content = preg_replace($fun_patten, "$2($1)", $this->template_content);
		}
		if (preg_match('/("|\')\s*[^"\']+\s*("|\')\|[^%]*/', $this->template_content)) {
			$fun_patten = '/(["|\']\s*[^"\']+\s*["|\'])\|([\w]*)\(([^\)]*)\)/';
			$this->template_content = preg_replace($fun_patten, "\$2($1,$3)", $this->template_content);
		}
		if (preg_match('/(@this->[a-zA-z0-9]+)(\([^\)]*\))/', $this->template_content)) {
			$fun_patten = '/@(this->[a-zA-z0-9]+)(\([^\)]*\))/';
			$this->template_content = preg_replace($fun_patten, "$$1$2", $this->template_content);
		}
	}

	private function _parse_echo() {
		if (preg_match('/' . $this->left_delimiter . '\s*([^%]+)\s*' . $this->right_delimiter . '/', $this->template_content)) {
			$echo_patten = '/' . $this->left_delimiter . '\s*([^%]+)\s*' . $this->right_delimiter . '/';
			$this->template_content = preg_replace($echo_patten, "<?php echo $1 ?>", $this->template_content);
		}
	}

	private function _parse_array__list($bearkarray, $left_delimiter, $right_delimiter) {
		$classvar = explode(',', $bearkarray[11]);
		$newarray = array();
		foreach ($classvar as $key => $variable) {
			if (strstr($variable, '$this->_tpl_vars')) {
				$echo_patten = '/(\$this->[^\,]+]|[\w]+\(\$this->[^\,]+]\))/';
				$newarray[$key] = preg_replace($echo_patten, "<?php echo $1 ?>", $variable);
			} else {
				$newarray[$key] = $variable;
			}
		}
		if (strstr($bearkarray[7], '$this->_tpl_vars')) {
			$bearkarray[7] = preg_replace('/(\$this->[^\,]+])/', "<?php echo $1 ?>", $bearkarray[7]);
		}
		$bearkarray[11] = implode(',', $newarray);
		$left_delimiter = str_replace("\\", "", $left_delimiter);
		$right_delimiter = str_replace("\\", "", $right_delimiter);
		$iscachestr = !empty($bearkarray[5]) ? " iscache=" . $bearkarray[5] : '';
		$cachefile = !empty($bearkarray[7]) ? " cachefile=" . $bearkarray[7] : '';
		$libdir = !empty($bearkarray[9]) ? " libdir=" . $bearkarray[9] : '';
		if ($bearkarray[11]) {
			$newText = $left_delimiter . "list name=" . $bearkarray[1] . " " . $bearkarray[2] . $iscachestr . $cachefile . $libdir . " class=" . $bearkarray[11] . $right_delimiter;
		} else {
			$newText = $left_delimiter . "list name=" . $bearkarray[1] . " " . $bearkarray[2] . $iscachestr . $cachefile . $libdir . $right_delimiter;
		}
		return $newText;
	}

	private function _parse_array__get($bearkarray, $left_delimiter, $right_delimiter) {
		$classvar = explode(',', $bearkarray[7][0]);
		$newarray = array();
		foreach ($classvar as $key => $variable) {
			if (strstr($variable, '$this->_tpl_vars')) {
				$echo_patten = '/(\$this->[^\,]+]|[\w]+\(\$this->[^\,]+]\))/';
				$newarray[$key] = preg_replace($echo_patten, "<?php echo $1 ?>", $variable);
			} else {
				$newarray[$key] = $variable;
			}
		}
		if (strstr($bearkarray[5][0], '$this->_tpl_vars')) {
			$echo_patten = '/(\$this->[^\,]+])/';
			$bearkarray[5][0] = preg_replace($echo_patten, "<?php echo $1 ?>", $bearkarray[5][0]);
		}
		$bearkarray[7][0] = implode(',', $newarray);
		$left_delimiter = str_replace("\\", "", $left_delimiter);
		$right_delimiter = str_replace("\\", "", $right_delimiter);
		$iscachestr = !empty($bearkarray[3][0]) ? " iscache=" . $bearkarray[3][0] : '';
		$cachefile = !empty($bearkarray[5][0]) ? " cachefile=" . $bearkarray[5][0] : '';
		if ($bearkarray[7][0]) {
			$newText = $left_delimiter . "get name=" . $bearkarray[1][0] . $iscachestr . $cachefile . " class=" . $bearkarray[7][0] . $right_delimiter;
		} else {
			$newText = $left_delimiter . "get name=" . $bearkarray[1][0] . $iscachestr . $cachefile . $right_delimiter;
		}
		return $newText;
	}

	private function _parse_array_tag($arraylist) {
		preg_match_all('/\s*([\w]+)\s*=\s*([$\w->\[\]\'\"]+)\s*/', $arraylist, $arg_list);
		for ($i = 0; $i < count($arg_list[1]); $i++) {
			$attrs[$arg_list[1][$i]] = $arg_list[2][$i];
		}
		return $attrs;
	}

	private function _parse_value_preg($value) {
		$arraylist = preg_split("/(\])\./", $value);
		$arraycount = count($arraylist);
		foreach ($arraylist as $key => $variable) {
			if (($key + 1) != $arraycount) {
				if ($key == 0) {
					$variableFind = str_replace('[', '', strrchr($variable, '['));
					$variableText = str_replace('[' . $variableFind, '', $variable);
					$arraylistNew = $variableText . "[$$variableFind]";
				} else {
					$variableFind = str_replace('[', '', strrchr($variable, '['));
					$variableText = str_replace('[' . $variableFind, '', $variable);
					$arraylistNew .= "['$variableText'][$$variableFind]";
				}
			} else {
				$variableFun = strrchr($variable, '|');
				$variableText = str_replace($variableFun, '', $variable);
				$arraylistNew .= "['$variableText']$variableFun";
			}
		}
		return $arraylistNew;
	}

}
