国内流行的内容管理系统(CMS)多端全媒体解决方案 https://www.dedebiz.com
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

1132 рядки
34KB

  1. <?php if (!defined('DEDEINC')) exit("dedebiz");
  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) 2022, 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. try {
  574. @eval($phpcode);
  575. $this->CTags[$i]->TagValue = $DedeMeValue;
  576. $this->CTags[$i]->IsReplace = TRUE;
  577. } catch (Exception $e) {
  578. //or die("<xmp>$phpcode</xmp>");
  579. }
  580. }
  581. /**
  582. * 把分析模板输出到一个字符串中
  583. * 不替换没被处理的值
  584. *
  585. * @access public
  586. * @return string
  587. */
  588. function GetResultNP()
  589. {
  590. $ResultString = '';
  591. if ($this->Count == -1) {
  592. return $this->SourceString;
  593. }
  594. $this->AssignSysTag();
  595. $nextTagEnd = 0;
  596. $strok = "";
  597. for ($i = 0; $i <= $this->Count; $i++) {
  598. if ($this->CTags[$i]->GetValue() != "") {
  599. if ($this->CTags[$i]->GetValue() == '#@Delete@#') {
  600. $this->CTags[$i]->TagValue = "";
  601. }
  602. $ResultString .= substr($this->SourceString, $nextTagEnd, $this->CTags[$i]->StartPos - $nextTagEnd);
  603. $ResultString .= $this->CTags[$i]->GetValue();
  604. $nextTagEnd = $this->CTags[$i]->EndPos;
  605. }
  606. }
  607. $slen = strlen($this->SourceString);
  608. if ($slen > $nextTagEnd) {
  609. $ResultString .= substr($this->SourceString, $nextTagEnd, $slen - $nextTagEnd);
  610. }
  611. return $ResultString;
  612. }
  613. /**
  614. * 把分析模板输出到一个字符串中,并返回
  615. *
  616. * @access public
  617. * @return string
  618. */
  619. function GetResult()
  620. {
  621. $ResultString = '';
  622. if ($this->Count == -1) {
  623. return $this->SourceString;
  624. }
  625. $this->AssignSysTag();
  626. $nextTagEnd = 0;
  627. $strok = "";
  628. for ($i = 0; $i <= $this->Count; $i++) {
  629. $ResultString .= substr($this->SourceString, $nextTagEnd, $this->CTags[$i]->StartPos - $nextTagEnd);
  630. $ResultString .= $this->CTags[$i]->GetValue();
  631. $nextTagEnd = $this->CTags[$i]->EndPos;
  632. }
  633. $slen = strlen($this->SourceString);
  634. if ($slen > $nextTagEnd) {
  635. $ResultString .= substr($this->SourceString, $nextTagEnd, $slen - $nextTagEnd);
  636. }
  637. return $ResultString;
  638. }
  639. /**
  640. * 直接输出解析模板
  641. *
  642. * @access public
  643. * @return void
  644. */
  645. function Display()
  646. {
  647. echo $this->GetResult();
  648. }
  649. /**
  650. * 把解析模板输出为文件
  651. *
  652. * @access public
  653. * @param string $filename 要保存到的文件
  654. * @return string
  655. */
  656. function SaveTo($filename)
  657. {
  658. $fp = @fopen($filename, "w") or die("DedeTag Engine Create File False");
  659. fwrite($fp, $this->GetResult());
  660. fclose($fp);
  661. }
  662. /**
  663. * 解析模板
  664. *
  665. * @access public
  666. * @return string
  667. */
  668. function ParseTemplet()
  669. {
  670. $TagStartWord = $this->TagStartWord;
  671. $TagEndWord = $this->TagEndWord;
  672. $sPos = 0;
  673. $ePos = 0;
  674. $FullTagStartWord = $TagStartWord.$this->NameSpace.":";
  675. $sTagEndWord = $TagStartWord."/".$this->NameSpace.":";
  676. $eTagEndWord = "/".$TagEndWord;
  677. $tsLen = strlen($FullTagStartWord);
  678. $sourceLen = strlen($this->SourceString);
  679. if ($sourceLen <= ($tsLen + 3)) {
  680. return;
  681. }
  682. $cAtt = new DedeAttributeParse();
  683. $cAtt->charToLow = $this->CharToLow;
  684. //遍历模板字符串,请取标记及其属性信息
  685. for ($i = 0; $i < $sourceLen; $i++) {
  686. $tTagName = '';
  687. //如果不进行此判断,将无法识别相连的两个标记
  688. if ($i - 1 >= 0) {
  689. $ss = $i - 1;
  690. } else {
  691. $ss = 0;
  692. }
  693. $sPos = strpos($this->SourceString, $FullTagStartWord, $ss);
  694. $isTag = $sPos;
  695. if ($i == 0) {
  696. $headerTag = substr($this->SourceString, 0, strlen($FullTagStartWord));
  697. if ($headerTag == $FullTagStartWord) {
  698. $isTag = TRUE;
  699. $sPos = 0;
  700. }
  701. }
  702. if ($isTag === FALSE) {
  703. break;
  704. }
  705. //判断是否已经到倒数第三个字符(可能性几率极小,取消此逻辑)
  706. /*
  707. if($sPos > ($sourceLen-$tsLen-3) )
  708. {
  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. try {
  818. @eval($functionname.";");
  819. if (empty($DedeFieldValue)) {
  820. return '';
  821. } else {
  822. return $DedeFieldValue;
  823. }
  824. } catch (Exception $e) {
  825. //or die("<xmp>$functionname</xmp>");
  826. return '';
  827. }
  828. }
  829. /**
  830. * 获得一个外部变量
  831. *
  832. * @access public
  833. * @param string $varname 变量名称
  834. * @return string
  835. */
  836. function GetGlobals($varname)
  837. {
  838. $varname = trim($varname);
  839. //禁止在模板文件读取数据库密码
  840. if ($varname == "dbuserpwd" || $varname == "cfg_dbpwd") {
  841. return "";
  842. }
  843. //正常情况
  844. if (isset($GLOBALS[$varname])) {
  845. return $GLOBALS[$varname];
  846. } else {
  847. return "";
  848. }
  849. }
  850. /**
  851. * 引入文件
  852. *
  853. * @access public
  854. * @param string $filename 文件名
  855. * @param string $ismake 是否需要编译
  856. * @return string
  857. */
  858. function IncludeFile($filename, $ismake = 'no')
  859. {
  860. global $cfg_df_style;
  861. $restr = '';
  862. if ($filename == '') {
  863. return '';
  864. }
  865. if (file_exists(DEDEROOT."/templets/".$filename)) {
  866. $okfile = DEDEROOT."/templets/".$filename;
  867. } else if (file_exists(DEDEROOT.'/templets/'.$cfg_df_style.'/'.$filename)) {
  868. $okfile = DEDEROOT.'/templets/'.$cfg_df_style.'/'.$filename;
  869. } else {
  870. return "无法在这个位置找到: $filename";
  871. }
  872. //编译
  873. if ($ismake != "no") {
  874. require_once(DEDEINC."/channelunit.func.php");
  875. $dtp = new DedeTagParse();
  876. $dtp->LoadTemplet($okfile);
  877. MakeOneTag($dtp, $this->refObj);
  878. $restr = $dtp->GetResult();
  879. } else {
  880. $fp = @fopen($okfile, "r");
  881. while ($line = fgets($fp, 1024)) $restr .= $line;
  882. fclose($fp);
  883. }
  884. return $restr;
  885. }
  886. }
  887. /**********************************************
  888. //class DedeAttribute Dede模板标记属性集合
  889. function c____DedeAttribute();
  890. **********************************************/
  891. //属性的数据描述
  892. class DedeAttribute
  893. {
  894. var $Count = -1;
  895. var $Items = ""; //属性元素的集合
  896. //获得某个属性
  897. function GetAtt($str)
  898. {
  899. if ($str == "") {
  900. return "";
  901. }
  902. if (isset($this->Items[$str])) {
  903. return $this->Items[$str];
  904. } else {
  905. return "";
  906. }
  907. }
  908. //同上
  909. function GetAttribute($str)
  910. {
  911. return $this->GetAtt($str);
  912. }
  913. //判断属性是否存在
  914. function IsAttribute($str)
  915. {
  916. if (isset($this->Items[$str])) return TRUE;
  917. else return FALSE;
  918. }
  919. //获得标记名称
  920. function GetTagName()
  921. {
  922. return $this->GetAtt("tagname");
  923. }
  924. //获得属性个数
  925. function GetCount()
  926. {
  927. return $this->Count + 1;
  928. }
  929. }
  930. /*******************************
  931. //属性解析器(本版本中已经支持使用\'这种语法,和用.间隔表示name属性,如 field.body)
  932. function c____DedeAttributeParse();
  933. ********************************/
  934. class DedeAttributeParse
  935. {
  936. var $sourceString = "";
  937. var $sourceMaxSize = 1024;
  938. var $cAttributes = "";
  939. var $charToLow = TRUE;
  940. function SetSource($str = '')
  941. {
  942. $this->cAttributes = new DedeAttribute();
  943. $strLen = 0;
  944. $this->sourceString = trim(preg_replace("/[ \r\n\t]{1,}/", " ", $str));
  945. //为了在function内能使用数组,这里允许对[ ]进行转义使用
  946. $this->sourceString = str_replace('\]', ']', $this->sourceString);
  947. $this->sourceString = str_replace('[', '[', $this->sourceString);
  948. /*
  949. $this->sourceString = str_replace('\>','>',$this->sourceString);
  950. $this->sourceString = str_replace('<','>',$this->sourceString);
  951. $this->sourceString = str_replace('{','{',$this->sourceString);
  952. $this->sourceString = str_replace('\}','}',$this->sourceString);
  953. */
  954. $strLen = strlen($this->sourceString);
  955. if ($strLen > 0 && $strLen <= $this->sourceMaxSize) {
  956. $this->ParseAttribute();
  957. }
  958. }
  959. //解析属性
  960. function ParseAttribute()
  961. {
  962. $d = '';
  963. $tmpatt = '';
  964. $tmpvalue = '';
  965. $startdd = -1;
  966. $ddtag = '';
  967. $hasAttribute = FALSE;
  968. $strLen = strlen($this->sourceString);
  969. $this->cAttributes->Items = array();
  970. //获得Tag的名称,解析到 cAtt->GetAtt('tagname') 中
  971. for ($i = 0; $i < $strLen; $i++) {
  972. if ($this->sourceString[$i] == ' ') {
  973. $this->cAttributes->Count++;
  974. $tmpvalues = explode('.', $tmpvalue);
  975. $this->cAttributes->Items['tagname'] = ($this->charToLow ? strtolower($tmpvalues[0]) : $tmpvalues[0]);
  976. if (isset($tmpvalues[1]) && $tmpvalues[1] != '') {
  977. $this->cAttributes->Items['name'] = $tmpvalues[1];
  978. }
  979. $tmpvalue = '';
  980. $hasAttribute = TRUE;
  981. break;
  982. } else {
  983. $tmpvalue .= $this->sourceString[$i];
  984. }
  985. }
  986. //不存在属性列表的情况
  987. if (!$hasAttribute) {
  988. $this->cAttributes->Count++;
  989. $tmpvalues = explode('.', $tmpvalue);
  990. $this->cAttributes->Items['tagname'] = ($this->charToLow ? strtolower($tmpvalues[0]) : $tmpvalues[0]);
  991. if (isset($tmpvalues[1]) && $tmpvalues[1] != '') {
  992. $this->cAttributes->Items['name'] = $tmpvalues[1];
  993. }
  994. return;
  995. }
  996. $tmpvalue = '';
  997. //如果字符串含有属性值,遍历源字符串,并获得各属性
  998. for ($i; $i < $strLen; $i++) {
  999. $d = $this->sourceString[$i];
  1000. //查找属性名称
  1001. if ($startdd == -1) {
  1002. if ($d != '=') {
  1003. $tmpatt .= $d;
  1004. } else {
  1005. if ($this->charToLow) {
  1006. $tmpatt = strtolower(trim($tmpatt));
  1007. } else {
  1008. $tmpatt = trim($tmpatt);
  1009. }
  1010. $startdd = 0;
  1011. }
  1012. }
  1013. //查找属性的限定标志
  1014. else if ($startdd == 0) {
  1015. switch ($d) {
  1016. case ' ':
  1017. break;
  1018. case '"':
  1019. $ddtag = '"';
  1020. $startdd = 1;
  1021. break;
  1022. case '\'':
  1023. $ddtag = '\'';
  1024. $startdd = 1;
  1025. break;
  1026. default:
  1027. $tmpvalue .= $d;
  1028. $ddtag = ' ';
  1029. $startdd = 1;
  1030. break;
  1031. }
  1032. } else if ($startdd == 1) {
  1033. if ($d == $ddtag && (isset($this->sourceString[$i - 1]) && $this->sourceString[$i - 1] != "\\")) {
  1034. $this->cAttributes->Count++;
  1035. $this->cAttributes->Items[$tmpatt] = trim($tmpvalue);
  1036. $tmpatt = '';
  1037. $tmpvalue = '';
  1038. $startdd = -1;
  1039. } else {
  1040. $tmpvalue .= $d;
  1041. }
  1042. }
  1043. } //for
  1044. //最后一个属性的给值
  1045. if ($tmpatt != '') {
  1046. $this->cAttributes->Count++;
  1047. $this->cAttributes->Items[$tmpatt] = trim($tmpvalue);
  1048. }
  1049. //print_r($this->cAttributes->Items);
  1050. } //end func
  1051. }