国内流行的内容管理系统(CMS)多端全媒体解决方案 https://www.dedebiz.com
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

dedetag.class.php 34KB

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