<?php

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

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 = true;
    private $left_delimiter;
    private $right_delimiter;
    private $fetch_filename;
    private $templates_themss_dirname;

    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("/(^[\s]*\/\/[^\n]+)/im", '', $str);
        $str = preg_replace("/\/\*(\s|.)*?\*\//is", '', $str);
        $str = preg_replace("#<!--[^\!\[]*?(?<!\/\/)-->#", '', $str);
        $str = preg_replace("/[\t]+/is", '', $str);
        $str = preg_replace("/^([\s\n]{1,})/im", '', $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 (espcms_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;
    }
}
