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

1121 lines
34KB

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