PageRenderTime 51ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/common/system/template.php

http://lazycms.googlecode.com/
PHP | 569 lines | 310 code | 8 blank | 251 comment | 53 complexity | 3e9dff841d2de860a1c0a51f5c25f9d2 MD5 | raw file
Possible License(s): LGPL-3.0, LGPL-2.1
  1. <?php
  2. /**
  3. * +---------------------------------------------------------------------------+
  4. * | LL LLLL LL L LLLL LLLL |
  5. * | LL LL L LLL LL LL L LL LL |
  6. * | LL LLLL LLLLL LL LL LL LLLL LLL LL LL LL LL |
  7. * | LL LL LL LL LL LL L LLL LL LLLLL LL LL LL |
  8. * | LL LLLLL LL LLLL LL L L LL LLLLL LL LL LL |
  9. * | LL LL LL LL LLLL LL L LL LL LLLL LL |
  10. * | LL LL LL LL LL LL L L LL L LL LLLL LL |
  11. * | LLLLLL LLLLL LLLLL LL LLLL L LL LLLL LL LLLLLL |
  12. * | LL |
  13. * | LL |
  14. * +---------------------------------------------------------------------------+
  15. * | Copyright (C) 2007-2010 LazyCMS.com All rights reserved. |
  16. * +---------------------------------------------------------------------------+
  17. * | LazyCMS is free software. See LICENSE for copyright notices and details. |
  18. * +---------------------------------------------------------------------------+
  19. */
  20. defined('COM_PATH') or die('Restricted access!');
  21. /**
  22. * ?????
  23. *
  24. * @author Lukin <my@lukin.cn>
  25. * @version $Id: template.php 760 2011-03-10 16:10:56Z mylukin $
  26. */
  27. class Template {
  28. var $type = 'LC_TEMPLATE';
  29. var $_vars = array();
  30. var $_args = array();
  31. var $_plugins = array();
  32. function __construct(){
  33. global $LC_tpl_plugins;
  34. if (is_array($LC_tpl_plugins))
  35. $this->_plugins = $LC_tpl_plugins;
  36. }
  37. function Template() {
  38. $args = func_get_args();
  39. call_user_func_array( array(&$this, '__construct'), $args );
  40. }
  41. /**
  42. * ??html??
  43. *
  44. * @param $html
  45. * @return mixed
  46. */
  47. function load($html) {
  48. // ?? include ??
  49. $tags = array(); $base = ABS_PATH.'/'.system_themes_path().'/';
  50. if (preg_match_all('/\{(inc|include)[^\}]*file=([^\}]*)\/\}/isU',$html,$r)) {
  51. $tags = $r[2];
  52. foreach ($tags as $i=>$tag) {
  53. $file = trim($tag,'"\' ');
  54. $html = str_replace($r[0][$i],$this->load_file($base.$file),$html);
  55. }
  56. }
  57. $html = preg_replace('/<title>/isU',"<meta name=\"generator\" content=\"LazyCMS ".LAZY_VERSION."\" />\n\${0}",$html, 1);
  58. // ??????css?js??
  59. $html = preg_replace('/(<(((script|link|img|input|embed|object|base|area|map|table|td|th|tr).+?(src|href|background))|((param).+?(src|value)))=([^\/]+?))((images|scripts)\/.{0,}?\>)/i','${1}'.ROOT.system_themes_path().'/${10}',$html);
  60. return $html;
  61. }
  62. /**
  63. * ????
  64. *
  65. * @param $file
  66. * @return mixed
  67. */
  68. function load_file($file) {
  69. return is_file($file) ? $this->load(file_get_contents($file)) : '';
  70. }
  71. /**
  72. * ????
  73. *
  74. * @param string $tag_name
  75. * @param string $tag
  76. * @param array $block ????????????
  77. * @param array $vars ?????
  78. * @return mixed
  79. */
  80. function apply_plugins($tag_name,$tag,$block=null,$vars=null) {
  81. $result = null; $tag_name = strtolower($tag_name);
  82. foreach ((array)$this->_plugins as $func) {
  83. $result = call_user_func($func,$tag_name,$tag,$block,$vars);
  84. if (null !== $result) break;
  85. }
  86. return $result;
  87. }
  88. /**
  89. * ??????
  90. *
  91. * @param string $type
  92. * @return void
  93. */
  94. function clean(){
  95. $this->_vars = array();
  96. }
  97. /**
  98. * ????
  99. *
  100. * @param string|array $key
  101. * @param mixed $val
  102. * @return bool
  103. */
  104. function set_var($key, $val=null) {
  105. // ?key???
  106. if (empty($key)) return true;
  107. // ????
  108. if (is_array($key)) {
  109. foreach ($key as $k=>$v) {
  110. if (empty($k)) continue;
  111. $this->_vars[strtolower($k)] = $this->encode($v);
  112. }
  113. }
  114. // ????
  115. else {
  116. $this->_vars[strtolower($key)] = $this->encode($val);
  117. }
  118. return true;
  119. }
  120. /**
  121. * ??????
  122. *
  123. * @return array
  124. */
  125. function get_vars() {
  126. return $this->_vars;
  127. }
  128. /**
  129. * ????
  130. *
  131. * @param string $key
  132. * @return array
  133. */
  134. function get_var($key) {
  135. if (strpos($key, '.') !== false) {
  136. $val = $this->_vars;
  137. $keys = explode('.', $key);
  138. foreach ($keys as $k) $val = $val[$k];
  139. } else {
  140. $key = strtolower($key);
  141. $val = isset($this->_vars[$key]) ? $this->_vars[$key] : null;
  142. }
  143. return $val;
  144. }
  145. /**
  146. * ????????
  147. *
  148. * @param $html
  149. * @return array
  150. */
  151. function get_blocks($html){
  152. $result = array();
  153. // ?????????
  154. if (preg_match_all('/\{[\w+\:\-]+\b[^\}]*(?<!\/)\}|\{\/[\w+\:\-]+\}/isU',$html,$r)) {
  155. $content = $html;
  156. $position = $tag_len = $id = 0;
  157. $matches = $r[0];
  158. $stacks = array();
  159. $result = array();
  160. // ????
  161. foreach($matches as $match) {
  162. // ????????
  163. if ($index = strpos($content,$match)) {
  164. // ???????????
  165. $position += $index + $tag_len;
  166. // ????
  167. $tag_len = strlen($match);
  168. // ??
  169. if (preg_match('/\{([\w+\:\-]+)\b[^\}]*\}/isU',$match,$tag)) {
  170. $stacks[] = array(
  171. 'id' => ++$id,
  172. 'name' => $tag[1],
  173. 'start' => $position,
  174. 'inner_start' => $position + $tag_len,
  175. );
  176. }
  177. // ??
  178. else {
  179. $data = array_pop($stacks);
  180. $parent = array_pop(array_slice($stacks,count($stacks)-1,1));
  181. $data['offset'] = $data['inner_start'] - $data['start'];
  182. $data['length'] = $position - $data['inner_start'];
  183. $data['end'] = $position + $tag_len;
  184. $data['pid'] = isset($parent['id']) ? $parent['id'] : 0;
  185. $data['tag'] = substr($html,$data['start'],$data['end']-$data['start']);
  186. unset($data['start'],$data['inner_start'],$data['end']);
  187. $result[$data['id']] = $data;
  188. }
  189. // ??????
  190. $content = substr($content,$index + $tag_len);
  191. }
  192. }
  193. // ???????????????????????????
  194. $un = array();
  195. foreach ($result as $id=>$item) {
  196. if ($item['pid']) {
  197. $result[$item['pid']]['sub'][$id] = &$result[$id];
  198. $un[] = $id;
  199. }
  200. }
  201. foreach($un as $v) unset($result[$v]);
  202. }
  203. return $result;
  204. }
  205. /**
  206. * ???????
  207. *
  208. * @param string $html
  209. * @param string $tag_name
  210. * @param string $type
  211. * @return array|null
  212. */
  213. function get_block($html,$tag_name,$type=null) {
  214. $result = null;
  215. // ???????
  216. $blocks = $this->get_blocks($html);
  217. // ??????
  218. foreach ($blocks as $block) {
  219. // type value
  220. $type_val = $this->get_attr($block['tag'],'type');
  221. // ????????
  222. if (instr(strtolower($block['name']),$tag_name) && ($type_val==$type || $type==null)) {
  223. $result = $block; break;
  224. }
  225. }
  226. return $result;
  227. }
  228. /**
  229. * ????????
  230. *
  231. * @param $block
  232. * @return string
  233. */
  234. function get_block_inner($block) {
  235. return substr($block['tag'], $block['offset'], $block['length']);
  236. }
  237. /**
  238. * ?????
  239. *
  240. * @param $html
  241. * @return mixed
  242. */
  243. function process_blocks($html) {
  244. // ???????
  245. $blocks = $this->get_blocks($html);
  246. // ??????
  247. foreach ($blocks as $block) {
  248. $html = str_replace($block['tag'], $this->apply_plugins($block['name'], $block['tag'], $block, $this->_vars), $html);
  249. }
  250. return $html;
  251. }
  252. /**
  253. * ?????
  254. *
  255. * @param string $html
  256. * @param array $subs
  257. * @return string
  258. */
  259. function parse_subs($html, $subs) {
  260. foreach($subs as $block) {
  261. $result = $this->apply_plugins($block['name'], $block['tag'], $block, $this->_vars);
  262. $guid = guid($block['tag']);
  263. $html = str_replace($block['tag'], '{$'.$guid.'}' , $html);
  264. $this->set_var($guid, $result);
  265. }
  266. return $html;
  267. }
  268. /**
  269. * ????
  270. *
  271. * @param string $html
  272. * @return mixed
  273. */
  274. function process_vars($html){
  275. if (preg_match_all('/\{\$([\w\.\-]++)\b[^\}]*+\}/',$html,$r)) {
  276. $tags = $r[1];
  277. foreach ($r[0] as $k => $tag) {
  278. // ??????
  279. $value = $this->apply_plugins('$'.$tags[$k], $tag, null, $this->_vars);
  280. // ????
  281. if (null === $value) {
  282. $value = $this->get_var($tags[$k]);
  283. }
  284. // ??????
  285. $value = $this->process_attr($value, $tag);
  286. $html = str_replace($tag, $value, $html);
  287. }
  288. }
  289. return $this->decode($html);
  290. }
  291. /**
  292. * ????
  293. *
  294. * @param string $html
  295. * @param array $block
  296. * @return mixed|string
  297. */
  298. function parse($html, $block=null) {
  299. if ($block && isset($block['sub']))
  300. $html = $this->parse_subs($html, $block['sub']);
  301. $html = $this->process_blocks($html);
  302. $html = $this->process_vars($html);
  303. return $html;
  304. }
  305. /**
  306. * ??????
  307. *
  308. * @param $value ????
  309. * @param $tag ???????
  310. * @return array|mixed|string
  311. */
  312. function process_attr($value,$tag) {
  313. $result = $value;
  314. // size
  315. $size = $this->get_attr($tag,'size');
  316. if ($size && validate_is($size,VALIDATE_IS_NUMERIC)) {
  317. if (intval(mb_strlen($value,'UTF-8')) > intval($size)) {
  318. $result = mb_substr($value, 0, $size, 'UTF-8') . '...';
  319. } else{
  320. $result = $value;
  321. }
  322. }
  323. // datemode
  324. $date = $this->get_attr($tag,'mode');
  325. if (strlen($date) > 0 && (is_numeric($value) || $value = strtotime($value))) {
  326. switch (strval($date)) {
  327. case '0':
  328. $result = date('Y-n-j G:i:s', $value);
  329. break;
  330. case '1':
  331. $result = date('Y-m-d H:i:s', $value);
  332. break;
  333. default:
  334. $result = date($date, $value);
  335. break;
  336. }
  337. }
  338. // code
  339. $code = $this->get_attr($tag,'code');
  340. if (is_scalar($result) && strlen($result) > 0 && $code) {
  341. $code = strtolower($code);
  342. switch ($code) {
  343. case 'javascript': case 'js':
  344. $result = sprintf('document.writeln("%s");',str_replace(array("\r", "\n"), array('', '\n'), addslashes($result)));
  345. break;
  346. case 'xmlencode': case 'xml':
  347. $result = xmlencode($result);
  348. break;
  349. case 'urlencode': case 'url':
  350. $result = rawurlencode($result);
  351. break;
  352. case 'htmlencode': case 'html':
  353. $result = esc_html($result);
  354. break;
  355. }
  356. }
  357. // thumb
  358. $width = $this->get_attr($tag,'width');
  359. $height = $this->get_attr($tag,'height');
  360. if (is_scalar($value) && is_numeric($width) && is_numeric($height)) {
  361. $result = image_thumb(ABS_PATH.$value, $width, $height, basename($value, '.' . pathinfo($value, PATHINFO_EXTENSION)) . '_' . $width . 'x' . $height);
  362. if ($result) {
  363. $result = substr($result, strlen(ABS_PATH));
  364. } else {
  365. $result = $value;
  366. }
  367. }
  368. // apply
  369. $func = $this->get_attr($tag,'func');
  370. if (strlen($func) > 0 && $func) {
  371. if (stripos($func,'@me') !== false) {
  372. $func = preg_replace("/'@me'|\"@me\"|@me/isU",'$result',$func);
  373. }
  374. $result = eval('return '.$func.';');
  375. }
  376. return $result;
  377. }
  378. /**
  379. * ???????
  380. *
  381. * @param string $tag
  382. * @param string $attr
  383. * @param string $separator
  384. * @return string
  385. */
  386. function get_attr($tag,$attr,$separator='=') {
  387. $value = mid($tag, $attr.$separator.'"','"');
  388. if ($value === null)
  389. $value = mid($tag, $attr.$separator."'","'");
  390. return $value;
  391. }
  392. /**
  393. * ????
  394. *
  395. * @param $str
  396. * @return mixed
  397. */
  398. function encode($str) {
  399. return is_array($str) ? array_map(array(&$this,'encode'), $str) : str_replace(array(chr(36),chr(123),chr(125)), array('&#36;','&#123;','&#125;'), $str);
  400. }
  401. /**
  402. * ????
  403. *
  404. * @param $str
  405. * @return mixed
  406. */
  407. function decode($str) {
  408. return str_replace(array('&#36;','&#123;','&#125;'), array(chr(36),chr(123),chr(125)), $str);
  409. }
  410. }
  411. /**
  412. * ???????
  413. *
  414. * @param string $type
  415. * @return Template
  416. */
  417. function &tpl_init($type=null) {
  418. global $LC_templates;
  419. if ($type === null) $type = 'LC_TEMPLATE';
  420. if (!isset($LC_templates[$type])) {
  421. $LC_templates[$type] = new Template();
  422. $LC_templates[$type]->type = $type;
  423. }
  424. return $LC_templates[$type];
  425. }
  426. /**
  427. * ??????
  428. *
  429. * @param object $tpl
  430. * @return Template
  431. */
  432. function &_tpl_get_object($tpl=null) {
  433. global $LC_templates;
  434. if ($tpl && is_object($tpl) && get_class($tpl)=='Template') {
  435. return $LC_templates[$tpl->type];
  436. }
  437. else
  438. return tpl_init();
  439. }
  440. /**
  441. * ??????
  442. *
  443. * @param object $tpl
  444. * @return void
  445. */
  446. function tpl_clean($tpl=null) {
  447. $tpl = _tpl_get_object($tpl);
  448. return $tpl->clean();
  449. }
  450. /**
  451. * ????
  452. *
  453. * @param string|mixed $key
  454. * @param mixed $val
  455. * @param object $tpl
  456. * @return bool
  457. */
  458. function tpl_set_var($key, $val=null, $tpl=null) {
  459. if (is_array($key)) $tpl = &$val;
  460. $tpl = _tpl_get_object($tpl);
  461. return $tpl->set_var($key, $val);
  462. }
  463. /**
  464. * ????
  465. *
  466. * @param string $key
  467. * @param object $tpl
  468. * @return array
  469. */
  470. function tpl_get_var($key, $tpl=null) {
  471. $tpl = _tpl_get_object($tpl);
  472. return $tpl->get_var($key);
  473. }
  474. /**
  475. * ??????
  476. *
  477. * @param object $tpl
  478. * @return array
  479. */
  480. function tpl_get_vars($tpl=null) {
  481. $tpl = _tpl_get_object($tpl);
  482. return $tpl->get_vars();
  483. }
  484. /**
  485. * ????
  486. *
  487. * @param string $html
  488. * @param array $block
  489. * @param object $tpl
  490. * @return mixed|string
  491. */
  492. function tpl_parse($html, $block=null, $tpl=null) {
  493. if (is_object($block) && get_class($block)=='Template') {
  494. $tpl = $block; $block = null;
  495. }
  496. $tpl = _tpl_get_object($tpl);
  497. return $tpl->parse($html, $block);
  498. }
  499. /**
  500. * ??????
  501. *
  502. * @param string $file
  503. * @return mixed
  504. */
  505. function tpl_loadfile($file) {
  506. return tpl_init()->load_file($file);
  507. }
  508. /**
  509. * ????
  510. *
  511. * @param $func
  512. * @return void
  513. */
  514. function tpl_add_plugin($funcs) {
  515. global $LC_tpl_plugins; $LC_tpl_plugins = empty($LC_tpl_plugins) ? array() : $LC_tpl_plugins;
  516. if (is_array($funcs)) {
  517. foreach ($funcs as $func) {
  518. if (!in_array($func, $LC_tpl_plugins)) {
  519. $LC_tpl_plugins[] = $func;
  520. }
  521. }
  522. return true;
  523. } else {
  524. if (!in_array($funcs, $LC_tpl_plugins)) {
  525. $LC_tpl_plugins[] = $funcs;
  526. return true;
  527. }
  528. }
  529. return false;
  530. }
  531. /**
  532. * ???????
  533. *
  534. * @param string $html
  535. * @param string $tag_name
  536. * @param string $type
  537. * @return array|null
  538. */
  539. function tpl_get_block($html,$tag_name,$type=null) {
  540. return tpl_init()->get_block($html,$tag_name,$type);
  541. }
  542. /**
  543. * ???????
  544. *
  545. * @param array $block
  546. * @return string
  547. */
  548. function tpl_get_block_inner($block) {
  549. return tpl_init()->get_block_inner($block);
  550. }
  551. /**
  552. * ????
  553. *
  554. * @param string $tag
  555. * @param string $attr
  556. * @param string $separator
  557. * @return string
  558. */
  559. function tpl_get_attr($tag, $attr, $separator='=') {
  560. return tpl_init()->get_attr($tag, $attr,$separator);
  561. }