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

1039 lines
34KB

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