国内流行的内容管理系统(CMS)多端全媒体解决方案 https://www.dedebiz.com
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

1205 linhas
42KB

  1. <?php
  2. if (!defined('DEDEINC')) exit('dedebiz');
  3. /**
  4. * 主题模板引擎
  5. *
  6. * @version $id:dedetemplate.class.php 3 15:44 2010年7月6日 tianya $
  7. * @package DedeBIZ.Libraries
  8. * @copyright Copyright (c) 2022 DedeBIZ.COM
  9. * @license GNU GPL v2 (https://www.dedebiz.com/license)
  10. * @link https://www.dedebiz.com
  11. */
  12. function MakePublicTag($atts = array(), $refObj = null, $fields = array())
  13. {
  14. $atts['tagname'] = preg_replace("/[0-9]{1,}$/", "", $atts['tagname']);
  15. $plusfile = DEDEINC.'/tpllib/plus_'.$atts['tagname'].'.php';
  16. if (!file_exists($plusfile)) {
  17. if (isset($atts['rstype']) && $atts['rstype'] == 'string') {
  18. return '';
  19. } else {
  20. return array();
  21. }
  22. } else {
  23. include_once($plusfile);
  24. $func = 'plus_'.$atts['tagname'];
  25. return $func($atts, $refObj, $fields);
  26. }
  27. }
  28. /**
  29. * 设定属性的默认值
  30. *
  31. * @access public
  32. * @param array $atts 属性
  33. * @param string $attlist 属性列表
  34. * @return void
  35. */
  36. function FillAtts(&$atts, $attlist="")
  37. {
  38. $attlists = explode(',', $attlist);
  39. foreach ($attlists as $att) {
  40. list($k, $v) = explode('=', $att);
  41. if (!isset($atts[$k])) {
  42. $atts[$k] = $v;
  43. }
  44. }
  45. }
  46. /**
  47. * 把上级的fields传递给atts
  48. *
  49. * @access public
  50. * @param array $atts 属性
  51. * @param object $refObj 所属对象
  52. * @param array $fields 字段
  53. * @return void
  54. */
  55. function FillFields(&$atts, &$refObj, &$fields)
  56. {
  57. global $_vars;
  58. foreach ($atts as $k => $v) {
  59. if (preg_match('/^field\./i', $v)) {
  60. $key = preg_replace('/^field\./i', '', $v);
  61. if (isset($fields[$key])) {
  62. $atts[$k] = $fields[$key];
  63. }
  64. } else if (preg_match('/^var\./i', $v)) {
  65. $key = preg_replace('/^var\./i', '', $v);
  66. if (isset($_vars[$key])) {
  67. $atts[$k] = $_vars[$key];
  68. }
  69. } else if (preg_match('/^global\./i', $v)) {
  70. $key = preg_replace('/^global\./i', '', $v);
  71. if (isset($GLOBALS[$key])) {
  72. $atts[$k] = $GLOBALS[$key];
  73. }
  74. }
  75. }
  76. }
  77. /**
  78. * class Tag 标记的数据结构描述
  79. * function C__Tag();
  80. *
  81. * @package Tag
  82. * @subpackage DedeBIZ.Libraries
  83. * @link https://www.dedebiz.com
  84. */
  85. class Tag
  86. {
  87. var $isCompiler = FALSE; //标记是否已被替代,供解析器使用
  88. var $tagName = ''; //标记名称
  89. var $innerText = ''; //标记之间的文本
  90. var $startPos = 0; //标记起始位置
  91. var $endPos = 0; //标记结束位置
  92. var $cAtt; //标记属性描述,即是class TagAttribute
  93. var $tagValue = ''; //标记的值
  94. var $tagID = 0;
  95. /**
  96. * 获取标记的名称和值
  97. *
  98. * @access public
  99. * @return string
  100. */
  101. function GetName()
  102. {
  103. return strtolower($this->tagName);
  104. }
  105. function GetValue()
  106. {
  107. return $this->tagValue;
  108. }
  109. function IsAtt($str)
  110. {
  111. return $this->cAtt->IsAttribute($str);
  112. }
  113. function GetAtt($str)
  114. {
  115. return $this->cAtt->GetAtt($str);
  116. }
  117. /**
  118. * 获取底层模板
  119. *
  120. * @return string
  121. */
  122. function GetinnerText()
  123. {
  124. return $this->innerText;
  125. }
  126. }
  127. /**
  128. * 模板解析器
  129. * function C__DedeTemplate
  130. *
  131. * @package DedeTemplate
  132. * @subpackage DedeBIZ.Libraries
  133. * @link https://www.dedebiz.com
  134. */
  135. class DedeTemplate
  136. {
  137. var $tagMaxLen = 64;
  138. var $charToLow = TRUE;
  139. var $isCache = TRUE;
  140. var $isParse = FALSE;
  141. var $isCompiler = TRUE;
  142. var $templateDir = '';
  143. var $tempMkTime = 0;
  144. var $cacheFile = '';
  145. var $configFile = '';
  146. var $buildFile = '';
  147. var $refDir = '';
  148. var $cacheDir = '';
  149. var $templateFile = '';
  150. var $sourceString = '';
  151. var $cTags = array();
  152. var $count = -1;
  153. var $loopNum = 0;
  154. var $refObj = '';
  155. var $makeLoop = 0;
  156. var $tagStartWord = '{dede:';
  157. var $fullTagEndWord = '{/dede:';
  158. var $sTagEndWord = '/}';
  159. var $tagEndWord = '}';
  160. var $tpCfgs = array();
  161. /**
  162. * 析构函数
  163. *
  164. * @access public
  165. * @param string $templatedir 模板目录
  166. * @param string $refDir 所属目录
  167. * @return void
  168. */
  169. function __construct($templatedir = '', $refDir = '')
  170. {
  171. //缓存目录
  172. if ($templatedir == '') {
  173. $this->templateDir = DEDEROOT.'/templates';
  174. } else {
  175. $this->templateDir = $templatedir;
  176. }
  177. //模板include目录
  178. if ($refDir == '') {
  179. if (isset($GLOBALS['cfg_df_style'])) {
  180. $this->refDir = $this->templateDir.'/'.$GLOBALS['cfg_df_style'].'/';
  181. } else {
  182. $this->refDir = $this->templateDir;
  183. }
  184. }
  185. $this->cacheDir = DEDEROOT.$GLOBALS['cfg_tplcache_dir'];
  186. }
  187. //构造函数,兼容PHP4
  188. function DedeTemplate($templatedir = '', $refDir = '')
  189. {
  190. $this->__construct($templatedir, $refDir);
  191. }
  192. /**
  193. * 设定本类自身实例的类引用和使用本类的类实例,如果在类中使用本模板引擎,后一参数一般为$this
  194. *
  195. * @access public
  196. * @param object $refObj 实例对象
  197. * @return void
  198. */
  199. function SetObject(&$refObj)
  200. {
  201. $this->refObj = $refObj;
  202. }
  203. /**
  204. * 设定Var的键值对
  205. *
  206. * @access public
  207. * @param string $k 键
  208. * @param string $v 值
  209. * @return void
  210. */
  211. function SetVar($k, $v)
  212. {
  213. $GLOBALS['_vars'][$k] = $v;
  214. }
  215. /**
  216. * 设定Var的键值对
  217. *
  218. * @access public
  219. * @param string $k 键
  220. * @param string $v 值
  221. * @return void
  222. */
  223. function Assign($k, $v)
  224. {
  225. $GLOBALS['_vars'][$k] = $v;
  226. }
  227. /**
  228. * 设定数组
  229. *
  230. * @access public
  231. * @param string $k 键
  232. * @param string $v 值
  233. * @return void
  234. */
  235. function SetArray($k, $v)
  236. {
  237. $GLOBALS[$k] = $v;
  238. }
  239. /**
  240. * 设置标记风格
  241. *
  242. * @access public
  243. * @param string $ts 标签开始标记
  244. * @param string $ftend 标签结束标记
  245. * @param string $stend 标签尾部结束标记
  246. * @param string $tend 结束标记
  247. * @return void
  248. */
  249. function SetTagStyle($ts = '{dede:', $ftend = '{/dede:', $stend = '/}', $tend = '}')
  250. {
  251. $this->tagStartWord = $ts;
  252. $this->fullTagEndWord = $ftend;
  253. $this->sTagEndWord = $stend;
  254. $this->tagEndWord = $tend;
  255. }
  256. /**
  257. * 获得模板设定的config值
  258. *
  259. * @access public
  260. * @param string $k 键名
  261. * @return string
  262. */
  263. function GetConfig($k)
  264. {
  265. return (isset($this->tpCfgs[$k]) ? $this->tpCfgs[$k] : '');
  266. }
  267. /**
  268. * 设定模板文件
  269. *
  270. * @access public
  271. * @param string $tmpfile 模板文件
  272. * @return void
  273. */
  274. function LoadTemplate($tmpfile)
  275. {
  276. if (!file_exists($tmpfile)) {
  277. echo " Template Not Found! ";
  278. exit();
  279. }
  280. $tmpfile = preg_replace("/[\\/]{1,}/", "/", $tmpfile);
  281. $tmpfiles = explode('/', $tmpfile);
  282. $tmpfileOnlyName = preg_replace("/(.*)\//", "", $tmpfile);
  283. $this->templateFile = $tmpfile;
  284. $this->refDir = '';
  285. for ($i = 0; $i < count($tmpfiles) - 1; $i++) {
  286. $this->refDir .= $tmpfiles[$i].'/';
  287. }
  288. if (!is_dir($this->cacheDir)) {
  289. $this->cacheDir = $this->refDir;
  290. }
  291. if ($this->cacheDir != '') {
  292. $this->cacheDir = $this->cacheDir.'/';
  293. }
  294. if (isset($GLOBALS['_DEBUG_CACHE'])) {
  295. $this->cacheDir = $this->refDir;
  296. }
  297. $this->cacheFile = $this->cacheDir.preg_replace("/\.(wml|html|htm|php)$/", "_".$this->GetEncodeStr($tmpfile).'.inc', $tmpfileOnlyName);
  298. $this->configFile = $this->cacheDir.preg_replace("/\.(wml|html|htm|php)$/", "_".$this->GetEncodeStr($tmpfile).'_config.inc', $tmpfileOnlyName);
  299. //不开启缓存、当缓存文件不存在、及模板为更新的文件的时候才载入模板并进行解析
  300. if (
  301. $this->isCache == FALSE || !file_exists($this->cacheFile)
  302. || filemtime($this->templateFile) > filemtime($this->cacheFile)
  303. ) {
  304. $t1 = ExecTime(); //debug
  305. $fp = fopen($this->templateFile, 'r');
  306. $this->sourceString = fread($fp, filesize($this->templateFile));
  307. fclose($fp);
  308. $this->ParseTemplate();
  309. //模板解析时间
  310. //echo ExecTime() - $t1;
  311. } else {
  312. //如果存在config文件,则载入此文件,该文件用于保存 $this->tpCfgs的文档,以供扩展用途,模板中用“{tag:config name=''/}”来设定该值
  313. if (file_exists($this->configFile)) {
  314. include($this->configFile);
  315. }
  316. }
  317. }
  318. /**
  319. * 载入模板字符串
  320. *
  321. * @access public
  322. * @param string $str 模板字符串
  323. * @return void
  324. */
  325. function LoadString($str = '')
  326. {
  327. $this->sourceString = $str;
  328. $hashcode = md5($this->sourceString);
  329. $this->cacheFile = $this->cacheDir."/string_".$hashcode.".inc";
  330. $this->configFile = $this->cacheDir."/string_".$hashcode."_config.inc";
  331. $this->ParseTemplate();
  332. }
  333. /**
  334. * 调用此函数include一个编译后的PHP文件,通常是在最后一个步骤才调用本文件
  335. *
  336. * @access public
  337. * @return string
  338. */
  339. function CacheFile()
  340. {
  341. global $gtmpfile;
  342. $this->WriteCache();
  343. return $this->cacheFile;
  344. }
  345. /**
  346. * 显示文档,由于函数中会重新解压一次$GLOBALS变量,所以在动态页中,应该尽量少用本方法,取代之是直接在程序中 include $tpl->CacheFile(),不过include $tpl->CacheFile()这种方式不能在类或函数内使用
  347. *
  348. * @access public
  349. * @param string
  350. * @return void
  351. */
  352. function Display()
  353. {
  354. global $gtmpfile;
  355. extract($GLOBALS, EXTR_SKIP);
  356. $this->WriteCache();
  357. include $this->cacheFile;
  358. }
  359. /**
  360. * 保存运行后的程序为文件
  361. *
  362. * @access public
  363. * @param string $savefile 保存到的文件目录
  364. * @return void
  365. */
  366. function SaveTo($savefile)
  367. {
  368. extract($GLOBALS, EXTR_SKIP);
  369. $this->WriteCache();
  370. ob_start();
  371. include $this->cacheFile;
  372. $okstr = ob_get_contents();
  373. ob_end_clean();
  374. $fp = @fopen($savefile, "w") or die(" Tag Engine Create File FALSE! ");
  375. fwrite($fp, $okstr);
  376. fclose($fp);
  377. }
  378. /**
  379. * COMMENT : CheckDisabledFunctions : 检查是否存在禁止的函数
  380. *
  381. * @access public
  382. * @param string
  383. * @return bool
  384. */
  385. function CheckDisabledFunctions($str, &$errmsg = '')
  386. {
  387. global $cfg_disable_funs;
  388. $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';
  389. //模板引擎添加disable_functions
  390. if (!defined('DEDEDISFUN')) {
  391. $tokens = token_get_all_nl($str);
  392. $disabled_functions = explode(',', $cfg_disable_funs);
  393. foreach ($tokens as $token) {
  394. if (is_array($token)) {
  395. if ($token[0] = '306' && in_array($token[1], $disabled_functions)) {
  396. $errmsg = 'DedeBIZ Error:function disabled "'.$token[1].'" <a href="https://www.dedebiz.com/help" target="_blank">more</a>';
  397. return FALSE;
  398. }
  399. }
  400. }
  401. }
  402. return TRUE;
  403. }
  404. /**
  405. * 解析模板并写缓存文件
  406. *
  407. * @access public
  408. * @param string $ctype 缓存类型
  409. * @return void
  410. */
  411. function WriteCache($ctype = 'all')
  412. {
  413. if (
  414. !file_exists($this->cacheFile) || $this->isCache == FALSE
  415. || (file_exists($this->templateFile) && (filemtime($this->templateFile) > filemtime($this->cacheFile)))
  416. ) {
  417. if (!$this->isParse) {
  418. $this->ParseTemplate();
  419. }
  420. $fp = fopen($this->cacheFile, 'w') or dir("Write Cache File Error! ");
  421. flock($fp, 3);
  422. $result = trim($this->GetResult());
  423. $errmsg = '';
  424. if (!$this->CheckDisabledFunctions($result, $errmsg)) {
  425. fclose($fp);
  426. @unlink($this->cacheFile);
  427. die($errmsg);
  428. }
  429. fwrite($fp, $result);
  430. fclose($fp);
  431. if (count($this->tpCfgs) > 0) {
  432. $fp = fopen($this->configFile, 'w') or dir("Write Config File Error! ");
  433. flock($fp, 3);
  434. fwrite($fp, '<'.'?php'."\r\n");
  435. foreach ($this->tpCfgs as $k => $v) {
  436. $v = str_replace("\"", "\\\"", $v);
  437. $v = str_replace("\$", "\\\$", $v);
  438. fwrite($fp, "\$this->tpCfgs['$k']=\"$v\";\r\n");
  439. }
  440. fwrite($fp, '?'.'>');
  441. fclose($fp);
  442. }
  443. }
  444. }
  445. /**
  446. * 获得模板文件名的md5字符串
  447. *
  448. * @access public
  449. * @param string $tmpfile 模板文件
  450. * @return string
  451. */
  452. function GetEncodeStr($tmpfile)
  453. {
  454. //$tmpfiles = explode('/',$tmpfile);
  455. $encodeStr = substr(md5($tmpfile), 0, 24);
  456. return $encodeStr;
  457. }
  458. /**
  459. * 解析模板
  460. *
  461. * @access public
  462. * @return void
  463. */
  464. function ParseTemplate()
  465. {
  466. if ($this->makeLoop > 5) {
  467. return;
  468. }
  469. $this->count = -1;
  470. $this->cTags = array();
  471. $this->isParse = TRUE;
  472. $sPos = 0;
  473. $ePos = 0;
  474. $tagStartWord = $this->tagStartWord;
  475. $fullTagEndWord = $this->fullTagEndWord;
  476. $sTagEndWord = $this->sTagEndWord;
  477. $tagEndWord = $this->tagEndWord;
  478. $startWordLen = strlen($tagStartWord);
  479. $sourceLen = strlen($this->sourceString);
  480. if ($sourceLen <= ($startWordLen + 3)) {
  481. return;
  482. }
  483. $cAtt = new TagAttributeParse();
  484. $cAtt->charToLow = TRUE;
  485. //遍历模板字符串,请取标记及其属性信息
  486. $t = 0;
  487. $preTag = '';
  488. $tswLen = strlen($tagStartWord);
  489. for ($i = 0; $i < $sourceLen; $i++) {
  490. $ttagName = '';
  491. //如果不进行此判断,无法识别相连的两个标记
  492. if ($i - 1 >= 0) {
  493. $ss = $i - 1;
  494. } else {
  495. $ss = 0;
  496. }
  497. $tagPos = strpos($this->sourceString, $tagStartWord, $ss);
  498. //判断后面是否还有模板标记
  499. if ($tagPos == 0 && ($sourceLen - $i < $tswLen
  500. || substr($this->sourceString, $i, $tswLen) != $tagStartWord)) {
  501. $tagPos = -1;
  502. break;
  503. }
  504. //获取TAG基本信息
  505. for ($j = $tagPos + $startWordLen; $j < $tagPos + $startWordLen + $this->tagMaxLen; $j++) {
  506. if (preg_match("/[ >\/\r\n\t\}\.]/", $this->sourceString[$j])) {
  507. break;
  508. } else {
  509. $ttagName .= $this->sourceString[$j];
  510. }
  511. }
  512. if ($ttagName != '') {
  513. $i = $tagPos + $startWordLen;
  514. $endPos = -1;
  515. //判断 '/}' '{tag:下一标记开始' '{/tag:标记结束' 谁最靠近
  516. $fullTagEndWordThis = $fullTagEndWord.$ttagName.$tagEndWord;
  517. $e1 = strpos($this->sourceString, $sTagEndWord, $i);
  518. $e2 = strpos($this->sourceString, $tagStartWord, $i);
  519. $e3 = strpos($this->sourceString, $fullTagEndWordThis, $i);
  520. $e1 = trim($e1);
  521. $e2 = trim($e2);
  522. $e3 = trim($e3);
  523. $e1 = ($e1 == '' ? '-1' : $e1);
  524. $e2 = ($e2 == '' ? '-1' : $e2);
  525. $e3 = ($e3 == '' ? '-1' : $e3);
  526. if ($e3 == -1) {
  527. //不存在'{/tag:标记'
  528. $endPos = $e1;
  529. $elen = $endPos + strlen($sTagEndWord);
  530. } else if ($e1 == -1) {
  531. //不存在 '/}'
  532. $endPos = $e3;
  533. $elen = $endPos + strlen($fullTagEndWordThis);
  534. }
  535. //同时存在 '/}' 和 '{/tag:标记'
  536. else {
  537. //如果 '/}' 比 '{tag:'、'{/tag:标记' 都要靠近,则认为结束标志是 '/}',否则结束标志为 '{/tag:标记'
  538. if ($e1 < $e2 && $e1 < $e3) {
  539. $endPos = $e1;
  540. $elen = $endPos + strlen($sTagEndWord);
  541. } else {
  542. $endPos = $e3;
  543. $elen = $endPos + strlen($fullTagEndWordThis);
  544. }
  545. }
  546. //如果找不到结束标记,则认为这个标记存在错误
  547. if ($endPos == -1) {
  548. echo "Tpl Character postion $tagPos, '$ttagName' Error<br>\r\n";
  549. break;
  550. }
  551. $i = $elen;
  552. //分析所找到的标记位置等信息
  553. $attStr = '';
  554. $innerText = '';
  555. $startInner = 0;
  556. for ($j = $tagPos + $startWordLen; $j < $endPos; $j++) {
  557. if ($startInner == 0) {
  558. if ($this->sourceString[$j] == $tagEndWord) {
  559. $startInner = 1;
  560. continue;
  561. } else {
  562. $attStr .= $this->sourceString[$j];
  563. }
  564. } else {
  565. $innerText .= $this->sourceString[$j];
  566. }
  567. }
  568. $ttagName = strtolower($ttagName);
  569. //if、php标记,把整个属性串视为属性
  570. if (preg_match("/^if[0-9]{0,}$/", $ttagName)) {
  571. $cAtt->cAttributes = new TagAttribute();
  572. $cAtt->cAttributes->count = 2;
  573. $cAtt->cAttributes->items['tagname'] = $ttagName;
  574. $cAtt->cAttributes->items['condition'] = preg_replace("/^if[0-9]{0,}[\r\n\t ]/", "", $attStr);
  575. $innerText = preg_replace("/\{else\}/i", '<'."?php\r\n}\r\nelse{\r\n".'?'.'>', $innerText);
  576. } else if ($ttagName == 'php') {
  577. $cAtt->cAttributes = new TagAttribute();
  578. $cAtt->cAttributes->count = 2;
  579. $cAtt->cAttributes->items['tagname'] = $ttagName;
  580. $cAtt->cAttributes->items['code'] = '<'."?php\r\n".trim(preg_replace(
  581. "/^php[0-9]{0,}[\r\n\t ]/",
  582. "",
  583. $attStr
  584. ))."\r\n?".'>';
  585. } else {
  586. //普通标记,解释属性
  587. $cAtt->SetSource($attStr);
  588. }
  589. $this->count++;
  590. $cTag = new Tag();
  591. $cTag->tagName = $ttagName;
  592. $cTag->startPos = $tagPos;
  593. $cTag->endPos = $i;
  594. $cTag->cAtt = $cAtt->cAttributes;
  595. $cTag->isCompiler = FALSE;
  596. $cTag->tagID = $this->count;
  597. $cTag->innerText = $innerText;
  598. $this->cTags[$this->count] = $cTag;
  599. } else {
  600. $i = $tagPos + $startWordLen;
  601. break;
  602. }
  603. }//结束遍历模板字符串
  604. if ($this->count > -1 && $this->isCompiler) {
  605. $this->CompilerAll();
  606. }
  607. }
  608. /**
  609. * 把模板标记转换为PHP代码
  610. *
  611. * @access public
  612. * @return void
  613. */
  614. function CompilerAll()
  615. {
  616. $this->loopNum++;
  617. if ($this->loopNum > 10) {
  618. return;//限制最大递归深度为10以防止因标记出错等,导致死循环
  619. }
  620. $ResultString = '';
  621. $nextTagEnd = 0;
  622. for ($i = 0; isset($this->cTags[$i]); $i++) {
  623. $ResultString .= substr($this->sourceString, $nextTagEnd, $this->cTags[$i]->startPos - $nextTagEnd);
  624. $ResultString .= $this->CompilerOneTag($this->cTags[$i]);
  625. $nextTagEnd = $this->cTags[$i]->endPos;
  626. }
  627. $slen = strlen($this->sourceString);
  628. if ($slen > $nextTagEnd) {
  629. $ResultString .= substr($this->sourceString, $nextTagEnd, $slen - $nextTagEnd);
  630. }
  631. $this->sourceString = $ResultString;
  632. $this->ParseTemplate();
  633. }
  634. /**
  635. * 获得最终结果
  636. *
  637. * @access public
  638. * @return string
  639. */
  640. function GetResult()
  641. {
  642. if (!$this->isParse) {
  643. $this->ParseTemplate();
  644. }
  645. $addset = '';
  646. $addset .= '<'.'?php'."\r\n".'if (!isset($GLOBALS[\'_vars\'])) $GLOBALS[\'_vars\'] = array(); '."\r\n".'$fields = array();'."\r\n".'?'.'>';
  647. return preg_replace("/\?".">[ \r\n\t]{0,}<"."\?php/", "", $addset.$this->sourceString);
  648. }
  649. /**
  650. * 编译单个标记
  651. *
  652. * @access public
  653. * @param object $cTag 标签
  654. * @return string
  655. */
  656. function CompilerOneTag(&$cTag)
  657. {
  658. $cTag->isCompiler = TRUE;
  659. $tagname = $cTag->tagName;
  660. $varname = $cTag->GetAtt('name');
  661. $rsvalue = '';
  662. //用于在模板中设置一个变量以提供作扩展用途,此变量直接提交到 this->tpCfgs 中,并会生成与模板对应的缓存文件 ***_config.php 文件
  663. if ($tagname == 'config') {
  664. $this->tpCfgs[$varname] = $cTag->GetAtt('value');
  665. } else if ($tagname == 'global') {
  666. $cTag->tagValue = $this->CompilerArrayVar('global', $varname);
  667. if ($cTag->GetAtt('function') != '') {
  668. $cTag->tagValue = $this->CompilerFunction($cTag->GetAtt('function'), $cTag->tagValue);
  669. }
  670. $cTag->tagValue = '<'.'?php echo '.$cTag->tagValue.'; ?'.'>';
  671. } else if ($tagname == 'cfg') {
  672. $cTag->tagValue = '$GLOBALS[\'cfg_'.$varname.'\']'; //处理函数
  673. if ($cTag->GetAtt('function') != '') {
  674. $cTag->tagValue = $this->CompilerFunction($cTag->GetAtt('function'), $cTag->tagValue);
  675. }
  676. $cTag->tagValue = '<'.'?php echo '.$cTag->tagValue.'; ?'.'>';
  677. } else if ($tagname == 'name') {
  678. $cTag->tagValue = '$'.$varname; //处理函数
  679. if ($cTag->GetAtt('function') != '') {
  680. $cTag->tagValue = $this->CompilerFunction($cTag->GetAtt('function'), $cTag->tagValue);
  681. }
  682. $cTag->tagValue = '<'.'?php echo '.$cTag->tagValue.'; ?'.'>';
  683. } else if ($tagname == 'object') {
  684. list($_obs, $_em) = explode('->', $varname);
  685. $cTag->tagValue = "\$GLOBALS['{$_obs}']->{$_em}"; //处理函数
  686. if ($cTag->GetAtt('function') != '') {
  687. $cTag->tagValue = $this->CompilerFunction($cTag->GetAtt('function'), $cTag->tagValue);
  688. }
  689. $cTag->tagValue = '<'.'?php echo '.$cTag->tagValue.'; ?'.'>';
  690. } else if ($tagname == 'var') {
  691. $cTag->tagValue = $this->CompilerArrayVar('var', $varname);
  692. if ($cTag->GetAtt('function') != '') {
  693. $cTag->tagValue = $this->CompilerFunction($cTag->GetAtt('function'), $cTag->tagValue);
  694. }
  695. //添加默认空值处理
  696. if ($cTag->GetAtt('default') != '') {
  697. $cTag->tagValue = '<'.'?php echo empty('.$cTag->tagValue.')? \''.addslashes($cTag->GetAtt('default')).'\':'.$cTag->tagValue.'; ?'.'>';
  698. } else {
  699. $cTag->tagValue = '<'.'?php echo '.$cTag->tagValue.'; ?'.'>';
  700. }
  701. } else if ($tagname == 'field') {
  702. $cTag->tagValue = '$fields[\''.$varname.'\']';
  703. if ($cTag->GetAtt('function') != '') {
  704. $cTag->tagValue = $this->CompilerFunction($cTag->GetAtt('function'), $cTag->tagValue);
  705. }
  706. $cTag->tagValue = '<'.'?php echo '.$cTag->tagValue.'; ?'.'>';
  707. } else if ($tagname == 'sfield') {
  708. $cTag->tagValue = '$fields[\'__safe\'][\''.$varname.'\']';
  709. if ($cTag->GetAtt('function') != '') {
  710. $cTag->tagValue = $this->CompilerFunction($cTag->GetAtt('function'), $cTag->tagValue);
  711. }
  712. $cTag->tagValue = '<'.'?php echo '.$cTag->tagValue.'; ?'.'>';
  713. } else if (preg_match("/^key[0-9]{0,}/", $tagname) || preg_match("/^value[0-9]{0,}/", $tagname)) {
  714. if (preg_match("/^value[0-9]{0,}/", $tagname) && $varname != '') {
  715. $cTag->tagValue = '<'.'?php echo '.$this->CompilerArrayVar($tagname, $varname).'; ?'.'>';
  716. } else {
  717. $cTag->tagValue = '<'.'?php echo $'.$tagname.'; ?'.'>';
  718. }
  719. } else if (preg_match("/^if[0-9]{0,}$/", $tagname)) {
  720. $cTag->tagValue = $this->Compilerif ($cTag);
  721. } else if ($tagname == 'echo') {
  722. if (trim($cTag->GetInnerText()) == '') $cTag->tagValue = $cTag->GetAtt('code');
  723. else {
  724. $cTag->tagValue = '<'."?php echo $".trim($cTag->GetInnerText())." ;?".'>';
  725. }
  726. } else if ($tagname == 'php') {
  727. if (trim($cTag->GetInnerText()) == '') $cTag->tagValue = $cTag->GetAtt('code');
  728. else {
  729. $cTag->tagValue = '<'."?php\r\n".trim($cTag->GetInnerText())."\r\n?".'>';
  730. }
  731. }
  732. //遍历数组
  733. else if (preg_match("/^array[0-9]{0,}/", $tagname)) {
  734. $kk = '$key';
  735. $vv = '$value';
  736. if ($cTag->GetAtt('key') != '') {
  737. $kk = '$key'.$cTag->GetAtt('key');
  738. }
  739. if ($cTag->GetAtt('value') != '') {
  740. $vv = '$value'.$cTag->GetAtt('value');
  741. }
  742. $addvar = '';
  743. if (!preg_match("/\(/", $varname)) {
  744. $varname = '$GLOBALS[\''.$varname.'\']';
  745. } else {
  746. $addvar = "\r\n".'$myarrs = $pageClass->'.$varname.";\r\n";
  747. $varname = ' $myarrs ';
  748. }
  749. $rsvalue = '<'.'?php '.$addvar.' foreach('.$varname.' as '.$kk.'=>'.$vv.'){ ?'.">";
  750. $rsvalue .= $cTag->GetInnerText();
  751. $rsvalue .= '<'.'?php } ?'.">\r\n";
  752. $cTag->tagValue = $rsvalue;
  753. }
  754. //system文件
  755. else if ($tagname == 'include') {
  756. $filename = $cTag->GetAtt('file');
  757. if ($filename == '') {
  758. $filename = $cTag->GetAtt('filename');
  759. }
  760. $cTag->tagValue = $this->CompilerInclude($filename, FALSE);
  761. if ($cTag->tagValue == 0) $cTag->tagValue = '';
  762. $cTag->tagValue = '<'.'?php include $this->CompilerInclude("'.$filename.'");'."\r\n".' ?'.'>';
  763. } else if ($tagname == 'label') {
  764. $bindFunc = $cTag->GetAtt('bind');
  765. $rsvalue = 'echo '.$bindFunc.";\r\n";
  766. $rsvalue = '<'.'?php '.$rsvalue.' ?'.">\r\n";
  767. $cTag->tagValue = $rsvalue;
  768. } else if ($tagname == 'datalist') {
  769. //生成属性数组
  770. foreach ($cTag->cAtt->items as $k => $v) {
  771. $v = $this->TrimAtts($v);
  772. $rsvalue .= '$atts[\''.$k.'\'] = \''.str_replace("'", "\\'", $v)."';\r\n";
  773. }
  774. $rsvalue = '<'.'?php'."\r\n".'$atts = array();'."\r\n".$rsvalue;
  775. $rsvalue .= '$blockValue = $this->refObj->GetArcList($atts,$this->refObj,$fields); '."\r\n";
  776. $rsvalue .= '$total = $this->refObj->totalResult;'."\r\n";
  777. $rsvalue .= 'if (is_array($blockValue)){'."\r\n";
  778. $rsvalue .= 'foreach( $blockValue as $key=>$fields )'."\r\n{\r\n".'?'.">";
  779. $rsvalue .= $cTag->GetInnerText();
  780. $rsvalue .= '<'.'?php'."\r\n}if (\$total==0 && !empty(\$atts['empty'])) echo \$atts['empty'];\r\n}".'?'.'>';
  781. $cTag->tagValue = $rsvalue;
  782. } else if ($tagname == 'pagelist') {
  783. //生成属性数组
  784. foreach ($cTag->cAtt->items as $k => $v) {
  785. $v = $this->TrimAtts($v);
  786. $rsvalue .= '$atts[\''.$k.'\'] = \''.str_replace("'", "\\'", $v)."';\r\n";
  787. }
  788. $rsvalue = '<'.'?php'."\r\n".'$atts = array();'."\r\n".$rsvalue;
  789. $rsvalue .= ' echo $this->refObj->GetPageList($atts,$this->refObj,$fields); '."\r\n".'?'.">\r\n";
  790. $cTag->tagValue = $rsvalue;
  791. } else {
  792. $bindFunc = $cTag->GetAtt('bind');
  793. $bindType = $cTag->GetAtt('bindtype');
  794. $rstype = ($cTag->GetAtt('resulttype') == '' ? $cTag->GetAtt('rstype') : $cTag->GetAtt('resulttype'));
  795. $rstype = strtolower($rstype);
  796. //生成属性数组
  797. foreach ($cTag->cAtt->items as $k => $v) {
  798. if (preg_match("/(bind|bindtype)/i", $k)) {
  799. continue;
  800. }
  801. $v = $this->TrimAtts($v);
  802. $rsvalue .= '$atts[\''.$k.'\'] = \''.str_replace("'", "\\'", $v)."';\r\n";
  803. }
  804. $rsvalue = '<'.'?php'."\r\n".'$atts = array();'."\r\n".$rsvalue;
  805. //绑定到默认函数还是指定函数(datasource属性指定)
  806. if ($bindFunc == '') {
  807. $rsvalue .= '$blockValue = MakePublicTag($atts,$this->refObj,$fields); '."\r\n";
  808. } else {
  809. //自定义绑定函数如果不指定 bindtype,则指向$this->refObj->绑定函数名,即是默认指向被引用的类对象
  810. if ($bindType == '') $rsvalue .= '$blockValue = $this->refObj->'.$bindFunc.'($atts,$this->refObj,$fields); '."\r\n";
  811. else $rsvalue .= '$blockValue = '.$bindFunc.'($atts,$this->refObj,$fields); '."\r\n";
  812. }
  813. //返回结果类型:默认为 array 是一个二维数组,string 是字符串
  814. if ($rstype == 'string') {
  815. $rsvalue .= 'echo $blockValue;'."\r\n".'?'.">";
  816. } else {
  817. $rsvalue .= 'if (is_array($blockValue) && count($blockValue) > 0){'."\r\n";
  818. $rsvalue .= 'foreach( $blockValue as $key=>$fields )'."\r\n{\r\n".'?'.">";
  819. $rsvalue .= $cTag->GetInnerText();
  820. $rsvalue .= '<'.'?php'."\r\n}\r\n}\r\n".'?'.'>';
  821. }
  822. $cTag->tagValue = $rsvalue;
  823. }
  824. return $cTag->tagValue;
  825. }
  826. /**
  827. * 编译可能为数组的变量
  828. *
  829. * @access public
  830. * @param string $vartype 变量类型
  831. * @param string $varname 变量名称
  832. * @return string
  833. */
  834. function CompilerArrayVar($vartype, $varname)
  835. {
  836. $okvalue = '';
  837. if (!preg_match("/\[/", $varname)) {
  838. if (preg_match("/^value/", $vartype)) {
  839. $varname = $vartype.'.'.$varname;
  840. }
  841. $varnames = explode('.', $varname);
  842. if (isset($varnames[1])) {
  843. $varname = $varnames[0];
  844. for ($i = 1; isset($varnames[$i]); $i++) {
  845. $varname .= "['".$varnames[$i]."']";
  846. }
  847. }
  848. }
  849. if (preg_match("/\[/", $varname)) {
  850. $varnames = explode('[', $varname);
  851. $arrend = '';
  852. for ($i = 1; isset($varnames[$i]); $i++) {
  853. $arrend .= '['.$varnames[$i];
  854. }
  855. if (!preg_match("/[\"']/", $arrend)) {
  856. $arrend = str_replace('[', '', $arrend);
  857. $arrend = str_replace(']', '', $arrend);
  858. $arrend = "['{$arrend}']";
  859. }
  860. if ($vartype == 'var') {
  861. $okvalue = '$GLOBALS[\'_vars\'][\''.$varnames[0].'\']'.$arrend;
  862. } else if (preg_match("/^value/", $vartype)) {
  863. $okvalue = '$'.$varnames[0].$arrend;
  864. } else if ($vartype == 'field') {
  865. $okvalue = '$fields[\''.$varnames[0].'\']'.$arrend;
  866. } else {
  867. $okvalue = '$GLOBALS[\''.$varnames[0].'\']'.$arrend;
  868. }
  869. } else {
  870. if ($vartype == 'var') {
  871. $okvalue = '$GLOBALS[\'_vars\'][\''.$varname.'\']';
  872. } else if (preg_match("/^value/", $vartype)) {
  873. $okvalue = '$'.$vartype;
  874. } else if ($vartype == 'field') {
  875. $okvalue = '$fields[\''.trim($varname).'\']';
  876. } else {
  877. $okvalue = '$GLOBALS[\''.$varname.'\']';
  878. }
  879. }
  880. return $okvalue;
  881. }
  882. /**
  883. * 编译if标记
  884. *
  885. * @access public
  886. * @param object $cTag 标签
  887. * @return string
  888. */
  889. function Compilerif ($cTag)
  890. {
  891. $condition = trim($cTag->GetAtt('condition'));
  892. if ($condition == '') {
  893. $cTag->tagValue = '';
  894. return '';
  895. }
  896. if (version_compare(PHP_VERSION, '5.5.0', '>=')) {
  897. $condition = preg_replace_callback("/((var\.|field\.|cfg\.|global\.|key[0-9]{0,}\.|value[0-9]{0,}\.)[\._a-z0-9]+)/is", "private_rt", $condition);
  898. } else {
  899. $condition = preg_replace("/((var\.|field\.|cfg\.|global\.|key[0-9]{0,}\.|value[0-9]{0,}\.)[\._a-z0-9]+)/ies", "private_rt('\\1')", $condition);
  900. }
  901. $rsvalue = '<'.'?php if ('.$condition.'){ ?'.'>';
  902. $rsvalue .= $cTag->GetInnerText();
  903. $rsvalue .= '<'.'?php } ?'.'>';
  904. return $rsvalue;
  905. }
  906. /**
  907. * 处理block区块传递的atts属性的值
  908. *
  909. * @access public
  910. * @param string $v 值
  911. * @return string
  912. */
  913. function TrimAtts($v)
  914. {
  915. $v = str_replace('<'.'?', '&lt;?', $v);
  916. $v = str_replace('?'.'>', '?&gt;', $v);
  917. return $v;
  918. }
  919. /**
  920. * 函数 function 语法处理
  921. *
  922. * @access public
  923. * @param string $funcstr 函数字符串
  924. * @param string $nvalue 函数值
  925. * @return string
  926. */
  927. function CompilerFunction($funcstr, $nvalue)
  928. {
  929. $funcstr = str_replace('@quote', '"', $funcstr);
  930. $funcstr = str_replace('@me', $nvalue, $funcstr);
  931. return $funcstr;
  932. }
  933. /**
  934. * 引入文件system语法处理
  935. *
  936. * @access public
  937. * @param string $filename 文件名
  938. * @param string $isload 是否载入
  939. * @return string
  940. */
  941. function CompilerInclude($filename, $isload = TRUE)
  942. {
  943. $okfile = '';
  944. if (@file_exists($filename)) {
  945. $okfile = $filename;
  946. } else if (@file_exists($this->refDir.$filename)) {
  947. $okfile = $this->refDir.$filename;
  948. } else if (@file_exists($this->refDir."/".$filename)) {
  949. $okfile = $this->refDir.'/'.$filename;
  950. }
  951. if ($okfile == '') return 0;
  952. if (!$isload) return 1;
  953. $itpl = new DedeTemplate($this->templateDir);
  954. $itpl->isCache = $this->isCache;
  955. $itpl->SetObject($this->refObj);
  956. $itpl->LoadTemplate($okfile);
  957. return $itpl->CacheFile();
  958. }
  959. }
  960. /**
  961. * class TagAttribute Tag属性集合
  962. * function C__TagAttribute();
  963. * 属性的数据描述
  964. *
  965. * @package TagAttribute
  966. * @subpackage DedeBIZ.Libraries
  967. * @link https://www.dedebiz.com
  968. */
  969. class TagAttribute
  970. {
  971. var $count = -1;
  972. var $items = array(); //属性元素的集合
  973. /**
  974. * 获得某个属性
  975. *
  976. * @access public
  977. * @param string $str 预处理字符串
  978. * @return string
  979. */
  980. function GetAtt($str)
  981. {
  982. if ($str == "") {
  983. return "";
  984. }
  985. if (isset($this->items[$str])) {
  986. return $this->items[$str];
  987. } else {
  988. return "";
  989. }
  990. }
  991. /**
  992. * 同上
  993. *
  994. * @access public
  995. * @param string $str 预处理字符串
  996. * @return string
  997. */
  998. function GetAttribute($str)
  999. {
  1000. return $this->GetAtt($str);
  1001. }
  1002. /**
  1003. * 判断属性是否存在
  1004. *
  1005. * @access public
  1006. * @param string $str 预处理字符串
  1007. * @return bool
  1008. */
  1009. function IsAttribute($str)
  1010. {
  1011. if (isset($this->items[$str])) return TRUE;
  1012. else return FALSE;
  1013. }
  1014. /**
  1015. * 获得标记名称
  1016. *
  1017. * @access public
  1018. * @return string
  1019. */
  1020. function GettagName()
  1021. {
  1022. return $this->GetAtt("tagname");
  1023. }
  1024. /**
  1025. * 获得属性个数
  1026. *
  1027. * @access public
  1028. * @return int
  1029. */
  1030. function Getcount()
  1031. {
  1032. return $this->count + 1;
  1033. }
  1034. }
  1035. /**
  1036. * 属性解析器
  1037. * function C__TagAttributeParse();
  1038. *
  1039. * @package TagAttribute
  1040. * @subpackage DedeBIZ.Libraries
  1041. * @link https://www.dedebiz.com
  1042. */
  1043. class TagAttributeParse
  1044. {
  1045. var $sourceString = '';
  1046. var $sourceMaxSize = 1024;
  1047. var $cAttributes;
  1048. var $charToLow = TRUE;
  1049. function SetSource($str = "")
  1050. {
  1051. $this->cAttributes = new TagAttribute();
  1052. $strLen = 0;
  1053. $this->sourceString = trim(preg_replace("/[ \r\n\t\f]{1,}/", " ", $str));
  1054. $strLen = strlen($this->sourceString);
  1055. if ($strLen > 0 && $strLen <= $this->sourceMaxSize) {
  1056. $this->ParseAttribute();
  1057. }
  1058. }
  1059. /**
  1060. * 解析属性
  1061. *
  1062. * @access public
  1063. * @return void
  1064. */
  1065. function ParseAttribute()
  1066. {
  1067. $d = '';
  1068. $tmpatt = '';
  1069. $tmpvalue = '';
  1070. $startdd = -1;
  1071. $ddtag = '';
  1072. $hasAttribute = FALSE;
  1073. $strLen = strlen($this->sourceString);
  1074. $this->cAttributes->items = array();
  1075. //获得Tag的名称,解析到 cAtt->GetAtt('tagname') 中
  1076. for ($i = 0; $i < $strLen; $i++) {
  1077. if ($this->sourceString[$i] == ' ') {
  1078. $this->cAttributes->count++;
  1079. $tmpvalues = explode('.', $tmpvalue);
  1080. $this->cAttributes->items['tagname'] = ($this->charToLow ? strtolower($tmpvalues[0]) : $tmpvalues[0]);
  1081. if (isset($tmpvalues[2])) {
  1082. $okname = $tmpvalues[1];
  1083. for ($j = 2; isset($tmpvalues[$j]); $j++) {
  1084. $okname .= "['".$tmpvalues[$j]."']";
  1085. }
  1086. $this->cAttributes->items['name'] = $okname;
  1087. } else if (isset($tmpvalues[1]) && $tmpvalues[1] != '') {
  1088. $this->cAttributes->items['name'] = $tmpvalues[1];
  1089. }
  1090. $tmpvalue = '';
  1091. $hasAttribute = TRUE;
  1092. break;
  1093. } else {
  1094. $tmpvalue .= $this->sourceString[$i];
  1095. }
  1096. }
  1097. //不存在属性列表的情况
  1098. if (!$hasAttribute) {
  1099. $this->cAttributes->count++;
  1100. $tmpvalues = explode('.', $tmpvalue);
  1101. $this->cAttributes->items['tagname'] = ($this->charToLow ? strtolower($tmpvalues[0]) : $tmpvalues[0]);
  1102. if (isset($tmpvalues[2])) {
  1103. $okname = $tmpvalues[1];
  1104. for ($i = 2; isset($tmpvalues[$i]); $i++) {
  1105. $okname .= "['".$tmpvalues[$i]."']";
  1106. }
  1107. $this->cAttributes->items['name'] = $okname;
  1108. } else if (isset($tmpvalues[1]) && $tmpvalues[1] != '') {
  1109. $this->cAttributes->items['name'] = $tmpvalues[1];
  1110. }
  1111. return;
  1112. }
  1113. $tmpvalue = '';
  1114. //如果字符串含有属性值,遍历源字符串,并获得各属性
  1115. for ($i; $i < $strLen; $i++) {
  1116. $d = $this->sourceString[$i];
  1117. //查找属性名称
  1118. if ($startdd == -1) {
  1119. if ($d != '=') {
  1120. $tmpatt .= $d;
  1121. } else {
  1122. if ($this->charToLow) {
  1123. $tmpatt = strtolower(trim($tmpatt));
  1124. } else {
  1125. $tmpatt = trim($tmpatt);
  1126. }
  1127. $startdd = 0;
  1128. }
  1129. }
  1130. //查找属性的限定标志
  1131. else if ($startdd == 0) {
  1132. switch ($d) {
  1133. case ' ':
  1134. break;
  1135. case '\'':
  1136. $ddtag = '\'';
  1137. $startdd = 1;
  1138. break;
  1139. case '"':
  1140. $ddtag = '"';
  1141. $startdd = 1;
  1142. break;
  1143. default:
  1144. $tmpvalue .= $d;
  1145. $ddtag = ' ';
  1146. $startdd = 1;
  1147. break;
  1148. }
  1149. } else if ($startdd == 1) {
  1150. if ($d == $ddtag && (isset($this->sourceString[$i - 1]) && $this->sourceString[$i - 1] != "\\")) {
  1151. $this->cAttributes->count++;
  1152. $this->cAttributes->items[$tmpatt] = trim($tmpvalue);
  1153. $tmpatt = '';
  1154. $tmpvalue = '';
  1155. $startdd = -1;
  1156. } else {
  1157. $tmpvalue .= $d;
  1158. }
  1159. }
  1160. }
  1161. //最后一个属性的给值
  1162. if ($tmpatt != '') {
  1163. $this->cAttributes->count++;
  1164. $this->cAttributes->items[$tmpatt] = trim($tmpvalue);
  1165. } //print_r($this->cAttributes->items);
  1166. }
  1167. }
  1168. /**
  1169. * 私有标签编译,主要用于if标签内的字符串解析
  1170. *
  1171. * @access public
  1172. * @param string $str 需要编译的字符串
  1173. * @return string
  1174. */
  1175. function private_rt($str)
  1176. {
  1177. if (is_array($str)) {
  1178. $arr = explode('.', $str[0]);
  1179. } else {
  1180. $arr = explode('.', $str);
  1181. }
  1182. $rs = '$GLOBALS[\'';
  1183. if ($arr[0] == 'cfg') {
  1184. return $rs.'cfg_'.$arr[1]."']";
  1185. } elseif ($arr[0] == 'var') {
  1186. $arr[0] = '_vars';
  1187. $rs .= implode('\'][\'', $arr);
  1188. $rs .= "']";
  1189. return $rs;
  1190. } elseif ($arr[0] == 'global') {
  1191. unset($arr[0]);
  1192. $rs .= implode('\'][\'', $arr);
  1193. $rs .= "']";
  1194. return $rs;
  1195. } else {
  1196. if ($arr[0] == 'field') $arr[0] = 'fields';
  1197. $rs = '$'.$arr[0]."['";
  1198. unset($arr[0]);
  1199. $rs .= implode('\'][\'', $arr);
  1200. $rs .= "']";
  1201. return $rs;
  1202. }
  1203. }
  1204. ?>