Guest User

class.compiler.php

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