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

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