国内流行的内容管理系统(CMS)多端全媒体解决方案 https://www.dedebiz.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1550 lines
47KB

  1. <?php if(!defined('DEDEINC')) exit("Request Error!");
  2. /**
  3. * 模板引擎文件
  4. *
  5. * @version $Id: dedetemplate.class.php 3 15:44 2010年7月6日Z tianya $
  6. * @package DedeCMS.Libraries
  7. * @copyright Copyright (c) 2007 - 2020, DesDev, Inc.
  8. * @license http://help.dedecms.com/usersguide/license.html
  9. * @link http://www.dedecms.com
  10. */
  11. /**
  12. * 这个函数用于定义任意名称的块使用的接口
  13. * 返回值应是一个二维数组
  14. * 块调用对应的文件为 include/taglib/plus_blockname.php
  15. * ----------------------------------------------------------------
  16. * 由于标记一般存在默认属性,在编写块函数时,应该在块函数中进行给属性赋省缺值处理,如:
  17. * $attlist = "titlelen=30,catalogid=0,modelid=0,flag=,addon=,row=8,ids=,orderby=id,orderway=desc,limit=,subday=0";
  18. * 给属性赋省缺值
  19. * FillAtts($atts,$attlist);
  20. * 处理属性中使用的系统变量 var、global、field 类型(不支持多维数组)
  21. * FillFields($atts,$fields,$refObj);
  22. *
  23. * @access public
  24. * @param array $atts 属性
  25. * @param object $refObj 所属对象
  26. * @param array $fields 字段
  27. * @return string
  28. */
  29. function MakePublicTag($atts=array(),$refObj='',$fields=array())
  30. {
  31. $atts['tagname'] = preg_replace("/[0-9]{1,}$/", "", $atts['tagname']);
  32. $plusfile = DEDEINC.'/tpllib/plus_'.$atts['tagname'].'.php';
  33. if(!file_exists($plusfile))
  34. {
  35. if(isset($atts['rstype']) && $atts['rstype']=='string')
  36. {
  37. return '';
  38. }
  39. else
  40. {
  41. return array();
  42. }
  43. }
  44. else
  45. {
  46. include_once($plusfile);
  47. $func = 'plus_'.$atts['tagname'];
  48. return $func($atts, $refObj, $fields);
  49. }
  50. }
  51. /**
  52. * 设定属性的默认值
  53. *
  54. * @access public
  55. * @param array $atts 属性
  56. * @param array $attlist 属性列表
  57. * @return void
  58. */
  59. function FillAtts(&$atts, $attlist)
  60. {
  61. $attlists = explode(',', $attlist);
  62. foreach($attlists as $att)
  63. {
  64. list($k, $v)=explode('=', $att);
  65. if(!isset($atts[$k]))
  66. {
  67. $atts[$k] = $v;
  68. }
  69. }
  70. }
  71. /**
  72. * 把上级的fields传递给atts
  73. *
  74. * @access public
  75. * @param array $atts 属性
  76. * @param object $refObj 所属对象
  77. * @param array $fields 字段
  78. * @return string
  79. */
  80. function FillFields(&$atts, &$refObj, &$fields)
  81. {
  82. global $_vars;
  83. foreach($atts as $k=>$v)
  84. {
  85. if(preg_match('/^field\./i',$v))
  86. {
  87. $key = preg_replace('/^field\./i', '', $v);
  88. if( isset($fields[$key]) )
  89. {
  90. $atts[$k] = $fields[$key];
  91. }
  92. }
  93. else if(preg_match('/^var\./i', $v))
  94. {
  95. $key = preg_replace('/^var\./i', '', $v);
  96. if( isset($_vars[$key]) )
  97. {
  98. $atts[$k] = $_vars[$key];
  99. }
  100. }
  101. else if(preg_match('/^global\./i', $v))
  102. {
  103. $key = preg_replace('/^global\./i', '', $v);
  104. if( isset($GLOBALS[$key]) )
  105. {
  106. $atts[$k] = $GLOBALS[$key];
  107. }
  108. }
  109. }
  110. }
  111. /**
  112. * class Tag 标记的数据结构描述
  113. * function C__Tag();
  114. *
  115. * @package Tag
  116. * @subpackage DedeCMS.Libraries
  117. * @link http://www.dedecms.com
  118. */
  119. class Tag
  120. {
  121. var $isCompiler=FALSE; //标记是否已被替代,供解析器使用
  122. var $tagName=""; //标记名称
  123. var $innerText=""; //标记之间的文本
  124. var $startPos=0; //标记起始位置
  125. var $endPos=0; //标记结束位置
  126. var $cAtt=""; //标记属性描述,即是class TagAttribute
  127. var $tagValue=""; //标记的值
  128. var $tagID = 0;
  129. /**
  130. * 获取标记的名称和值
  131. *
  132. * @access public
  133. * @return string
  134. */
  135. function GetName()
  136. {
  137. return strtolower($this->tagName);
  138. }
  139. function GetValue()
  140. {
  141. return $this->tagValue;
  142. }
  143. function IsAtt($str)
  144. {
  145. return $this->cAtt->IsAttribute($str);
  146. }
  147. function GetAtt($str)
  148. {
  149. return $this->cAtt->GetAtt($str);
  150. }
  151. /**
  152. * 获取底层模板
  153. *
  154. * @return string
  155. */
  156. function GetinnerText()
  157. {
  158. return $this->innerText;
  159. }
  160. }
  161. /**
  162. * 模板解析器
  163. * function C__DedeTemplate
  164. *
  165. * @package DedeTemplate
  166. * @subpackage DedeCMS.Libraries
  167. * @link http://www.dedecms.com
  168. */
  169. class DedeTemplate
  170. {
  171. var $tagMaxLen = 64;
  172. var $charToLow = TRUE;
  173. var $isCache = TRUE;
  174. var $isParse = FALSE;
  175. var $isCompiler = TRUE;
  176. var $templateDir = '';
  177. var $tempMkTime = 0;
  178. var $cacheFile = '';
  179. var $configFile = '';
  180. var $buildFile = '';
  181. var $refDir = '';
  182. var $cacheDir = '';
  183. var $templateFile = '';
  184. var $sourceString = '';
  185. var $cTags = array();
  186. //var $definedVars = array();
  187. var $count = -1;
  188. var $loopNum = 0;
  189. var $refObj = '';
  190. var $makeLoop = 0;
  191. var $tagStartWord = '{dede:';
  192. var $fullTagEndWord = '{/dede:';
  193. var $sTagEndWord = '/}';
  194. var $tagEndWord = '}';
  195. var $tpCfgs = array();
  196. /**
  197. * 析构函数
  198. *
  199. * @access public
  200. * @param string $templatedir 模板目录
  201. * @param string $refDir 所属目录
  202. * @return void
  203. */
  204. function __construct($templatedir='',$refDir='')
  205. {
  206. //$definedVars[] = 'var';
  207. //缓存目录
  208. if($templatedir=='')
  209. {
  210. $this->templateDir = DEDEROOT.'/templates';
  211. }
  212. else
  213. {
  214. $this->templateDir = $templatedir;
  215. }
  216. //模板include目录
  217. if($refDir=='')
  218. {
  219. if(isset($GLOBALS['cfg_df_style']))
  220. {
  221. $this->refDir = $this->templateDir.'/'.$GLOBALS['cfg_df_style'].'/';
  222. }
  223. else
  224. {
  225. $this->refDir = $this->templateDir;
  226. }
  227. }
  228. $this->cacheDir = DEDEROOT.$GLOBALS['cfg_tplcache_dir'];
  229. }
  230. //构造函数,兼容PHP4
  231. function DedeTemplate($templatedir='',$refDir='')
  232. {
  233. $this->__construct($templatedir,$refDir);
  234. }
  235. /**
  236. * 设定本类自身实例的类引用和使用本类的类实例(如果在类中使用本模板引擎,后一参数一般为$this)
  237. *
  238. * @access public
  239. * @param object $refObj 实例对象
  240. * @return string
  241. */
  242. function SetObject(&$refObj)
  243. {
  244. $this->refObj = $refObj;
  245. }
  246. /**
  247. * 设定Var的键值对
  248. *
  249. * @access public
  250. * @param string $k 键
  251. * @param string $v 值
  252. * @return string
  253. */
  254. function SetVar($k, $v)
  255. {
  256. $GLOBALS['_vars'][$k] = $v;
  257. }
  258. /**
  259. * 设定Var的键值对
  260. *
  261. * @access public
  262. * @param string $k 键
  263. * @param string $v 值
  264. * @return string
  265. */
  266. function Assign($k, $v)
  267. {
  268. $GLOBALS['_vars'][$k] = $v;
  269. }
  270. /**
  271. * 设定数组
  272. *
  273. * @access public
  274. * @param string $k 键
  275. * @param string $v 值
  276. * @return string
  277. */
  278. function SetArray($k, $v)
  279. {
  280. $GLOBALS[$k] = $v;
  281. }
  282. /**
  283. * 设置标记风格
  284. *
  285. * @access public
  286. * @param string $ts 标签开始标记
  287. * @param string $ftend 标签结束标记
  288. * @param string $stend 标签尾部结束标记
  289. * @param string $tend 结束标记
  290. * @return void
  291. */
  292. function SetTagStyle($ts='{dede:',$ftend='{/dede:',$stend='/}',$tend='}')
  293. {
  294. $this->tagStartWord = $ts;
  295. $this->fullTagEndWord = $ftend;
  296. $this->sTagEndWord = $stend;
  297. $this->tagEndWord = $tend;
  298. }
  299. /**
  300. * 获得模板设定的config值
  301. *
  302. * @access public
  303. * @param string $k 键名
  304. * @return string
  305. */
  306. function GetConfig($k)
  307. {
  308. return (isset($this->tpCfgs[$k]) ? $this->tpCfgs[$k] : '');
  309. }
  310. /**
  311. * 设定模板文件
  312. *
  313. * @access public
  314. * @param string $tmpfile 模板文件
  315. * @return void
  316. */
  317. function LoadTemplate($tmpfile)
  318. {
  319. if(!file_exists($tmpfile))
  320. {
  321. echo " Template Not Found! ";
  322. exit();
  323. }
  324. $tmpfile = preg_replace("/[\\/]{1,}/", "/", $tmpfile);
  325. $tmpfiles = explode('/',$tmpfile);
  326. $tmpfileOnlyName = preg_replace("/(.*)\//", "", $tmpfile);
  327. $this->templateFile = $tmpfile;
  328. $this->refDir = '';
  329. for($i=0; $i < count($tmpfiles)-1; $i++)
  330. {
  331. $this->refDir .= $tmpfiles[$i].'/';
  332. }
  333. if(!is_dir($this->cacheDir))
  334. {
  335. $this->cacheDir = $this->refDir;
  336. }
  337. if($this->cacheDir!='')
  338. {
  339. $this->cacheDir = $this->cacheDir.'/';
  340. }
  341. if(isset($GLOBALS['_DEBUG_CACHE']))
  342. {
  343. $this->cacheDir = $this->refDir;
  344. }
  345. $this->cacheFile = $this->cacheDir.preg_replace("/\.(wml|html|htm|php)$/", "_".$this->GetEncodeStr($tmpfile).'.inc', $tmpfileOnlyName);
  346. $this->configFile = $this->cacheDir.preg_replace("/\.(wml|html|htm|php)$/", "_".$this->GetEncodeStr($tmpfile).'_config.inc', $tmpfileOnlyName);
  347. //不开启缓存、当缓存文件不存在、及模板为更新的文件的时候才载入模板并进行解析
  348. if($this->isCache==FALSE || !file_exists($this->cacheFile)
  349. || filemtime($this->templateFile) > filemtime($this->cacheFile))
  350. {
  351. $t1 = ExecTime(); //debug
  352. $fp = fopen($this->templateFile,'r');
  353. $this->sourceString = fread($fp,filesize($this->templateFile));
  354. fclose($fp);
  355. $this->ParseTemplate();
  356. //模板解析时间
  357. //echo ExecTime() - $t1;
  358. }
  359. else
  360. {
  361. //如果存在config文件,则载入此文件,该文件用于保存 $this->tpCfgs的内容,以供扩展用途
  362. //模板中用{tag:config name='' value=''/}来设定该值
  363. if(file_exists($this->configFile))
  364. {
  365. include($this->configFile);
  366. }
  367. }
  368. }
  369. /**
  370. * 载入模板字符串
  371. *
  372. * @access public
  373. * @param string $str 模板字符串
  374. * @return void
  375. */
  376. function LoadString($str='')
  377. {
  378. $this->sourceString = $str;
  379. $hashcode = md5($this->sourceString);
  380. $this->cacheFile = $this->cacheDir."/string_".$hashcode.".inc";
  381. $this->configFile = $this->cacheDir."/string_".$hashcode."_config.inc";
  382. $this->ParseTemplate();
  383. }
  384. /**
  385. * 调用此函数include一个编译后的PHP文件,通常是在最后一个步骤才调用本文件
  386. *
  387. * @access public
  388. * @return string
  389. */
  390. function CacheFile()
  391. {
  392. global $gtmpfile;
  393. $this->WriteCache();
  394. return $this->cacheFile;
  395. }
  396. /**
  397. * 显示内容,由于函数中会重新解压一次$GLOBALS变量,所以在动态页中,应该尽量少用本方法,
  398. * 取代之是直接在程序中 include $tpl->CacheFile(),不过include $tpl->CacheFile()这种方式不能在类或函数内使用
  399. *
  400. * @access public
  401. * @param string
  402. * @return void
  403. */
  404. function Display()
  405. {
  406. global $gtmpfile;
  407. extract($GLOBALS, EXTR_SKIP);
  408. $this->WriteCache();
  409. include $this->cacheFile;
  410. }
  411. /**
  412. * 保存运行后的程序为文件
  413. *
  414. * @access public
  415. * @param string $savefile 保存到的文件目录
  416. * @return void
  417. */
  418. function SaveTo($savefile)
  419. {
  420. extract($GLOBALS, EXTR_SKIP);
  421. $this->WriteCache();
  422. ob_start();
  423. include $this->cacheFile;
  424. $okstr = ob_get_contents();
  425. ob_end_clean();
  426. $fp = @fopen($savefile,"w") or die(" Tag Engine Create File FALSE! ");
  427. fwrite($fp,$okstr);
  428. fclose($fp);
  429. }
  430. // ------------------------------------------------------------------------
  431. /**
  432. * CheckDisabledFunctions
  433. *
  434. * COMMENT : CheckDisabledFunctions : 检查是否存在禁止的函数
  435. *
  436. * @access public
  437. * @param string
  438. * @return bool
  439. */
  440. function CheckDisabledFunctions($str,&$errmsg='')
  441. {
  442. global $cfg_disable_funs;
  443. $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';
  444. // 模板引擎增加disable_functions
  445. if (!defined('DEDEDISFUN')) {
  446. $tokens = token_get_all_nl($str);
  447. $disabled_functions = explode(',', $cfg_disable_funs);
  448. foreach ($tokens as $token)
  449. {
  450. if (is_array($token))
  451. {
  452. if ($token[0] = '306' && in_array($token[1], $disabled_functions))
  453. {
  454. $errmsg = 'DedeCMS Error:function disabled "'.$token[1].'" <a href="http://help.dedecms.com/install-use/apply/2013/0711/2324.html" target="_blank">more...</a>';
  455. return FALSE;
  456. }
  457. }
  458. }
  459. }
  460. return TRUE;
  461. }
  462. /**
  463. * 解析模板并写缓存文件
  464. *
  465. * @access public
  466. * @param string $ctype 缓存类型
  467. * @return void
  468. */
  469. function WriteCache($ctype='all')
  470. {
  471. if(!file_exists($this->cacheFile) || $this->isCache==FALSE
  472. || ( file_exists($this->templateFile) && (filemtime($this->templateFile) > filemtime($this->cacheFile)) ) )
  473. {
  474. if(!$this->isParse)
  475. {
  476. $this->ParseTemplate();
  477. }
  478. $fp = fopen($this->cacheFile,'w') or dir("Write Cache File Error! ");
  479. flock($fp,3);
  480. $result = trim($this->GetResult());
  481. $errmsg = '';
  482. //var_dump($result);exit();
  483. if (!$this->CheckDisabledFunctions($result, $errmsg))
  484. {
  485. fclose($fp);
  486. @unlink($this->cacheFile);
  487. die($errmsg);
  488. }
  489. fwrite($fp,$result);
  490. fclose($fp);
  491. if(count($this->tpCfgs) > 0)
  492. {
  493. $fp = fopen($this->configFile,'w') or dir("Write Config File Error! ");
  494. flock($fp,3);
  495. fwrite($fp,'<'.'?php'."\r\n");
  496. foreach($this->tpCfgs as $k=>$v)
  497. {
  498. $v = str_replace("\"","\\\"",$v);
  499. $v = str_replace("\$","\\\$",$v);
  500. fwrite($fp,"\$this->tpCfgs['$k']=\"$v\";\r\n");
  501. }
  502. fwrite($fp,'?'.'>');
  503. fclose($fp);
  504. }
  505. }
  506. /*
  507. if(!file_exists($this->cacheFile) || $this->isCache==FALSE
  508. || ( file_exists($this->templateFile) && (filemtime($this->templateFile) > filemtime($this->cacheFile)) ) )
  509. {
  510. if($ctype!='config')
  511. {
  512. if(!$this->isParse)
  513. {
  514. $this->ParseTemplate();
  515. }
  516. $fp = fopen($this->cacheFile,'w') or dir("Write Cache File Error! ");
  517. flock($fp,3);
  518. fwrite($fp,trim($this->GetResult()));
  519. fclose($fp);
  520. }
  521. else
  522. {
  523. if(count($this->tpCfgs) > 0)
  524. {
  525. $fp = fopen($this->configFile,'w') or dir("Write Config File Error! ");
  526. flock($fp,3);
  527. fwrite($fp,'<'.'?php'."\r\n");
  528. foreach($this->tpCfgs as $k=>$v)
  529. {
  530. $v = str_replace("\"","\\\"",$v);
  531. $v = str_replace("\$","\\\$",$v);
  532. fwrite($fp,"\$this->tpCfgs['$k']=\"$v\";\r\n");
  533. }
  534. fwrite($fp,'?'.'>');
  535. fclose($fp);
  536. }
  537. }
  538. }
  539. else
  540. {
  541. if($ctype=='config' && count($this->tpCfgs) > 0 )
  542. {
  543. $fp = fopen($this->configFile,'w') or dir("Write Config File Error! ");
  544. flock($fp,3);
  545. fwrite($fp,'<'.'?php'."\r\n");
  546. foreach($this->tpCfgs as $k=>$v)
  547. {
  548. $v = str_replace("\"","\\\"",$v);
  549. $v = str_replace("\$","\\\$",$v);
  550. fwrite($fp,"\$this->tpCfgs['$k']=\"$v\";\r\n");
  551. }
  552. fwrite($fp,'?'.'>');
  553. fclose($fp);
  554. }
  555. }
  556. */
  557. }
  558. /**
  559. * 获得模板文件名的md5字符串
  560. *
  561. * @access public
  562. * @param string $tmpfile 模板文件
  563. * @return string
  564. */
  565. function GetEncodeStr($tmpfile)
  566. {
  567. //$tmpfiles = explode('/',$tmpfile);
  568. $encodeStr = substr(md5($tmpfile),0,24);
  569. return $encodeStr;
  570. }
  571. /**
  572. * 解析模板
  573. *
  574. * @access public
  575. * @return void
  576. */
  577. function ParseTemplate()
  578. {
  579. if($this->makeLoop > 5)
  580. {
  581. return ;
  582. }
  583. $this->count = -1;
  584. $this->cTags = array();
  585. $this->isParse = TRUE;
  586. $sPos = 0;
  587. $ePos = 0;
  588. $tagStartWord = $this->tagStartWord;
  589. $fullTagEndWord = $this->fullTagEndWord;
  590. $sTagEndWord = $this->sTagEndWord;
  591. $tagEndWord = $this->tagEndWord;
  592. $startWordLen = strlen($tagStartWord);
  593. $sourceLen = strlen($this->sourceString);
  594. if( $sourceLen <= ($startWordLen + 3) )
  595. {
  596. return;
  597. }
  598. $cAtt = new TagAttributeParse();
  599. $cAtt->CharToLow = TRUE;
  600. //遍历模板字符串,请取标记及其属性信息
  601. $t = 0;
  602. $preTag = '';
  603. $tswLen = strlen($tagStartWord);
  604. $cAtt->cAttributes->items = array();
  605. for($i=0; $i<$sourceLen; $i++)
  606. {
  607. $ttagName = '';
  608. //如果不进行此判断,将无法识别相连的两个标记
  609. if($i-1>=0)
  610. {
  611. $ss = $i-1;
  612. }
  613. else
  614. {
  615. $ss = 0;
  616. }
  617. $tagPos = strpos($this->sourceString,$tagStartWord,$ss);
  618. //判断后面是否还有模板标记
  619. if($tagPos==0 && ($sourceLen-$i < $tswLen
  620. || substr($this->sourceString,$i,$tswLen)!=$tagStartWord ))
  621. {
  622. $tagPos = -1;
  623. break;
  624. }
  625. //获取TAG基本信息
  626. for($j = $tagPos+$startWordLen; $j < $tagPos+$startWordLen+$this->tagMaxLen; $j++)
  627. {
  628. if(preg_match("/[ >\/\r\n\t\}\.]/", $this->sourceString[$j]))
  629. {
  630. break;
  631. }
  632. else
  633. {
  634. $ttagName .= $this->sourceString[$j];
  635. }
  636. }
  637. if($ttagName!='')
  638. {
  639. $i = $tagPos + $startWordLen;
  640. $endPos = -1;
  641. //判断 '/}' '{tag:下一标记开始' '{/tag:标记结束' 谁最靠近
  642. $fullTagEndWordThis = $fullTagEndWord.$ttagName.$tagEndWord;
  643. $e1 = strpos($this->sourceString, $sTagEndWord, $i);
  644. $e2 = strpos($this->sourceString, $tagStartWord, $i);
  645. $e3 = strpos($this->sourceString, $fullTagEndWordThis, $i);
  646. $e1 = trim($e1); $e2 = trim($e2); $e3 = trim($e3);
  647. $e1 = ($e1=='' ? '-1' : $e1);
  648. $e2 = ($e2=='' ? '-1' : $e2);
  649. $e3 = ($e3=='' ? '-1' : $e3);
  650. if($e3==-1)
  651. {
  652. //不存在'{/tag:标记'
  653. $endPos = $e1;
  654. $elen = $endPos + strlen($sTagEndWord);
  655. }
  656. else if($e1==-1)
  657. {
  658. //不存在 '/}'
  659. $endPos = $e3;
  660. $elen = $endPos + strlen($fullTagEndWordThis);
  661. }
  662. //同时存在 '/}' 和 '{/tag:标记'
  663. else
  664. {
  665. //如果 '/}' 比 '{tag:'、'{/tag:标记' 都要靠近,则认为结束标志是 '/}',否则结束标志为 '{/tag:标记'
  666. if($e1 < $e2 && $e1 < $e3 )
  667. {
  668. $endPos = $e1;
  669. $elen = $endPos + strlen($sTagEndWord);
  670. }
  671. else
  672. {
  673. $endPos = $e3;
  674. $elen = $endPos + strlen($fullTagEndWordThis);
  675. }
  676. }
  677. //如果找不到结束标记,则认为这个标记存在错误
  678. if($endPos==-1)
  679. {
  680. echo "Tpl Character postion $tagPos, '$ttagName' Error!<br />\r\n";
  681. break;
  682. }
  683. $i = $elen;
  684. //分析所找到的标记位置等信息
  685. $attStr = '';
  686. $innerText = '';
  687. $startInner = 0;
  688. for($j = $tagPos+$startWordLen; $j < $endPos; $j++)
  689. {
  690. if($startInner==0)
  691. {
  692. if($this->sourceString[$j]==$tagEndWord)
  693. {
  694. $startInner=1; continue;
  695. }
  696. else
  697. {
  698. $attStr .= $this->sourceString[$j];
  699. }
  700. }
  701. else
  702. {
  703. $innerText .= $this->sourceString[$j];
  704. }
  705. }
  706. $ttagName = strtolower($ttagName);
  707. //if、php标记,把整个属性串视为属性
  708. if(preg_match("/^if[0-9]{0,}$/", $ttagName))
  709. {
  710. $cAtt->cAttributes = new TagAttribute();
  711. $cAtt->cAttributes->count = 2;
  712. $cAtt->cAttributes->items['tagname'] = $ttagName;
  713. $cAtt->cAttributes->items['condition'] = preg_replace("/^if[0-9]{0,}[\r\n\t ]/", "", $attStr);
  714. $innerText = preg_replace("/\{else\}/i", '<'."?php\r\n}\r\nelse{\r\n".'?'.'>', $innerText);
  715. }
  716. else if($ttagName=='php')
  717. {
  718. $cAtt->cAttributes = new TagAttribute();
  719. $cAtt->cAttributes->count = 2;
  720. $cAtt->cAttributes->items['tagname'] = $ttagName;
  721. $cAtt->cAttributes->items['code'] = '<'."?php\r\n".trim(preg_replace("/^php[0-9]{0,}[\r\n\t ]/",
  722. "",$attStr))."\r\n?".'>';
  723. }
  724. else
  725. {
  726. //普通标记,解释属性
  727. $cAtt->SetSource($attStr);
  728. }
  729. $this->count++;
  730. $cTag = new Tag();
  731. $cTag->tagName = $ttagName;
  732. $cTag->startPos = $tagPos;
  733. $cTag->endPos = $i;
  734. $cTag->cAtt = $cAtt->cAttributes;
  735. $cTag->isCompiler = FALSE;
  736. $cTag->tagID = $this->count;
  737. $cTag->innerText = $innerText;
  738. $this->cTags[$this->count] = $cTag;
  739. }
  740. else
  741. {
  742. $i = $tagPos+$startWordLen;
  743. break;
  744. }
  745. }//结束遍历模板字符串
  746. if( $this->count > -1 && $this->isCompiler )
  747. {
  748. $this->CompilerAll();
  749. }
  750. }
  751. /**
  752. * 把模板标记转换为PHP代码
  753. *
  754. * @access public
  755. * @return void
  756. */
  757. function CompilerAll()
  758. {
  759. $this->loopNum++;
  760. if($this->loopNum > 10)
  761. {
  762. return; //限制最大递归深度为 10 以防止因标记出错等可能性导致死循环
  763. }
  764. $ResultString = '';
  765. $nextTagEnd = 0;
  766. for($i=0; isset($this->cTags[$i]); $i++)
  767. {
  768. $ResultString .= substr($this->sourceString, $nextTagEnd, $this->cTags[$i]->startPos - $nextTagEnd);
  769. $ResultString .= $this->CompilerOneTag($this->cTags[$i]);
  770. $nextTagEnd = $this->cTags[$i]->endPos;
  771. }
  772. $slen = strlen($this->sourceString);
  773. if($slen > $nextTagEnd)
  774. {
  775. $ResultString .= substr($this->sourceString,$nextTagEnd,$slen-$nextTagEnd);
  776. }
  777. $this->sourceString = $ResultString;
  778. $this->ParseTemplate();
  779. }
  780. /**
  781. * 获得最终结果
  782. *
  783. * @access public
  784. * @return string
  785. */
  786. function GetResult()
  787. {
  788. if(!$this->isParse)
  789. {
  790. $this->ParseTemplate();
  791. }
  792. $addset = '';
  793. $addset .= '<'.'?php'."\r\n".'if(!isset($GLOBALS[\'_vars\'])) $GLOBALS[\'_vars\'] = array(); '."\r\n".'$fields = array();'."\r\n".'?'.'>';
  794. return preg_replace("/\?".">[ \r\n\t]{0,}<"."\?php/", "", $addset.$this->sourceString);
  795. }
  796. /**
  797. * 编译单个标记
  798. *
  799. * @access public
  800. * @param string $cTag 标签
  801. * @return string
  802. */
  803. function CompilerOneTag(&$cTag)
  804. {
  805. $cTag->isCompiler = TRUE;
  806. $tagname = $cTag->tagName;
  807. $varname = $cTag->GetAtt('name');
  808. $rsvalue = "";
  809. //用于在模板中设置一个变量以提供作扩展用途
  810. //此变量直接提交到 this->tpCfgs 中,并会生成与模板对应的缓存文件 ***_config.php 文件
  811. if( $tagname == 'config' )
  812. {
  813. $this->tpCfgs[$varname] = $cTag->GetAtt('value');
  814. }
  815. else if( $tagname == 'global' )
  816. {
  817. $cTag->tagValue = $this->CompilerArrayVar('global',$varname);
  818. if( $cTag->GetAtt('function') != '' )
  819. {
  820. $cTag->tagValue = $this->CompilerFunction($cTag->GetAtt('function'), $cTag->tagValue);
  821. }
  822. $cTag->tagValue = '<'.'?php echo '.$cTag->tagValue.'; ?'.'>';
  823. }
  824. else if( $tagname == 'cfg' )
  825. {
  826. $cTag->tagValue = '$GLOBALS[\'cfg_'.$varname.'\']'; //处理函数
  827. if( $cTag->GetAtt('function')!='' )
  828. {
  829. $cTag->tagValue = $this->CompilerFunction($cTag->GetAtt('function'), $cTag->tagValue);
  830. }
  831. $cTag->tagValue = '<'.'?php echo '.$cTag->tagValue.'; ?'.'>';
  832. }
  833. else if( $tagname == 'name' )
  834. {
  835. $cTag->tagValue = '$'.$varname; //处理函数
  836. if( $cTag->GetAtt('function')!='' )
  837. {
  838. $cTag->tagValue = $this->CompilerFunction($cTag->GetAtt('function'), $cTag->tagValue);
  839. }
  840. $cTag->tagValue = '<'.'?php echo '.$cTag->tagValue.'; ?'.'>';
  841. }
  842. else if( $tagname == 'object' )
  843. {
  844. list($_obs,$_em) = explode('->',$varname);
  845. $cTag->tagValue = "\$GLOBALS['{$_obs}']->{$_em}"; //处理函数
  846. if( $cTag->GetAtt('function')!='' )
  847. {
  848. $cTag->tagValue = $this->CompilerFunction($cTag->GetAtt('function'), $cTag->tagValue);
  849. }
  850. $cTag->tagValue = '<'.'?php echo '.$cTag->tagValue.'; ?'.'>';
  851. }
  852. else if($tagname == 'var')
  853. {
  854. $cTag->tagValue = $this->CompilerArrayVar('var', $varname);
  855. if( $cTag->GetAtt('function')!='' )
  856. {
  857. $cTag->tagValue = $this->CompilerFunction($cTag->GetAtt('function'), $cTag->tagValue);
  858. }
  859. // 增加默认空值处理
  860. if ($cTag->GetAtt('default')!='')
  861. {
  862. $cTag->tagValue = '<'.'?php echo empty('.$cTag->tagValue.')? \''.addslashes($cTag->GetAtt('default')).'\':'.$cTag->tagValue.'; ?'.'>';
  863. } else {
  864. $cTag->tagValue = '<'.'?php echo '.$cTag->tagValue.'; ?'.'>';
  865. }
  866. }
  867. else if($tagname == 'field')
  868. {
  869. $cTag->tagValue = '$fields[\''.$varname.'\']';
  870. if( $cTag->GetAtt('function')!='' )
  871. {
  872. $cTag->tagValue = $this->CompilerFunction($cTag->GetAtt('function'), $cTag->tagValue);
  873. }
  874. $cTag->tagValue = '<'.'?php echo '.$cTag->tagValue.'; ?'.'>';
  875. }
  876. else if( preg_match("/^key[0-9]{0,}/", $tagname) || preg_match("/^value[0-9]{0,}/", $tagname))
  877. {
  878. if( preg_match("/^value[0-9]{0,}/", $tagname) && $varname!='' )
  879. {
  880. $cTag->tagValue = '<'.'?php echo '.$this->CompilerArrayVar($tagname,$varname).'; ?'.'>';
  881. }
  882. else
  883. {
  884. $cTag->tagValue = '<'.'?php echo $'.$tagname.'; ?'.'>';
  885. }
  886. }
  887. else if( preg_match("/^if[0-9]{0,}$/", $tagname) )
  888. {
  889. $cTag->tagValue = $this->CompilerIf($cTag);
  890. }
  891. else if( $tagname=='echo' )
  892. {
  893. if(trim($cTag->GetInnerText())=='') $cTag->tagValue = $cTag->GetAtt('code');
  894. else
  895. {
  896. $cTag->tagValue = '<'."?php echo $".trim($cTag->GetInnerText())." ;?".'>';
  897. }
  898. }
  899. else if( $tagname=='php' )
  900. {
  901. if(trim($cTag->GetInnerText())=='') $cTag->tagValue = $cTag->GetAtt('code');
  902. else
  903. {
  904. $cTag->tagValue = '<'."?php\r\n".trim($cTag->GetInnerText())."\r\n?".'>';
  905. }
  906. }
  907. //遍历数组
  908. else if( preg_match("/^array[0-9]{0,}/",$tagname) )
  909. {
  910. $kk = '$key';
  911. $vv = '$value';
  912. if($cTag->GetAtt('key')!='')
  913. {
  914. $kk = '$key'.$cTag->GetAtt('key');
  915. }
  916. if($cTag->GetAtt('value')!='')
  917. {
  918. $vv = '$value'.$cTag->GetAtt('value');
  919. }
  920. $addvar = '';
  921. if(!preg_match("/\(/",$varname))
  922. {
  923. $varname = '$GLOBALS[\''.$varname.'\']';
  924. }
  925. else
  926. {
  927. $addvar = "\r\n".'$myarrs = $pageClass->'.$varname.";\r\n";
  928. $varname = ' $myarrs ';
  929. }
  930. $rsvalue = '<'.'?php '.$addvar.' foreach('.$varname.' as '.$kk.'=>'.$vv.'){ ?'.">";
  931. $rsvalue .= $cTag->GetInnerText();
  932. $rsvalue .= '<'.'?php } ?'.">\r\n";
  933. $cTag->tagValue = $rsvalue;
  934. }
  935. //include 文件
  936. else if($tagname == 'include')
  937. {
  938. $filename = $cTag->GetAtt('file');
  939. if($filename=='')
  940. {
  941. $filename = $cTag->GetAtt('filename');
  942. }
  943. $cTag->tagValue = $this->CompilerInclude($filename, FALSE);
  944. if($cTag->tagValue==0) $cTag->tagValue = '';
  945. $cTag->tagValue = '<'.'?php include $this->CompilerInclude("'.$filename.'");'."\r\n".' ?'.'>';
  946. }
  947. else if( $tagname=='label' )
  948. {
  949. $bindFunc = $cTag->GetAtt('bind');
  950. $rsvalue = 'echo '.$bindFunc.";\r\n";
  951. $rsvalue = '<'.'?php '.$rsvalue.' ?'.">\r\n";
  952. $cTag->tagValue = $rsvalue;
  953. }
  954. else if( $tagname=='datalist' )
  955. {
  956. //生成属性数组
  957. foreach($cTag->cAtt->items as $k=>$v)
  958. {
  959. $v = $this->TrimAtts($v);
  960. $rsvalue .= '$atts[\''.$k.'\'] = \''.str_replace("'","\\'",$v)."';\r\n";
  961. }
  962. $rsvalue = '<'.'?php'."\r\n".'$atts = array();'."\r\n".$rsvalue;
  963. $rsvalue .= '$blockValue = $this->refObj->GetArcList($atts,$this->refObj,$fields); '."\r\n";
  964. $rsvalue .= 'if(is_array($blockValue)){'."\r\n";
  965. $rsvalue .= 'foreach( $blockValue as $key=>$fields )'."\r\n{\r\n".'?'.">";
  966. $rsvalue .= $cTag->GetInnerText();
  967. $rsvalue .= '<'.'?php'."\r\n}\r\n}".'?'.'>';
  968. $cTag->tagValue = $rsvalue;
  969. }
  970. else if( $tagname=='pagelist' )
  971. {
  972. //生成属性数组
  973. foreach($cTag->cAtt->items as $k=>$v)
  974. {
  975. $v = $this->TrimAtts($v);
  976. $rsvalue .= '$atts[\''.$k.'\'] = \''.str_replace("'","\\'",$v)."';\r\n";
  977. }
  978. $rsvalue = '<'.'?php'."\r\n".'$atts = array();'."\r\n".$rsvalue;
  979. $rsvalue .= ' echo $this->refObj->GetPageList($atts,$this->refObj,$fields); '."\r\n".'?'.">\r\n";
  980. $cTag->tagValue = $rsvalue;
  981. }
  982. else
  983. {
  984. $bindFunc = $cTag->GetAtt('bind');
  985. $bindType = $cTag->GetAtt('bindtype');
  986. $rstype = ($cTag->GetAtt('resulttype')=='' ? $cTag->GetAtt('rstype') : $cTag->GetAtt('resulttype') );
  987. $rstype = strtolower($rstype);
  988. //生成属性数组
  989. foreach($cTag->cAtt->items as $k=>$v)
  990. {
  991. if(preg_match("/(bind|bindtype)/i",$k))
  992. {
  993. continue;
  994. }
  995. $v = $this->TrimAtts($v);
  996. $rsvalue .= '$atts[\''.$k.'\'] = \''.str_replace("'","\\'",$v)."';\r\n";
  997. }
  998. $rsvalue = '<'.'?php'."\r\n".'$atts = array();'."\r\n".$rsvalue;
  999. //绑定到默认函数还是指定函数(datasource属性指定)
  1000. if($bindFunc=='')
  1001. {
  1002. $rsvalue .= '$blockValue = MakePublicTag($atts,$this->refObj,$fields); '."\r\n";
  1003. }
  1004. else
  1005. {
  1006. //自定义绑定函数如果不指定 bindtype,则指向$this->refObj->绑定函数名,即是默认指向被引用的类对象
  1007. if($bindType=='') $rsvalue .= '$blockValue = $this->refObj->'.$bindFunc.'($atts,$this->refObj,$fields); '."\r\n";
  1008. else $rsvalue .= '$blockValue = '.$bindFunc.'($atts,$this->refObj,$fields); '."\r\n";
  1009. }
  1010. //返回结果类型:默认为 array 是一个二维数组,string 是字符串
  1011. if($rstype=='string')
  1012. {
  1013. $rsvalue .= 'echo $blockValue;'."\r\n".'?'.">";
  1014. }
  1015. else
  1016. {
  1017. $rsvalue .= 'if(is_array($blockValue) && count($blockValue) > 0){'."\r\n";
  1018. $rsvalue .= 'foreach( $blockValue as $key=>$fields )'."\r\n{\r\n".'?'.">";
  1019. $rsvalue .= $cTag->GetInnerText();
  1020. $rsvalue .= '<'.'?php'."\r\n}\r\n}\r\n".'?'.'>';
  1021. }
  1022. $cTag->tagValue = $rsvalue;
  1023. }
  1024. return $cTag->tagValue;
  1025. }
  1026. /**
  1027. * 编译可能为数组的变量
  1028. *
  1029. * @access public
  1030. * @param string $vartype 变量类型
  1031. * @param string $varname 变量名称
  1032. * @return string
  1033. */
  1034. function CompilerArrayVar($vartype, $varname)
  1035. {
  1036. $okvalue = '';
  1037. if(!preg_match("/\[/", $varname))
  1038. {
  1039. if(preg_match("/^value/",$vartype))
  1040. {
  1041. $varname = $vartype.'.'.$varname;
  1042. }
  1043. $varnames = explode('.',$varname);
  1044. if(isset($varnames[1]))
  1045. {
  1046. $varname = $varnames[0];
  1047. for($i=1; isset($varnames[$i]); $i++)
  1048. {
  1049. $varname .= "['".$varnames[$i]."']";
  1050. }
  1051. }
  1052. }
  1053. if(preg_match("/\[/", $varname))
  1054. {
  1055. $varnames = explode('[', $varname);
  1056. $arrend = '';
  1057. for($i=1;isset($varnames[$i]);$i++)
  1058. {
  1059. $arrend .= '['.$varnames[$i];
  1060. }
  1061. if(!preg_match("/[\"']/", $arrend)) {
  1062. $arrend = str_replace('[', '', $arrend);
  1063. $arrend = str_replace(']', '', $arrend);
  1064. $arrend = "['{$arrend}']";
  1065. }
  1066. if($vartype=='var')
  1067. {
  1068. $okvalue = '$GLOBALS[\'_vars\'][\''.$varnames[0].'\']'.$arrend;
  1069. }
  1070. else if( preg_match("/^value/", $vartype) )
  1071. {
  1072. $okvalue = '$'.$varnames[0].$arrend;
  1073. }
  1074. else if($vartype=='field')
  1075. {
  1076. $okvalue = '$fields[\''.$varnames[0].'\']'.$arrend;
  1077. }
  1078. else
  1079. {
  1080. $okvalue = '$GLOBALS[\''.$varnames[0].'\']'.$arrend;
  1081. }
  1082. }
  1083. else
  1084. {
  1085. if($vartype=='var')
  1086. {
  1087. $okvalue = '$GLOBALS[\'_vars\'][\''.$varname.'\']';
  1088. }
  1089. else if( preg_match("/^value/",$vartype) )
  1090. {
  1091. $okvalue = '$'.$vartype;
  1092. }
  1093. else if($vartype=='field')
  1094. {
  1095. $okvalue = '$'.str_replace($varname);
  1096. }
  1097. else
  1098. {
  1099. $okvalue = '$GLOBALS[\''.$varname.'\']';
  1100. }
  1101. }
  1102. return $okvalue;
  1103. }
  1104. /**
  1105. * 编译if标记
  1106. *
  1107. * @access public
  1108. * @param string $cTag 标签
  1109. * @return string
  1110. */
  1111. function CompilerIf($cTag)
  1112. {
  1113. $condition = trim($cTag->GetAtt('condition'));
  1114. if($condition =='')
  1115. {
  1116. $cTag->tagValue=''; return '';
  1117. }
  1118. if (version_compare(PHP_VERSION, '5.5.0', '>='))
  1119. {
  1120. $condition = preg_replace_callback("/((var\.|field\.|cfg\.|global\.|key[0-9]{0,}\.|value[0-9]{0,}\.)[\._a-z0-9]+)/is", "private_rt", $condition);
  1121. } else {
  1122. $condition = preg_replace("/((var\.|field\.|cfg\.|global\.|key[0-9]{0,}\.|value[0-9]{0,}\.)[\._a-z0-9]+)/ies", "private_rt('\\1')", $condition);
  1123. } $rsvalue = '<'.'?php if('.$condition.'){ ?'.'>';
  1124. $rsvalue .= $cTag->GetInnerText();
  1125. $rsvalue .= '<'.'?php } ?'.'>';
  1126. return $rsvalue;
  1127. }
  1128. /**
  1129. * 处理block区块传递的atts属性的值
  1130. *
  1131. * @access public
  1132. * @param string $v 值
  1133. * @return string
  1134. */
  1135. function TrimAtts($v)
  1136. {
  1137. $v = str_replace('<'.'?','&lt;?',$v);
  1138. $v = str_replace('?'.'>','?&gt;',$v);
  1139. return $v;
  1140. }
  1141. /**
  1142. * 函数 function 语法处理
  1143. *
  1144. * @access public
  1145. * @param string $funcstr 函数字符串
  1146. * @param string $nvalue 函数值
  1147. * @return string
  1148. */
  1149. function CompilerFunction($funcstr, $nvalue)
  1150. {
  1151. $funcstr = str_replace('@quote', '"', $funcstr);
  1152. $funcstr = str_replace('@me', $nvalue, $funcstr);
  1153. return $funcstr;
  1154. }
  1155. /**
  1156. * 引入文件 include 语法处理
  1157. *
  1158. * @access public
  1159. * @param string $filename 文件名
  1160. * @param string $isload 是否载入
  1161. * @return string
  1162. */
  1163. function CompilerInclude($filename, $isload=TRUE)
  1164. {
  1165. $okfile = '';
  1166. if( @file_exists($filename) )
  1167. {
  1168. $okfile = $filename;
  1169. }
  1170. else if( @file_exists($this->refDir.$filename) )
  1171. {
  1172. $okfile = $this->refDir.$filename;
  1173. }
  1174. else if( @file_exists($this->refDir."../".$filename) )
  1175. {
  1176. $okfile = $this->refDir."../".$filename;
  1177. }
  1178. if($okfile=='') return 0;
  1179. if( !$isload ) return 1;
  1180. $itpl = new DedeTemplate($this->templateDir);
  1181. $itpl->isCache = $this->isCache;
  1182. $itpl->SetObject($this->refObj);
  1183. $itpl->LoadTemplate($okfile);
  1184. return $itpl->CacheFile();
  1185. }
  1186. }
  1187. /**
  1188. * class TagAttribute Tag属性集合
  1189. * function C__TagAttribute();
  1190. * 属性的数据描述
  1191. *
  1192. * @package TagAttribute
  1193. * @subpackage DedeCMS.Libraries
  1194. * @link http://www.dedecms.com
  1195. */
  1196. class TagAttribute
  1197. {
  1198. var $count = -1;
  1199. var $items = array(); //属性元素的集合
  1200. /**
  1201. * 获得某个属性
  1202. *
  1203. * @access public
  1204. * @param string $str 预处理字符串
  1205. * @return string
  1206. */
  1207. function GetAtt($str)
  1208. {
  1209. if($str=="")
  1210. {
  1211. return "";
  1212. }
  1213. if(isset($this->items[$str]))
  1214. {
  1215. return $this->items[$str];
  1216. }
  1217. else
  1218. {
  1219. return "";
  1220. }
  1221. }
  1222. /**
  1223. * 同上
  1224. *
  1225. * @access public
  1226. * @param string $str 预处理字符串
  1227. * @return string
  1228. */
  1229. function GetAttribute($str)
  1230. {
  1231. return $this->GetAtt($str);
  1232. }
  1233. /**
  1234. * 判断属性是否存在
  1235. *
  1236. * @access public
  1237. * @param string $str 预处理字符串
  1238. * @return bool
  1239. */
  1240. function IsAttribute($str)
  1241. {
  1242. if(isset($this->items[$str])) return TRUE;
  1243. else return FALSE;
  1244. }
  1245. /**
  1246. * 获得标记名称
  1247. *
  1248. * @access public
  1249. * @return string
  1250. */
  1251. function GettagName()
  1252. {
  1253. return $this->GetAtt("tagname");
  1254. }
  1255. /**
  1256. * 获得属性个数
  1257. *
  1258. * @access public
  1259. * @return int
  1260. */
  1261. function Getcount()
  1262. {
  1263. return $this->count+1;
  1264. }
  1265. }//End Class
  1266. /**
  1267. * 属性解析器
  1268. * function C__TagAttributeParse();
  1269. *
  1270. * @package TagAttribute
  1271. * @subpackage DedeCMS.Libraries
  1272. * @link http://www.dedecms.com
  1273. */
  1274. class TagAttributeParse
  1275. {
  1276. var $sourceString = "";
  1277. var $sourceMaxSize = 1024;
  1278. var $cAttributes = array();
  1279. var $charToLow = TRUE;
  1280. function SetSource($str="")
  1281. {
  1282. $this->cAttributes = new TagAttribute();
  1283. $strLen = 0;
  1284. $this->sourceString = trim(preg_replace("/[ \r\n\t\f]{1,}/"," ",$str));
  1285. $strLen = strlen($this->sourceString);
  1286. if($strLen>0 && $strLen <= $this->sourceMaxSize)
  1287. {
  1288. $this->ParseAttribute();
  1289. }
  1290. }
  1291. /**
  1292. * 解析属性
  1293. *
  1294. * @access public
  1295. * @return void
  1296. */
  1297. function ParseAttribute()
  1298. {
  1299. $d = '';
  1300. $tmpatt = '';
  1301. $tmpvalue = '';
  1302. $startdd = -1;
  1303. $ddtag = '';
  1304. $hasAttribute=FALSE;
  1305. $strLen = strlen($this->sourceString);
  1306. $this->cAttributes->items = array();
  1307. // 获得Tag的名称,解析到 cAtt->GetAtt('tagname') 中
  1308. for($i=0; $i<$strLen; $i++)
  1309. {
  1310. if($this->sourceString[$i]==' ')
  1311. {
  1312. $this->cAttributes->count++;
  1313. $tmpvalues = explode('.', $tmpvalue);
  1314. $this->cAttributes->items['tagname'] = ($this->charToLow ? strtolower($tmpvalues[0]) : $tmpvalues[0]);
  1315. if( isset($tmpvalues[2]) )
  1316. {
  1317. $okname = $tmpvalues[1];
  1318. for($j=2;isset($tmpvalues[$j]);$j++)
  1319. {
  1320. $okname .= "['".$tmpvalues[$j]."']";
  1321. }
  1322. $this->cAttributes->items['name'] = $okname;
  1323. }
  1324. else if(isset($tmpvalues[1]) && $tmpvalues[1]!='')
  1325. {
  1326. $this->cAttributes->items['name'] = $tmpvalues[1];
  1327. }
  1328. $tmpvalue = '';
  1329. $hasAttribute = TRUE;
  1330. break;
  1331. }
  1332. else
  1333. {
  1334. $tmpvalue .= $this->sourceString[$i];
  1335. }
  1336. }
  1337. //不存在属性列表的情况
  1338. if(!$hasAttribute)
  1339. {
  1340. $this->cAttributes->count++;
  1341. $tmpvalues = explode('.', $tmpvalue);
  1342. $this->cAttributes->items['tagname'] = ($this->charToLow ? strtolower($tmpvalues[0]) : $tmpvalues[0]);
  1343. if( isset($tmpvalues[2]) )
  1344. {
  1345. $okname = $tmpvalues[1];
  1346. for($i=2;isset($tmpvalues[$i]);$i++)
  1347. {
  1348. $okname .= "['".$tmpvalues[$i]."']";
  1349. }
  1350. $this->cAttributes->items['name'] = $okname;
  1351. }
  1352. else if(isset($tmpvalues[1]) && $tmpvalues[1]!='')
  1353. {
  1354. $this->cAttributes->items['name'] = $tmpvalues[1];
  1355. }
  1356. return ;
  1357. }
  1358. $tmpvalue = '';
  1359. //如果字符串含有属性值,遍历源字符串,并获得各属性
  1360. for($i; $i<$strLen; $i++)
  1361. {
  1362. $d = $this->sourceString[$i];
  1363. //查找属性名称
  1364. if($startdd==-1)
  1365. {
  1366. if($d != '=')
  1367. {
  1368. $tmpatt .= $d;
  1369. }
  1370. else
  1371. {
  1372. if($this->charToLow)
  1373. {
  1374. $tmpatt = strtolower(trim($tmpatt));
  1375. }
  1376. else
  1377. {
  1378. $tmpatt = trim($tmpatt);
  1379. }
  1380. $startdd=0;
  1381. }
  1382. }
  1383. //查找属性的限定标志
  1384. else if($startdd==0)
  1385. {
  1386. switch($d)
  1387. {
  1388. case ' ':
  1389. break;
  1390. case '\'':
  1391. $ddtag = '\'';
  1392. $startdd = 1;
  1393. break;
  1394. case '"':
  1395. $ddtag = '"';
  1396. $startdd = 1;
  1397. break;
  1398. default:
  1399. $tmpvalue .= $d;
  1400. $ddtag = ' ';
  1401. $startdd = 1;
  1402. break;
  1403. }
  1404. }
  1405. else if($startdd==1)
  1406. {
  1407. if($d==$ddtag && ( isset($this->sourceString[$i-1]) && $this->sourceString[$i-1]!="\\") )
  1408. {
  1409. $this->cAttributes->count++;
  1410. $this->cAttributes->items[$tmpatt] = trim($tmpvalue);
  1411. $tmpatt = '';
  1412. $tmpvalue = '';
  1413. $startdd = -1;
  1414. }
  1415. else
  1416. {
  1417. $tmpvalue .= $d;
  1418. }
  1419. }
  1420. }//for
  1421. //最后一个属性的给值
  1422. if($tmpatt != '')
  1423. {
  1424. $this->cAttributes->count++;
  1425. $this->cAttributes->items[$tmpatt] = trim($tmpvalue);
  1426. }//print_r($this->cAttributes->items);
  1427. }// end func
  1428. }//End Class
  1429. /**
  1430. * 私有标签编译,主要用于if标签内的字符串解析
  1431. *
  1432. * @access public
  1433. * @param string $str 需要编译的字符串
  1434. * @return string
  1435. */
  1436. function private_rt($str)
  1437. {
  1438. if (is_array($str)) {
  1439. $arr = explode('.', $str[0]);
  1440. } else {
  1441. $arr = explode('.', $str);
  1442. }
  1443. $rs = '$GLOBALS[\'';
  1444. if($arr[0] == 'cfg')
  1445. {
  1446. return $rs.'cfg_'.$arr[1]."']";
  1447. }
  1448. elseif($arr[0] == 'var')
  1449. {
  1450. $arr[0] = '_vars';
  1451. $rs .= implode('\'][\'', $arr);
  1452. $rs .= "']";
  1453. return $rs;
  1454. }
  1455. elseif($arr[0] == 'global')
  1456. {
  1457. unset($arr[0]);
  1458. $rs .= implode('\'][\'', $arr);
  1459. $rs .= "']";
  1460. return $rs;
  1461. }
  1462. else
  1463. {
  1464. if($arr[0] == 'field') $arr[0] = 'fields';
  1465. $rs = '$'.$arr[0]."['";
  1466. unset($arr[0]);
  1467. $rs .= implode('\'][\'', $arr);
  1468. $rs .= "']";
  1469. return $rs;
  1470. }
  1471. }