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

1053 lines
34KB

  1. <?php
  2. if (!defined('DEDEINC')) exit('dedebiz');
  3. /**
  4. * DedeBIZ模板类
  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 Dede织梦模板类
  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. // 校验代码安全
  570. $error = checkCode($phpcode);
  571. if ($error) {
  572. if (DEBUG_LEVEL) {
  573. echo htmlErrors($error);
  574. }
  575. return;
  576. }
  577. try {
  578. @eval($phpcode);
  579. $this->CTags[$i]->TagValue = $DedeMeValue;
  580. $this->CTags[$i]->IsReplace = TRUE;
  581. } catch (Exception $e) {
  582. //or die("<xmp>$phpcode</xmp>");
  583. }
  584. $this->CTags[$i]->TagValue = $DedeMeValue;
  585. $this->CTags[$i]->IsReplace = TRUE;
  586. }
  587. /**
  588. * 把分析模板输出到一个字符串中
  589. * 不替换没被处理的值
  590. *
  591. * @access public
  592. * @return string
  593. */
  594. function GetResultNP()
  595. {
  596. $ResultString = '';
  597. if ($this->Count == -1) {
  598. return $this->SourceString;
  599. }
  600. $this->AssignSysTag();
  601. $nextTagEnd = 0;
  602. $strok = "";
  603. for ($i = 0; $i <= $this->Count; $i++) {
  604. if ($this->CTags[$i]->GetValue() != "") {
  605. if ($this->CTags[$i]->GetValue() == '#@Delete@#') {
  606. $this->CTags[$i]->TagValue = "";
  607. }
  608. $ResultString .= substr($this->SourceString, $nextTagEnd, $this->CTags[$i]->StartPos - $nextTagEnd);
  609. $ResultString .= $this->CTags[$i]->GetValue();
  610. $nextTagEnd = $this->CTags[$i]->EndPos;
  611. }
  612. }
  613. $slen = strlen($this->SourceString);
  614. if ($slen > $nextTagEnd) {
  615. $ResultString .= substr($this->SourceString, $nextTagEnd, $slen - $nextTagEnd);
  616. }
  617. return $ResultString;
  618. }
  619. /**
  620. * 把分析模板输出到一个字符串中,并返回
  621. *
  622. * @access public
  623. * @return string
  624. */
  625. function GetResult()
  626. {
  627. $ResultString = '';
  628. if ($this->Count == -1) {
  629. return $this->SourceString;
  630. }
  631. $this->AssignSysTag();
  632. $nextTagEnd = 0;
  633. $strok = "";
  634. for ($i = 0; $i <= $this->Count; $i++) {
  635. $ResultString .= substr($this->SourceString, $nextTagEnd, $this->CTags[$i]->StartPos - $nextTagEnd);
  636. $ResultString .= $this->CTags[$i]->GetValue();
  637. $nextTagEnd = $this->CTags[$i]->EndPos;
  638. }
  639. $slen = strlen($this->SourceString);
  640. if ($slen > $nextTagEnd) {
  641. $ResultString .= substr($this->SourceString, $nextTagEnd, $slen - $nextTagEnd);
  642. }
  643. return $ResultString;
  644. }
  645. /**
  646. * 直接输出解析模板
  647. *
  648. * @access public
  649. * @return void
  650. */
  651. function Display()
  652. {
  653. echo $this->GetResult();
  654. }
  655. /**
  656. * 把解析模板输出为文件
  657. *
  658. * @access public
  659. * @param string $filename 要保存到的文件
  660. * @return string
  661. */
  662. function SaveTo($filename)
  663. {
  664. $fp = @fopen($filename, "w") or die("请检查文件保存目录是否填写正确,目录文件是否存在");
  665. fwrite($fp, $this->GetResult());
  666. fclose($fp);
  667. }
  668. /**
  669. * 解析模板
  670. *
  671. * @access public
  672. * @return string
  673. */
  674. function ParseTemplet()
  675. {
  676. $TagStartWord = $this->TagStartWord;
  677. $TagEndWord = $this->TagEndWord;
  678. $sPos = 0;
  679. $ePos = 0;
  680. $FullTagStartWord = $TagStartWord.$this->NameSpace.":";
  681. $sTagEndWord = $TagStartWord."/".$this->NameSpace.":";
  682. $eTagEndWord = "/".$TagEndWord;
  683. $tsLen = strlen($FullTagStartWord);
  684. $sourceLen = strlen($this->SourceString);
  685. if ($sourceLen <= ($tsLen + 3)) {
  686. return;
  687. }
  688. $cAtt = new DedeAttributeParse();
  689. $cAtt->charToLow = $this->CharToLow;
  690. //遍历模板字符串,请取标记及其属性信息
  691. for ($i = 0; $i < $sourceLen; $i++) {
  692. $tTagName = '';
  693. //如果不进行此判断,将无法识别相连的两个标记
  694. if ($i - 1 >= 0) {
  695. $ss = $i - 1;
  696. } else {
  697. $ss = 0;
  698. }
  699. $sPos = strpos($this->SourceString, $FullTagStartWord, $ss);
  700. $isTag = $sPos;
  701. if ($i == 0) {
  702. $headerTag = substr($this->SourceString, 0, strlen($FullTagStartWord));
  703. if ($headerTag == $FullTagStartWord) {
  704. $isTag = TRUE;
  705. $sPos = 0;
  706. }
  707. }
  708. if ($isTag === FALSE) {
  709. break;
  710. }
  711. //判断是否已经到倒数第三个字符(可能性几率极小,取消此逻辑)
  712. for ($j = ($sPos + $tsLen); $j < ($sPos + $tsLen + $this->TagMaxLen); $j++) {
  713. if ($j > ($sourceLen - 1)) {
  714. break;
  715. } else if (preg_match("/[\/ \t\r\n]/", $this->SourceString[$j]) || $this->SourceString[$j] == $this->TagEndWord) {
  716. break;
  717. } else {
  718. $tTagName .= $this->SourceString[$j];
  719. }
  720. }
  721. if ($tTagName != '') {
  722. $i = $sPos + $tsLen;
  723. $endPos = -1;
  724. $fullTagEndWordThis = $sTagEndWord.$tTagName.$TagEndWord;
  725. $e1 = strpos($this->SourceString, $eTagEndWord, $i);
  726. $e2 = strpos($this->SourceString, $FullTagStartWord, $i);
  727. $e3 = strpos($this->SourceString, $fullTagEndWordThis, $i);
  728. //$eTagEndWord = /} $FullTagStartWord = {tag: $fullTagEndWordThis = {/tag:xxx]
  729. $e1 = trim($e1);
  730. $e2 = trim($e2);
  731. $e3 = trim($e3);
  732. $e1 = ($e1 == '' ? '-1' : $e1);
  733. $e2 = ($e2 == '' ? '-1' : $e2);
  734. $e3 = ($e3 == '' ? '-1' : $e3);
  735. //not found '{/tag:'
  736. if ($e3 == -1) {
  737. $endPos = $e1;
  738. $elen = $endPos + strlen($eTagEndWord);
  739. }
  740. //not found '/}'
  741. else if ($e1 == -1) {
  742. $endPos = $e3;
  743. $elen = $endPos + strlen($fullTagEndWordThis);
  744. }
  745. //found '/}' and found '{/dede:'
  746. else {
  747. //if '/}' more near '{dede:'、'{/dede:' , end tag is '/}', else is '{/dede:'
  748. if ($e1 < $e2 && $e1 < $e3) {
  749. $endPos = $e1;
  750. $elen = $endPos + strlen($eTagEndWord);
  751. } else {
  752. $endPos = $e3;
  753. $elen = $endPos + strlen($fullTagEndWordThis);
  754. }
  755. }
  756. //not found end tag , error
  757. if ($endPos == -1) {
  758. echo "Tag Character postion $sPos, '$tTagName' Error<br>\r\n";
  759. break;
  760. }
  761. $i = $elen;
  762. $ePos = $endPos;
  763. //分析所找到的标记位置等信息
  764. $attStr = '';
  765. $innerText = '';
  766. $startInner = 0;
  767. for ($j = ($sPos + $tsLen); $j < $ePos; $j++) {
  768. if ($startInner == 0 && ($this->SourceString[$j] == $TagEndWord && $this->SourceString[$j - 1] != "\\")) {
  769. $startInner = 1;
  770. continue;
  771. }
  772. if ($startInner == 0) {
  773. $attStr .= $this->SourceString[$j];
  774. } else {
  775. $innerText .= $this->SourceString[$j];
  776. }
  777. }
  778. //echo "<xmp>$attStr</xmp>\r\n";
  779. $cAtt->SetSource($attStr);
  780. if ($cAtt->cAttributes->GetTagName() != '') {
  781. $this->Count++;
  782. $CDTag = new DedeTag();
  783. $CDTag->TagName = $cAtt->cAttributes->GetTagName();
  784. $CDTag->StartPos = $sPos;
  785. $CDTag->EndPos = $i;
  786. $CDTag->CAttribute = $cAtt->cAttributes;
  787. $CDTag->IsReplace = FALSE;
  788. $CDTag->TagID = $this->Count;
  789. $CDTag->InnerText = $innerText;
  790. $this->CTags[$this->Count] = $CDTag;
  791. }
  792. } else {
  793. $i = $sPos + $tsLen;
  794. break;
  795. }
  796. } //结束遍历模板字符串
  797. if ($this->IsCache) {
  798. $this->SaveCache();
  799. }
  800. }
  801. /**
  802. * 处理某字段的函数
  803. *
  804. * @access public
  805. * @param string $fieldvalue 字段值
  806. * @param string $functionname 函数名称
  807. * @param object $refObj 隶属对象
  808. * @return string
  809. */
  810. function EvalFunc($fieldvalue, $functionname, &$refObj)
  811. {
  812. $DedeFieldValue = $fieldvalue;
  813. $functionname = str_replace("{\"", "[\"", $functionname);
  814. $functionname = str_replace("\"}", "\"]", $functionname);
  815. $functionname = preg_replace("/'@me'|\"@me\"|@me/i", '$DedeFieldValue', $functionname);
  816. $functionname = "\$DedeFieldValue = ".$functionname;
  817. $error = checkCode($functionname);
  818. if ($error) {
  819. if (DEBUG_LEVEL) {
  820. echo htmlErrors($error);
  821. }
  822. return "";
  823. }
  824. try {
  825. @eval($functionname.";");
  826. if (empty($DedeFieldValue)) {
  827. return '';
  828. } else {
  829. return $DedeFieldValue;
  830. }
  831. } catch (Exception $e) {
  832. //or die("<xmp>$functionname</xmp>");
  833. return '';
  834. }
  835. }
  836. /**
  837. * 获得一个外部变量
  838. *
  839. * @access public
  840. * @param string $varname 变量名称
  841. * @return string
  842. */
  843. function GetGlobals($varname)
  844. {
  845. $varname = trim($varname);
  846. //禁止在模板文件读取数据库密码
  847. if ($varname == "dbuserpwd" || $varname == "cfg_dbpwd") {
  848. return "";
  849. }
  850. //正常情况
  851. if (isset($GLOBALS[$varname])) {
  852. return $GLOBALS[$varname];
  853. } else {
  854. return "";
  855. }
  856. }
  857. /**
  858. * 引入文件
  859. *
  860. * @access public
  861. * @param string $filename 文件名
  862. * @param string $ismake 是否需要编译
  863. * @return string
  864. */
  865. function IncludeFile($filename, $ismake = 'no')
  866. {
  867. global $cfg_df_style;
  868. $restr = '';
  869. if ($filename == '') {
  870. return '';
  871. }
  872. if (file_exists(DEDEROOT."/theme/".$filename)) {
  873. $okfile = DEDEROOT."/theme/".$filename;
  874. } else if (file_exists(DEDEROOT.'/theme/'.$cfg_df_style.'/'.$filename)) {
  875. $okfile = DEDEROOT.'/theme/'.$cfg_df_style.'/'.$filename;
  876. } else {
  877. return "无法在这个位置找到:$filename";
  878. }
  879. //编译
  880. if ($ismake != "no") {
  881. require_once(DEDEINC."/channelunit.func.php");
  882. $dtp = new DedeTagParse();
  883. $dtp->LoadTemplet($okfile);
  884. MakeOneTag($dtp, $this->refObj);
  885. $restr = $dtp->GetResult();
  886. } else {
  887. $fp = @fopen($okfile, "r");
  888. while ($line = fgets($fp, 1024)) $restr .= $line;
  889. fclose($fp);
  890. }
  891. return $restr;
  892. }
  893. }
  894. /**********************************************
  895. //class DedeAttribute Dede模板标记属性集合
  896. function c____DedeAttribute();
  897. **********************************************/
  898. //属性的数据描述
  899. class DedeAttribute
  900. {
  901. var $Count = -1;
  902. var $Items = ""; //属性元素的集合
  903. //获得某个属性
  904. function GetAtt($str)
  905. {
  906. if ($str == "") {
  907. return "";
  908. }
  909. if (isset($this->Items[$str])) {
  910. return $this->Items[$str];
  911. } else {
  912. return "";
  913. }
  914. }
  915. //同上
  916. function GetAttribute($str)
  917. {
  918. return $this->GetAtt($str);
  919. }
  920. //判断属性是否存在
  921. function IsAttribute($str)
  922. {
  923. if (isset($this->Items[$str])) return TRUE;
  924. else return FALSE;
  925. }
  926. //获得标记名称
  927. function GetTagName()
  928. {
  929. return $this->GetAtt("tagname");
  930. }
  931. //获得属性个数
  932. function GetCount()
  933. {
  934. return $this->Count + 1;
  935. }
  936. }
  937. /*******************************
  938. //属性解析器(本版本中已经支持使用\'这种语法,和用.间隔表示name属性,如 field.body)
  939. function c____DedeAttributeParse();
  940. ********************************/
  941. class DedeAttributeParse
  942. {
  943. var $sourceString = "";
  944. var $sourceMaxSize = 1024;
  945. var $cAttributes = null;
  946. var $charToLow = TRUE;
  947. function SetSource($str = '')
  948. {
  949. $this->cAttributes = new DedeAttribute();
  950. $strLen = 0;
  951. $this->sourceString = trim(preg_replace("/[ \r\n\t]{1,}/", " ", $str));
  952. //为了在function内能使用数组,这里允许对[ ]进行转义使用
  953. $this->sourceString = str_replace('\]', ']', $this->sourceString);
  954. $this->sourceString = str_replace('[', '[', $this->sourceString);
  955. $strLen = strlen($this->sourceString);
  956. if ($strLen > 0 && $strLen <= $this->sourceMaxSize) {
  957. $this->ParseAttribute();
  958. }
  959. }
  960. //解析属性
  961. function ParseAttribute()
  962. {
  963. $d = '';
  964. $tmpatt = '';
  965. $tmpvalue = '';
  966. $startdd = -1;
  967. $ddtag = '';
  968. $hasAttribute = FALSE;
  969. $strLen = strlen($this->sourceString);
  970. $this->cAttributes->Items = array();
  971. //获得Tag的名称,解析到 cAtt->GetAtt('tagname') 中
  972. for ($i = 0; $i < $strLen; $i++) {
  973. if ($this->sourceString[$i] == ' ') {
  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. $tmpvalue = '';
  981. $hasAttribute = TRUE;
  982. break;
  983. } else {
  984. $tmpvalue .= $this->sourceString[$i];
  985. }
  986. }
  987. //不存在属性列表的情况
  988. if (!$hasAttribute) {
  989. $this->cAttributes->Count++;
  990. $tmpvalues = explode('.', $tmpvalue);
  991. $this->cAttributes->Items['tagname'] = ($this->charToLow ? strtolower($tmpvalues[0]) : $tmpvalues[0]);
  992. if (isset($tmpvalues[1]) && $tmpvalues[1] != '') {
  993. $this->cAttributes->Items['name'] = $tmpvalues[1];
  994. }
  995. return;
  996. }
  997. $tmpvalue = '';
  998. //如果字符串含有属性值,遍历源字符串,并获得各属性
  999. for ($i; $i < $strLen; $i++) {
  1000. $d = $this->sourceString[$i];
  1001. //查找属性名称
  1002. if ($startdd == -1) {
  1003. if ($d != '=') {
  1004. $tmpatt .= $d;
  1005. } else {
  1006. if ($this->charToLow) {
  1007. $tmpatt = strtolower(trim($tmpatt));
  1008. } else {
  1009. $tmpatt = trim($tmpatt);
  1010. }
  1011. $startdd = 0;
  1012. }
  1013. }
  1014. //查找属性的限定标志
  1015. else if ($startdd == 0) {
  1016. switch ($d) {
  1017. case ' ':
  1018. break;
  1019. case '"':
  1020. $ddtag = '"';
  1021. $startdd = 1;
  1022. break;
  1023. case '\'':
  1024. $ddtag = '\'';
  1025. $startdd = 1;
  1026. break;
  1027. default:
  1028. $tmpvalue .= $d;
  1029. $ddtag = ' ';
  1030. $startdd = 1;
  1031. break;
  1032. }
  1033. } else if ($startdd == 1) {
  1034. if ($d == $ddtag && (isset($this->sourceString[$i - 1]) && $this->sourceString[$i - 1] != "\\")) {
  1035. $this->cAttributes->Count++;
  1036. $this->cAttributes->Items[$tmpatt] = trim($tmpvalue);
  1037. $tmpatt = '';
  1038. $tmpvalue = '';
  1039. $startdd = -1;
  1040. } else {
  1041. $tmpvalue .= $d;
  1042. }
  1043. }
  1044. }//for
  1045. //最后一个属性的给值
  1046. if ($tmpatt != '') {
  1047. $this->cAttributes->Count++;
  1048. $this->cAttributes->Items[$tmpatt] = trim($tmpvalue);
  1049. }
  1050. //print_r($this->cAttributes->Items);
  1051. } //end func
  1052. }