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

1025 lines
33KB

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