$v) { if(preg_match('/^field\./i',$v)) { $key = preg_replace('/^field\./i', '', $v); if( isset($fields[$key]) ) { $atts[$k] = $fields[$key]; } } else if(preg_match('/^var\./i', $v)) { $key = preg_replace('/^var\./i', '', $v); if( isset($_vars[$key]) ) { $atts[$k] = $_vars[$key]; } } else if(preg_match('/^global\./i', $v)) { $key = preg_replace('/^global\./i', '', $v); if( isset($GLOBALS[$key]) ) { $atts[$k] = $GLOBALS[$key]; } } } } /** * class Tag 标记的数据结构描述 * function C__Tag(); * * @package Tag * @subpackage DedeCMS.Libraries * @link http://www.dedecms.com */ class Tag { var $isCompiler=FALSE; //标记是否已被替代,供解析器使用 var $tagName=""; //标记名称 var $innerText=""; //标记之间的文本 var $startPos=0; //标记起始位置 var $endPos=0; //标记结束位置 var $cAtt=""; //标记属性描述,即是class TagAttribute var $tagValue=""; //标记的值 var $tagID = 0; /** * 获取标记的名称和值 * * @access public * @return string */ function GetName() { return strtolower($this->tagName); } function GetValue() { return $this->tagValue; } function IsAtt($str) { return $this->cAtt->IsAttribute($str); } function GetAtt($str) { return $this->cAtt->GetAtt($str); } /** * 获取底层模板 * * @return string */ function GetinnerText() { return $this->innerText; } } /** * 模板解析器 * function C__DedeTemplate * * @package DedeTemplate * @subpackage DedeCMS.Libraries * @link http://www.dedecms.com */ class DedeTemplate { var $tagMaxLen = 64; var $charToLow = TRUE; var $isCache = TRUE; var $isParse = FALSE; var $isCompiler = TRUE; var $templateDir = ''; var $tempMkTime = 0; var $cacheFile = ''; var $configFile = ''; var $buildFile = ''; var $refDir = ''; var $cacheDir = ''; var $templateFile = ''; var $sourceString = ''; var $cTags = array(); //var $definedVars = array(); var $count = -1; var $loopNum = 0; var $refObj = ''; var $makeLoop = 0; var $tagStartWord = '{dede:'; var $fullTagEndWord = '{/dede:'; var $sTagEndWord = '/}'; var $tagEndWord = '}'; var $tpCfgs = array(); /** * 析构函数 * * @access public * @param string $templatedir 模板目录 * @param string $refDir 所属目录 * @return void */ function __construct($templatedir='',$refDir='') { //$definedVars[] = 'var'; //缓存目录 if($templatedir=='') { $this->templateDir = DEDEROOT.'/templates'; } else { $this->templateDir = $templatedir; } //模板include目录 if($refDir=='') { if(isset($GLOBALS['cfg_df_style'])) { $this->refDir = $this->templateDir.'/'.$GLOBALS['cfg_df_style'].'/'; } else { $this->refDir = $this->templateDir; } } $this->cacheDir = DEDEROOT.$GLOBALS['cfg_tplcache_dir']; } //构造函数,兼容PHP4 function DedeTemplate($templatedir='',$refDir='') { $this->__construct($templatedir,$refDir); } /** * 设定本类自身实例的类引用和使用本类的类实例(如果在类中使用本模板引擎,后一参数一般为$this) * * @access public * @param object $refObj 实例对象 * @return string */ function SetObject(&$refObj) { $this->refObj = $refObj; } /** * 设定Var的键值对 * * @access public * @param string $k 键 * @param string $v 值 * @return string */ function SetVar($k, $v) { $GLOBALS['_vars'][$k] = $v; } /** * 设定Var的键值对 * * @access public * @param string $k 键 * @param string $v 值 * @return string */ function Assign($k, $v) { $GLOBALS['_vars'][$k] = $v; } /** * 设定数组 * * @access public * @param string $k 键 * @param string $v 值 * @return string */ function SetArray($k, $v) { $GLOBALS[$k] = $v; } /** * 设置标记风格 * * @access public * @param string $ts 标签开始标记 * @param string $ftend 标签结束标记 * @param string $stend 标签尾部结束标记 * @param string $tend 结束标记 * @return void */ function SetTagStyle($ts='{dede:',$ftend='{/dede:',$stend='/}',$tend='}') { $this->tagStartWord = $ts; $this->fullTagEndWord = $ftend; $this->sTagEndWord = $stend; $this->tagEndWord = $tend; } /** * 获得模板设定的config值 * * @access public * @param string $k 键名 * @return string */ function GetConfig($k) { return (isset($this->tpCfgs[$k]) ? $this->tpCfgs[$k] : ''); } /** * 设定模板文件 * * @access public * @param string $tmpfile 模板文件 * @return void */ function LoadTemplate($tmpfile) { if(!file_exists($tmpfile)) { echo " Template Not Found! "; exit(); } $tmpfile = preg_replace("/[\\/]{1,}/", "/", $tmpfile); $tmpfiles = explode('/',$tmpfile); $tmpfileOnlyName = preg_replace("/(.*)\//", "", $tmpfile); $this->templateFile = $tmpfile; $this->refDir = ''; for($i=0; $i < count($tmpfiles)-1; $i++) { $this->refDir .= $tmpfiles[$i].'/'; } if(!is_dir($this->cacheDir)) { $this->cacheDir = $this->refDir; } if($this->cacheDir!='') { $this->cacheDir = $this->cacheDir.'/'; } if(isset($GLOBALS['_DEBUG_CACHE'])) { $this->cacheDir = $this->refDir; } $this->cacheFile = $this->cacheDir.preg_replace("/\.(wml|html|htm|php)$/", "_".$this->GetEncodeStr($tmpfile).'.inc', $tmpfileOnlyName); $this->configFile = $this->cacheDir.preg_replace("/\.(wml|html|htm|php)$/", "_".$this->GetEncodeStr($tmpfile).'_config.inc', $tmpfileOnlyName); //不开启缓存、当缓存文件不存在、及模板为更新的文件的时候才载入模板并进行解析 if($this->isCache==FALSE || !file_exists($this->cacheFile) || filemtime($this->templateFile) > filemtime($this->cacheFile)) { $t1 = ExecTime(); //debug $fp = fopen($this->templateFile,'r'); $this->sourceString = fread($fp,filesize($this->templateFile)); fclose($fp); $this->ParseTemplate(); //模板解析时间 //echo ExecTime() - $t1; } else { //如果存在config文件,则载入此文件,该文件用于保存 $this->tpCfgs的内容,以供扩展用途 //模板中用{tag:config name='' value=''/}来设定该值 if(file_exists($this->configFile)) { include($this->configFile); } } } /** * 载入模板字符串 * * @access public * @param string $str 模板字符串 * @return void */ function LoadString($str='') { $this->sourceString = $str; $hashcode = md5($this->sourceString); $this->cacheFile = $this->cacheDir."/string_".$hashcode.".inc"; $this->configFile = $this->cacheDir."/string_".$hashcode."_config.inc"; $this->ParseTemplate(); } /** * 调用此函数include一个编译后的PHP文件,通常是在最后一个步骤才调用本文件 * * @access public * @return string */ function CacheFile() { global $gtmpfile; $this->WriteCache(); return $this->cacheFile; } /** * 显示内容,由于函数中会重新解压一次$GLOBALS变量,所以在动态页中,应该尽量少用本方法, * 取代之是直接在程序中 include $tpl->CacheFile(),不过include $tpl->CacheFile()这种方式不能在类或函数内使用 * * @access public * @param string * @return void */ function Display() { global $gtmpfile; extract($GLOBALS, EXTR_SKIP); $this->WriteCache(); include $this->cacheFile; } /** * 保存运行后的程序为文件 * * @access public * @param string $savefile 保存到的文件目录 * @return void */ function SaveTo($savefile) { extract($GLOBALS, EXTR_SKIP); $this->WriteCache(); ob_start(); include $this->cacheFile; $okstr = ob_get_contents(); ob_end_clean(); $fp = @fopen($savefile,"w") or die(" Tag Engine Create File FALSE! "); fwrite($fp,$okstr); fclose($fp); } // ------------------------------------------------------------------------ /** * CheckDisabledFunctions * * COMMENT : CheckDisabledFunctions : 检查是否存在禁止的函数 * * @access public * @param string * @return bool */ function CheckDisabledFunctions($str,&$errmsg='') { global $cfg_disable_funs; $cfg_disable_funs = isset($cfg_disable_funs)? $cfg_disable_funs : 'phpinfo,eval,exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source,file_put_contents,fsockopen,fopen,fwrite'; // 模板引擎增加disable_functions if (!defined('DEDEDISFUN')) { $tokens = token_get_all_nl($str); $disabled_functions = explode(',', $cfg_disable_funs); foreach ($tokens as $token) { if (is_array($token)) { if ($token[0] = '306' && in_array($token[1], $disabled_functions)) { $errmsg = 'DedeCMS Error:function disabled "'.$token[1].'" more...'; return FALSE; } } } } return TRUE; } /** * 解析模板并写缓存文件 * * @access public * @param string $ctype 缓存类型 * @return void */ function WriteCache($ctype='all') { if(!file_exists($this->cacheFile) || $this->isCache==FALSE || ( file_exists($this->templateFile) && (filemtime($this->templateFile) > filemtime($this->cacheFile)) ) ) { if(!$this->isParse) { $this->ParseTemplate(); } $fp = fopen($this->cacheFile,'w') or dir("Write Cache File Error! "); flock($fp,3); $result = trim($this->GetResult()); $errmsg = ''; //var_dump($result);exit(); if (!$this->CheckDisabledFunctions($result, $errmsg)) { fclose($fp); @unlink($this->cacheFile); die($errmsg); } fwrite($fp,$result); fclose($fp); if(count($this->tpCfgs) > 0) { $fp = fopen($this->configFile,'w') or dir("Write Config File Error! "); flock($fp,3); fwrite($fp,'<'.'?php'."\r\n"); foreach($this->tpCfgs as $k=>$v) { $v = str_replace("\"","\\\"",$v); $v = str_replace("\$","\\\$",$v); fwrite($fp,"\$this->tpCfgs['$k']=\"$v\";\r\n"); } fwrite($fp,'?'.'>'); fclose($fp); } } /* if(!file_exists($this->cacheFile) || $this->isCache==FALSE || ( file_exists($this->templateFile) && (filemtime($this->templateFile) > filemtime($this->cacheFile)) ) ) { if($ctype!='config') { if(!$this->isParse) { $this->ParseTemplate(); } $fp = fopen($this->cacheFile,'w') or dir("Write Cache File Error! "); flock($fp,3); fwrite($fp,trim($this->GetResult())); fclose($fp); } else { if(count($this->tpCfgs) > 0) { $fp = fopen($this->configFile,'w') or dir("Write Config File Error! "); flock($fp,3); fwrite($fp,'<'.'?php'."\r\n"); foreach($this->tpCfgs as $k=>$v) { $v = str_replace("\"","\\\"",$v); $v = str_replace("\$","\\\$",$v); fwrite($fp,"\$this->tpCfgs['$k']=\"$v\";\r\n"); } fwrite($fp,'?'.'>'); fclose($fp); } } } else { if($ctype=='config' && count($this->tpCfgs) > 0 ) { $fp = fopen($this->configFile,'w') or dir("Write Config File Error! "); flock($fp,3); fwrite($fp,'<'.'?php'."\r\n"); foreach($this->tpCfgs as $k=>$v) { $v = str_replace("\"","\\\"",$v); $v = str_replace("\$","\\\$",$v); fwrite($fp,"\$this->tpCfgs['$k']=\"$v\";\r\n"); } fwrite($fp,'?'.'>'); fclose($fp); } } */ } /** * 获得模板文件名的md5字符串 * * @access public * @param string $tmpfile 模板文件 * @return string */ function GetEncodeStr($tmpfile) { //$tmpfiles = explode('/',$tmpfile); $encodeStr = substr(md5($tmpfile),0,24); return $encodeStr; } /** * 解析模板 * * @access public * @return void */ function ParseTemplate() { if($this->makeLoop > 5) { return ; } $this->count = -1; $this->cTags = array(); $this->isParse = TRUE; $sPos = 0; $ePos = 0; $tagStartWord = $this->tagStartWord; $fullTagEndWord = $this->fullTagEndWord; $sTagEndWord = $this->sTagEndWord; $tagEndWord = $this->tagEndWord; $startWordLen = strlen($tagStartWord); $sourceLen = strlen($this->sourceString); if( $sourceLen <= ($startWordLen + 3) ) { return; } $cAtt = new TagAttributeParse(); $cAtt->CharToLow = TRUE; //遍历模板字符串,请取标记及其属性信息 $t = 0; $preTag = ''; $tswLen = strlen($tagStartWord); $cAtt->cAttributes->items = array(); for($i=0; $i<$sourceLen; $i++) { $ttagName = ''; //如果不进行此判断,将无法识别相连的两个标记 if($i-1>=0) { $ss = $i-1; } else { $ss = 0; } $tagPos = strpos($this->sourceString,$tagStartWord,$ss); //判断后面是否还有模板标记 if($tagPos==0 && ($sourceLen-$i < $tswLen || substr($this->sourceString,$i,$tswLen)!=$tagStartWord )) { $tagPos = -1; break; } //获取TAG基本信息 for($j = $tagPos+$startWordLen; $j < $tagPos+$startWordLen+$this->tagMaxLen; $j++) { if(preg_match("/[ >\/\r\n\t\}\.]/", $this->sourceString[$j])) { break; } else { $ttagName .= $this->sourceString[$j]; } } if($ttagName!='') { $i = $tagPos + $startWordLen; $endPos = -1; //判断 '/}' '{tag:下一标记开始' '{/tag:标记结束' 谁最靠近 $fullTagEndWordThis = $fullTagEndWord.$ttagName.$tagEndWord; $e1 = strpos($this->sourceString, $sTagEndWord, $i); $e2 = strpos($this->sourceString, $tagStartWord, $i); $e3 = strpos($this->sourceString, $fullTagEndWordThis, $i); $e1 = trim($e1); $e2 = trim($e2); $e3 = trim($e3); $e1 = ($e1=='' ? '-1' : $e1); $e2 = ($e2=='' ? '-1' : $e2); $e3 = ($e3=='' ? '-1' : $e3); if($e3==-1) { //不存在'{/tag:标记' $endPos = $e1; $elen = $endPos + strlen($sTagEndWord); } else if($e1==-1) { //不存在 '/}' $endPos = $e3; $elen = $endPos + strlen($fullTagEndWordThis); } //同时存在 '/}' 和 '{/tag:标记' else { //如果 '/}' 比 '{tag:'、'{/tag:标记' 都要靠近,则认为结束标志是 '/}',否则结束标志为 '{/tag:标记' if($e1 < $e2 && $e1 < $e3 ) { $endPos = $e1; $elen = $endPos + strlen($sTagEndWord); } else { $endPos = $e3; $elen = $endPos + strlen($fullTagEndWordThis); } } //如果找不到结束标记,则认为这个标记存在错误 if($endPos==-1) { echo "Tpl Character postion $tagPos, '$ttagName' Error!
\r\n"; break; } $i = $elen; //分析所找到的标记位置等信息 $attStr = ''; $innerText = ''; $startInner = 0; for($j = $tagPos+$startWordLen; $j < $endPos; $j++) { if($startInner==0) { if($this->sourceString[$j]==$tagEndWord) { $startInner=1; continue; } else { $attStr .= $this->sourceString[$j]; } } else { $innerText .= $this->sourceString[$j]; } } $ttagName = strtolower($ttagName); //if、php标记,把整个属性串视为属性 if(preg_match("/^if[0-9]{0,}$/", $ttagName)) { $cAtt->cAttributes = new TagAttribute(); $cAtt->cAttributes->count = 2; $cAtt->cAttributes->items['tagname'] = $ttagName; $cAtt->cAttributes->items['condition'] = preg_replace("/^if[0-9]{0,}[\r\n\t ]/", "", $attStr); $innerText = preg_replace("/\{else\}/i", '<'."?php\r\n}\r\nelse{\r\n".'?'.'>', $innerText); } else if($ttagName=='php') { $cAtt->cAttributes = new TagAttribute(); $cAtt->cAttributes->count = 2; $cAtt->cAttributes->items['tagname'] = $ttagName; $cAtt->cAttributes->items['code'] = '<'."?php\r\n".trim(preg_replace("/^php[0-9]{0,}[\r\n\t ]/", "",$attStr))."\r\n?".'>'; } else { //普通标记,解释属性 $cAtt->SetSource($attStr); } $this->count++; $cTag = new Tag(); $cTag->tagName = $ttagName; $cTag->startPos = $tagPos; $cTag->endPos = $i; $cTag->cAtt = $cAtt->cAttributes; $cTag->isCompiler = FALSE; $cTag->tagID = $this->count; $cTag->innerText = $innerText; $this->cTags[$this->count] = $cTag; } else { $i = $tagPos+$startWordLen; break; } }//结束遍历模板字符串 if( $this->count > -1 && $this->isCompiler ) { $this->CompilerAll(); } } /** * 把模板标记转换为PHP代码 * * @access public * @return void */ function CompilerAll() { $this->loopNum++; if($this->loopNum > 10) { return; //限制最大递归深度为 10 以防止因标记出错等可能性导致死循环 } $ResultString = ''; $nextTagEnd = 0; for($i=0; isset($this->cTags[$i]); $i++) { $ResultString .= substr($this->sourceString, $nextTagEnd, $this->cTags[$i]->startPos - $nextTagEnd); $ResultString .= $this->CompilerOneTag($this->cTags[$i]); $nextTagEnd = $this->cTags[$i]->endPos; } $slen = strlen($this->sourceString); if($slen > $nextTagEnd) { $ResultString .= substr($this->sourceString,$nextTagEnd,$slen-$nextTagEnd); } $this->sourceString = $ResultString; $this->ParseTemplate(); } /** * 获得最终结果 * * @access public * @return string */ function GetResult() { if(!$this->isParse) { $this->ParseTemplate(); } $addset = ''; $addset .= '<'.'?php'."\r\n".'if(!isset($GLOBALS[\'_vars\'])) $GLOBALS[\'_vars\'] = array(); '."\r\n".'$fields = array();'."\r\n".'?'.'>'; return preg_replace("/\?".">[ \r\n\t]{0,}<"."\?php/", "", $addset.$this->sourceString); } /** * 编译单个标记 * * @access public * @param string $cTag 标签 * @return string */ function CompilerOneTag(&$cTag) { $cTag->isCompiler = TRUE; $tagname = $cTag->tagName; $varname = $cTag->GetAtt('name'); $rsvalue = ""; //用于在模板中设置一个变量以提供作扩展用途 //此变量直接提交到 this->tpCfgs 中,并会生成与模板对应的缓存文件 ***_config.php 文件 if( $tagname == 'config' ) { $this->tpCfgs[$varname] = $cTag->GetAtt('value'); } else if( $tagname == 'global' ) { $cTag->tagValue = $this->CompilerArrayVar('global',$varname); if( $cTag->GetAtt('function') != '' ) { $cTag->tagValue = $this->CompilerFunction($cTag->GetAtt('function'), $cTag->tagValue); } $cTag->tagValue = '<'.'?php echo '.$cTag->tagValue.'; ?'.'>'; } else if( $tagname == 'cfg' ) { $cTag->tagValue = '$GLOBALS[\'cfg_'.$varname.'\']'; //处理函数 if( $cTag->GetAtt('function')!='' ) { $cTag->tagValue = $this->CompilerFunction($cTag->GetAtt('function'), $cTag->tagValue); } $cTag->tagValue = '<'.'?php echo '.$cTag->tagValue.'; ?'.'>'; } else if( $tagname == 'name' ) { $cTag->tagValue = '$'.$varname; //处理函数 if( $cTag->GetAtt('function')!='' ) { $cTag->tagValue = $this->CompilerFunction($cTag->GetAtt('function'), $cTag->tagValue); } $cTag->tagValue = '<'.'?php echo '.$cTag->tagValue.'; ?'.'>'; } else if( $tagname == 'object' ) { list($_obs,$_em) = explode('->',$varname); $cTag->tagValue = "\$GLOBALS['{$_obs}']->{$_em}"; //处理函数 if( $cTag->GetAtt('function')!='' ) { $cTag->tagValue = $this->CompilerFunction($cTag->GetAtt('function'), $cTag->tagValue); } $cTag->tagValue = '<'.'?php echo '.$cTag->tagValue.'; ?'.'>'; } else if($tagname == 'var') { $cTag->tagValue = $this->CompilerArrayVar('var', $varname); if( $cTag->GetAtt('function')!='' ) { $cTag->tagValue = $this->CompilerFunction($cTag->GetAtt('function'), $cTag->tagValue); } // 增加默认空值处理 if ($cTag->GetAtt('default')!='') { $cTag->tagValue = '<'.'?php echo empty('.$cTag->tagValue.')? \''.addslashes($cTag->GetAtt('default')).'\':'.$cTag->tagValue.'; ?'.'>'; } else { $cTag->tagValue = '<'.'?php echo '.$cTag->tagValue.'; ?'.'>'; } } else if($tagname == 'field') { $cTag->tagValue = '$fields[\''.$varname.'\']'; if( $cTag->GetAtt('function')!='' ) { $cTag->tagValue = $this->CompilerFunction($cTag->GetAtt('function'), $cTag->tagValue); } $cTag->tagValue = '<'.'?php echo '.$cTag->tagValue.'; ?'.'>'; } else if( preg_match("/^key[0-9]{0,}/", $tagname) || preg_match("/^value[0-9]{0,}/", $tagname)) { if( preg_match("/^value[0-9]{0,}/", $tagname) && $varname!='' ) { $cTag->tagValue = '<'.'?php echo '.$this->CompilerArrayVar($tagname,$varname).'; ?'.'>'; } else { $cTag->tagValue = '<'.'?php echo $'.$tagname.'; ?'.'>'; } } else if( preg_match("/^if[0-9]{0,}$/", $tagname) ) { $cTag->tagValue = $this->CompilerIf($cTag); } else if( $tagname=='echo' ) { if(trim($cTag->GetInnerText())=='') $cTag->tagValue = $cTag->GetAtt('code'); else { $cTag->tagValue = '<'."?php echo $".trim($cTag->GetInnerText())." ;?".'>'; } } else if( $tagname=='php' ) { if(trim($cTag->GetInnerText())=='') $cTag->tagValue = $cTag->GetAtt('code'); else { $cTag->tagValue = '<'."?php\r\n".trim($cTag->GetInnerText())."\r\n?".'>'; } } //遍历数组 else if( preg_match("/^array[0-9]{0,}/",$tagname) ) { $kk = '$key'; $vv = '$value'; if($cTag->GetAtt('key')!='') { $kk = '$key'.$cTag->GetAtt('key'); } if($cTag->GetAtt('value')!='') { $vv = '$value'.$cTag->GetAtt('value'); } $addvar = ''; if(!preg_match("/\(/",$varname)) { $varname = '$GLOBALS[\''.$varname.'\']'; } else { $addvar = "\r\n".'$myarrs = $pageClass->'.$varname.";\r\n"; $varname = ' $myarrs '; } $rsvalue = '<'.'?php '.$addvar.' foreach('.$varname.' as '.$kk.'=>'.$vv.'){ ?'.">"; $rsvalue .= $cTag->GetInnerText(); $rsvalue .= '<'.'?php } ?'.">\r\n"; $cTag->tagValue = $rsvalue; } //include 文件 else if($tagname == 'include') { $filename = $cTag->GetAtt('file'); if($filename=='') { $filename = $cTag->GetAtt('filename'); } $cTag->tagValue = $this->CompilerInclude($filename, FALSE); if($cTag->tagValue==0) $cTag->tagValue = ''; $cTag->tagValue = '<'.'?php include $this->CompilerInclude("'.$filename.'");'."\r\n".' ?'.'>'; } else if( $tagname=='label' ) { $bindFunc = $cTag->GetAtt('bind'); $rsvalue = 'echo '.$bindFunc.";\r\n"; $rsvalue = '<'.'?php '.$rsvalue.' ?'.">\r\n"; $cTag->tagValue = $rsvalue; } else if( $tagname=='datalist' ) { //生成属性数组 foreach($cTag->cAtt->items as $k=>$v) { $v = $this->TrimAtts($v); $rsvalue .= '$atts[\''.$k.'\'] = \''.str_replace("'","\\'",$v)."';\r\n"; } $rsvalue = '<'.'?php'."\r\n".'$atts = array();'."\r\n".$rsvalue; $rsvalue .= '$blockValue = $this->refObj->GetArcList($atts,$this->refObj,$fields); '."\r\n"; $rsvalue .= 'if(is_array($blockValue)){'."\r\n"; $rsvalue .= 'foreach( $blockValue as $key=>$fields )'."\r\n{\r\n".'?'.">"; $rsvalue .= $cTag->GetInnerText(); $rsvalue .= '<'.'?php'."\r\n}\r\n}".'?'.'>'; $cTag->tagValue = $rsvalue; } else if( $tagname=='pagelist' ) { //生成属性数组 foreach($cTag->cAtt->items as $k=>$v) { $v = $this->TrimAtts($v); $rsvalue .= '$atts[\''.$k.'\'] = \''.str_replace("'","\\'",$v)."';\r\n"; } $rsvalue = '<'.'?php'."\r\n".'$atts = array();'."\r\n".$rsvalue; $rsvalue .= ' echo $this->refObj->GetPageList($atts,$this->refObj,$fields); '."\r\n".'?'.">\r\n"; $cTag->tagValue = $rsvalue; } else { $bindFunc = $cTag->GetAtt('bind'); $bindType = $cTag->GetAtt('bindtype'); $rstype = ($cTag->GetAtt('resulttype')=='' ? $cTag->GetAtt('rstype') : $cTag->GetAtt('resulttype') ); $rstype = strtolower($rstype); //生成属性数组 foreach($cTag->cAtt->items as $k=>$v) { if(preg_match("/(bind|bindtype)/i",$k)) { continue; } $v = $this->TrimAtts($v); $rsvalue .= '$atts[\''.$k.'\'] = \''.str_replace("'","\\'",$v)."';\r\n"; } $rsvalue = '<'.'?php'."\r\n".'$atts = array();'."\r\n".$rsvalue; //绑定到默认函数还是指定函数(datasource属性指定) if($bindFunc=='') { $rsvalue .= '$blockValue = MakePublicTag($atts,$this->refObj,$fields); '."\r\n"; } else { //自定义绑定函数如果不指定 bindtype,则指向$this->refObj->绑定函数名,即是默认指向被引用的类对象 if($bindType=='') $rsvalue .= '$blockValue = $this->refObj->'.$bindFunc.'($atts,$this->refObj,$fields); '."\r\n"; else $rsvalue .= '$blockValue = '.$bindFunc.'($atts,$this->refObj,$fields); '."\r\n"; } //返回结果类型:默认为 array 是一个二维数组,string 是字符串 if($rstype=='string') { $rsvalue .= 'echo $blockValue;'."\r\n".'?'.">"; } else { $rsvalue .= 'if(is_array($blockValue) && count($blockValue) > 0){'."\r\n"; $rsvalue .= 'foreach( $blockValue as $key=>$fields )'."\r\n{\r\n".'?'.">"; $rsvalue .= $cTag->GetInnerText(); $rsvalue .= '<'.'?php'."\r\n}\r\n}\r\n".'?'.'>'; } $cTag->tagValue = $rsvalue; } return $cTag->tagValue; } /** * 编译可能为数组的变量 * * @access public * @param string $vartype 变量类型 * @param string $varname 变量名称 * @return string */ function CompilerArrayVar($vartype, $varname) { $okvalue = ''; if(!preg_match("/\[/", $varname)) { if(preg_match("/^value/",$vartype)) { $varname = $vartype.'.'.$varname; } $varnames = explode('.',$varname); if(isset($varnames[1])) { $varname = $varnames[0]; for($i=1; isset($varnames[$i]); $i++) { $varname .= "['".$varnames[$i]."']"; } } } if(preg_match("/\[/", $varname)) { $varnames = explode('[', $varname); $arrend = ''; for($i=1;isset($varnames[$i]);$i++) { $arrend .= '['.$varnames[$i]; } if(!preg_match("/[\"']/", $arrend)) { $arrend = str_replace('[', '', $arrend); $arrend = str_replace(']', '', $arrend); $arrend = "['{$arrend}']"; } if($vartype=='var') { $okvalue = '$GLOBALS[\'_vars\'][\''.$varnames[0].'\']'.$arrend; } else if( preg_match("/^value/", $vartype) ) { $okvalue = '$'.$varnames[0].$arrend; } else if($vartype=='field') { $okvalue = '$fields[\''.$varnames[0].'\']'.$arrend; } else { $okvalue = '$GLOBALS[\''.$varnames[0].'\']'.$arrend; } } else { if($vartype=='var') { $okvalue = '$GLOBALS[\'_vars\'][\''.$varname.'\']'; } else if( preg_match("/^value/",$vartype) ) { $okvalue = '$'.$vartype; } else if($vartype=='field') { $okvalue = '$'.str_replace($varname); } else { $okvalue = '$GLOBALS[\''.$varname.'\']'; } } return $okvalue; } /** * 编译if标记 * * @access public * @param string $cTag 标签 * @return string */ function CompilerIf($cTag) { $condition = trim($cTag->GetAtt('condition')); if($condition =='') { $cTag->tagValue=''; return ''; } if (version_compare(PHP_VERSION, '5.5.0', '>=')) { $condition = preg_replace_callback("/((var\.|field\.|cfg\.|global\.|key[0-9]{0,}\.|value[0-9]{0,}\.)[\._a-z0-9]+)/is", "private_rt", $condition); } else { $condition = preg_replace("/((var\.|field\.|cfg\.|global\.|key[0-9]{0,}\.|value[0-9]{0,}\.)[\._a-z0-9]+)/ies", "private_rt('\\1')", $condition); } $rsvalue = '<'.'?php if('.$condition.'){ ?'.'>'; $rsvalue .= $cTag->GetInnerText(); $rsvalue .= '<'.'?php } ?'.'>'; return $rsvalue; } /** * 处理block区块传递的atts属性的值 * * @access public * @param string $v 值 * @return string */ function TrimAtts($v) { $v = str_replace('<'.'?','<?',$v); $v = str_replace('?'.'>','?>',$v); return $v; } /** * 函数 function 语法处理 * * @access public * @param string $funcstr 函数字符串 * @param string $nvalue 函数值 * @return string */ function CompilerFunction($funcstr, $nvalue) { $funcstr = str_replace('@quote', '"', $funcstr); $funcstr = str_replace('@me', $nvalue, $funcstr); return $funcstr; } /** * 引入文件 include 语法处理 * * @access public * @param string $filename 文件名 * @param string $isload 是否载入 * @return string */ function CompilerInclude($filename, $isload=TRUE) { $okfile = ''; if( @file_exists($filename) ) { $okfile = $filename; } else if( @file_exists($this->refDir.$filename) ) { $okfile = $this->refDir.$filename; } else if( @file_exists($this->refDir."../".$filename) ) { $okfile = $this->refDir."../".$filename; } if($okfile=='') return 0; if( !$isload ) return 1; $itpl = new DedeTemplate($this->templateDir); $itpl->isCache = $this->isCache; $itpl->SetObject($this->refObj); $itpl->LoadTemplate($okfile); return $itpl->CacheFile(); } } /** * class TagAttribute Tag属性集合 * function C__TagAttribute(); * 属性的数据描述 * * @package TagAttribute * @subpackage DedeCMS.Libraries * @link http://www.dedecms.com */ class TagAttribute { var $count = -1; var $items = array(); //属性元素的集合 /** * 获得某个属性 * * @access public * @param string $str 预处理字符串 * @return string */ function GetAtt($str) { if($str=="") { return ""; } if(isset($this->items[$str])) { return $this->items[$str]; } else { return ""; } } /** * 同上 * * @access public * @param string $str 预处理字符串 * @return string */ function GetAttribute($str) { return $this->GetAtt($str); } /** * 判断属性是否存在 * * @access public * @param string $str 预处理字符串 * @return bool */ function IsAttribute($str) { if(isset($this->items[$str])) return TRUE; else return FALSE; } /** * 获得标记名称 * * @access public * @return string */ function GettagName() { return $this->GetAtt("tagname"); } /** * 获得属性个数 * * @access public * @return int */ function Getcount() { return $this->count+1; } }//End Class /** * 属性解析器 * function C__TagAttributeParse(); * * @package TagAttribute * @subpackage DedeCMS.Libraries * @link http://www.dedecms.com */ class TagAttributeParse { var $sourceString = ""; var $sourceMaxSize = 1024; var $cAttributes = array(); var $charToLow = TRUE; function SetSource($str="") { $this->cAttributes = new TagAttribute(); $strLen = 0; $this->sourceString = trim(preg_replace("/[ \r\n\t\f]{1,}/"," ",$str)); $strLen = strlen($this->sourceString); if($strLen>0 && $strLen <= $this->sourceMaxSize) { $this->ParseAttribute(); } } /** * 解析属性 * * @access public * @return void */ function ParseAttribute() { $d = ''; $tmpatt = ''; $tmpvalue = ''; $startdd = -1; $ddtag = ''; $hasAttribute=FALSE; $strLen = strlen($this->sourceString); $this->cAttributes->items = array(); // 获得Tag的名称,解析到 cAtt->GetAtt('tagname') 中 for($i=0; $i<$strLen; $i++) { if($this->sourceString[$i]==' ') { $this->cAttributes->count++; $tmpvalues = explode('.', $tmpvalue); $this->cAttributes->items['tagname'] = ($this->charToLow ? strtolower($tmpvalues[0]) : $tmpvalues[0]); if( isset($tmpvalues[2]) ) { $okname = $tmpvalues[1]; for($j=2;isset($tmpvalues[$j]);$j++) { $okname .= "['".$tmpvalues[$j]."']"; } $this->cAttributes->items['name'] = $okname; } else if(isset($tmpvalues[1]) && $tmpvalues[1]!='') { $this->cAttributes->items['name'] = $tmpvalues[1]; } $tmpvalue = ''; $hasAttribute = TRUE; break; } else { $tmpvalue .= $this->sourceString[$i]; } } //不存在属性列表的情况 if(!$hasAttribute) { $this->cAttributes->count++; $tmpvalues = explode('.', $tmpvalue); $this->cAttributes->items['tagname'] = ($this->charToLow ? strtolower($tmpvalues[0]) : $tmpvalues[0]); if( isset($tmpvalues[2]) ) { $okname = $tmpvalues[1]; for($i=2;isset($tmpvalues[$i]);$i++) { $okname .= "['".$tmpvalues[$i]."']"; } $this->cAttributes->items['name'] = $okname; } else if(isset($tmpvalues[1]) && $tmpvalues[1]!='') { $this->cAttributes->items['name'] = $tmpvalues[1]; } return ; } $tmpvalue = ''; //如果字符串含有属性值,遍历源字符串,并获得各属性 for($i; $i<$strLen; $i++) { $d = $this->sourceString[$i]; //查找属性名称 if($startdd==-1) { if($d != '=') { $tmpatt .= $d; } else { if($this->charToLow) { $tmpatt = strtolower(trim($tmpatt)); } else { $tmpatt = trim($tmpatt); } $startdd=0; } } //查找属性的限定标志 else if($startdd==0) { switch($d) { case ' ': break; case '\'': $ddtag = '\''; $startdd = 1; break; case '"': $ddtag = '"'; $startdd = 1; break; default: $tmpvalue .= $d; $ddtag = ' '; $startdd = 1; break; } } else if($startdd==1) { if($d==$ddtag && ( isset($this->sourceString[$i-1]) && $this->sourceString[$i-1]!="\\") ) { $this->cAttributes->count++; $this->cAttributes->items[$tmpatt] = trim($tmpvalue); $tmpatt = ''; $tmpvalue = ''; $startdd = -1; } else { $tmpvalue .= $d; } } }//for //最后一个属性的给值 if($tmpatt != '') { $this->cAttributes->count++; $this->cAttributes->items[$tmpatt] = trim($tmpvalue); }//print_r($this->cAttributes->items); }// end func }//End Class /** * 私有标签编译,主要用于if标签内的字符串解析 * * @access public * @param string $str 需要编译的字符串 * @return string */ function private_rt($str) { if (is_array($str)) { $arr = explode('.', $str[0]); } else { $arr = explode('.', $str); } $rs = '$GLOBALS[\''; if($arr[0] == 'cfg') { return $rs.'cfg_'.$arr[1]."']"; } elseif($arr[0] == 'var') { $arr[0] = '_vars'; $rs .= implode('\'][\'', $arr); $rs .= "']"; return $rs; } elseif($arr[0] == 'global') { unset($arr[0]); $rs .= implode('\'][\'', $arr); $rs .= "']"; return $rs; } else { if($arr[0] == 'field') $arr[0] = 'fields'; $rs = '$'.$arr[0]."['"; unset($arr[0]); $rs .= implode('\'][\'', $arr); $rs .= "']"; return $rs; } }