昨天是柏拉图的生日,生日快乐!
Dede织梦模板类 dedetag.class.php,再读代码,回忆下柏拉图。
<?php if (!defined(‘DEDEINC’)) exit(“DedeCMS Error: Request Error!”);/*** Dede织梦模板类** @version $Id: dedetag.class.php 1 10:33 2010年7月6日 $* @package DedeCMS.Libraries* @founder IT柏拉图, https://weibo.com/itprato* @author DedeCMS团队* @copyright Copyright (c) 2004 – 2024, 上海卓卓网络科技有限公司 (DesDev, Inc.)* @license http://help.dedecms.com/usersguide/license.html* @link http://www.dedecms.com*//*class DedeTag 标记的数据结构描述//获取标记的名称和值//获取值//下面两个成员函数仅是为了兼容旧版//获取标记的指定属性class DedeTagParse Dede织梦模板类初始化模板解析器的基本配置和属性DedeTagParse构造函数设置标记的命名空间,默认为dede重置成员变量或Clear强制引用获取计数器值并加1清除当前对象的状态并将其重置为默认值检查是否存在禁止的函数检测模板缓存写入缓存载入模板文件仅用于兼容旧版本LoadTemplet仅用于兼容旧版本LoadFile载入模板字符串加载字符串数据获得指定名称的Tag的ID(如果有多个同名的Tag,则取没有被取代为内容的第一个Tag)获得指定名称的CTag数据类(如果有多个同名的Tag,则取没有被分配内容的第一个Tag)通过名称获取标记获得指定ID的CTag数据类给_vars数组传递一个元素分配指定ID的标记的值分配指定名称的标记的值,如果标记包含属性,请不要用此函数处理特殊标记运行PHP代码把分析模板输出到一个字符串中把分析模板输出到一个字符串中,并返回直接输出解析模板把解析模板输出为文件解析模板处理某字段的函数获得一个外部变量引入文件class DedeAttribute Dede模板标记属性集合 属性的数据描述属性的数据描述判断属性是否存在获得标记名称获得属性个数class DedeAttributeParse 属性解析器(本版本中已经支持使用\’这种语法,和用.间隔表示name属性,如 field.body)解析属性*/
/*** class DedeTag 标记的数据结构描述* function c____DedeTag();** @package DedeTag* @subpackage DedeCMS.Libraries* @link http://www.dedecms.com*/class DedeTag{var $IsReplace = FALSE; //标记是否已被替代,供解析器使用var $TagName = “”; //标记名称var $InnerText = “”; //标记之间的文本var $StartPos = 0; //标记起始位置var $EndPos = 0; //标记结束位置var $CAttribute = “”; //标记属性描述,即是class DedeAttributevar $TagValue = “”; //标记的值var $TagID = 0;/*** 获取标记的名称和值** @access public* @return string*/function GetName(){return strtolower($this->TagName);}/*** 获取值** @access public* @return string*/function GetValue(){return $this->TagValue;}//下面两个成员函数仅是为了兼容旧版function GetTagName(){return strtolower($this->TagName);}/*** 获取标签值** @return mixed 返回标签的值*/function GetTagValue(){return $this->TagValue;}//获取标记的指定属性function IsAttribute($str){return $this->CAttribute->IsAttribute($str);}/*** 获取属性值** @param string $str 属性名称* @return mixed 返回指定属性的值*/function GetAttribute($str){return $this->CAttribute->GetAtt($str);}/*** 获取属性值** @param string $str 属性名称* @return mixed 返回指定属性的值*/function GetAtt($str){return $this->CAttribute->GetAtt($str);}/*** 获取内部文本内容** @return string 返回元素的内部文本内容*/function GetInnerText(){return $this->InnerText;}}/*** DedeTagParse Dede织梦模板类* function c____DedeTagParse();** @package DedeTagParse* @subpackage DedeCMS.Libraries* @link http://www.dedecms.com*/class DedeTagParse{var $NameSpace = ‘dede’; //标记的名字空间var $TagStartWord = ‘{‘; //标记起始var $TagEndWord = ‘}’; //标记结束var $TagMaxLen = 64; //标记名称的最大值var $CharToLow = TRUE; // TRUE表示对属性和标记名称不区分大小写var $IsCache = FALSE; //是否使用缓冲var $TempMkTime = 0;var $CacheFile = ”;var $SourceString = ”; //模板字符串var $CTags = array(); //标记集合var $Count = -1; //$Tags标记个数var $refObj = ”; //引用当前模板类的对象var $taghashfile = ”;/*** 构造函数** 初始化模板解析器的基本配置和属性** @access public* @return void*/function __construct(){// 检查全局模板缓存配置,如果未设置则默认为关闭状态if (!isset($GLOBALS[‘cfg_tplcache’])) {$GLOBALS[‘cfg_tplcache’] = ‘N’;}// 根据全局配置设置是否启用缓存if ($GLOBALS[‘cfg_tplcache’] == ‘Y’) {$this->IsCache = TRUE;} else {$this->IsCache = FALSE;}// 在开发环境中强制关闭缓存功能if (DEDE_ENVIRONMENT == ‘development’) {$this->IsCache = FALSE;}// 初始化模板解析器的基本属性$this->NameSpace = ‘dede’;$this->TagStartWord = ‘{‘;$this->TagEndWord = ‘}’;$this->TagMaxLen = 64;$this->CharToLow = TRUE;$this->SourceString = ”;$this->CTags = array();$this->Count = -1;$this->TempMkTime = 0;$this->CacheFile = ”;}/*** DedeTagParse构造函数** 该函数用于初始化DedeTagParse对象,调用内部的__construct方法完成对象的构造过程*/function DedeTagParse(){$this->__construct();}/*** 设置标记的命名空间,默认为dede** @access public* @param string $str 字符串* @param string $s 开始标记* @param string $e 结束标记* @return void*/function SetNameSpace($str, $s = “{“, $e = “}”){$this->NameSpace = strtolower($str);$this->TagStartWord = $s;$this->TagEndWord = $e;}/*** 重置成员变量或Clear** @access public* @return void*/function SetDefault(){$this->SourceString = ”;$this->CTags = array();$this->Count = -1;}/*** 强制引用** @access public* @param object $refObj 隶属对象* @return void*/function SetRefObj(&$refObj){$this->refObj = $refObj;}/*** 获取计数器值并加1** @return int 返回当前计数器值加1的结果*/function GetCount(){return $this->Count + 1;}/*** 清除当前对象的状态并将其重置为默认值** 该函数通过调用SetDefault方法来重置对象的所有属性* 到其初始状态或预定义的默认配置** @return void*/function Clear(){$this->SetDefault();}// ————————————————————————/*** CheckDisabledFunctions** COMMENT : CheckDisabledFunctions : 检查是否存在禁止的函数** @access public* @param string $str 待检查的字符串内容* @param string $errmsg 错误信息引用返回参数* @return bool 检查结果,true表示无禁用函数,false表示存在禁用函数*/function CheckDisabledFunctions($str, &$errmsg = ”){// 检查是否包含<script language=’php’>标签if (!empty($str) && preg_match(“#(script)[\s]*(language)[\s]*(=)[\s]*[‘\”]{1}(php)#i”, ” {$str}”) == TRUE) {$errmsg = dede_htmlspecialchars(“DedeCMS Error:<script language= ‘php’>…</script>”);return FALSE;}global $cfg_disable_funs;$cfg_disable_funs = isset($cfg_disable_funs) ? $cfg_disable_funs : ‘phpinfo,eval,assert,exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source,file_put_contents,fsockopen,fopen,fwrite,preg_replace’;// 模板引擎增加disable_functions安全检查if (defined(‘DEDEDISFUN’)) {$tokens = token_get_all_nl(‘<?php’ . $str . “\n\r?>”);$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] . ‘” <a href=”http://help.dedecms.com/install-use/apply/2013/0711/2324.html” target=”_blank”>more…</a>’;return FALSE;}}}}return TRUE;}/*** 检测模板缓存** @access public* @param string $filename 文件名称* @return string*/function LoadCache($filename){global $cfg_tplcache, $cfg_tplcache_dir;if (!$this->IsCache) {return FALSE;}$cdir = dirname($filename);$cachedir = DEDEROOT . $cfg_tplcache_dir;$ckfile = str_replace($cdir, ”, $filename) . substr(md5($filename), 0, 16) . ‘.inc’;$ckfullfile = $cachedir . ‘/’ . $ckfile;$ckfullfile_t = $cachedir . ‘/’ . $ckfile . ‘.txt’;$this->CacheFile = $ckfullfile;$this->TempMkTime = filemtime($filename);if (!file_exists($ckfullfile) || !file_exists($ckfullfile_t)) {return FALSE;}//检测模板最后更新时间$fp = fopen($ckfullfile_t, ‘r’);$time_info = trim(fgets($fp, 64));fclose($fp);if ($time_info != $this->TempMkTime) {return FALSE;}//引入缓冲数组include($this->CacheFile);$errmsg = ”;//把缓冲数组内容读入类if (isset($z) && is_array($z)) {foreach ($z as $k => $v) {$this->Count++;$ctag = new DedeTAg();$ctag->CAttribute = new DedeAttribute();$ctag->IsReplace = FALSE;$ctag->TagName = $v[0];$ctag->InnerText = $v[1];$ctag->StartPos = $v[2];$ctag->EndPos = $v[3];$ctag->TagValue = ”;$ctag->TagID = $k;if (isset($v[4]) && is_array($v[4])) {$i = 0;$ctag->CAttribute->Items = array();foreach ($v[4] as $k => $v) {$ctag->CAttribute->Count++;$ctag->CAttribute->Items[$k] = $v;}}$this->CTags[$this->Count] = $ctag;}} else {//模板没有缓冲数组$this->CTags = ”;$this->Count = -1;}return TRUE;}/*** 写入缓存** @access public* @param string* @return string*/function SaveCache(){$fp = fopen($this->CacheFile . ‘.txt’, “w”);fwrite($fp, $this->TempMkTime . “\n”);fclose($fp);$fp = fopen($this->CacheFile, “w”);flock($fp, 3);fwrite($fp, ‘<‘ . ‘?php’ . “\r\n”);$errmsg = ”;if (is_array($this->CTags)) {foreach ($this->CTags as $tid => $ctag) {$arrayValue = ‘Array(“‘ . $ctag->TagName . ‘”,’;if (!$this->CheckDisabledFunctions($ctag->InnerText, $errmsg)) {fclose($fp);@unlink($this->taghashfile);@unlink($this->CacheFile);@unlink($this->CacheFile . ‘.txt’);die($errmsg);}$arrayValue .= ‘”‘ . str_replace(‘$’, ‘\$’, str_replace(“\r”, “\\r”, str_replace(“\n”, “\\n”, str_replace(‘”‘, ‘\”‘, str_replace(“\\”, “\\\\”, $ctag->InnerText))))) . ‘”‘;$arrayValue .= “,{$ctag->StartPos},{$ctag->EndPos});”;fwrite($fp, “\$z[$tid]={$arrayValue}\n”);if (is_array($ctag->CAttribute->Items)) {fwrite($fp, “\$z[$tid][4]=array();\n”);foreach ($ctag->CAttribute->Items as $k => $v) {$v = str_replace(“\\”, “\\\\”, $v);$v = str_replace(‘”‘, “\\” . ‘”‘, $v);$v = str_replace(‘$’, ‘\$’, $v);$k = trim(str_replace(“‘”, “”, $k));if ($k == “”) {continue;}if ($k != ‘tagname’) {fwrite($fp, “\$z[$tid][4][‘$k’]=\”$v\”;\n”);}}}}}fwrite($fp, “\n” . ‘?’ . ‘>’);fclose($fp);}/*** 载入模板文件** @access public* @param string $filename 文件名称* @return string*/function LoadTemplate($filename){$this->SetDefault();if (!file_exists($filename)) {$this->SourceString = ” $filename Not Found! “;$this->ParseTemplet();} else {$fp = @fopen($filename, “r”);while ($line = fgets($fp, 1024)) {$this->SourceString .= $line;}fclose($fp);if ($this->LoadCache($filename)) {return ”;} else {$this->ParseTemplet();}}}// 仅用于兼容旧版本function LoadTemplet($filename){$this->LoadTemplate($filename);}// 仅用于兼容旧版本function LoadFile($filename){$this->LoadTemplate($filename);}/*** 载入模板字符串** @access public* @param string $str 字符串* @return void*/function LoadSource($str){/*$this->SetDefault();$this->SourceString = $str;$this->IsCache = FALSE;$this->ParseTemplet();*///优化模板字符串存取读取方式$this->taghashfile = $filename = DEDEDATA . ‘/tplcache/’ . md5($str) . ‘.inc’;if (!is_file($filename)) {file_put_contents($filename, $str);}$this->LoadTemplate($filename);}/*** 加载字符串数据** @param string $str 要加载的字符串数据* @return void*/function LoadString($str){$this->LoadSource($str);}/*** 获得指定名称的Tag的ID(如果有多个同名的Tag,则取没有被取代为内容的第一个Tag)** @access public* @param string $str 字符串* @return int*/function GetTagID($str){if ($this->Count == -1) {return -1;}if ($this->CharToLow) {$str = strtolower($str);}foreach ($this->CTags as $id => $CTag) {if ($CTag->TagName == $str && !$CTag->IsReplace) {return $id;break;}}return -1;}/*** 获得指定名称的CTag数据类(如果有多个同名的Tag,则取没有被分配内容的第一个Tag)** @access public* @param string $str 字符串* @return string*/function GetTag($str){if ($this->Count == -1) {return ”;}if ($this->CharToLow) {$str = strtolower($str);}foreach ($this->CTags as $id => $CTag) {if ($CTag->TagName == $str && !$CTag->IsReplace) {return $CTag;break;}}return ”;}/*** 通过名称获取标记** @access public* @param string $str 字符串* @return string*/function GetTagByName($str){return $this->GetTag($str);}/*** 获得指定ID的CTag数据类** @access public* @param string 标签id* @return string*/function GetTagByID($id){if (isset($this->CTags[$id])) {return $this->CTags[$id];} else {return ”;}}/*** 给_vars数组传递一个元素** @access public* @param string $vname 标签名* @param string $vvalue 标签值* @return string*/function AssignVar($vname, $vvalue){if (!isset($_sys_globals[‘define’])) {$_sys_globals[‘define’] = ‘yes’;}$_sys_globals[$vname] = $vvalue;}/*** 分配指定ID的标记的值** @access public* @param string $i 标签id* @param string $str 字符串* @param string $runfunc 运行函数* @return void*/function Assign($i, $str, $runfunc = TRUE){global $cfg_replacestr;if ($cfg_replacestr != “”) {$str = preg_replace(“#{$cfg_replacestr}#i”, “***”, $str);}if (isset($this->CTags[$i])) {$this->CTags[$i]->IsReplace = TRUE;$this->CTags[$i]->TagValue = $str;if ($this->CTags[$i]->GetAtt(‘function’) != ” && $runfunc) {$this->CTags[$i]->TagValue = $this->EvalFunc($str, $this->CTags[$i]->GetAtt(‘function’), $this->CTags[$i]);}}}/*** 分配指定名称的标记的值,如果标记包含属性,请不要用此函数** @access public* @param string $tagname 标签名称* @param string $str 字符串* @return void*/function AssignName($tagname, $str){foreach ($this->CTags as $id => $CTag) {if ($CTag->TagName == $tagname) {$this->Assign($id, $str);}}}/*** 处理特殊标记** @access public* @return void*/function AssignSysTag(){global $_sys_globals;for ($i = 0; $i <= $this->Count; $i++) {$CTag = $this->CTags[$i];$str = ”;//获取一个外部变量if ($CTag->TagName == ‘global’) {$str = $this->GetGlobals($CTag->GetAtt(‘name’));if ($this->CTags[$i]->GetAtt(‘function’) != ”) {//$str = $this->EvalFunc( $this->CTags[$i]->TagValue, $this->CTags[$i]->GetAtt(‘function’),$this->CTags[$i] );$str = $this->EvalFunc($str, $this->CTags[$i]->GetAtt(‘function’), $this->CTags[$i]);}$this->CTags[$i]->IsReplace = TRUE;$this->CTags[$i]->TagValue = $str;}//引入静态文件else if ($CTag->TagName == ‘include’) {$filename = ($CTag->GetAtt(‘file’) == ” ? $CTag->GetAtt(‘filename’) : $CTag->GetAtt(‘file’));$str = $this->IncludeFile($filename, $CTag->GetAtt(‘ismake’));$this->CTags[$i]->IsReplace = TRUE;$this->CTags[$i]->TagValue = $str;}//循环一个普通数组else if ($CTag->TagName == ‘foreach’) {$arr = $this->CTags[$i]->GetAtt(‘array’);if (isset($GLOBALS[$arr])) {foreach ($GLOBALS[$arr] as $k => $v) {$istr = ”;$istr .= preg_replace(“/\[field:key([\r\n\t\f ]+)\/\]/is”, $k, $this->CTags[$i]->InnerText);$str .= preg_replace(“/\[field:value([\r\n\t\f ]+)\/\]/is”, $v, $istr);}}$this->CTags[$i]->IsReplace = TRUE;$this->CTags[$i]->TagValue = $str;}//设置/获取变量值else if ($CTag->TagName == ‘var’) {$vname = $this->CTags[$i]->GetAtt(‘name’);if ($vname == ”) {$str = ”;} else if ($this->CTags[$i]->GetAtt(‘value’) != ”) {$_vars[$vname] = $this->CTags[$i]->GetAtt(‘value’);} else {$str = (isset($_vars[$vname]) ? $_vars[$vname] : ”);}$this->CTags[$i]->IsReplace = TRUE;$this->CTags[$i]->TagValue = $str;}//运行PHP接口if ($CTag->GetAtt(‘runphp’) == ‘yes’) {$this->RunPHP($CTag, $i);}if (is_array($this->CTags[$i]->TagValue)) {$this->CTags[$i]->TagValue = ‘array’;}}}//运行PHP代码function RunPHP(&$refObj, $i){$DedeMeValue = $phpcode = ”;if ($refObj->GetAtt(‘source’) == ‘value’) {$phpcode = $this->CTags[$i]->TagValue;} else {$DedeMeValue = $this->CTags[$i]->TagValue;$phpcode = $refObj->GetInnerText();}$phpcode = preg_replace(“/’@me’|\”@me\”|@me/i”, ‘$DedeMeValue’, $phpcode);// 不允许这些字符$phpcode = preg_replace(“#(/\*)[\s\S]*(\*/)#i”, ”, $phpcode);global $cfg_disable_funs;$cfg_disable_funs = isset($cfg_disable_funs) ? $cfg_disable_funs : ‘phpinfo,eval,assert,exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source,file_put_contents,fsockopen,fopen,fwrite,preg_replace’;$cfg_disable_funs = $cfg_disable_funs . ‘,[$]GLOBALS,[$]_GET,[$]_POST,[$]_REQUEST,[$]_FILES,[$]_COOKIE,[$]_SERVER,include,require,create_function,array_map,call_user_func,call_user_func_array,array_filert’;foreach (explode(“,”, $cfg_disable_funs) as $value) {$value = str_replace(” “, “”, $value);if (!empty($value) && preg_match(“#[^a-z]+[‘\”]*{$value}[‘\”]*[\s]*[([{‘]#i”, ” {$phpcode}”) == TRUE) {$phpcode = dede_htmlspecialchars($phpcode);die(“DedeCMS提示:当前页面中存在恶意代码!<pre>{$phpcode}</pre>”);}}@eval($phpcode);$this->CTags[$i]->TagValue = $DedeMeValue;$this->CTags[$i]->IsReplace = TRUE;}/*** 把分析模板输出到一个字符串中* 不替换没被处理的值** @access public* @return string*/function GetResultNP(){$ResultString = ”;if ($this->Count == -1) {return $this->SourceString;}$this->AssignSysTag();$nextTagEnd = 0;$strok = “”;for ($i = 0; $i <= $this->Count; $i++) {if ($this->CTags[$i]->GetValue() != “”) {if ($this->CTags[$i]->GetValue() == ‘#@Delete@#’) {$this->CTags[$i]->TagValue = “”;}$ResultString .= substr($this->SourceString, $nextTagEnd, $this->CTags[$i]->StartPos – $nextTagEnd);$ResultString .= $this->CTags[$i]->GetValue();$nextTagEnd = $this->CTags[$i]->EndPos;}}$slen = strlen($this->SourceString);if ($slen > $nextTagEnd) {$ResultString .= substr($this->SourceString, $nextTagEnd, $slen – $nextTagEnd);}return $ResultString;}/*** 把分析模板输出到一个字符串中,并返回** @access public* @return string*/function GetResult(){$ResultString = ”;if ($this->Count == -1) {return $this->SourceString;}$this->AssignSysTag();$nextTagEnd = 0;$strok = “”;for ($i = 0; $i <= $this->Count; $i++) {$ResultString .= substr($this->SourceString, $nextTagEnd, $this->CTags[$i]->StartPos – $nextTagEnd);$ResultString .= $this->CTags[$i]->GetValue();$nextTagEnd = $this->CTags[$i]->EndPos;}$slen = strlen($this->SourceString);if ($slen > $nextTagEnd) {$ResultString .= substr($this->SourceString, $nextTagEnd, $slen – $nextTagEnd);}return $ResultString;}/*** 直接输出解析模板** @access public* @return void*/function Display(){echo $this->GetResult();}/*** 把解析模板输出为文件** @access public* @param string $filename 要保存到的文件* @return string*/function SaveTo($filename){$fp = @fopen($filename, “w”) or die(“DedeTag Engine Create File False: {$filename}”);fwrite($fp, $this->GetResult());fclose($fp);}/*** 解析模板** 该函数用于解析模板字符串,提取其中的标记(tag)及其属性和内容。* 它会遍历整个模板源字符串,识别符合命名空间规则的标签,并将其封装为 DedeTag 对象存储在 $this->CTags 数组中。* 同时支持缓存机制,在解析完成后可选择保存缓存。** @access public* @return void 无返回值*/function ParseTemplet(){// 初始化标签起始和结束标识符$TagStartWord = $this->TagStartWord;$TagEndWord = $this->TagEndWord;$sPos = 0;$ePos = 0;// 构造完整标签开始与结束标识$FullTagStartWord = $TagStartWord . $this->NameSpace . “:”;$sTagEndWord = $TagStartWord . “/” . $this->NameSpace . “:”;$eTagEndWord = “/” . $TagEndWord;// 计算标签起始标识长度及源字符串长度$tsLen = strlen($FullTagStartWord);$sourceLen = strlen($this->SourceString);// 如果源字符串长度不足以包含一个有效标签,则直接返回if ($sourceLen <= ($tsLen + 3)) {return;}// 创建属性解析对象并设置大小写转换选项$cAtt = new DedeAttributeParse();$cAtt->charToLow = $this->CharToLow;// 遍历模板字符串,提取标记及其属性信息for ($i = 0; $i < $sourceLen; $i++) {$tTagName = ”;// 调整搜索起始位置以避免遗漏相邻标签if ($i – 1 >= 0) {$ss = $i – 1;} else {$ss = 0;}$sPos = strpos($this->SourceString, $FullTagStartWord, $ss);$isTag = $sPos;// 处理模板开头即为标签的情况if ($i == 0) {$headerTag = substr($this->SourceString, 0, strlen($FullTagStartWord));if ($headerTag == $FullTagStartWord) {$isTag = TRUE;$sPos = 0;}}// 若未找到标签起始位置,则跳出循环if ($isTag === FALSE) {break;}// 提取标签名称for ($j = ($sPos + $tsLen); $j < ($sPos + $tsLen + $this->TagMaxLen); $j++) {if ($j > ($sourceLen – 1)) {break;} else if (preg_match(“/[\/ \t\r\n]/”, $this->SourceString[$j]) || $this->SourceString[$j] == $this->TagEndWord) {break;} else {$tTagName .= $this->SourceString[$j];}}// 如果成功提取到标签名if ($tTagName != ”) {$i = $sPos + $tsLen;$endPos = -1;// 构造当前标签的结束标识$fullTagEndWordThis = $sTagEndWord . $tTagName . $TagEndWord;// 查找三种可能的结束标识位置$e1 = strpos($this->SourceString, $eTagEndWord, $i);$e2 = strpos($this->SourceString, $FullTagStartWord, $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) {$endPos = $e1;$elen = $endPos + strlen($eTagEndWord);} else if ($e1 == -1) {$endPos = $e3;$elen = $endPos + strlen($fullTagEndWordThis);} else {// 比较多个结束标识的位置,选取最近的一个if ($e1 < $e2 && $e1 < $e3) {$endPos = $e1;$elen = $endPos + strlen($eTagEndWord);} else {$endPos = $e3;$elen = $endPos + strlen($fullTagEndWordThis);}}// 若未找到结束标识则报错并跳出循环if ($endPos == -1) {echo “Tag Character postion $sPos, ‘$tTagName’ Error!<br />\r\n”;break;}$i = $elen;$ePos = $endPos;// 分离属性字符串和内部文本内容$attStr = ”;$innerText = ”;$startInner = 0;for ($j = ($sPos + $tsLen); $j < $ePos; $j++) {if ($startInner == 0 && ($this->SourceString[$j] == $TagEndWord && $this->SourceString[$j – 1] != “\\”)) {$startInner = 1;continue;}if ($startInner == 0) {$attStr .= $this->SourceString[$j];} else {$innerText .= $this->SourceString[$j];}}// 解析属性并创建标签对象$cAtt->SetSource($attStr);if ($cAtt->cAttributes->GetTagName() != ”) {$this->Count++;$CDTag = new DedeTag();$CDTag->TagName = $cAtt->cAttributes->GetTagName();$CDTag->StartPos = $sPos;$CDTag->EndPos = $i;$CDTag->CAttribute = $cAtt->cAttributes;$CDTag->IsReplace = FALSE;$CDTag->TagID = $this->Count;$CDTag->InnerText = $innerText;$this->CTags[$this->Count] = $CDTag;}} else {$i = $sPos + $tsLen;break;}} // 结束遍历模板字符串// 若启用缓存则保存解析结果if ($this->IsCache) {$this->SaveCache();}}/*** 处理某字段的函数** @access public* @param string $fieldvalue 字段值* @param string $functionname 函数名称* @param object $refObj 隶属对象* @return string*/function EvalFunc($fieldvalue, $functionname, &$refObj){$DedeFieldValue = $fieldvalue;$functionname = str_replace(“{\””, “[\””, $functionname);$functionname = str_replace(“\”}”, “\”]”, $functionname);$functionname = preg_replace(“/’@me’|\”@me\”|@me/i”, ‘$DedeFieldValue’, $functionname);$functionname = “\$DedeFieldValue = ” . $functionname;@eval($functionname . “;”); //or die(“<xmp>$functionname</xmp>”);if (empty($DedeFieldValue)) {return ”;} else {return $DedeFieldValue;}}/*** 获得一个外部变量** @access public* @param string $varname 变量名称* @return string*/function GetGlobals($varname){$varname = trim($varname);//禁止在模板文件读取数据库密码if ($varname == “dbuserpwd” || $varname == “cfg_dbpwd”) {return “”;}//正常情况if (isset($GLOBALS[$varname])) {return $GLOBALS[$varname];} else {return “”;}}/*** 引入文件** @access public* @param string $filename 文件名* @param string $ismake 是否需要编译* @return string*/function IncludeFile($filename, $ismake = ‘no’){global $cfg_df_style;$restr = ”;if ($filename == ”) {return ”;}if (file_exists(DEDEROOT . “/templets/” . $filename)) {$okfile = DEDEROOT . “/templets/” . $filename;} else if (file_exists(DEDEROOT . ‘/templets/’ . $cfg_df_style . ‘/’ . $filename)) {$okfile = DEDEROOT . ‘/templets/’ . $cfg_df_style . ‘/’ . $filename;} else {return “无法在这个位置找到: $filename”;}//编译if ($ismake != “no”) {require_once(DEDEINC . “/channelunit.func.php”);$dtp = new DedeTagParse();$dtp->LoadTemplet($okfile);MakeOneTag($dtp, $this->refObj);$restr = $dtp->GetResult();} else {$fp = @fopen($okfile, “r”);while ($line = fgets($fp, 1024)) $restr .= $line;fclose($fp);}return $restr;}}/**********************************************//class DedeAttribute Dede模板标记属性集合function c____DedeAttribute();**********************************************///属性的数据描述class DedeAttribute{var $Count = -1;var $Items = array(); //属性元素的集合//获得某个属性function GetAtt($str){if ($str == “”) {return “”;}if (isset($this->Items[$str])) {return $this->Items[$str];} else {return “”;}}//同上function GetAttribute($str){return $this->GetAtt($str);}//判断属性是否存在function IsAttribute($str){if (isset($this->Items[$str])) return TRUE;else return FALSE;}//获得标记名称function GetTagName(){return $this->GetAtt(“tagname”);}// 获得属性个数function GetCount(){return $this->Count + 1;}}/*******************************//属性解析器(本版本中已经支持使用\’这种语法,和用.间隔表示name属性,如 field.body)function c____DedeAttributeParse();********************************/class DedeAttributeParse{var $sourceString = “”;var $sourceMaxSize = 1024;var $cAttributes = “”;var $charToLow = TRUE;function SetSource($str = ”){$this->cAttributes = new DedeAttribute();$strLen = 0;$this->sourceString = trim(preg_replace(“/[ \r\n\t]{1,}/”, ” “, $str));//为了在function内能使用数组,这里允许对[ ]进行转义使用$this->sourceString = str_replace(‘\]’, ‘]’, $this->sourceString);$this->sourceString = str_replace(‘[‘, ‘[‘, $this->sourceString);/*$this->sourceString = str_replace(‘\>’,’>’,$this->sourceString);$this->sourceString = str_replace(‘<‘,’>’,$this->sourceString);$this->sourceString = str_replace(‘{‘,'{‘,$this->sourceString);$this->sourceString = str_replace(‘\}’,’}’,$this->sourceString);*/$strLen = strlen($this->sourceString);if ($strLen > 0 && $strLen <= $this->sourceMaxSize) {$this->ParseAttribute();}}//解析属性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[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[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}