国内流行的内容管理系统(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.

1265 lines
35KB

  1. <?php if(!defined('DEDEINC')) exit("Request Error!");
  2. /**
  3. * Dede织梦模板类
  4. *
  5. * @version $Id: dedetag.class.php 1 10:33 2010年7月6日Z tianya $
  6. * @package DedeCMS.Libraries
  7. * @copyright Copyright (c) 2007 - 2020, DesDev, Inc.
  8. * @copyright Copyright (c) 2020, DedeBIZ.COM
  9. * @license http://help.dedecms.com/usersguide/license.html
  10. * @link http://www.dedecms.com
  11. */
  12. /**
  13. * class DedeTag 标记的数据结构描述
  14. * function c____DedeTag();
  15. *
  16. * @package DedeTag
  17. * @subpackage DedeCMS.Libraries
  18. * @link http://www.dedecms.com
  19. */
  20. class DedeTag
  21. {
  22. var $IsReplace=FALSE; //标记是否已被替代,供解析器使用
  23. var $TagName=""; //标记名称
  24. var $InnerText=""; //标记之间的文本
  25. var $StartPos=0; //标记起始位置
  26. var $EndPos=0; //标记结束位置
  27. var $CAttribute=""; //标记属性描述,即是class DedeAttribute
  28. var $TagValue=""; //标记的值
  29. var $TagID = 0;
  30. /**
  31. * 获取标记的名称和值
  32. *
  33. * @access public
  34. * @return string
  35. */
  36. function GetName()
  37. {
  38. return strtolower($this->TagName);
  39. }
  40. /**
  41. * 获取值
  42. *
  43. * @access public
  44. * @return string
  45. */
  46. function GetValue()
  47. {
  48. return $this->TagValue;
  49. }
  50. //下面两个成员函数仅是为了兼容旧版
  51. function GetTagName()
  52. {
  53. return strtolower($this->TagName);
  54. }
  55. function GetTagValue()
  56. {
  57. return $this->TagValue;
  58. }
  59. //获取标记的指定属性
  60. function IsAttribute($str)
  61. {
  62. return $this->CAttribute->IsAttribute($str);
  63. }
  64. function GetAttribute($str)
  65. {
  66. return $this->CAttribute->GetAtt($str);
  67. }
  68. function GetAtt($str)
  69. {
  70. return $this->CAttribute->GetAtt($str);
  71. }
  72. function GetInnerText()
  73. {
  74. return $this->InnerText;
  75. }
  76. }
  77. /**
  78. * DedeTagParse Dede织梦模板类
  79. * function c____DedeTagParse();
  80. *
  81. * @package DedeTagParse
  82. * @subpackage DedeCMS.Libraries
  83. * @link http://www.dedecms.com
  84. */
  85. class DedeTagParse
  86. {
  87. var $NameSpace = 'dede'; //标记的名字空间
  88. var $TagStartWord = '{'; //标记起始
  89. var $TagEndWord = '}'; //标记结束
  90. var $TagMaxLen = 64; //标记名称的最大值
  91. var $CharToLow = TRUE; // TRUE表示对属性和标记名称不区分大小写
  92. var $IsCache = FALSE; //是否使用缓冲
  93. var $TempMkTime = 0;
  94. var $CacheFile = '';
  95. var $SourceString = ''; //模板字符串
  96. var $CTags = array(); //标记集合
  97. var $Count = -1; //$Tags标记个数
  98. var $refObj = ''; //引用当前模板类的对象
  99. var $taghashfile = '';
  100. function __construct()
  101. {
  102. if(!isset($GLOBALS['cfg_tplcache']))
  103. {
  104. $GLOBALS['cfg_tplcache'] = 'N';
  105. }
  106. if($GLOBALS['cfg_tplcache']=='Y')
  107. {
  108. $this->IsCache = TRUE;
  109. }
  110. else
  111. {
  112. $this->IsCache = FALSE;
  113. }
  114. if ( DEDE_ENVIRONMENT == 'development' )
  115. {
  116. $this->IsCache = FALSE;
  117. }
  118. $this->NameSpace = 'dede';
  119. $this->TagStartWord = '{';
  120. $this->TagEndWord = '}';
  121. $this->TagMaxLen = 64;
  122. $this->CharToLow = TRUE;
  123. $this->SourceString = '';
  124. $this->CTags = array();
  125. $this->Count = -1;
  126. $this->TempMkTime = 0;
  127. $this->CacheFile = '';
  128. }
  129. function DedeTagParse()
  130. {
  131. $this->__construct();
  132. }
  133. /**
  134. * 设置标记的命名空间,默认为dede
  135. *
  136. * @access public
  137. * @param string $str 字符串
  138. * @param string $s 开始标记
  139. * @param string $e 结束标记
  140. * @return void
  141. */
  142. function SetNameSpace($str, $s="{", $e="}")
  143. {
  144. $this->NameSpace = strtolower($str);
  145. $this->TagStartWord = $s;
  146. $this->TagEndWord = $e;
  147. }
  148. /**
  149. * 重置成员变量或Clear
  150. *
  151. * @access public
  152. * @return void
  153. */
  154. function SetDefault()
  155. {
  156. $this->SourceString = '';
  157. $this->CTags = array();
  158. $this->Count=-1;
  159. }
  160. /**
  161. * 强制引用
  162. *
  163. * @access public
  164. * @param object $refObj 隶属对象
  165. * @return void
  166. */
  167. function SetRefObj(&$refObj)
  168. {
  169. $this->refObj = $refObj;
  170. }
  171. function GetCount()
  172. {
  173. return $this->Count+1;
  174. }
  175. function Clear()
  176. {
  177. $this->SetDefault();
  178. }
  179. // ------------------------------------------------------------------------
  180. /**
  181. * CheckDisabledFunctions
  182. *
  183. * COMMENT : CheckDisabledFunctions : 检查是否存在禁止的函数
  184. *
  185. * @access public
  186. * @param string
  187. * @return bool
  188. */
  189. function CheckDisabledFunctions($str,&$errmsg='')
  190. {
  191. global $cfg_disable_funs;
  192. $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';
  193. // 模板引擎增加disable_functions
  194. if (defined('DEDEDISFUN')) {
  195. $tokens = token_get_all_nl('<?php'.$str."\n\r?>");
  196. $disabled_functions = explode(',', $cfg_disable_funs);
  197. foreach ($tokens as $token)
  198. {
  199. if (is_array($token))
  200. {
  201. if ($token[0] = '306' && in_array($token[1], $disabled_functions))
  202. {
  203. $errmsg = 'DedeCMS Error:function disabled "'.$token[1].'" <a href="http://help.dedecms.com/install-use/apply/2013/0711/2324.html" target="_blank">more...</a>';
  204. return FALSE;
  205. }
  206. }
  207. }
  208. }
  209. return TRUE;
  210. }
  211. /**
  212. * 检测模板缓存
  213. *
  214. * @access public
  215. * @param string $filename 文件名称
  216. * @return string
  217. */
  218. function LoadCache($filename)
  219. {
  220. global $cfg_tplcache,$cfg_tplcache_dir;
  221. if(!$this->IsCache)
  222. {
  223. return FALSE;
  224. }
  225. $cdir = dirname($filename);
  226. $cachedir = DEDEROOT.$cfg_tplcache_dir;
  227. $ckfile = str_replace($cdir,'',$filename).substr(md5($filename),0,16).'.inc';
  228. $ckfullfile = $cachedir.'/'.$ckfile;
  229. $ckfullfile_t = $cachedir.'/'.$ckfile.'.txt';
  230. $this->CacheFile = $ckfullfile;
  231. $this->TempMkTime = filemtime($filename);
  232. if(!file_exists($ckfullfile)||!file_exists($ckfullfile_t))
  233. {
  234. return FALSE;
  235. }
  236. //检测模板最后更新时间
  237. $fp = fopen($ckfullfile_t,'r');
  238. $time_info = trim(fgets($fp,64));
  239. fclose($fp);
  240. if($time_info != $this->TempMkTime)
  241. {
  242. return FALSE;
  243. }
  244. //引入缓冲数组
  245. include($this->CacheFile);
  246. $errmsg = '';
  247. //把缓冲数组内容读入类
  248. if( isset($z) && is_array($z) )
  249. {
  250. foreach($z as $k=>$v)
  251. {
  252. $this->Count++;
  253. $ctag = new DedeTAg();
  254. $ctag->CAttribute = new DedeAttribute();
  255. $ctag->IsReplace = FALSE;
  256. $ctag->TagName = $v[0];
  257. $ctag->InnerText = $v[1];
  258. $ctag->StartPos = $v[2];
  259. $ctag->EndPos = $v[3];
  260. $ctag->TagValue = '';
  261. $ctag->TagID = $k;
  262. if(isset($v[4]) && is_array($v[4]))
  263. {
  264. $i = 0;
  265. $ctag->CAttribute->Items = array();
  266. foreach($v[4] as $k=>$v)
  267. {
  268. $ctag->CAttribute->Count++;
  269. $ctag->CAttribute->Items[$k]=$v;
  270. }
  271. }
  272. $this->CTags[$this->Count] = $ctag;
  273. }
  274. }
  275. else
  276. {
  277. //模板没有缓冲数组
  278. $this->CTags = '';
  279. $this->Count = -1;
  280. }
  281. return TRUE;
  282. }
  283. /**
  284. * 写入缓存
  285. *
  286. * @access public
  287. * @param string
  288. * @return string
  289. */
  290. function SaveCache()
  291. {
  292. $fp = fopen($this->CacheFile.'.txt',"w");
  293. fwrite($fp,$this->TempMkTime."\n");
  294. fclose($fp);
  295. $fp = fopen($this->CacheFile,"w");
  296. flock($fp,3);
  297. fwrite($fp,'<'.'?php'."\r\n");
  298. $errmsg = '';
  299. if(is_array($this->CTags))
  300. {
  301. foreach($this->CTags as $tid=>$ctag)
  302. {
  303. $arrayValue = 'Array("'.$ctag->TagName.'",';
  304. if (!$this->CheckDisabledFunctions($ctag->InnerText, $errmsg)) {
  305. fclose($fp);
  306. @unlink($this->taghashfile);
  307. @unlink($this->CacheFile);
  308. @unlink($this->CacheFile.'.txt');
  309. die($errmsg);
  310. }
  311. $arrayValue .= '"'.str_replace('$','\$',str_replace("\r","\\r",str_replace("\n","\\n",str_replace('"','\"',str_replace("\\","\\\\",$ctag->InnerText))))).'"';
  312. $arrayValue .= ",{$ctag->StartPos},{$ctag->EndPos});";
  313. fwrite($fp,"\$z[$tid]={$arrayValue}\n");
  314. if(is_array($ctag->CAttribute->Items))
  315. {
  316. fwrite($fp,"\$z[$tid][4]=array();\n");
  317. foreach($ctag->CAttribute->Items as $k=>$v)
  318. {
  319. $v = str_replace("\\","\\\\",$v);
  320. $v = str_replace('"',"\\".'"',$v);
  321. $v = str_replace('$','\$',$v);
  322. $k = trim(str_replace("'","",$k));
  323. if($k=="")
  324. {
  325. continue;
  326. }
  327. if($k!='tagname')
  328. {
  329. fwrite($fp,"\$z[$tid][4]['$k']=\"$v\";\n");
  330. }
  331. }
  332. }
  333. }
  334. }
  335. fwrite($fp,"\n".'?'.'>');
  336. fclose($fp);
  337. }
  338. /**
  339. * 载入模板文件
  340. *
  341. * @access public
  342. * @param string $filename 文件名称
  343. * @return string
  344. */
  345. function LoadTemplate($filename)
  346. {
  347. $this->SetDefault();
  348. if(!file_exists($filename))
  349. {
  350. $this->SourceString = " $filename Not Found! ";
  351. $this->ParseTemplet();
  352. }
  353. else
  354. {
  355. $fp = @fopen($filename, "r");
  356. while($line = fgets($fp,1024))
  357. {
  358. $this->SourceString .= $line;
  359. }
  360. fclose($fp);
  361. if($this->LoadCache($filename))
  362. {
  363. return '';
  364. }
  365. else
  366. {
  367. $this->ParseTemplet();
  368. }
  369. }
  370. }
  371. // 仅用于兼容旧版本
  372. function LoadTemplet($filename)
  373. {
  374. $this->LoadTemplate($filename);
  375. }
  376. // 仅用于兼容旧版本
  377. function LoadFile($filename)
  378. {
  379. $this->LoadTemplate($filename);
  380. }
  381. /**
  382. * 载入模板字符串
  383. *
  384. * @access public
  385. * @param string $str 字符串
  386. * @return void
  387. */
  388. function LoadSource($str)
  389. {
  390. /*
  391. $this->SetDefault();
  392. $this->SourceString = $str;
  393. $this->IsCache = FALSE;
  394. $this->ParseTemplet();
  395. */
  396. //优化模板字符串存取读取方式
  397. $this->taghashfile = $filename = DEDEDATA.'/tplcache/'.md5($str).'.inc';
  398. if( !is_file($filename) )
  399. {
  400. file_put_contents($filename, $str);
  401. }
  402. $this->LoadTemplate($filename);
  403. }
  404. function LoadString($str)
  405. {
  406. $this->LoadSource($str);
  407. }
  408. /**
  409. * 获得指定名称的Tag的ID(如果有多个同名的Tag,则取没有被取代为内容的第一个Tag)
  410. *
  411. * @access public
  412. * @param string $str 字符串
  413. * @return int
  414. */
  415. function GetTagID($str)
  416. {
  417. if($this->Count==-1)
  418. {
  419. return -1;
  420. }
  421. if($this->CharToLow)
  422. {
  423. $str=strtolower($str);
  424. }
  425. foreach($this->CTags as $id=>$CTag)
  426. {
  427. if($CTag->TagName==$str && !$CTag->IsReplace)
  428. {
  429. return $id;
  430. break;
  431. }
  432. }
  433. return -1;
  434. }
  435. /**
  436. * 获得指定名称的CTag数据类(如果有多个同名的Tag,则取没有被分配内容的第一个Tag)
  437. *
  438. * @access public
  439. * @param string $str 字符串
  440. * @return string
  441. */
  442. function GetTag($str)
  443. {
  444. if($this->Count==-1)
  445. {
  446. return '';
  447. }
  448. if($this->CharToLow)
  449. {
  450. $str=strtolower($str);
  451. }
  452. foreach($this->CTags as $id=>$CTag)
  453. {
  454. if($CTag->TagName==$str && !$CTag->IsReplace)
  455. {
  456. return $CTag;
  457. break;
  458. }
  459. }
  460. return '';
  461. }
  462. /**
  463. * 通过名称获取标记
  464. *
  465. * @access public
  466. * @param string $str 字符串
  467. * @return string
  468. */
  469. function GetTagByName($str)
  470. {
  471. return $this->GetTag($str);
  472. }
  473. /**
  474. * 获得指定ID的CTag数据类
  475. *
  476. * @access public
  477. * @param string 标签id
  478. * @return string
  479. */
  480. function GetTagByID($id)
  481. {
  482. if(isset($this->CTags[$id]))
  483. {
  484. return $this->CTags[$id];
  485. }
  486. else
  487. {
  488. return '';
  489. }
  490. }
  491. /**
  492. * 给_vars数组传递一个元素
  493. *
  494. * @access public
  495. * @param string $vname 标签名
  496. * @param string $vvalue 标签值
  497. * @return string
  498. */
  499. function AssignVar($vname, $vvalue)
  500. {
  501. if(!isset($_sys_globals['define']))
  502. {
  503. $_sys_globals['define'] = 'yes';
  504. }
  505. $_sys_globals[$vname] = $vvalue;
  506. }
  507. /**
  508. * 分配指定ID的标记的值
  509. *
  510. * @access public
  511. * @param string $i 标签id
  512. * @param string $str 字符串
  513. * @param string $runfunc 运行函数
  514. * @return void
  515. */
  516. function Assign($i, $str, $runfunc = TRUE)
  517. {
  518. if(isset($this->CTags[$i]))
  519. {
  520. $this->CTags[$i]->IsReplace = TRUE;
  521. $this->CTags[$i]->TagValue = $str;
  522. if( $this->CTags[$i]->GetAtt('function')!='' && $runfunc )
  523. {
  524. $this->CTags[$i]->TagValue = $this->EvalFunc( $str, $this->CTags[$i]->GetAtt('function'),$this->CTags[$i] );
  525. }
  526. }
  527. }
  528. /**
  529. * 分配指定名称的标记的值,如果标记包含属性,请不要用此函数
  530. *
  531. * @access public
  532. * @param string $tagname 标签名称
  533. * @param string $str 字符串
  534. * @return void
  535. */
  536. function AssignName($tagname, $str)
  537. {
  538. foreach($this->CTags as $id=>$CTag)
  539. {
  540. if($CTag->TagName==$tagname)
  541. {
  542. $this->Assign($id,$str);
  543. }
  544. }
  545. }
  546. /**
  547. * 处理特殊标记
  548. *
  549. * @access public
  550. * @return void
  551. */
  552. function AssignSysTag()
  553. {
  554. global $_sys_globals;
  555. for($i=0;$i<=$this->Count;$i++)
  556. {
  557. $CTag = $this->CTags[$i];
  558. $str = '';
  559. //获取一个外部变量
  560. if( $CTag->TagName == 'global' )
  561. {
  562. $str = $this->GetGlobals($CTag->GetAtt('name'));
  563. if( $this->CTags[$i]->GetAtt('function')!='' )
  564. {
  565. //$str = $this->EvalFunc( $this->CTags[$i]->TagValue, $this->CTags[$i]->GetAtt('function'),$this->CTags[$i] );
  566. $str = $this->EvalFunc( $str, $this->CTags[$i]->GetAtt('function'),$this->CTags[$i] );
  567. }
  568. $this->CTags[$i]->IsReplace = TRUE;
  569. $this->CTags[$i]->TagValue = $str;
  570. }
  571. //引入静态文件
  572. else if( $CTag->TagName == 'include' )
  573. {
  574. $filename = ($CTag->GetAtt('file')=='' ? $CTag->GetAtt('filename') : $CTag->GetAtt('file') );
  575. $str = $this->IncludeFile($filename,$CTag->GetAtt('ismake'));
  576. $this->CTags[$i]->IsReplace = TRUE;
  577. $this->CTags[$i]->TagValue = $str;
  578. }
  579. //循环一个普通数组
  580. else if( $CTag->TagName == 'foreach' )
  581. {
  582. $arr = $this->CTags[$i]->GetAtt('array');
  583. if(isset($GLOBALS[$arr]))
  584. {
  585. foreach($GLOBALS[$arr] as $k=>$v)
  586. {
  587. $istr = '';
  588. $istr .= preg_replace("/\[field:key([\r\n\t\f ]+)\/\]/is",$k,$this->CTags[$i]->InnerText);
  589. $str .= preg_replace("/\[field:value([\r\n\t\f ]+)\/\]/is",$v,$istr);
  590. }
  591. }
  592. $this->CTags[$i]->IsReplace = TRUE;
  593. $this->CTags[$i]->TagValue = $str;
  594. }
  595. //设置/获取变量值
  596. else if( $CTag->TagName == 'var' )
  597. {
  598. $vname = $this->CTags[$i]->GetAtt('name');
  599. if($vname=='')
  600. {
  601. $str = '';
  602. }
  603. else if($this->CTags[$i]->GetAtt('value')!='')
  604. {
  605. $_vars[$vname] = $this->CTags[$i]->GetAtt('value');
  606. }
  607. else
  608. {
  609. $str = (isset($_vars[$vname]) ? $_vars[$vname] : '');
  610. }
  611. $this->CTags[$i]->IsReplace = TRUE;
  612. $this->CTags[$i]->TagValue = $str;
  613. }
  614. //运行PHP接口
  615. if( $CTag->GetAtt('runphp') == 'yes' )
  616. {
  617. $this->RunPHP($CTag, $i);
  618. }
  619. if(is_array($this->CTags[$i]->TagValue))
  620. {
  621. $this->CTags[$i]->TagValue = 'array';
  622. }
  623. }
  624. }
  625. //运行PHP代码
  626. function RunPHP(&$refObj, $i)
  627. {
  628. $DedeMeValue = $phpcode = '';
  629. if($refObj->GetAtt('source')=='value')
  630. {
  631. $phpcode = $this->CTags[$i]->TagValue;
  632. }
  633. else
  634. {
  635. $DedeMeValue = $this->CTags[$i]->TagValue;
  636. $phpcode = $refObj->GetInnerText();
  637. }
  638. $phpcode = preg_replace("/'@me'|\"@me\"|@me/i", '$DedeMeValue', $phpcode);
  639. @eval($phpcode); //or die("<xmp>$phpcode</xmp>");
  640. $this->CTags[$i]->TagValue = $DedeMeValue;
  641. $this->CTags[$i]->IsReplace = TRUE;
  642. }
  643. /**
  644. * 把分析模板输出到一个字符串中
  645. * 不替换没被处理的值
  646. *
  647. * @access public
  648. * @return string
  649. */
  650. function GetResultNP()
  651. {
  652. $ResultString = '';
  653. if($this->Count==-1)
  654. {
  655. return $this->SourceString;
  656. }
  657. $this->AssignSysTag();
  658. $nextTagEnd = 0;
  659. $strok = "";
  660. for($i=0;$i<=$this->Count;$i++)
  661. {
  662. if($this->CTags[$i]->GetValue()!="")
  663. {
  664. if($this->CTags[$i]->GetValue()=='#@Delete@#')
  665. {
  666. $this->CTags[$i]->TagValue = "";
  667. }
  668. $ResultString .= substr($this->SourceString,$nextTagEnd,$this->CTags[$i]->StartPos-$nextTagEnd);
  669. $ResultString .= $this->CTags[$i]->GetValue();
  670. $nextTagEnd = $this->CTags[$i]->EndPos;
  671. }
  672. }
  673. $slen = strlen($this->SourceString);
  674. if($slen>$nextTagEnd)
  675. {
  676. $ResultString .= substr($this->SourceString,$nextTagEnd,$slen-$nextTagEnd);
  677. }
  678. return $ResultString;
  679. }
  680. /**
  681. * 把分析模板输出到一个字符串中,并返回
  682. *
  683. * @access public
  684. * @return string
  685. */
  686. function GetResult()
  687. {
  688. $ResultString = '';
  689. if($this->Count==-1)
  690. {
  691. return $this->SourceString;
  692. }
  693. $this->AssignSysTag();
  694. $nextTagEnd = 0;
  695. $strok = "";
  696. for($i=0;$i<=$this->Count;$i++)
  697. {
  698. $ResultString .= substr($this->SourceString,$nextTagEnd,$this->CTags[$i]->StartPos-$nextTagEnd);
  699. $ResultString .= $this->CTags[$i]->GetValue();
  700. $nextTagEnd = $this->CTags[$i]->EndPos;
  701. }
  702. $slen = strlen($this->SourceString);
  703. if($slen>$nextTagEnd)
  704. {
  705. $ResultString .= substr($this->SourceString,$nextTagEnd,$slen-$nextTagEnd);
  706. }
  707. return $ResultString;
  708. }
  709. /**
  710. * 直接输出解析模板
  711. *
  712. * @access public
  713. * @return void
  714. */
  715. function Display()
  716. {
  717. echo $this->GetResult();
  718. }
  719. /**
  720. * 把解析模板输出为文件
  721. *
  722. * @access public
  723. * @param string $filename 要保存到的文件
  724. * @return string
  725. */
  726. function SaveTo($filename)
  727. {
  728. $fp = @fopen($filename,"w") or die("DedeTag Engine Create File False");
  729. fwrite($fp,$this->GetResult());
  730. fclose($fp);
  731. }
  732. /**
  733. * 解析模板
  734. *
  735. * @access public
  736. * @return string
  737. */
  738. function ParseTemplet()
  739. {
  740. $TagStartWord = $this->TagStartWord;
  741. $TagEndWord = $this->TagEndWord;
  742. $sPos = 0; $ePos = 0;
  743. $FullTagStartWord = $TagStartWord.$this->NameSpace.":";
  744. $sTagEndWord = $TagStartWord."/".$this->NameSpace.":";
  745. $eTagEndWord = "/".$TagEndWord;
  746. $tsLen = strlen($FullTagStartWord);
  747. $sourceLen=strlen($this->SourceString);
  748. if( $sourceLen <= ($tsLen + 3) )
  749. {
  750. return;
  751. }
  752. $cAtt = new DedeAttributeParse();
  753. $cAtt->charToLow = $this->CharToLow;
  754. //遍历模板字符串,请取标记及其属性信息
  755. for($i=0; $i < $sourceLen; $i++)
  756. {
  757. $tTagName = '';
  758. //如果不进行此判断,将无法识别相连的两个标记
  759. if($i-1 >= 0)
  760. {
  761. $ss = $i-1;
  762. }
  763. else
  764. {
  765. $ss = 0;
  766. }
  767. $sPos = strpos($this->SourceString,$FullTagStartWord,$ss);
  768. $isTag = $sPos;
  769. if($i==0)
  770. {
  771. $headerTag = substr($this->SourceString,0,strlen($FullTagStartWord));
  772. if($headerTag==$FullTagStartWord)
  773. {
  774. $isTag=TRUE; $sPos=0;
  775. }
  776. }
  777. if($isTag===FALSE)
  778. {
  779. break;
  780. }
  781. //判断是否已经到倒数第三个字符(可能性几率极小,取消此逻辑)
  782. /*
  783. if($sPos > ($sourceLen-$tsLen-3) )
  784. {
  785. break;
  786. }
  787. */
  788. for($j=($sPos+$tsLen);$j<($sPos+$tsLen+$this->TagMaxLen);$j++)
  789. {
  790. if($j>($sourceLen-1))
  791. {
  792. break;
  793. }
  794. else if( preg_match("/[\/ \t\r\n]/", $this->SourceString[$j]) || $this->SourceString[$j] == $this->TagEndWord )
  795. {
  796. break;
  797. }
  798. else
  799. {
  800. $tTagName .= $this->SourceString[$j];
  801. }
  802. }
  803. if($tTagName!='')
  804. {
  805. $i = $sPos+$tsLen;
  806. $endPos = -1;
  807. $fullTagEndWordThis = $sTagEndWord.$tTagName.$TagEndWord;
  808. $e1 = strpos($this->SourceString,$eTagEndWord, $i);
  809. $e2 = strpos($this->SourceString,$FullTagStartWord, $i);
  810. $e3 = strpos($this->SourceString,$fullTagEndWordThis,$i);
  811. //$eTagEndWord = /} $FullTagStartWord = {tag: $fullTagEndWordThis = {/tag:xxx]
  812. $e1 = trim($e1); $e2 = trim($e2); $e3 = trim($e3);
  813. $e1 = ($e1=='' ? '-1' : $e1);
  814. $e2 = ($e2=='' ? '-1' : $e2);
  815. $e3 = ($e3=='' ? '-1' : $e3);
  816. //not found '{/tag:'
  817. if($e3==-1)
  818. {
  819. $endPos = $e1;
  820. $elen = $endPos + strlen($eTagEndWord);
  821. }
  822. //not found '/}'
  823. else if($e1==-1)
  824. {
  825. $endPos = $e3;
  826. $elen = $endPos + strlen($fullTagEndWordThis);
  827. }
  828. //found '/}' and found '{/dede:'
  829. else
  830. {
  831. //if '/}' more near '{dede:'、'{/dede:' , end tag is '/}', else is '{/dede:'
  832. if($e1 < $e2 && $e1 < $e3 )
  833. {
  834. $endPos = $e1;
  835. $elen = $endPos + strlen($eTagEndWord);
  836. }
  837. else
  838. {
  839. $endPos = $e3;
  840. $elen = $endPos + strlen($fullTagEndWordThis);
  841. }
  842. }
  843. //not found end tag , error
  844. if($endPos==-1)
  845. {
  846. echo "Tag Character postion $sPos, '$tTagName' Error!<br />\r\n";
  847. break;
  848. }
  849. $i = $elen;
  850. $ePos = $endPos;
  851. //分析所找到的标记位置等信息
  852. $attStr = '';
  853. $innerText = '';
  854. $startInner = 0;
  855. for($j=($sPos+$tsLen);$j < $ePos;$j++)
  856. {
  857. if($startInner==0 && ($this->SourceString[$j]==$TagEndWord && $this->SourceString[$j-1]!="\\") )
  858. {
  859. $startInner=1;
  860. continue;
  861. }
  862. if($startInner==0)
  863. {
  864. $attStr .= $this->SourceString[$j];
  865. }
  866. else
  867. {
  868. $innerText .= $this->SourceString[$j];
  869. }
  870. }
  871. //echo "<xmp>$attStr</xmp>\r\n";
  872. $cAtt->SetSource($attStr);
  873. if($cAtt->cAttributes->GetTagName()!='')
  874. {
  875. $this->Count++;
  876. $CDTag = new DedeTag();
  877. $CDTag->TagName = $cAtt->cAttributes->GetTagName();
  878. $CDTag->StartPos = $sPos;
  879. $CDTag->EndPos = $i;
  880. $CDTag->CAttribute = $cAtt->cAttributes;
  881. $CDTag->IsReplace = FALSE;
  882. $CDTag->TagID = $this->Count;
  883. $CDTag->InnerText = $innerText;
  884. $this->CTags[$this->Count] = $CDTag;
  885. }
  886. }
  887. else
  888. {
  889. $i = $sPos+$tsLen;
  890. break;
  891. }
  892. }//结束遍历模板字符串
  893. if($this->IsCache)
  894. {
  895. $this->SaveCache();
  896. }
  897. }
  898. /**
  899. * 处理某字段的函数
  900. *
  901. * @access public
  902. * @param string $fieldvalue 字段值
  903. * @param string $functionname 函数名称
  904. * @param object $refObj 隶属对象
  905. * @return string
  906. */
  907. function EvalFunc($fieldvalue,$functionname,&$refObj)
  908. {
  909. $DedeFieldValue = $fieldvalue;
  910. $functionname = str_replace("{\"","[\"",$functionname);
  911. $functionname = str_replace("\"}","\"]",$functionname);
  912. $functionname = preg_replace("/'@me'|\"@me\"|@me/i",'$DedeFieldValue',$functionname);
  913. $functionname = "\$DedeFieldValue = ".$functionname;
  914. @eval($functionname.";"); //or die("<xmp>$functionname</xmp>");
  915. if(empty($DedeFieldValue))
  916. {
  917. return '';
  918. }
  919. else
  920. {
  921. return $DedeFieldValue;
  922. }
  923. }
  924. /**
  925. * 获得一个外部变量
  926. *
  927. * @access public
  928. * @param string $varname 变量名称
  929. * @return string
  930. */
  931. function GetGlobals($varname)
  932. {
  933. $varname = trim($varname);
  934. //禁止在模板文件读取数据库密码
  935. if($varname=="dbuserpwd"||$varname=="cfg_dbpwd")
  936. {
  937. return "";
  938. }
  939. //正常情况
  940. if(isset($GLOBALS[$varname]))
  941. {
  942. return $GLOBALS[$varname];
  943. }
  944. else
  945. {
  946. return "";
  947. }
  948. }
  949. /**
  950. * 引入文件
  951. *
  952. * @access public
  953. * @param string $filename 文件名
  954. * @param string $ismake 是否需要编译
  955. * @return string
  956. */
  957. function IncludeFile($filename, $ismake='no')
  958. {
  959. global $cfg_df_style;
  960. $restr = '';
  961. if($filename=='')
  962. {
  963. return '';
  964. }
  965. if( file_exists(DEDEROOT."/templets/".$filename) )
  966. {
  967. $okfile = DEDEROOT."/templets/".$filename;
  968. }
  969. else if(file_exists(DEDEROOT.'/templets/'.$cfg_df_style.'/'.$filename) )
  970. {
  971. $okfile = DEDEROOT.'/templets/'.$cfg_df_style.'/'.$filename;
  972. }
  973. else
  974. {
  975. return "无法在这个位置找到: $filename";
  976. }
  977. //编译
  978. if($ismake!="no")
  979. {
  980. require_once(DEDEINC."/channelunit.func.php");
  981. $dtp = new DedeTagParse();
  982. $dtp->LoadTemplet($okfile);
  983. MakeOneTag($dtp,$this->refObj);
  984. $restr = $dtp->GetResult();
  985. }
  986. else
  987. {
  988. $fp = @fopen($okfile,"r");
  989. while($line=fgets($fp,1024)) $restr.=$line;
  990. fclose($fp);
  991. }
  992. return $restr;
  993. }
  994. }
  995. /**********************************************
  996. //class DedeAttribute Dede模板标记属性集合
  997. function c____DedeAttribute();
  998. **********************************************/
  999. //属性的数据描述
  1000. class DedeAttribute
  1001. {
  1002. var $Count = -1;
  1003. var $Items = ""; //属性元素的集合
  1004. //获得某个属性
  1005. function GetAtt($str)
  1006. {
  1007. if($str=="")
  1008. {
  1009. return "";
  1010. }
  1011. if(isset($this->Items[$str]))
  1012. {
  1013. return $this->Items[$str];
  1014. }
  1015. else
  1016. {
  1017. return "";
  1018. }
  1019. }
  1020. //同上
  1021. function GetAttribute($str)
  1022. {
  1023. return $this->GetAtt($str);
  1024. }
  1025. //判断属性是否存在
  1026. function IsAttribute($str)
  1027. {
  1028. if(isset($this->Items[$str])) return TRUE;
  1029. else return FALSE;
  1030. }
  1031. //获得标记名称
  1032. function GetTagName()
  1033. {
  1034. return $this->GetAtt("tagname");
  1035. }
  1036. // 获得属性个数
  1037. function GetCount()
  1038. {
  1039. return $this->Count+1;
  1040. }
  1041. }
  1042. /*******************************
  1043. //属性解析器(本版本中已经支持使用\'这种语法,和用.间隔表示name属性,如 field.body)
  1044. function c____DedeAttributeParse();
  1045. ********************************/
  1046. class DedeAttributeParse
  1047. {
  1048. var $sourceString = "";
  1049. var $sourceMaxSize = 1024;
  1050. var $cAttributes = "";
  1051. var $charToLow = TRUE;
  1052. function SetSource($str='')
  1053. {
  1054. $this->cAttributes = new DedeAttribute();
  1055. $strLen = 0;
  1056. $this->sourceString = trim(preg_replace("/[ \r\n\t]{1,}/"," ",$str));
  1057. //为了在function内能使用数组,这里允许对[ ]进行转义使用
  1058. $this->sourceString = str_replace('\]',']',$this->sourceString);
  1059. $this->sourceString = str_replace('[','[',$this->sourceString);
  1060. /*
  1061. $this->sourceString = str_replace('\>','>',$this->sourceString);
  1062. $this->sourceString = str_replace('<','>',$this->sourceString);
  1063. $this->sourceString = str_replace('{','{',$this->sourceString);
  1064. $this->sourceString = str_replace('\}','}',$this->sourceString);
  1065. */
  1066. $strLen = strlen($this->sourceString);
  1067. if($strLen>0 && $strLen <= $this->sourceMaxSize)
  1068. {
  1069. $this->ParseAttribute();
  1070. }
  1071. }
  1072. //解析属性
  1073. function ParseAttribute()
  1074. {
  1075. $d = '';
  1076. $tmpatt = '';
  1077. $tmpvalue = '';
  1078. $startdd = -1;
  1079. $ddtag = '';
  1080. $hasAttribute=FALSE;
  1081. $strLen = strlen($this->sourceString);
  1082. $this->cAttributes->Items = array();
  1083. // 获得Tag的名称,解析到 cAtt->GetAtt('tagname') 中
  1084. for($i=0; $i<$strLen; $i++)
  1085. {
  1086. if($this->sourceString[$i]==' ')
  1087. {
  1088. $this->cAttributes->Count++;
  1089. $tmpvalues = explode('.', $tmpvalue);
  1090. $this->cAttributes->Items['tagname'] = ($this->charToLow ? strtolower($tmpvalues[0]) : $tmpvalues[0]);
  1091. if(isset($tmpvalues[1]) && $tmpvalues[1]!='')
  1092. {
  1093. $this->cAttributes->Items['name'] = $tmpvalues[1];
  1094. }
  1095. $tmpvalue = '';
  1096. $hasAttribute = TRUE;
  1097. break;
  1098. }
  1099. else
  1100. {
  1101. $tmpvalue .= $this->sourceString[$i];
  1102. }
  1103. }
  1104. //不存在属性列表的情况
  1105. if(!$hasAttribute)
  1106. {
  1107. $this->cAttributes->Count++;
  1108. $tmpvalues = explode('.', $tmpvalue);
  1109. $this->cAttributes->Items['tagname'] = ($this->charToLow ? strtolower($tmpvalues[0]) : $tmpvalues[0]);
  1110. if(isset($tmpvalues[1]) && $tmpvalues[1]!='')
  1111. {
  1112. $this->cAttributes->Items['name'] = $tmpvalues[1];
  1113. }
  1114. return ;
  1115. }
  1116. $tmpvalue = '';
  1117. //如果字符串含有属性值,遍历源字符串,并获得各属性
  1118. for($i; $i<$strLen; $i++)
  1119. {
  1120. $d = $this->sourceString[$i];
  1121. //查找属性名称
  1122. if($startdd==-1)
  1123. {
  1124. if($d != '=')
  1125. {
  1126. $tmpatt .= $d;
  1127. }
  1128. else
  1129. {
  1130. if($this->charToLow)
  1131. {
  1132. $tmpatt = strtolower(trim($tmpatt));
  1133. }
  1134. else
  1135. {
  1136. $tmpatt = trim($tmpatt);
  1137. }
  1138. $startdd=0;
  1139. }
  1140. }
  1141. //查找属性的限定标志
  1142. else if($startdd==0)
  1143. {
  1144. switch($d)
  1145. {
  1146. case ' ':
  1147. break;
  1148. case '"':
  1149. $ddtag = '"';
  1150. $startdd = 1;
  1151. break;
  1152. case '\'':
  1153. $ddtag = '\'';
  1154. $startdd = 1;
  1155. break;
  1156. default:
  1157. $tmpvalue .= $d;
  1158. $ddtag = ' ';
  1159. $startdd = 1;
  1160. break;
  1161. }
  1162. }
  1163. else if($startdd==1)
  1164. {
  1165. if($d==$ddtag && ( isset($this->sourceString[$i-1]) && $this->sourceString[$i-1]!="\\") )
  1166. {
  1167. $this->cAttributes->Count++;
  1168. $this->cAttributes->Items[$tmpatt] = trim($tmpvalue);
  1169. $tmpatt = '';
  1170. $tmpvalue = '';
  1171. $startdd = -1;
  1172. }
  1173. else
  1174. {
  1175. $tmpvalue .= $d;
  1176. }
  1177. }
  1178. }//for
  1179. //最后一个属性的给值
  1180. if($tmpatt != '')
  1181. {
  1182. $this->cAttributes->Count++;
  1183. $this->cAttributes->Items[$tmpatt] = trim($tmpvalue);
  1184. }
  1185. //print_r($this->cAttributes->Items);
  1186. }// end func
  1187. }