<?php
namespace imcat;
// 模板编译 类
class vopComp{
static $tplCfg = array(); //配置
static function main($tplname) {
$vob = new self();
$res = $vob->build($tplname);
unset($vob);
return $res;
}
function __construct($tpl='') {
global $_cbase;
self::$tplCfg = $_cbase['tpl'];
if($tpl) return $this->build($tpl);
}
//模板编译 ----------
function build($tpl){
global $_cbase;
// check
$dtpl = strpos($tpl,':') ? str_replace(':', '/', $tpl) : $_cbase['tpl']['vdir'].'/'.$tpl;
$tplfp = DIR_VIEWS."/$dtpl.htm";
$cacfp = DIR_CTPL.'/'.$dtpl.self::$tplCfg['tpc_ext'];
if(!file_exists($tplfp)) glbError::show("$tplfp NOT Exists!");
comFiles::chkDirs($dtpl,'ctpl');
// build
$_cbase['run']['comp'] = $tpl; //当前编译模板,js标签中使用
$stpl = comFiles::get($tplfp);
$stpl = $this->bcore($stpl); //获取经编译后的内容
$shead = NSP_INIT."\n\$this->tagRun('tplnow','$tpl','s');";
$tpfp = vopTpls::tinc('_ctrls/texBase',0); $spend = '';
if(file_exists($tpfp)){
$class = '\\imcat\\'.$_cbase['tpl']['vdir'].'\\texBase';
$shead .= "\ninclude_once '$tpfp';\nif(method_exists('$class','init'))";
$shead .= "{ \$__i_vars=$class::init(\$this); if(!empty(\$__i_vars)){extract(\$__i_vars,EXTR_OVERWRITE);unset(\$__i_vars);} }";
$spend = "<?php\nif(method_exists('$class','pend')){ $class::pend(); }\n?>";
}
$cfp = empty($_cbase['tpl']['fixmkv']) ? $cacfp : $cacfp.'.'.$_cbase['tpl']['fixmkv'];
comFiles::put($cfp, "<?php \n$shead \n?>\n".$stpl.$spend); //写入缓存
return $cfp;
}
//模板编译核心
function bcore($stpl=''){
$stpl = self::impBlock($stpl); // 解析模板继承
$stpl = self::incBlock($stpl); // 解析{code|inc|md}
$stpl = self::phpBasic($stpl); // 基本php语法解析
$stpl = self::phpFlow($stpl); // 流程控制语句
$stpl = vopCTag::tagMain($stpl); // 系统标签解析
return $stpl;
}
// 解析区块(code|inc|md), 如:{inc:"_pub/_head"}
static function incBlock($stpl=''){ // `{inc:"{mod}_key.md"}`
global $_cbase;
preg_match_all("/{(inc|md|code):\"(.*)\"}/i", $stpl, $match);
if(count($match[2])>0){
$arr = $match[2];
foreach($arr as $k0=>$tpl){
$mstr = $match[0][$k0];
$mkey = $match[1][$k0];
if($mkey=='code'){
$pfile = "vopTpls::tinc('$tpl',0)";
$ptpl = "<?php include $pfile; ?>";
}else{
$mkv = [];
if(strpos($tpl,'}')){ // 漏洞???
$mkv = $_cbase['mkv'];
$from = ['{mod}', '{key}', '{view}', '{mkv}'];
$to = [$mkv['mod'], $mkv['key'], $mkv['view'], $mkv['mkv']];
$tpl = str_replace($from, $to, $tpl);
}
$ext = strpos($tpl,'.')>0 ? '' : ($mkey=='md'?'md':'htm');
$pfile = vopTpls::tinc("$tpl.$ext", 0);
$ptpl = comFiles::get($pfile, 1);
if(!empty($mkv['mkv'])){
if(!$ptpl){
glbHtml::httpStatus('404');
$ptpl = "File `{$_cbase['tpl']['vdir']}/$tpl.$ext` NOT Found!";
}else{
$_cbase['tpl']['fixmkv'] = $mkv['mkv'];
}
}
strpos($ptpl,'"}')>0 && $ptpl = self::incBlock($ptpl);
$mkey=='md' && $ptpl = extMkdown::pdext($ptpl, 0);
$ptpl || $ptpl = '<!-- '.str_replace('"','`',$mstr).' -->';
}
$stpl = str_replace($mstr, $ptpl, $stpl);
}
}
return $stpl;
}
// 模板继承extend,block,layout,parent,inherit
// {imp:"_dir/layout"] // {block:title]Welcome!{/block:title]
// {block:title] {:parent} {:clear} News - Project Name{/block:title]
static function impBlock($stpl=''){
preg_match("/\{imp:\"([\S]{3,48})\"\}/i", $stpl, $match);
if(empty($match[0]) || empty($match[1])) return $stpl; //没有imp,原样返回
$layfile = vopTpls::tinc($match[1].'.htm', 0);
$layout = comFiles::get($layfile);
$stpl = substr($stpl,strlen($match[0]));
preg_match_all("/\{block:([a-z][a-z0-9_]{1,17})\}/i", $layout, $match);
if(empty($match[1])){ return $layout; }//没有block
foreach($match[1] as $key){
$k1 = "{block:$key}"; $k2 = "{/block:$key}";
$blk1 = basElm::getPos($stpl,array($k1,$k2));
$blkp = basElm::getPos($layout,array($k1,$k2));
if($blk1=='{:clear}'){
$layout = str_replace("$k1{$blkp}$k2", "", $layout);
}elseif(!empty($blk1)){
if(strlen($blkp)>6 && strstr($blk1,'{:parent}')) $blk1 = str_replace("{:parent}", $blkp, $blk1);
$layout = str_replace("$k1{$blkp}$k2", "{$blk1}", $layout);
}
$layout = str_replace(array($k1,$k2,'{:parent}'), "", $layout);
}
return $layout;
}
// 基本php语法解析, 常量,变量,函数,php代码
static function phpBasic($stpl=''){
/* 路径自定义替换 ----------------------------
{outSwplayerPath}/ -=> http://cdn_d/ximps/vendui/swplayer/
*/
$reps = glbConfig::read('repath', 'sy');
if(!empty($reps['tpl'])){
$stpl = str_replace(array_keys($reps['tpl']), array_values($reps['tpl']), $stpl);
}
/* 常量/变量解析 ----------------------------
{=PATH_ROOT} -=> <?=PATH_ROOT; ?>
{=$name} -=> <?=$name; ?> $re1['title'], $this->mod, $this->ucfg['q']
*/
$stpl = preg_replace ( "/\{\=([A-Z_][A-Z0-9_]*)\}/s", "<?=\\1;?>", $stpl );
/*将变量{$name}替换成<?=$name; ?>,可以是数组 $name, $re1['title'], $this->mod, $this->ucfg['q'] */
$stpl = preg_replace("/{\=(\\$[a-zA-Z_][\w\.\"\'\[\]\$\-\>\:]{0,64})}/i", "<?=@$1; ?>", $stpl); # ?下几个版本移除`@`
/* php标签 ----------------------------
{= date('Y-m-d'); } => <?=date('Y-m-d'); ?>
{php phpinfo();} => <?php phpinfo(); ?>
*/
$stpl = preg_replace ( "/\{=\s+([^}]+)\}/", "<?=\\1?>", $stpl );
$stpl = preg_replace ( "/\{php\s+([^}]+)\}/", "<?php \\1?>", $stpl );
return $stpl;
}
//模板解析 流程控制语句(Flow control statements)
static function phpFlow($stpl){
/* if 标签
{if $name==1} => <?php if ($name==1){ ?>
{elseif $name==2} => <?php } elseif ($name==2){ ?>
{else} => <?php } else { ?>
{/if} => <?php } ?>
*/
$stpl = preg_replace ( "/\{if\s+(.+?)\}/", "<?php if(\\1) { ?>", $stpl );
$stpl = preg_replace ( "/\{else\}/", "<?php } else { ?>", $stpl );
$stpl = preg_replace ( "/\{elseif\s+(.+?)\}/", "<?php } elseif (\\1) { ?>", $stpl );
$stpl = preg_replace ( "/\{\/if\}/", "<?php } ?>", $stpl );
// ----------------------------
/* for 标签
{for $i=0;$i<10;$i++} => <?php for($i=0;$i<10;$i++) { ?>
{/for} => <?php } ?>
*/
$stpl = preg_replace("/\{for\s+(.+?)\}/","<?php for(\\1) { ?>",$stpl);
$stpl = preg_replace("/\{\/for\}/","<?php } ?>",$stpl);
// ----------------------------
/* loop 标签
{loop $arr $vo} => <?php $n=1; if (is_array($arr) foreach($arr as $vo){ ?>
{loop $arr $key $vo} => <?php $n=1; if (is_array($array) foreach($arr as $key => $vo){ ?>
{/loop} => <?php $n++;}unset($n) ?>
*/
$stpl = preg_replace ( "/\{loop\s+(\S+)\s+(\S+)\}/", "<?php if(is_array(\\1)) foreach(\\1 as \\2) { ?>", $stpl );
$stpl = preg_replace ( "/\{loop\s+(\S+)\s+(\S+)\s+(\S+)\}/", "<?php \$n=1; if(is_array(\\1)) foreach(\\1 as \\2 => \\3) { ?>", $stpl );
$stpl = preg_replace ( "/\{\/loop\}/", "<?php } ?>", $stpl );
// ----------------------------
// {php}{/php} 标签 --- 可在前后添加 <!--, --> 以便在html中显示调试
$_aorg = array('{php} ','{php}','{/php}','<!--<?php','?>-->');
$_aobj = array('{php}','<?php ','?>','<?php','?>');
$stpl = str_replace ( $_aorg, $_aobj, $stpl );
// ----------------------------
return $stpl;
}
}