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

dedetag.class.php 33KB

2 years ago
1 year ago
2 years ago
2 years ago
1 year ago
1 year ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
1 year ago
1 year ago
1 year ago
1 year ago
6 months ago
3 years ago
3 years ago
3 years ago
2 years ago
3 years ago
2 years ago
1 year ago
2 years ago
2 years ago
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015
  1. <?php
  2. if (!defined('DEDEINC')) exit ('dedebiz');
  3. /**
  4. * 主题模板
  5. *
  6. * @version $id:dedetag.class.php 10:33 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. class DedeTag
  13. {
  14. var $IsReplace = FALSE; //标记是否已被替代,供解析器使用
  15. var $TagName = ''; //标记名称
  16. var $InnerText = ''; //标记之间的文本
  17. var $StartPos = 0; //标记起始位置
  18. var $EndPos = 0; //标记结束位置
  19. var $CAttribute = null; //标记属性描述,即是class DedeAttribute
  20. var $TagValue = ''; //标记的值
  21. var $TagID = 0;
  22. /**
  23. * 获取标记的名称和值
  24. *
  25. * @access public
  26. * @return string
  27. */
  28. function GetName()
  29. {
  30. return strtolower($this->TagName);
  31. }
  32. /**
  33. * 获取值
  34. *
  35. * @access public
  36. * @return string
  37. */
  38. function GetValue()
  39. {
  40. return $this->TagValue;
  41. }
  42. //下面两个成员函数仅是为了兼容旧版
  43. function GetTagName()
  44. {
  45. return strtolower($this->TagName);
  46. }
  47. function GetTagValue()
  48. {
  49. return $this->TagValue;
  50. }
  51. //获取标记的指定属性
  52. function IsAttribute($str)
  53. {
  54. return $this->CAttribute->IsAttribute($str);
  55. }
  56. function GetAttribute($str)
  57. {
  58. return $this->CAttribute->GetAtt($str);
  59. }
  60. function GetAtt($str)
  61. {
  62. return $this->CAttribute->GetAtt($str);
  63. }
  64. function GetInnerText()
  65. {
  66. return $this->InnerText;
  67. }
  68. }
  69. /**
  70. * DedeTagParse模板类
  71. * function c____DedeTagParse();
  72. *
  73. * @package DedeTagParse
  74. * @subpackage DedeBIZ.Libraries
  75. * @link https://www.dedebiz.com
  76. */
  77. class DedeTagParse
  78. {
  79. var $NameSpace = 'dede'; //标记的名字空间
  80. var $TagStartWord = '{'; //标记起始
  81. var $TagEndWord = '}'; //标记结束
  82. var $TagMaxLen = 64; //标记名称的最大值
  83. var $CharToLow = TRUE; //TRUE表示对属性和标记名称不区分大小写
  84. var $IsCache = FALSE; //是否使用缓冲
  85. var $TempMkTime = 0;
  86. var $CacheFile = '';
  87. var $SourceString = ''; //模板字符串
  88. var $CTags = array(); //标记集合
  89. var $Count = -1; //$Tags标记个数
  90. var $refObj = ''; //引用当前模板类的对象
  91. var $taghashfile = '';
  92. function __construct()
  93. {
  94. if (!isset($GLOBALS['cfg_tplcache'])) {
  95. $GLOBALS['cfg_tplcache'] = 'N';
  96. }
  97. if ($GLOBALS['cfg_tplcache'] == 'Y') {
  98. $this->IsCache = TRUE;
  99. } else {
  100. $this->IsCache = FALSE;
  101. }
  102. if (DEDE_ENVIRONMENT == 'development') {
  103. $this->IsCache = FALSE;
  104. }
  105. $this->NameSpace = 'dede';
  106. $this->TagStartWord = '{';
  107. $this->TagEndWord = '}';
  108. $this->TagMaxLen = 64;
  109. $this->CharToLow = TRUE;
  110. $this->SourceString = '';
  111. $this->CTags = array();
  112. $this->Count = -1;
  113. $this->TempMkTime = 0;
  114. $this->CacheFile = '';
  115. }
  116. function DedeTagParse()
  117. {
  118. $this->__construct();
  119. }
  120. /**
  121. * 设置标记的命名空间,默认为dede
  122. *
  123. * @access public
  124. * @param string $str 字符串
  125. * @param string $s 开始标记
  126. * @param string $e 结束标记
  127. * @return void
  128. */
  129. function SetNameSpace($str, $s = "{", $e = "}")
  130. {
  131. $this->NameSpace = strtolower($str);
  132. $this->TagStartWord = $s;
  133. $this->TagEndWord = $e;
  134. }
  135. /**
  136. * 重置成员变量或Clear
  137. *
  138. * @access public
  139. * @return void
  140. */
  141. function SetDefault()
  142. {
  143. $this->SourceString = '';
  144. $this->CTags = array();
  145. $this->Count = -1;
  146. }
  147. /**
  148. * 强制引用
  149. *
  150. * @access public
  151. * @param object $refObj 隶属对象
  152. * @return void
  153. */
  154. function SetRefObj(&$refObj)
  155. {
  156. $this->refObj = $refObj;
  157. }
  158. function GetCount()
  159. {
  160. return $this->Count + 1;
  161. }
  162. function Clear()
  163. {
  164. $this->SetDefault();
  165. }
  166. /**
  167. * CheckDisabledFunctions COMMENT : CheckDisabledFunctions检查是否存在禁止的函数
  168. *
  169. * @access public
  170. * @param string
  171. * @return bool
  172. */
  173. function CheckDisabledFunctions($str, &$errmsg = '')
  174. {
  175. global $cfg_disable_funs;
  176. $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';
  177. //模板引擎添加disable_functions
  178. if (defined('DEDEDISFUN')) {
  179. $tokens = token_get_all_nl('<?php'.$str."\n\r?>");
  180. $disabled_functions = explode(',', $cfg_disable_funs);
  181. foreach ($tokens as $token) {
  182. if (is_array($token)) {
  183. if ($token[0] = '306' && in_array($token[1], $disabled_functions)) {
  184. $errmsg = 'DedeBIZ Error:function disabled "'.$token[1].'" <a href="https://www.dedebiz.com/help" target="_blank">more</a>';
  185. return FALSE;
  186. }
  187. }
  188. }
  189. }
  190. return TRUE;
  191. }
  192. /**
  193. * 检测模板缓存
  194. *
  195. * @access public
  196. * @param string $filename 文件名称
  197. * @return string
  198. */
  199. function LoadCache($filename)
  200. {
  201. global $cfg_tplcache, $cfg_tplcache_dir;
  202. if (!$this->IsCache) {
  203. return FALSE;
  204. }
  205. $cdir = dirname($filename);
  206. $cachedir = DEDEROOT.$cfg_tplcache_dir;
  207. $ckfile = str_replace($cdir, '', $filename).substr(md5($filename), 0, 16).'.inc';
  208. $ckfullfile = $cachedir.'/'.$ckfile;
  209. $ckfullfile_t = $cachedir.'/'.$ckfile.'.txt';
  210. $this->CacheFile = $ckfullfile;
  211. $this->TempMkTime = filemtime($filename);
  212. if (!file_exists($ckfullfile) || !file_exists($ckfullfile_t)) {
  213. return FALSE;
  214. }
  215. //检测模板最后更新时间
  216. $fp = fopen($ckfullfile_t, 'r');
  217. $time_info = trim(fgets($fp, 64));
  218. fclose($fp);
  219. if ($time_info != $this->TempMkTime) {
  220. return FALSE;
  221. }
  222. //引入缓冲数组
  223. include($this->CacheFile);
  224. $errmsg = '';
  225. //把缓冲数组文档读入类
  226. if (isset($z) && is_array($z)) {
  227. foreach ($z as $k => $v) {
  228. $this->Count++;
  229. $ctag = new DedeTAg();
  230. $ctag->CAttribute = new DedeAttribute();
  231. $ctag->IsReplace = FALSE;
  232. $ctag->TagName = $v[0];
  233. $ctag->InnerText = $v[1];
  234. $ctag->StartPos = $v[2];
  235. $ctag->EndPos = $v[3];
  236. $ctag->TagValue = '';
  237. $ctag->TagID = $k;
  238. if (isset($v[4]) && is_array($v[4])) {
  239. $i = 0;
  240. $ctag->CAttribute->Items = array();
  241. foreach ($v[4] as $k => $v) {
  242. $ctag->CAttribute->Count++;
  243. $ctag->CAttribute->Items[$k] = $v;
  244. }
  245. }
  246. $this->CTags[$this->Count] = $ctag;
  247. }
  248. } else {
  249. //模板没有缓冲数组
  250. $this->CTags = '';
  251. $this->Count = -1;
  252. }
  253. return TRUE;
  254. }
  255. /**
  256. * 写入缓存
  257. *
  258. * @access public
  259. * @param string
  260. * @return string
  261. */
  262. function SaveCache()
  263. {
  264. if (!empty($this->CacheFile)) {
  265. $fp = fopen($this->CacheFile.'.txt', "w");
  266. fwrite($fp, $this->TempMkTime."\n");
  267. fclose($fp);
  268. $fp = fopen($this->CacheFile, "w");
  269. flock($fp, 3);
  270. fwrite($fp, '<'.'?php'."\r\n");
  271. $errmsg = '';
  272. if (is_array($this->CTags)) {
  273. foreach ($this->CTags as $tid => $ctag) {
  274. $arrayValue = 'Array("'.$ctag->TagName.'",';
  275. if (!$this->CheckDisabledFunctions($ctag->InnerText, $errmsg)) {
  276. fclose($fp);
  277. @unlink($this->taghashfile);
  278. @unlink($this->CacheFile);
  279. @unlink($this->CacheFile.'.txt');
  280. die($errmsg);
  281. }
  282. $arrayValue .= '"'.str_replace('$', '\$', str_replace("\r", "\\r", str_replace("\n", "\\n", str_replace('"', '\"', str_replace("\\", "\\\\", $ctag->InnerText))))).'"';
  283. $arrayValue .= ",{$ctag->StartPos},{$ctag->EndPos});";
  284. fwrite($fp, "\$z[$tid]={$arrayValue}\n");
  285. if (is_array($ctag->CAttribute->Items)) {
  286. fwrite($fp, "\$z[$tid][4]=array();\n");
  287. foreach ($ctag->CAttribute->Items as $k => $v) {
  288. $v = str_replace("\\", "\\\\", $v);
  289. $v = str_replace('"', "\\".'"', $v);
  290. $v = str_replace('$', '\$', $v);
  291. $k = trim(str_replace("'", "", $k));
  292. if ($k == "") {
  293. continue;
  294. }
  295. if ($k != 'tagname') {
  296. fwrite($fp, "\$z[$tid][4]['$k']=\"$v\";\n");
  297. }
  298. }
  299. }
  300. }
  301. }
  302. fwrite($fp, "\n".'?'.'>');
  303. fclose($fp);
  304. }
  305. }
  306. /**
  307. * 载入模板文件
  308. *
  309. * @access public
  310. * @param string $filename 文件名称
  311. * @return string
  312. */
  313. function LoadTemplate($filename)
  314. {
  315. $this->SetDefault();
  316. if (!file_exists($filename)) {
  317. $this->SourceString = " $filename Not Found! ";
  318. $this->ParseTemplet();
  319. } else {
  320. $fp = @fopen($filename, "r");
  321. while ($line = fgets($fp, 1024)) {
  322. $this->SourceString .= $line;
  323. }
  324. fclose($fp);
  325. if ($this->LoadCache($filename)) {
  326. return '';
  327. } else {
  328. $this->ParseTemplet();
  329. }
  330. }
  331. }
  332. //仅用于兼容旧版本
  333. function LoadTemplet($filename)
  334. {
  335. $this->LoadTemplate($filename);
  336. }
  337. //仅用于兼容旧版本
  338. function LoadFile($filename)
  339. {
  340. $this->LoadTemplate($filename);
  341. }
  342. /**
  343. * 载入模板字符串
  344. *
  345. * @access public
  346. * @param string $str 字符串
  347. * @return void
  348. */
  349. function LoadSource($str)
  350. {
  351. //优化模板字符串存取读取方式
  352. $this->taghashfile = $filename = DEDEDATA.'/tplcache/'.md5($str).'.inc';
  353. if (!is_file($filename)) {
  354. file_put_contents($filename, $str);
  355. }
  356. $this->LoadTemplate($filename);
  357. }
  358. function LoadString($str)
  359. {
  360. $this->LoadSource($str);
  361. }
  362. /**
  363. * 获得指定名称的Tag的id,如果有多个同名的Tag,则取没有被取代为文档的第一个Tag
  364. *
  365. * @access public
  366. * @param string $str 字符串
  367. * @return int
  368. */
  369. function GetTagID($str)
  370. {
  371. if ($this->Count == -1) {
  372. return -1;
  373. }
  374. if ($this->CharToLow) {
  375. $str = strtolower($str);
  376. }
  377. foreach ($this->CTags as $id => $CTag) {
  378. if ($CTag->TagName == $str && !$CTag->IsReplace) {
  379. return $id;
  380. break;
  381. }
  382. }
  383. return -1;
  384. }
  385. /**
  386. * 获得指定名称的CTag数据类,如果有多个同名的Tag,则取没有被分配文档的第一个Tag
  387. *
  388. * @access public
  389. * @param string $str 字符串
  390. * @return mixed
  391. */
  392. function GetTag($str)
  393. {
  394. if ($this->Count == -1) {
  395. return '';
  396. }
  397. if ($this->CharToLow) {
  398. $str = strtolower($str);
  399. }
  400. foreach ($this->CTags as $id => $CTag) {
  401. if ($CTag->TagName == $str && !$CTag->IsReplace) {
  402. return $CTag;
  403. break;
  404. }
  405. }
  406. return '';
  407. }
  408. /**
  409. * 通过名称获取标记
  410. *
  411. * @access public
  412. * @param string $str 字符串
  413. * @return string
  414. */
  415. function GetTagByName($str)
  416. {
  417. return $this->GetTag($str);
  418. }
  419. /**
  420. * 获得指定id的CTag数据类
  421. *
  422. * @access public
  423. * @param string 标签id
  424. * @return string
  425. */
  426. function GetTagByID($id)
  427. {
  428. if (isset($this->CTags[$id])) {
  429. return $this->CTags[$id];
  430. } else {
  431. return '';
  432. }
  433. }
  434. /**
  435. * 给_vars数组传递一个元素
  436. *
  437. * @access public
  438. * @param string $vname 标签名
  439. * @param string $vvalue 标签值
  440. * @return string
  441. */
  442. function AssignVar($vname, $vvalue)
  443. {
  444. if (!isset($_sys_globals['define'])) {
  445. $_sys_globals['define'] = 'yes';
  446. }
  447. $_sys_globals[$vname] = $vvalue;
  448. }
  449. /**
  450. * 分配指定id的标记的值
  451. *
  452. * @access public
  453. * @param string $i 标签id
  454. * @param string $str 字符串
  455. * @param string $runfunc 运行函数
  456. * @return void
  457. */
  458. function Assign($i, $str, $runfunc = TRUE)
  459. {
  460. if (isset($this->CTags[$i])) {
  461. $this->CTags[$i]->IsReplace = TRUE;
  462. $this->CTags[$i]->TagValue = $str;
  463. if ($this->CTags[$i]->GetAtt('function') != '' && $runfunc) {
  464. $this->CTags[$i]->TagValue = $this->EvalFunc($str, $this->CTags[$i]->GetAtt('function'), $this->CTags[$i]);
  465. }
  466. }
  467. }
  468. /**
  469. * 分配指定名称的标记的值,如果标记包含属性,请不要用此函数
  470. *
  471. * @access public
  472. * @param string $tagname 标签名称
  473. * @param string $str 字符串
  474. * @return void
  475. */
  476. function AssignName($tagname, $str)
  477. {
  478. foreach ($this->CTags as $id => $CTag) {
  479. if ($CTag->TagName == $tagname) {
  480. $this->Assign($id, $str);
  481. }
  482. }
  483. }
  484. /**
  485. * 处理特殊标记
  486. *
  487. * @access public
  488. * @return void
  489. */
  490. function AssignSysTag()
  491. {
  492. global $_sys_globals;
  493. for ($i = 0; $i <= $this->Count; $i++) {
  494. $CTag = $this->CTags[$i];
  495. $str = '';
  496. //获取一个外部变量
  497. if ($CTag->TagName == 'global') {
  498. $str = $this->GetGlobals($CTag->GetAtt('name'));
  499. if ($this->CTags[$i]->GetAtt('function') != '') {
  500. //$str = $this->EvalFunc( $this->CTags[$i]->TagValue, $this->CTags[$i]->GetAtt('function'),$this->CTags[$i] );
  501. $str = $this->EvalFunc($str, $this->CTags[$i]->GetAtt('function'), $this->CTags[$i]);
  502. }
  503. $this->CTags[$i]->IsReplace = TRUE;
  504. $this->CTags[$i]->TagValue = $str;
  505. }
  506. //引入静态文件
  507. else if ($CTag->TagName == 'include') {
  508. $filename = ($CTag->GetAtt('file') == '' ? $CTag->GetAtt('filename') : $CTag->GetAtt('file'));
  509. $str = $this->IncludeFile($filename, $CTag->GetAtt('ismake'));
  510. $this->CTags[$i]->IsReplace = TRUE;
  511. $this->CTags[$i]->TagValue = $str;
  512. }
  513. //循环一个普通数组
  514. else if ($CTag->TagName == 'foreach') {
  515. $arr = $this->CTags[$i]->GetAtt('array');
  516. if (isset($GLOBALS[$arr])) {
  517. foreach ($GLOBALS[$arr] as $k => $v) {
  518. $istr = '';
  519. $istr .= preg_replace("/\[field:key([\r\n\t\f ]+)\/\]/is", $k, $this->CTags[$i]->InnerText);
  520. $str .= preg_replace("/\[field:value([\r\n\t\f ]+)\/\]/is", $v, $istr);
  521. }
  522. }
  523. $this->CTags[$i]->IsReplace = TRUE;
  524. $this->CTags[$i]->TagValue = $str;
  525. }
  526. //设置获取变量值
  527. else if ($CTag->TagName == 'var') {
  528. $vname = $this->CTags[$i]->GetAtt('name');
  529. if ($vname == '') {
  530. $str = '';
  531. } else if ($this->CTags[$i]->GetAtt('value') != '') {
  532. $_vars[$vname] = $this->CTags[$i]->GetAtt('value');
  533. } else {
  534. $str = (isset($_vars[$vname]) ? $_vars[$vname] : '');
  535. }
  536. $this->CTags[$i]->IsReplace = TRUE;
  537. $this->CTags[$i]->TagValue = $str;
  538. }
  539. //运行PHP接口
  540. if ($CTag->GetAtt('runphp') == 'yes') {
  541. $this->RunPHP($CTag, $i);
  542. }
  543. if (is_array($this->CTags[$i]->TagValue)) {
  544. $this->CTags[$i]->TagValue = 'array';
  545. }
  546. }
  547. }
  548. //运行PHP代码
  549. function RunPHP(&$refObj, $i)
  550. {
  551. $DedeMeValue = $phpcode = '';
  552. if ($refObj->GetAtt('source') == 'value') {
  553. $phpcode = $this->CTags[$i]->TagValue;
  554. } else {
  555. $DedeMeValue = $this->CTags[$i]->TagValue;
  556. $phpcode = $refObj->GetInnerText();
  557. }
  558. $phpcode = preg_replace("/'@me'|\"@me\"|@me/i", '$DedeMeValue', $phpcode);
  559. try {
  560. @eval($phpcode);
  561. $this->CTags[$i]->TagValue = $DedeMeValue;
  562. $this->CTags[$i]->IsReplace = TRUE;
  563. } catch (Exception $e) {
  564. //or die("<xmp>$phpcode</xmp>");
  565. }
  566. $this->CTags[$i]->TagValue = $DedeMeValue;
  567. $this->CTags[$i]->IsReplace = TRUE;
  568. }
  569. /**
  570. * 把分析模板输出到一个字符串中,不替换没被处理的值
  571. *
  572. * @access public
  573. * @return string
  574. */
  575. function GetResultNP()
  576. {
  577. $ResultString = '';
  578. if ($this->Count == -1) {
  579. return $this->SourceString;
  580. }
  581. $this->AssignSysTag();
  582. $nextTagEnd = 0;
  583. $strok = '';
  584. for ($i = 0; $i <= $this->Count; $i++) {
  585. if ($this->CTags[$i]->GetValue() != "") {
  586. if ($this->CTags[$i]->GetValue() == '#@Delete@#') {
  587. $this->CTags[$i]->TagValue = '';
  588. }
  589. $ResultString .= substr($this->SourceString, $nextTagEnd, $this->CTags[$i]->StartPos - $nextTagEnd);
  590. $ResultString .= $this->CTags[$i]->GetValue();
  591. $nextTagEnd = $this->CTags[$i]->EndPos;
  592. }
  593. }
  594. $slen = strlen($this->SourceString);
  595. if ($slen > $nextTagEnd) {
  596. $ResultString .= substr($this->SourceString, $nextTagEnd, $slen - $nextTagEnd);
  597. }
  598. return $ResultString;
  599. }
  600. /**
  601. * 把分析模板输出到一个字符串中并返回
  602. *
  603. * @access public
  604. * @return string
  605. */
  606. function GetResult()
  607. {
  608. $ResultString = '';
  609. if ($this->Count == -1) {
  610. return $this->SourceString;
  611. }
  612. $this->AssignSysTag();
  613. $nextTagEnd = 0;
  614. $strok = '';
  615. for ($i = 0; $i <= $this->Count; $i++) {
  616. $ResultString .= substr($this->SourceString, $nextTagEnd, $this->CTags[$i]->StartPos - $nextTagEnd);
  617. $ResultString .= $this->CTags[$i]->GetValue();
  618. $nextTagEnd = $this->CTags[$i]->EndPos;
  619. }
  620. $slen = strlen($this->SourceString);
  621. if ($slen > $nextTagEnd) {
  622. $ResultString .= substr($this->SourceString, $nextTagEnd, $slen - $nextTagEnd);
  623. }
  624. return $ResultString;
  625. }
  626. /**
  627. * 直接解析模板
  628. *
  629. * @access public
  630. * @return void
  631. */
  632. function Display()
  633. {
  634. echo $this->GetResult();
  635. }
  636. /**
  637. * 解析模板为文件
  638. *
  639. * @access public
  640. * @param string $filename 要保存到的文件
  641. * @return string
  642. */
  643. function SaveTo($filename)
  644. {
  645. $fp = @fopen($filename, "w") or die("请检查栏目生成目录是否填写正确,目录文件是否存在");
  646. fwrite($fp, $this->GetResult());
  647. fclose($fp);
  648. }
  649. /**
  650. * 解析模板
  651. *
  652. * @access public
  653. * @return string
  654. */
  655. function ParseTemplet()
  656. {
  657. $TagStartWord = $this->TagStartWord;
  658. $TagEndWord = $this->TagEndWord;
  659. $sPos = 0;
  660. $ePos = 0;
  661. $FullTagStartWord = $TagStartWord.$this->NameSpace.":";
  662. $sTagEndWord = $TagStartWord."/".$this->NameSpace.":";
  663. $eTagEndWord = "/".$TagEndWord;
  664. $tsLen = strlen($FullTagStartWord);
  665. $sourceLen = strlen($this->SourceString);
  666. if ($sourceLen <= ($tsLen + 3)) {
  667. return;
  668. }
  669. $cAtt = new DedeAttributeParse();
  670. $cAtt->charToLow = $this->CharToLow;
  671. //遍历模板字符串,请取标记及其属性信息
  672. for ($i = 0; $i < $sourceLen; $i++) {
  673. $tTagName = '';
  674. //如果不进行此判断,无法识别相连的两个标记
  675. if ($i - 1 >= 0) {
  676. $ss = $i - 1;
  677. } else {
  678. $ss = 0;
  679. }
  680. $sPos = strpos($this->SourceString, $FullTagStartWord, $ss);
  681. $isTag = $sPos;
  682. if ($i == 0) {
  683. $headerTag = substr($this->SourceString, 0, strlen($FullTagStartWord));
  684. if ($headerTag == $FullTagStartWord) {
  685. $isTag = TRUE;
  686. $sPos = 0;
  687. }
  688. }
  689. if ($isTag === FALSE) {
  690. break;
  691. }
  692. //判断是否已经到倒数第三个字符可能性几率极小,取消此逻辑
  693. for ($j = ($sPos + $tsLen); $j < ($sPos + $tsLen + $this->TagMaxLen); $j++) {
  694. if ($j > ($sourceLen - 1)) {
  695. break;
  696. } else if (preg_match("/[\/ \t\r\n]/", $this->SourceString[$j]) || $this->SourceString[$j] == $this->TagEndWord) {
  697. break;
  698. } else {
  699. $tTagName .= $this->SourceString[$j];
  700. }
  701. }
  702. if ($tTagName != '') {
  703. $i = $sPos + $tsLen;
  704. $endPos = -1;
  705. $fullTagEndWordThis = $sTagEndWord.$tTagName.$TagEndWord;
  706. $e1 = strpos($this->SourceString, $eTagEndWord, $i);
  707. $e2 = strpos($this->SourceString, $FullTagStartWord, $i);
  708. $e3 = strpos($this->SourceString, $fullTagEndWordThis, $i);
  709. $e1 = trim($e1);
  710. $e2 = trim($e2);
  711. $e3 = trim($e3);
  712. $e1 = ($e1 == '' ? '-1' : $e1);
  713. $e2 = ($e2 == '' ? '-1' : $e2);
  714. $e3 = ($e3 == '' ? '-1' : $e3);
  715. if ($e3 == -1) {
  716. $endPos = $e1;
  717. $elen = $endPos + strlen($eTagEndWord);
  718. } else if ($e1 == -1) {
  719. $endPos = $e3;
  720. $elen = $endPos + strlen($fullTagEndWordThis);
  721. } else {
  722. if ($e1 < $e3) {
  723. $endPos = $e3;
  724. $elen = $endPos + strlen($fullTagEndWordThis);
  725. } elseif ($e1 < $e2) {
  726. $endPos = $e1;
  727. $elen = $endPos + strlen($eTagEndWord);
  728. } else {
  729. $endPos = $e3;
  730. $elen = $endPos + strlen($fullTagEndWordThis);
  731. }
  732. }
  733. if ($endPos == -1) {
  734. echo "Tag Character postion $sPos, '$tTagName' Error<br>\r\n";
  735. break;
  736. }
  737. $i = $elen;
  738. $ePos = $endPos;
  739. //分析所找到的标记位置等信息
  740. $attStr = '';
  741. $innerText = '';
  742. $startInner = 0;
  743. for ($j = ($sPos + $tsLen); $j < $ePos; $j++) {
  744. if ($startInner == 0 && ($this->SourceString[$j] == $TagEndWord && $this->SourceString[$j - 1] != "\\")) {
  745. $startInner = 1;
  746. continue;
  747. }
  748. if ($startInner == 0) {
  749. $attStr .= $this->SourceString[$j];
  750. } else {
  751. $innerText .= $this->SourceString[$j];
  752. }
  753. }
  754. //echo "<xmp>$attStr</xmp>\r\n";
  755. $cAtt->SetSource($attStr);
  756. if ($cAtt->cAttributes->GetTagName() != '') {
  757. $this->Count++;
  758. $CDTag = new DedeTag();
  759. $CDTag->TagName = $cAtt->cAttributes->GetTagName();
  760. $CDTag->StartPos = $sPos;
  761. $CDTag->EndPos = $i;
  762. $CDTag->CAttribute = $cAtt->cAttributes;
  763. $CDTag->IsReplace = FALSE;
  764. $CDTag->TagID = $this->Count;
  765. $CDTag->InnerText = $innerText;
  766. $this->CTags[$this->Count] = $CDTag;
  767. }
  768. } else {
  769. $i = $sPos + $tsLen;
  770. break;
  771. }
  772. }
  773. if ($this->IsCache) {
  774. $this->SaveCache();
  775. }
  776. }
  777. /**
  778. * 处理某字段的函数
  779. *
  780. * @access public
  781. * @param string $fieldvalue 字段值
  782. * @param string $functionname 函数名称
  783. * @param object $refObj 隶属对象
  784. * @return string
  785. */
  786. function EvalFunc($fieldvalue, $functionname, &$refObj)
  787. {
  788. $DedeFieldValue = $fieldvalue;
  789. $functionname = str_replace("{\"", "[\"", $functionname);
  790. $functionname = str_replace("\"}", "\"]", $functionname);
  791. $functionname = preg_replace("/'@me'|\"@me\"|@me/i", '$DedeFieldValue', $functionname);
  792. $functionname = "\$DedeFieldValue = ".$functionname;
  793. try {
  794. @eval($functionname.";");
  795. if (empty($DedeFieldValue)) {
  796. return '';
  797. } else {
  798. return $DedeFieldValue;
  799. }
  800. } catch (Throwable $e) {
  801. //or die("<xmp>$functionname</xmp>");
  802. echo DedeAlert('模板存在无法解析的标签,请检查模板标签后更新网站,错误提示:'.$e->getMessage(),ALERT_WARNING);
  803. return '';
  804. }
  805. }
  806. /**
  807. * 获得一个外部变量
  808. *
  809. * @access public
  810. * @param string $varname 变量名称
  811. * @return string
  812. */
  813. function GetGlobals($varname)
  814. {
  815. $varname = trim($varname);
  816. //禁止在模板文件读取数据库密码
  817. if ($varname == "dbuserpwd" || $varname == "cfg_dbpwd") {
  818. return "";
  819. }
  820. //正常情况
  821. if (isset($GLOBALS[$varname])) {
  822. return $GLOBALS[$varname];
  823. } else {
  824. return "";
  825. }
  826. }
  827. /**
  828. * 引入文件
  829. *
  830. * @access public
  831. * @param string $filename 文件名
  832. * @param string $ismake 是否需要编译
  833. * @return string
  834. */
  835. function IncludeFile($filename, $ismake = 'no')
  836. {
  837. global $cfg_df_style;
  838. $restr = '';
  839. if ($filename == '') {
  840. return '';
  841. }
  842. if (file_exists(DEDEROOT."/theme/".$filename)) {
  843. $okfile = DEDEROOT."/theme/".$filename;
  844. } else if (file_exists(DEDEROOT.'/theme/'.$cfg_df_style.'/'.$filename)) {
  845. $okfile = DEDEROOT.'/theme/'.$cfg_df_style.'/'.$filename;
  846. } else {
  847. return "主题模板不存在:$filename";
  848. }
  849. //编译
  850. if ($ismake != "no") {
  851. require_once(DEDEINC."/channelunit.func.php");
  852. $dtp = new DedeTagParse();
  853. $dtp->LoadTemplet($okfile);
  854. MakeOneTag($dtp, $this->refObj);
  855. $restr = $dtp->GetResult();
  856. } else {
  857. $fp = @fopen($okfile, "r");
  858. while ($line = fgets($fp, 1024)) $restr .= $line;
  859. fclose($fp);
  860. }
  861. return $restr;
  862. }
  863. }
  864. //属性数据描述
  865. class DedeAttribute
  866. {
  867. var $Count = -1;
  868. var $Items = array(); //属性元素的集合
  869. //获得某个属性
  870. function GetAtt($str)
  871. {
  872. if ($str == "") {
  873. return "";
  874. }
  875. if (isset($this->Items[$str])) {
  876. return $this->Items[$str];
  877. } else {
  878. return "";
  879. }
  880. }
  881. //同上
  882. function GetAttribute($str)
  883. {
  884. return $this->GetAtt($str);
  885. }
  886. //判断属性是否存在
  887. function IsAttribute($str)
  888. {
  889. if (isset($this->Items[$str])) return TRUE;
  890. else return FALSE;
  891. }
  892. //获得标记名称
  893. function GetTagName()
  894. {
  895. return $this->GetAtt("tagname");
  896. }
  897. //获得属性个数
  898. function GetCount()
  899. {
  900. return $this->Count + 1;
  901. }
  902. }
  903. //属性解析器
  904. class DedeAttributeParse
  905. {
  906. var $sourceString = '';
  907. var $sourceMaxSize = 1024;
  908. var $cAttributes = null;
  909. var $charToLow = TRUE;
  910. function SetSource($str = '')
  911. {
  912. $this->cAttributes = new DedeAttribute();
  913. $strLen = 0;
  914. $this->sourceString = trim(preg_replace("/[ \r\n\t]{1,}/", " ", $str));
  915. //为了在function内能使用数组,这里允许对[ ]进行转义使用
  916. $this->sourceString = str_replace('\]', ']', $this->sourceString);
  917. $this->sourceString = str_replace('[', '[', $this->sourceString);
  918. $strLen = strlen($this->sourceString);
  919. if ($strLen > 0 && $strLen <= $this->sourceMaxSize) {
  920. $this->ParseAttribute();
  921. }
  922. }
  923. //解析属性
  924. function ParseAttribute()
  925. {
  926. $d = '';
  927. $tmpatt = '';
  928. $tmpvalue = '';
  929. $startdd = -1;
  930. $ddtag = '';
  931. $hasAttribute = FALSE;
  932. $strLen = strlen($this->sourceString);
  933. $this->cAttributes->Items = array();
  934. //获得Tag的名称,解析到cAtt->GetAtt('tagname')中
  935. for ($i = 0; $i < $strLen; $i++) {
  936. if ($this->sourceString[$i] == ' ') {
  937. $this->cAttributes->Count++;
  938. $tmpvalues = explode('.', $tmpvalue);
  939. $this->cAttributes->Items['tagname'] = ($this->charToLow ? strtolower($tmpvalues[0]) : $tmpvalues[0]);
  940. if (isset($tmpvalues[1]) && $tmpvalues[1] != '') {
  941. $this->cAttributes->Items['name'] = $tmpvalues[1];
  942. }
  943. $tmpvalue = '';
  944. $hasAttribute = TRUE;
  945. break;
  946. } else {
  947. $tmpvalue .= $this->sourceString[$i];
  948. }
  949. }
  950. //不存在属性列表的情况
  951. if (!$hasAttribute) {
  952. $this->cAttributes->Count++;
  953. $tmpvalues = explode('.', $tmpvalue);
  954. $this->cAttributes->Items['tagname'] = ($this->charToLow ? strtolower($tmpvalues[0]) : $tmpvalues[0]);
  955. if (isset($tmpvalues[1]) && $tmpvalues[1] != '') {
  956. $this->cAttributes->Items['name'] = $tmpvalues[1];
  957. }
  958. return;
  959. }
  960. $tmpvalue = '';
  961. //如果字符串含有属性值,遍历源字符串并获得各属性
  962. for ($i; $i < $strLen; $i++) {
  963. $d = $this->sourceString[$i];
  964. //查找属性名称
  965. if ($startdd == -1) {
  966. if ($d != '=') {
  967. $tmpatt .= $d;
  968. } else {
  969. if ($this->charToLow) {
  970. $tmpatt = strtolower(trim($tmpatt));
  971. } else {
  972. $tmpatt = trim($tmpatt);
  973. }
  974. $startdd = 0;
  975. }
  976. }
  977. //查找属性限定标志
  978. else if ($startdd == 0) {
  979. switch ($d) {
  980. case ' ':
  981. break;
  982. case '"':
  983. $ddtag = '"';
  984. $startdd = 1;
  985. break;
  986. case '\'':
  987. $ddtag = '\'';
  988. $startdd = 1;
  989. break;
  990. default:
  991. $tmpvalue .= $d;
  992. $ddtag = ' ';
  993. $startdd = 1;
  994. break;
  995. }
  996. } else if ($startdd == 1) {
  997. if ($d == $ddtag && (isset($this->sourceString[$i - 1]) && $this->sourceString[$i - 1] != "\\")) {
  998. $this->cAttributes->Count++;
  999. $this->cAttributes->Items[$tmpatt] = trim($tmpvalue);
  1000. $tmpatt = '';
  1001. $tmpvalue = '';
  1002. $startdd = -1;
  1003. } else {
  1004. $tmpvalue .= $d;
  1005. }
  1006. }
  1007. }
  1008. //最后一个属性给值
  1009. if ($tmpatt != '') {
  1010. $this->cAttributes->Count++;
  1011. $this->cAttributes->Items[$tmpatt] = trim($tmpvalue);
  1012. }
  1013. }
  1014. }
  1015. ?>