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

1221 lines
43KB

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