PageRenderTime 60ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/class.compiler.php

https://github.com/sad1990/--
PHP | 1098 lines | 913 code | 59 blank | 126 comment | 89 complexity | ff400a140c14f93ab8131de305d4b6f7 MD5 | raw file
Possible License(s): CC-BY-3.0, GPL-2.0, Apache-2.0
  1. <?php
  2. /*
  3. * Project: template_lite, a smarter template engine
  4. * File: class.compiler.php
  5. * Author: Paul Lockaby <paul@paullockaby.com>, Mark Dickenson <akapanamajack@sourceforge.net>
  6. * Copyright: 2003,2004,2005 by Paul Lockaby, 2005,2006 Mark Dickenson
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Lesser General Public
  10. * License as published by the Free Software Foundation; either
  11. * version 2.1 of the License, or (at your option) any later version.
  12. *
  13. * This library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with this library; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  21. *
  22. * The latest version of template_lite can be obtained from:
  23. * http://templatelite.sourceforge.net
  24. *
  25. */
  26. class Template_Lite_Compiler extends Template_Lite {
  27. // public configuration variables
  28. var $left_delimiter = "";
  29. var $right_delimiter = "";
  30. var $plugin_prefix = array();
  31. var $plugins_dir = array();
  32. var $compile_dir = "";
  33. var $template_dir = "";
  34. var $reserved_template_varname = "";
  35. var $default_modifiers = array();
  36. var $php_extract_vars = true; // Set this to false if you do not want the $this->_tpl variables to be extracted for use by PHP code inside the template.
  37. // private internal variables
  38. var $_vars = array(); // stores all internal assigned variables
  39. var $_confs = array(); // stores all internal config variables
  40. var $_plugins = array(); // stores all internal plugins
  41. var $_linenum = 0; // the current line number in the file we are processing
  42. var $_file = ""; // the current file we are processing
  43. var $_literal = array(); // stores all literal blocks
  44. var $_foreachelse_stack = array();
  45. var $_for_stack = 0;
  46. var $_sectionelse_stack = array(); // keeps track of whether section had 'else' part
  47. var $_switch_stack = array();
  48. var $_tag_stack = array();
  49. var $_require_stack = array(); // stores all files that are "required" inside of the template
  50. var $_php_blocks = array(); // stores all of the php blocks
  51. var $_error_level = null;
  52. var $_sl_md5 = '39fc70570b8b60cbc1b85839bf242aff';
  53. var $_db_qstr_regexp = null; // regexps are setup in the constructor
  54. var $_si_qstr_regexp = null;
  55. var $_qstr_regexp = null;
  56. var $_func_regexp = null;
  57. var $_reg_obj_regexp = null;
  58. var $_var_bracket_regexp = null;
  59. var $_num_const_regexp = null;
  60. var $_dvar_guts_regexp = null;
  61. var $_dvar_regexp = null;
  62. var $_cvar_regexp = null;
  63. var $_svar_regexp = null;
  64. var $_avar_regexp = null;
  65. var $_mod_regexp = null;
  66. var $_var_regexp = null;
  67. var $_parenth_param_regexp = null;
  68. var $_func_call_regexp = null;
  69. var $_obj_ext_regexp = null;
  70. var $_obj_start_regexp = null;
  71. var $_obj_params_regexp = null;
  72. var $_obj_call_regexp = null;
  73. var $_templatelite_vars = array();
  74. function Template_Lite_compiler()
  75. {
  76. // matches double quoted strings:
  77. // "foobar"
  78. // "foo\"bar"
  79. $this->_db_qstr_regexp = '"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"';
  80. // matches single quoted strings:
  81. // 'foobar'
  82. // 'foo\'bar'
  83. $this->_si_qstr_regexp = '\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'';
  84. // matches single or double quoted strings
  85. $this->_qstr_regexp = '(?:' . $this->_db_qstr_regexp . '|' . $this->_si_qstr_regexp . ')';
  86. // matches bracket portion of vars
  87. // [0]
  88. // [foo]
  89. // [$bar]
  90. $this->_var_bracket_regexp = '\[\$?[\w\.]+\]';
  91. // matches numerical constants
  92. // 30
  93. // -12
  94. // 13.22
  95. $this->_num_const_regexp = '(?:\-?\d+(?:\.\d+)?)';
  96. // matches $ vars (not objects):
  97. // $foo
  98. // $foo.bar
  99. // $foo.bar.foobar
  100. // $foo[0]
  101. // $foo[$bar]
  102. // $foo[5][blah]
  103. // $foo[5].bar[$foobar][4]
  104. $this->_dvar_math_regexp = '(?:[\+\*\/\%]|(?:-(?!>)))';
  105. $this->_dvar_math_var_regexp = '[\$\w\.\+\-\*\/\%\d\>\[\]]';
  106. $this->_dvar_guts_regexp = '\w+(?:' . $this->_var_bracket_regexp
  107. . ')*(?:\.\$?\w+(?:' . $this->_var_bracket_regexp . ')*)*(?:' . $this->_dvar_math_regexp . '(?:' . $this->_num_const_regexp . '|' . $this->_dvar_math_var_regexp . ')*)?';
  108. $this->_dvar_regexp = '\$' . $this->_dvar_guts_regexp;
  109. // matches config vars:
  110. // #foo#
  111. // #foobar123_foo#
  112. $this->_cvar_regexp = '\#\w+\#';
  113. // matches section vars:
  114. // %foo.bar%
  115. $this->_svar_regexp = '\%\w+\.\w+\%';
  116. // matches all valid variables (no quotes, no modifiers)
  117. $this->_avar_regexp = '(?:' . $this->_dvar_regexp . '|'
  118. . $this->_cvar_regexp . '|' . $this->_svar_regexp . ')';
  119. // matches valid variable syntax:
  120. // $foo
  121. // $foo
  122. // #foo#
  123. // #foo#
  124. // "text"
  125. // "text"
  126. $this->_var_regexp = '(?:' . $this->_avar_regexp . '|' . $this->_qstr_regexp . ')';
  127. // matches valid object call (one level of object nesting allowed in parameters):
  128. // $foo->bar
  129. // $foo->bar()
  130. // $foo->bar("text")
  131. // $foo->bar($foo, $bar, "text")
  132. // $foo->bar($foo, "foo")
  133. // $foo->bar->foo()
  134. // $foo->bar->foo->bar()
  135. // $foo->bar($foo->bar)
  136. // $foo->bar($foo->bar())
  137. // $foo->bar($foo->bar($blah,$foo,44,"foo",$foo[0].bar))
  138. $this->_obj_ext_regexp = '\->(?:\$?' . $this->_dvar_guts_regexp . ')';
  139. $this->_obj_restricted_param_regexp = '(?:'
  140. . '(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . ')(?:' . $this->_obj_ext_regexp . '(?:\((?:(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . ')'
  141. . '(?:\s*,\s*(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . '))*)?\))?)*)';
  142. $this->_obj_single_param_regexp = '(?:\w+|' . $this->_obj_restricted_param_regexp . '(?:\s*,\s*(?:(?:\w+|'
  143. . $this->_var_regexp . $this->_obj_restricted_param_regexp . ')))*)';
  144. $this->_obj_params_regexp = '\((?:' . $this->_obj_single_param_regexp
  145. . '(?:\s*,\s*' . $this->_obj_single_param_regexp . ')*)?\)';
  146. $this->_obj_start_regexp = '(?:' . $this->_dvar_regexp . '(?:' . $this->_obj_ext_regexp . ')+)';
  147. $this->_obj_call_regexp = '(?:' . $this->_obj_start_regexp . '(?:' . $this->_obj_params_regexp . ')?(?:' . $this->_dvar_math_regexp . '(?:' . $this->_num_const_regexp . '|' . $this->_dvar_math_var_regexp . ')*)?)';
  148. // matches valid modifier syntax:
  149. // |foo
  150. // |@foo
  151. // |foo:"bar"
  152. // |foo:$bar
  153. // |foo:"bar":$foobar
  154. // |foo|bar
  155. // |foo:$foo->bar
  156. $this->_mod_regexp = '(?:\|@?\w+(?::(?:\w+|' . $this->_num_const_regexp . '|'
  157. . $this->_obj_call_regexp . '|' . $this->_avar_regexp . '|' . $this->_qstr_regexp .'))*)';
  158. // matches valid function name:
  159. // foo123
  160. // _foo_bar
  161. $this->_func_regexp = '[a-zA-Z_]\w*';
  162. // matches valid registered object:
  163. // foo->bar
  164. $this->_reg_obj_regexp = '[a-zA-Z_]\w*->[a-zA-Z_]\w*';
  165. // matches valid parameter values:
  166. // true
  167. // $foo
  168. // $foo|bar
  169. // #foo#
  170. // #foo#|bar
  171. // "text"
  172. // "text"|bar
  173. // $foo->bar
  174. $this->_param_regexp = '(?:\s*(?:' . $this->_obj_call_regexp . '|'
  175. . $this->_var_regexp . '|' . $this->_num_const_regexp . '|\w+)(?>' . $this->_mod_regexp . '*)\s*)';
  176. // matches valid parenthesised function parameters:
  177. //
  178. // "text"
  179. // $foo, $bar, "text"
  180. // $foo|bar, "foo"|bar, $foo->bar($foo)|bar
  181. $this->_parenth_param_regexp = '(?:\((?:\w+|'
  182. . $this->_param_regexp . '(?:\s*,\s*(?:(?:\w+|'
  183. . $this->_param_regexp . ')))*)?\))';
  184. // matches valid function call:
  185. // foo()
  186. // foo_bar($foo)
  187. // _foo_bar($foo,"bar")
  188. // foo123($foo,$foo->bar(),"foo")
  189. $this->_func_call_regexp = '(?:' . $this->_func_regexp . '\s*(?:'
  190. . $this->_parenth_param_regexp . '))';
  191. }
  192. function _compile_file($file_contents)
  193. {
  194. $ldq = preg_quote($this->left_delimiter);
  195. $rdq = preg_quote($this->right_delimiter);
  196. $_match = array(); // a temp variable for the current regex match
  197. $tags = array(); // all original tags
  198. $text = array(); // all original text
  199. $compiled_text = '<?php /* '.$this->_version.' '.strftime("%Y-%m-%d %H:%M:%S %Z").' */ ?>'."\n\n"; // stores the compiled result
  200. $compiled_tags = array(); // all tags and stuff
  201. $this->_require_stack = array();
  202. $this->_load_filters();
  203. if (count($this->_plugins['prefilter']) > 0)
  204. {
  205. foreach ($this->_plugins['prefilter'] as $function)
  206. {
  207. if ($function === false)
  208. {
  209. continue;
  210. }
  211. if(is_array($function)) {
  212. $file_contents = $function[0]->$function[1]($file_contents, $this);
  213. }else{
  214. $file_contents = $function($file_contents, $this);
  215. }
  216. }
  217. }
  218. // remove all comments
  219. $file_contents = preg_replace("!{$ldq}\*.*?\*{$rdq}!se","",$file_contents);
  220. // replace all php start and end tags
  221. $file_contents = preg_replace('%(<\?(?!php|=|$))%i', '<?php echo \'\\1\'?>'."\n", $file_contents);
  222. // remove literal blocks
  223. preg_match_all("!{$ldq}\s*literal\s*{$rdq}(.*?){$ldq}\s*/literal\s*{$rdq}!s", $file_contents, $_match);
  224. $this->_literal = $_match[1];
  225. $file_contents = preg_replace("!{$ldq}\s*literal\s*{$rdq}(.*?){$ldq}\s*/literal\s*{$rdq}!s", stripslashes($ldq . "literal" . $rdq), $file_contents);
  226. // remove php blocks
  227. preg_match_all("!{$ldq}\s*php\s*{$rdq}(.*?){$ldq}\s*/php\s*{$rdq}!s", $file_contents, $_match);
  228. $this->_php_blocks = $_match[1];
  229. $file_contents = preg_replace("!{$ldq}\s*php\s*{$rdq}(.*?){$ldq}\s*/php\s*{$rdq}!s", stripslashes($ldq . "php" . $rdq), $file_contents);
  230. // gather all template tags
  231. preg_match_all("!{$ldq}\s*(.*?)\s*{$rdq}!s", $file_contents, $_match);
  232. $tags = $_match[1];
  233. // put all of the non-template tag text blocks into an array, using the template tags as delimiters
  234. $text = preg_split("!{$ldq}.*?{$rdq}!s", $file_contents);
  235. // compile template tags
  236. $count_tags = count($tags);
  237. for ($i = 0, $for_max = $count_tags; $i < $for_max; $i++)
  238. {
  239. $this->_linenum += substr_count($text[$i], "\n");
  240. $compiled_tags[] = $this->_compile_tag($tags[$i]);
  241. $this->_linenum += substr_count($tags[$i], "\n");
  242. }
  243. // build the compiled template by replacing and interleaving text blocks and compiled tags
  244. $count_compiled_tags = count($compiled_tags);
  245. for ($i = 0, $for_max = $count_compiled_tags; $i < $for_max; $i++)
  246. {
  247. if ($compiled_tags[$i] == '') {
  248. $text[$i+1] = preg_replace('~^(\r\n|\r|\n)~', '', $text[$i+1]);
  249. }
  250. $compiled_text .= $text[$i].$compiled_tags[$i];
  251. }
  252. $compiled_text .= $text[$i];
  253. foreach ($this->_require_stack as $key => $value)
  254. {
  255. $compiled_text = '<?php require_once(\''. $this->_get_plugin_dir($key) . $key . '\'); $this->register_' . $value[0] . '("' . $value[1] . '", "' . $value[2] . '"); ?>' . $compiled_text;
  256. }
  257. // remove unnecessary close/open tags
  258. $compiled_text = preg_replace('!\?>\n?<\?php!', '', $compiled_text);
  259. if (count($this->_plugins['postfilter']) > 0)
  260. {
  261. foreach ($this->_plugins['postfilter'] as $function)
  262. {
  263. if ($function === false)
  264. {
  265. continue;
  266. }
  267. if(is_array($function)) {
  268. $compiled_text = $function[0]->$function[1]($compiled_text, $this);
  269. }else{
  270. $compiled_text = $function($compiled_text, $this);
  271. }
  272. }
  273. }
  274. return $compiled_text;
  275. }
  276. function _compile_tag($tag)
  277. {
  278. $_match = array(); // stores the tags
  279. $_result = ""; // the compiled tag
  280. $_variable = ""; // the compiled variable
  281. // extract the tag command, modifier and arguments
  282. preg_match_all('/(?:(' . $this->_var_regexp . '|' . $this->_svar_regexp . '|\/?' . $this->_func_regexp . ')(' . $this->_mod_regexp . '*)(?:\s*[,\.]\s*)?)(?:\s+(.*))?/xs', $tag, $_match);
  283. if ($_match[1][0]{0} == '$' || ($_match[1][0]{0} == '#' && $_match[1][0]{strlen($_match[1][0]) - 1} == '#') || $_match[1][0]{0} == "'" || $_match[1][0]{0} == '"' || $_match[1][0]{0} == '%')
  284. {
  285. $_result = $this->_parse_variables($_match[1], $_match[2]);
  286. return "<?php echo $_result; ?>\n";
  287. }
  288. // process a function
  289. $tag_command = $_match[1][0];
  290. $tag_modifiers = !empty($_match[2][0]) ? $_match[2][0] : null;
  291. $tag_arguments = !empty($_match[3][0]) ? $_match[3][0] : null;
  292. $_result = $this->_parse_function($tag_command, $tag_modifiers, $tag_arguments);
  293. return $_result;
  294. }
  295. function _parse_function($function, $modifiers, $arguments)
  296. {
  297. switch ($function) {
  298. case 'include':
  299. if (!function_exists('compile_include'))
  300. {
  301. require_once(TEMPLATE_LITE_DIR . "internal/compile.include.php");
  302. }
  303. return compile_include($arguments, $this);
  304. break;
  305. case 'insert':
  306. $_args = $this->_parse_arguments($arguments);
  307. if (!isset($_args['name']))
  308. {
  309. $this->trigger_error("missing 'name' attribute in 'insert'", E_USER_ERROR, __FILE__, __LINE__);
  310. }
  311. foreach ($_args as $key => $value)
  312. {
  313. if (is_bool($value))
  314. {
  315. $value = $value ? 'true' : 'false';
  316. }
  317. $arg_list[] = "'$key' => $value";
  318. }
  319. return '<?php echo $this->_run_insert(array(' . implode(', ', (array)$arg_list) . ')); ?>';
  320. break;
  321. case 'ldelim':
  322. return $this->left_delimiter;
  323. break;
  324. case 'rdelim':
  325. return $this->right_delimiter;
  326. break;
  327. case 'literal':
  328. list (,$literal) = each($this->_literal);
  329. $this->_linenum += substr_count($literal, "\n");
  330. return "<?php echo '" . str_replace("'", "\'", str_replace("\\", "\\\\", $literal)) . "'; ?>\n";
  331. break;
  332. case 'php':
  333. list (,$php_block) = each($this->_php_blocks);
  334. $this->_linenum += substr_count($php_block, "\n");
  335. $php_extract = '';
  336. if($this->php_extract_vars)
  337. {
  338. if (strnatcmp(PHP_VERSION, '4.3.0') >= 0)
  339. {
  340. $php_extract = '<?php extract($this->_vars, EXTR_REFS); ?>' . "\n";
  341. }
  342. else
  343. {
  344. $php_extract = '<?php extract($this->_vars); ?>' . "\n";
  345. }
  346. }
  347. return $php_extract . '<?php '.$php_block.' ?>';
  348. break;
  349. case 'foreach':
  350. array_push($this->_foreachelse_stack, false);
  351. $_args = $this->_parse_arguments($arguments);
  352. if (!isset($_args['from']))
  353. {
  354. $this->trigger_error("missing 'from' attribute in 'foreach'", E_USER_ERROR, __FILE__, __LINE__);
  355. }
  356. if (!isset($_args['value']) && !isset($_args['item']))
  357. {
  358. $this->trigger_error("missing 'value' attribute in 'foreach'", E_USER_ERROR, __FILE__, __LINE__);
  359. }
  360. if (isset($_args['value']))
  361. {
  362. $_args['value'] = $this->_dequote($_args['value']);
  363. }
  364. elseif (isset($_args['item']))
  365. {
  366. $_args['value'] = $this->_dequote($_args['item']);
  367. }
  368. if (isset($_args['name']))
  369. {
  370. $_args['name'] = $this->_dequote($_args['name']);
  371. }
  372. isset($_args['key']) ? $_args['key'] = "\$this->_vars['".$this->_dequote($_args['key'])."'] => " : $_args['key'] = '';
  373. $foreach_props = '$this->_templatelite_vars[\'foreach\'][' . $_args['name'] . ']';
  374. $_result = '<?php if (count((array)' . $_args['from'] . ')): ?>';
  375. if (isset($_args['name']))
  376. {
  377. $_result .= '<?php ' . $foreach_props . '[\'iteration\'] = 0; ?>';
  378. }
  379. $_result .= '<?php foreach ((array)' . $_args['from'] . ' as ' . $_args['key'] . '$this->_vars[\'' . $_args['value'] . '\']): ?>';
  380. if (isset($_args['name']))
  381. {
  382. $_result .= '<?php ' . $foreach_props . '[\'iteration\']++; ?>';
  383. }
  384. return $_result;
  385. break;
  386. case 'foreachelse':
  387. $this->_foreachelse_stack[count($this->_foreachelse_stack)-1] = true;
  388. return "<?php endforeach; else: ?>";
  389. break;
  390. case '/foreach':
  391. if (array_pop($this->_foreachelse_stack))
  392. {
  393. return "<?php endif; ?>";
  394. }
  395. else
  396. {
  397. return "<?php endforeach; endif; ?>";
  398. }
  399. break;
  400. case 'for':
  401. $this->_for_stack++;
  402. $_args = $this->_parse_arguments($arguments);
  403. if (!isset($_args['start']))
  404. {
  405. $this->trigger_error("missing 'start' attribute in 'for'", E_USER_ERROR, __FILE__, __LINE__);
  406. }
  407. if (!isset($_args['stop']))
  408. {
  409. $this->trigger_error("missing 'stop' attribute in 'for'", E_USER_ERROR, __FILE__, __LINE__);
  410. }
  411. if (!isset($_args['step']))
  412. {
  413. $_args['step'] = 1;
  414. }
  415. $_result = '<?php for($for' . $this->_for_stack . ' = ' . $_args['start'] . '; ((' . $_args['start'] . ' < ' . $_args['stop'] . ') ? ($for' . $this->_for_stack . ' < ' . $_args['stop'] . ') : ($for' . $this->_for_stack . ' > ' . $_args['stop'] . ')); $for' . $this->_for_stack . ' += ((' . $_args['start'] . ' < ' . $_args['stop'] . ') ? ' . $_args['step'] . ' : -' . $_args['step'] . ')): ?>';
  416. if (isset($_args['value']))
  417. {
  418. $_result .= '<?php $this->assign(\'' . $this->_dequote($_args['value']) . '\', $for' . $this->_for_stack . '); ?>';
  419. }
  420. return $_result;
  421. break;
  422. case '/for':
  423. $this->_for_stack--;
  424. return "<?php endfor; ?>";
  425. break;
  426. case 'section':
  427. array_push($this->_sectionelse_stack, false);
  428. if (!function_exists('compile_section_start'))
  429. {
  430. require_once(TEMPLATE_LITE_DIR . "internal/compile.section_start.php");
  431. }
  432. return compile_section_start($arguments, $this);
  433. break;
  434. case 'sectionelse':
  435. $this->_sectionelse_stack[count($this->_sectionelse_stack)-1] = true;
  436. return "<?php endfor; else: ?>";
  437. break;
  438. case '/section':
  439. if (array_pop($this->_sectionelse_stack))
  440. {
  441. return "<?php endif; ?>";
  442. }
  443. else
  444. {
  445. return "<?php endfor; endif; ?>";
  446. }
  447. break;
  448. case 'while':
  449. $_args = $this->_compile_if($arguments, false, true);
  450. return '<?php while(' . $_args . '): ?>';
  451. break;
  452. case '/while':
  453. return "<?php endwhile; ?>";
  454. break;
  455. case 'if':
  456. return $this->_compile_if($arguments);
  457. break;
  458. case 'else':
  459. return "<?php else: ?>";
  460. break;
  461. case 'elseif':
  462. return $this->_compile_if($arguments, true);
  463. break;
  464. case '/if':
  465. return "<?php endif; ?>";
  466. break;
  467. case 'assign':
  468. $_args = $this->_parse_arguments($arguments);
  469. if (!isset($_args['var']))
  470. {
  471. $this->trigger_error("missing 'var' attribute in 'assign'", E_USER_ERROR, __FILE__, __LINE__);
  472. }
  473. if (!isset($_args['value']))
  474. {
  475. $this->trigger_error("missing 'value' attribute in 'assign'", E_USER_ERROR, __FILE__, __LINE__);
  476. }
  477. if (is_bool($_args['value']))
  478. $_args['value'] = $_args['value'] ? 'true' : 'false';
  479. return '<?php $this->assign(\'' . $this->_dequote($_args['var']) . '\', ' . $_args['value'] . '); ?>';
  480. break;
  481. case 'switch':
  482. $_args = $this->_parse_arguments($arguments);
  483. if (!isset($_args['from']))
  484. {
  485. $this->trigger_error("missing 'from' attribute in 'switch'", E_USER_ERROR, __FILE__, __LINE__);
  486. }
  487. array_push($this->_switch_stack, array("matched" => false, "var" => $this->_dequote($_args['from'])));
  488. return;
  489. break;
  490. case '/switch':
  491. array_pop($this->_switch_stack);
  492. return '<?php break; endswitch; ?>';
  493. break;
  494. case 'case':
  495. if (count($this->_switch_stack) > 0)
  496. {
  497. $_result = "<?php ";
  498. $_args = $this->_parse_arguments($arguments);
  499. $_index = count($this->_switch_stack) - 1;
  500. if (!$this->_switch_stack[$_index]["matched"])
  501. {
  502. $_result .= 'switch(' . $this->_switch_stack[$_index]["var"] . '): ';
  503. $this->_switch_stack[$_index]["matched"] = true;
  504. }
  505. else
  506. {
  507. $_result .= 'break; ';
  508. }
  509. if (!empty($_args['value']))
  510. {
  511. $_result .= 'case '.$_args['value'].': ';
  512. }
  513. else
  514. {
  515. $_result .= 'default: ';
  516. }
  517. return $_result . ' ?>';
  518. }
  519. else
  520. {
  521. $this->trigger_error("unexpected 'case', 'case' can only be in a 'switch'", E_USER_ERROR, __FILE__, __LINE__);
  522. }
  523. break;
  524. case 'config_load':
  525. $_args = $this->_parse_arguments($arguments);
  526. if (empty($_args['file']))
  527. {
  528. $this->trigger_error("missing 'file' attribute in 'config_load' tag", E_USER_ERROR, __FILE__, __LINE__);
  529. }
  530. isset($_args['section']) ? null : $_args['section'] = 'null';
  531. isset($_args['var']) ? null : $_args['var'] = 'null';
  532. return '<?php $this->config_load(' . $_args['file'] . ', ' . $_args['section'] . ', ' . $_args['var'] . '); ?>';
  533. break;
  534. default:
  535. $_result = "";
  536. if ($this->_compile_compiler_function($function, $arguments, $_result))
  537. {
  538. return $_result;
  539. }
  540. else if ($this->_compile_custom_block($function, $modifiers, $arguments, $_result))
  541. {
  542. return $_result;
  543. }
  544. elseif ($this->_compile_custom_function($function, $modifiers, $arguments, $_result))
  545. {
  546. return $_result;
  547. }
  548. else
  549. {
  550. $this->trigger_error($function." function does not exist", E_USER_ERROR, __FILE__, __LINE__);
  551. }
  552. break;
  553. }
  554. }
  555. function _compile_compiler_function($function, $arguments, &$_result)
  556. {
  557. if ($function = $this->_plugin_exists($function, "compiler"))
  558. {
  559. $_args = $this->_parse_arguments($arguments);
  560. $_result = '<?php ' . $function($_args, $this) . ' ?>';
  561. return true;
  562. }
  563. else
  564. {
  565. return false;
  566. }
  567. }
  568. function _compile_custom_function($function, $modifiers, $arguments, &$_result)
  569. {
  570. if (!function_exists('compile_compile_custom_function'))
  571. {
  572. require_once(TEMPLATE_LITE_DIR . "internal/compile.compile_custom_function.php");
  573. }
  574. return compile_compile_custom_function($function, $modifiers, $arguments, $_result, $this);
  575. }
  576. function _compile_custom_block($function, $modifiers, $arguments, &$_result)
  577. {
  578. if (!function_exists('compile_compile_custom_block'))
  579. {
  580. require_once(TEMPLATE_LITE_DIR . "internal/compile.compile_custom_block.php");
  581. }
  582. return compile_compile_custom_block($function, $modifiers, $arguments, $_result, $this);
  583. }
  584. function _compile_if($arguments, $elseif = false, $while = false)
  585. {
  586. if (!function_exists('compile_compile_if'))
  587. {
  588. require_once(TEMPLATE_LITE_DIR . "internal/compile.compile_if.php");
  589. }
  590. return compile_compile_if($arguments, $elseif, $while, $this);
  591. }
  592. function _parse_is_expr($is_arg, $_arg)
  593. {
  594. if (!function_exists('compile_parse_is_expr'))
  595. {
  596. require_once(TEMPLATE_LITE_DIR . "internal/compile.parse_is_expr.php");
  597. }
  598. return compile_parse_is_expr($is_arg, $_arg, $this);
  599. }
  600. function _compile_config($variable)
  601. {
  602. if (!function_exists('compile_compile_config'))
  603. {
  604. require_once(TEMPLATE_LITE_DIR . "internal/compile.compile_config.php");
  605. }
  606. return compile_compile_config($variable, $this);
  607. }
  608. function _dequote($string)
  609. {
  610. if (($string{0} == "'" || $string{0} == '"') && $string{strlen($string)-1} == $string{0})
  611. {
  612. return substr($string, 1, -1);
  613. }
  614. else
  615. {
  616. return $string;
  617. }
  618. }
  619. function _parse_arguments($arguments)
  620. {
  621. $_match = array();
  622. $_result = array();
  623. $_variables = array();
  624. preg_match_all('/(?:' . $this->_qstr_regexp . ' | (?>[^"\'=\s]+))+|[=]/x', $arguments, $_match);
  625. /*
  626. Parse state:
  627. 0 - expecting attribute name
  628. 1 - expecting '='
  629. 2 - expecting attribute value (not '=')
  630. */
  631. $state = 0;
  632. foreach($_match[0] as $value)
  633. {
  634. switch($state) {
  635. case 0:
  636. // valid attribute name
  637. if (is_string($value))
  638. {
  639. $a_name = $value;
  640. $state = 1;
  641. }
  642. else
  643. {
  644. $this->trigger_error("invalid attribute name: '$token'", E_USER_ERROR, __FILE__, __LINE__);
  645. }
  646. break;
  647. case 1:
  648. if ($value == '=')
  649. {
  650. $state = 2;
  651. }
  652. else
  653. {
  654. $this->trigger_error("expecting '=' after '$last_value'", E_USER_ERROR, __FILE__, __LINE__);
  655. }
  656. break;
  657. case 2:
  658. if ($value != '=')
  659. {
  660. if ($value == 'yes' || $value == 'on' || $value == 'true')
  661. {
  662. $value = true;
  663. }
  664. elseif ($value == 'no' || $value == 'off' || $value == 'false')
  665. {
  666. $value = false;
  667. }
  668. elseif ($value == 'null')
  669. {
  670. $value = null;
  671. }
  672. if(!preg_match_all('/(?:(' . $this->_var_regexp . '|' . $this->_svar_regexp . ')(' . $this->_mod_regexp . '*))(?:\s+(.*))?/xs', $value, $_variables))
  673. {
  674. $_result[$a_name] = $value;
  675. }
  676. else
  677. {
  678. $_result[$a_name] = $this->_parse_variables($_variables[1], $_variables[2]);
  679. }
  680. $state = 0;
  681. }
  682. else
  683. {
  684. $this->trigger_error("'=' cannot be an attribute value", E_USER_ERROR, __FILE__, __LINE__);
  685. }
  686. break;
  687. }
  688. $last_value = $value;
  689. }
  690. if($state != 0)
  691. {
  692. if($state == 1)
  693. {
  694. $this->trigger_error("expecting '=' after attribute name '$last_value'", E_USER_ERROR, __FILE__, __LINE__);
  695. }
  696. else
  697. {
  698. $this->trigger_error("missing attribute value", E_USER_ERROR, __FILE__, __LINE__);
  699. }
  700. }
  701. return $_result;
  702. }
  703. function _parse_variables($variables, $modifiers)
  704. {
  705. $_result = "";
  706. foreach($variables as $key => $value)
  707. {
  708. $tag_variable = trim($variables[$key]);
  709. if(!empty($this->default_modifiers) && !preg_match('!(^|\|)templatelite:nodefaults($|\|)!',$modifiers[$key]))
  710. {
  711. $_default_mod_string = implode('|',(array)$this->default_modifiers);
  712. $modifiers[$key] = empty($modifiers[$key]) ? $_default_mod_string : $_default_mod_string . '|' . $modifiers[$key];
  713. }
  714. if (empty($modifiers[$key]))
  715. {
  716. $_result .= $this->_parse_variable($tag_variable).'.';
  717. }
  718. else
  719. {
  720. $_result .= $this->_parse_modifier($this->_parse_variable($tag_variable), $modifiers[$key]).'.';
  721. }
  722. }
  723. return substr($_result, 0, -1);
  724. }
  725. function _parse_variable($variable)
  726. {
  727. // replace variable with value
  728. if ($variable{0} == '$')
  729. {
  730. // replace the variable
  731. return $this->_compile_variable($variable);
  732. }
  733. elseif ($variable{0} == '#')
  734. {
  735. // replace the config variable
  736. return $this->_compile_config($variable);
  737. }
  738. elseif ($variable{0} == '"')
  739. {
  740. // expand the quotes to pull any variables out of it
  741. // fortunately variables inside of a quote aren't fancy, no modifiers, no quotes
  742. // just get everything from the $ to the ending space and parse it
  743. // if the $ is escaped, then we won't expand it
  744. $_result = "";
  745. preg_match_all('/(?:' . $this->_dvar_regexp . ')/', substr($variable, 1, -1), $_expand); // old match
  746. // preg_match_all('/(?:[^\\\]' . $this->_dvar_regexp . '[^\\\])/', $variable, $_expand);
  747. $_expand = array_unique($_expand[0]);
  748. foreach($_expand as $key => $value)
  749. {
  750. $_expand[$key] = trim($value);
  751. if (strpos($_expand[$key], '$') > 0)
  752. {
  753. $_expand[$key] = substr($_expand[$key], strpos($_expand[$key], '$'));
  754. }
  755. }
  756. $_result = $variable;
  757. foreach($_expand as $value)
  758. {
  759. $value = trim($value);
  760. $_result = str_replace($value, '" . ' . $this->_parse_variable($value) . ' . "', $_result);
  761. }
  762. $_result = str_replace("`", "", $_result);
  763. return $_result;
  764. }
  765. elseif ($variable{0} == "'")
  766. {
  767. // return the value just as it is
  768. return $variable;
  769. }
  770. elseif ($variable{0} == "%")
  771. {
  772. return $this->_parse_section_prop($variable);
  773. }
  774. else
  775. {
  776. // return it as is; i believe that there was a reason before that i did not just return it as is,
  777. // but i forgot what that reason is ...
  778. // the reason i return the variable 'as is' right now is so that unquoted literals are allowed
  779. return $variable;
  780. }
  781. }
  782. function _parse_section_prop($section_prop_expr)
  783. {
  784. $parts = explode('|', $section_prop_expr, 2);
  785. $var_ref = $parts[0];
  786. $modifiers = isset($parts[1]) ? $parts[1] : '';
  787. preg_match('!%(\w+)\.(\w+)%!', $var_ref, $match);
  788. $section_name = $match[1];
  789. $prop_name = $match[2];
  790. $output = "\$this->_sections['$section_name']['$prop_name']";
  791. $this->_parse_modifier($output, $modifiers);
  792. return $output;
  793. }
  794. function _compile_variable($variable)
  795. {
  796. $_result = "";
  797. // remove the $
  798. $variable = substr($variable, 1);
  799. // get [foo] and .foo and (...) pieces
  800. preg_match_all('!(?:^\w+)|(?:' . $this->_var_bracket_regexp . ')|\.\$?\w+|\S+!', $variable, $_match);
  801. $variable = $_match[0];
  802. $var_name = array_shift($variable);
  803. if ($var_name == $this->reserved_template_varname)
  804. {
  805. if ($variable[0]{0} == '[' || $variable[0]{0} == '.')
  806. {
  807. $find = array("[", "]", ".");
  808. switch(strtoupper(str_replace($find, "", $variable[0])))
  809. {
  810. case 'GET':
  811. $_result = "\$_GET";
  812. break;
  813. case 'POST':
  814. $_result = "\$_POST";
  815. break;
  816. case 'COOKIE':
  817. $_result = "\$_COOKIE";
  818. break;
  819. case 'ENV':
  820. $_result = "\$_ENV";
  821. break;
  822. case 'SERVER':
  823. $_result = "\$_SERVER";
  824. break;
  825. case 'SESSION':
  826. $_result = "\$_SESSION";
  827. break;
  828. case 'NOW':
  829. $_result = "time()";
  830. break;
  831. case 'SECTION':
  832. $_result = "\$this->_sections";
  833. break;
  834. case 'LDELIM':
  835. $_result = "\$this->left_delimiter";
  836. break;
  837. case 'RDELIM':
  838. $_result = "\$this->right_delimiter";
  839. break;
  840. case 'VERSION':
  841. $_result = "\$this->_version";
  842. break;
  843. case 'CONFIG':
  844. $_result = "\$this->_confs";
  845. break;
  846. case 'TEMPLATE':
  847. $_result = "\$this->_file";
  848. break;
  849. case 'CONST':
  850. $constant = str_replace($find, "", $_match[0][2]);
  851. $_result = "constant('$constant')";
  852. $variable = array();
  853. break;
  854. default:
  855. $_var_name = str_replace($find, "", $variable[0]);
  856. $_result = "\$this->_templatelite_vars['$_var_name']";
  857. break;
  858. }
  859. array_shift($variable);
  860. }
  861. else
  862. {
  863. $this->trigger_error('$' . $var_name.implode('', $variable) . ' is an invalid $templatelite reference', E_USER_ERROR, __FILE__, __LINE__);
  864. }
  865. }
  866. else
  867. {
  868. $_result = "\$this->_vars['$var_name']";
  869. }
  870. foreach ($variable as $var)
  871. {
  872. if ($var{0} == '[')
  873. {
  874. $var = substr($var, 1, -1);
  875. if (is_numeric($var))
  876. {
  877. $_result .= "[$var]";
  878. }
  879. elseif ($var{0} == '$')
  880. {
  881. $_result .= "[" . $this->_compile_variable($var) . "]";
  882. }
  883. elseif ($var{0} == '#')
  884. {
  885. $_result .= "[" . $this->_compile_config($var) . "]";
  886. }
  887. else
  888. {
  889. // $_result .= "['$var']";
  890. $parts = explode('.', $var);
  891. $section = $parts[0];
  892. $section_prop = isset($parts[1]) ? $parts[1] : 'index';
  893. $_result .= "[\$this->_sections['$section']['$section_prop']]";
  894. }
  895. }
  896. else if ($var{0} == '.')
  897. {
  898. if ($var{1} == '$')
  899. {
  900. $_result .= "[\$this->_vars['" . substr($var, 2) . "']]";
  901. }
  902. else
  903. {
  904. $_result .= "['" . substr($var, 1) . "']";
  905. }
  906. }
  907. else if (substr($var,0,2) == '->')
  908. {
  909. if(substr($var,2,2) == '__')
  910. {
  911. $this->trigger_error('call to internal object members is not allowed', E_USER_ERROR, __FILE__, __LINE__);
  912. }
  913. else if (substr($var, 2, 1) == '$')
  914. {
  915. $_output .= '->{(($var=$this->_vars[\''.substr($var,3).'\']) && substr($var,0,2)!=\'__\') ? $_var : $this->trigger_error("cannot access property \\"$var\\"")}';
  916. }
  917. }
  918. else
  919. {
  920. //$this->trigger_error('$' . $var_name.implode('', $variable) . ' is an invalid reference', E_USER_ERROR, __FILE__, __LINE__);
  921. $_result .= ' . \'' . implode('', $variable) . '\'';
  922. }
  923. }
  924. return $_result;
  925. }
  926. function _parse_modifier($variable, $modifiers)
  927. {
  928. $_match = array();
  929. $_mods = array(); // stores all modifiers
  930. $_args = array(); // modifier arguments
  931. preg_match_all('!\|(@?\w+)((?>:(?:'. $this->_qstr_regexp . '|[^|]+))*)!', '|' . $modifiers, $_match);
  932. list(, $_mods, $_args) = $_match;
  933. $count_mods = count($_mods);
  934. for ($i = 0, $for_max = $count_mods; $i < $for_max; $i++)
  935. {
  936. preg_match_all('!:(' . $this->_qstr_regexp . '|[^:]+)!', $_args[$i], $_match);
  937. $_arg = $_match[1];
  938. if ($_mods[$i]{0} == '@')
  939. {
  940. $_mods[$i] = substr($_mods[$i], 1);
  941. $_map_array = 0;
  942. } else {
  943. $_map_array = 1;
  944. }
  945. foreach($_arg as $key => $value)
  946. {
  947. $_arg[$key] = $this->_parse_variable($value);
  948. }
  949. if ($this->_plugin_exists($_mods[$i], "modifier") || function_exists($_mods[$i]))
  950. {
  951. if (count($_arg) > 0)
  952. {
  953. $_arg = ', '.implode(', ', $_arg);
  954. }
  955. else
  956. {
  957. $_arg = '';
  958. }
  959. $php_function = "PHP";
  960. if ($this->_plugin_exists($_mods[$i], "modifier"))
  961. {
  962. $php_function = "plugin";
  963. }
  964. $variable = "\$this->_run_modifier($variable, '$_mods[$i]', '$php_function', $_map_array$_arg)";
  965. }
  966. else
  967. {
  968. $variable = "\$this->trigger_error(\"'" . $_mods[$i] . "' modifier does not exist\", E_USER_NOTICE, __FILE__, __LINE__);";
  969. }
  970. }
  971. return $variable;
  972. }
  973. function _plugin_exists($function, $type)
  974. {
  975. // check for object functions
  976. if (isset($this->_plugins[$type][$function]) && is_array($this->_plugins[$type][$function]) && is_object($this->_plugins[$type][$function][0]) && method_exists($this->_plugins[$type][$function][0], $this->_plugins[$type][$function][1]))
  977. {
  978. return '$this->_plugins[\'' . $type . '\'][\'' . $function . '\'][0]->' . $this->_plugins[$type][$function][1];
  979. }
  980. // check for a plugin in the plugin directory
  981. $plugin_filepath = $this->_get_plugin_filepath($type, $function);
  982. if (file_exists($plugin_filepath))
  983. {
  984. require_once($plugin_filepath);
  985. foreach($this->plugin_prefix AS $pfx) {
  986. if (function_exists($pfx . '_' . $type . '_' . $function))
  987. {
  988. $this->_require_stack[$type . '.' . $function . '.php'] = array($type, $function, $pfx . '_' . $type . '_' . $function);
  989. return ($pfx . '_' . $type . '_' . $function);
  990. }
  991. }
  992. }
  993. // check for standard functions
  994. if (isset($this->_plugins[$type][$function]) && function_exists($this->_plugins[$type][$function]))
  995. {
  996. return $this->_plugins[$type][$function];
  997. }
  998. return false;
  999. }
  1000. function _load_filters()
  1001. {
  1002. if (count($this->_plugins['prefilter']) > 0)
  1003. {
  1004. foreach ($this->_plugins['prefilter'] as $filter_name => $prefilter)
  1005. {
  1006. if (!function_exists($prefilter))
  1007. {
  1008. @include_once($this->_get_plugin_filepath('prefilter', $filter_name));
  1009. }
  1010. }
  1011. }
  1012. if (count($this->_plugins['postfilter']) > 0)
  1013. {
  1014. foreach ($this->_plugins['postfilter'] as $filter_name => $postfilter)
  1015. {
  1016. if (!function_exists($postfilter))
  1017. {
  1018. @include_once($this->_get_plugin_filepath('postfilter', $filter_name));
  1019. }
  1020. }
  1021. }
  1022. }
  1023. }
  1024. ?>