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

1133 lines
34KB

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