PageRenderTime 54ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/template_engines_bench/libs/smarty-light/src/class.compiler.php

https://github.com/limb-php-framework/limb-tools
PHP | 800 lines | 647 code | 51 blank | 102 comment | 127 complexity | ef663209fe749a742c3f18037e1288f0 MD5 | raw file
Possible License(s): AGPL-1.0, LGPL-2.1
  1. <?php
  2. /*
  3. * Project: Smarty-Light, a smarter template engine
  4. * File: class.compiler.php
  5. * Author: Paul Lockaby <paul@paullockaby.com>
  6. * Version: 2.2.11
  7. * Copyright: 2003,2004,2005 by Paul Lockaby
  8. * Credit: This work is a light version of Smarty: the PHP compiling
  9. * template engine, v2.5.0-CVS. Smarty was originally
  10. * programmed by Monte Ohrt and Andrei Zmievski and can be
  11. * found at http://smarty.php.net
  12. *
  13. * This library is free software; you can redistribute it and/or
  14. * modify it under the terms of the GNU Lesser General Public
  15. * License as published by the Free Software Foundation; either
  16. * version 2.1 of the License, or (at your option) any later version.
  17. *
  18. * This library is distributed in the hope that it will be useful,
  19. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  21. * Lesser General Public License for more details.
  22. *
  23. * You should have received a copy of the GNU Lesser General Public
  24. * License along with this library; if not, write to the Free Software
  25. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  26. *
  27. * You may contact the author of Smarty-Light by e-mail at:
  28. * paul@paullockaby.com
  29. *
  30. * The latest version of Smarty-Light can be obtained from:
  31. * http://www.paullockaby.com/projects/smarty-light
  32. *
  33. */
  34. class compiler extends template {
  35. // public configuration variables
  36. var $left_tag = "";
  37. var $right_tag = "";
  38. var $plugin_dir = "";
  39. var $template_dir = "";
  40. // private internal variables
  41. var $_vars = array(); // stores all internal assigned variables
  42. var $_confs = array(); // stores all internal config variables
  43. var $_plugins = array(); // stores all internal plugins
  44. var $_linenum = 0; // the current line number in the file we are processing
  45. var $_file = ""; // the current file we are processing
  46. var $_literal = array(); // stores all literal blocks
  47. var $_foreachelse_stack = array();
  48. var $_for_stack = 0;
  49. var $_switch_stack = array();
  50. var $_tag_stack = array();
  51. var $_require_stack = array(); // stores all files that are "required" inside of the template
  52. var $_php_blocks = array(); // stores all of the php blocks
  53. var $_error_level = null;
  54. var $_sl_md5 = '39fc70570b8b60cbc1b85839bf242aff';
  55. var $_db_qstr_regexp = null; // regexps are setup in the constructor
  56. var $_si_qstr_regexp = null;
  57. var $_qstr_regexp = null;
  58. var $_func_regexp = null;
  59. var $_var_bracket_regexp = null;
  60. var $_dvar_regexp = null;
  61. var $_cvar_regexp = null;
  62. var $_mod_regexp = null;
  63. var $_var_regexp = null;
  64. function compiler() {
  65. // matches double quoted strings:
  66. // "foobar"
  67. // "foo\"bar"
  68. // "foobar" . "foo\"bar"
  69. $this->_db_qstr_regexp = '"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"';
  70. // matches single quoted strings:
  71. // 'foobar'
  72. // 'foo\'bar'
  73. $this->_si_qstr_regexp = '\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'';
  74. // matches single or double quoted strings
  75. $this->_qstr_regexp = '(?:' . $this->_db_qstr_regexp . '|' . $this->_si_qstr_regexp . ')';
  76. // matches bracket portion of vars
  77. // [0]
  78. // [foo]
  79. // [$bar]
  80. // [#bar#]
  81. $this->_var_bracket_regexp = '\[[\$|\#]?\w+\#?\]';
  82. // matches $ vars (not objects):
  83. // $foo
  84. // $foo[0]
  85. // $foo[$bar]
  86. // $foo[5][blah]
  87. $this->_dvar_regexp = '\$[a-zA-Z0-9_]{1,}(?:' . $this->_var_bracket_regexp . ')*(?:' . $this->_var_bracket_regexp . ')*';
  88. // matches config vars:
  89. // #foo#
  90. // #foobar123_foo#
  91. $this->_cvar_regexp = '\#[a-zA-Z0-9_]{1,}(?:' . $this->_var_bracket_regexp . ')*(?:' . $this->_var_bracket_regexp . ')*\#';
  92. // matches valid variable syntax:
  93. // $foo
  94. // 'text'
  95. // "text"
  96. $this->_var_regexp = '(?:(?:' . $this->_dvar_regexp . '|' . $this->_cvar_regexp . ')|' . $this->_qstr_regexp . ')';
  97. // matches valid modifier syntax:
  98. // |foo
  99. // |@foo
  100. // |foo:"bar"
  101. // |foo:$bar
  102. // |foo:"bar":$foobar
  103. // |foo|bar
  104. $this->_mod_regexp = '(?:\|@?[0-9a-zA-Z_]+(?::(?>-?\w+|' . $this->_dvar_regexp . '|' . $this->_qstr_regexp .'))*)';
  105. // matches valid function name:
  106. // foo123
  107. // _foo_bar
  108. $this->_func_regexp = '[a-zA-Z0-9_]+';
  109. }
  110. function _compile_file($file_contents) {
  111. $ldq = preg_quote($this->left_tag);
  112. $rdq = preg_quote($this->right_tag);
  113. $_match = array(); // a temp variable for the current regex match
  114. $tags = array(); // all original tags
  115. $text = array(); // all original text
  116. $compiled_text = ""; // stores the compiled result
  117. $compiled_tags = array(); // all tags and stuff
  118. // remove all comments
  119. $file_contents = preg_replace("!{$ldq}\*.*?\*{$rdq}!se","",$file_contents);
  120. // replace all php start and end tags
  121. $file_contents = preg_replace('%(<\?(?!php|=|$))%i', '<?php echo \'\\1\'?>'."\n", $file_contents);
  122. // remove literal blocks
  123. preg_match_all("!{$ldq}\s*literal\s*{$rdq}(.*?){$ldq}\s*/literal\s*{$rdq}!s", $file_contents, $_match);
  124. $this->_literal = $_match[1];
  125. $file_contents = preg_replace("!{$ldq}\s*literal\s*{$rdq}(.*?){$ldq}\s*/literal\s*{$rdq}!s", stripslashes($ldq . "literal" . $rdq), $file_contents);
  126. // remove php blocks
  127. preg_match_all("!{$ldq}\s*php\s*{$rdq}(.*?){$ldq}\s*/php\s*{$rdq}!s", $file_contents, $_match);
  128. $this->_php_blocks = $_match[1];
  129. $file_contents = preg_replace("!{$ldq}\s*php\s*{$rdq}(.*?){$ldq}\s*/php\s*{$rdq}!s", stripslashes($ldq . "php" . $rdq), $file_contents);
  130. // gather all template tags
  131. preg_match_all("!{$ldq}\s*(.*?)\s*{$rdq}!s", $file_contents, $_match);
  132. $tags = $_match[1];
  133. // put all of the non-template tag text blocks into an array, using the template tags as delimiters
  134. $text = preg_split("!{$ldq}.*?{$rdq}!s", $file_contents);
  135. // compile template tags
  136. for ($i = 0, $for_max = count($tags); $i < $for_max; $i++) {
  137. $this->_linenum += substr_count($text[$i], "\n");
  138. $compiled_tags[] = $this->_compile_tag($tags[$i]);
  139. $this->_linenum += substr_count($tags[$i], "\n");
  140. }
  141. // build the compiled template by replacing and interleaving text blocks and compiled tags
  142. for ($i = 0, $for_max = count($compiled_tags); $i < $for_max; $i++)
  143. $compiled_text .= $text[$i].$compiled_tags[$i];
  144. $compiled_text .= $text[$i];
  145. foreach ($this->_require_stack as $key => $value)
  146. $compiled_text = '<?php require_once(\''. $this->_get_plugin_dir() . $key . '\'); $this->register_' . $value[0] . '("' . $value[1] . '", "' . $value[2] . '"); ?>' . $compiled_text;
  147. // remove unnecessary close/open tags
  148. $compiled_text = preg_replace('!\?>\n?<\?php!', '', $compiled_text);
  149. return $compiled_text;
  150. }
  151. function _compile_tag($tag) {
  152. $_match = array(); // stores the tags
  153. $_result = ""; // the compiled tag
  154. $_variable = ""; // the compiled variable
  155. // extract the tag command, modifier and arguments
  156. preg_match_all('/(?:(' . $this->_var_regexp . '|\/?' . $this->_func_regexp . ')(' . $this->_mod_regexp . '*)(?:\s*[,\.]\s*)?)(?:\s+(.*))?/xs', $tag, $_match);
  157. 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} == '"') {
  158. $_result = $this->_parse_variables($_match[1], $_match[2]);
  159. return "<?php echo $_result; ?>\n";
  160. }
  161. // process a function
  162. $tag_command = $_match[1][0];
  163. $tag_modifiers = !empty($_match[2][0]) ? $_match[2][0] : null;
  164. $tag_arguments = !empty($_match[3][0]) ? $_match[3][0] : null;
  165. $_result = $this->_parse_function($tag_command, $tag_modifiers, $tag_arguments);
  166. return $_result;
  167. }
  168. function _parse_function($function, $modifiers, $arguments) {
  169. switch ($function) {
  170. case 'include':
  171. $_args = $this->_parse_arguments($arguments);
  172. if (!isset($_args['file']))
  173. $this->trigger_error("missing 'file' attribute in 'include'", E_USER_ERROR, __FILE__, __LINE__);
  174. if (!isset($_args['assign']))
  175. return '<?php echo $this->_fetch_compile(' . $_args['file'] . '); ?>';
  176. else
  177. return '<?php $this->assign("' . $this->_dequote($_args['assign']) . '", $this->_fetch_compile(' . $_args['file'] . ')); ?>';
  178. break;
  179. case 'insert':
  180. $_args = $this->_parse_arguments($arguments);
  181. if (!isset($_args['name']))
  182. $this->trigger_error("missing 'name' attribute in 'insert'", E_USER_ERROR, __FILE__, __LINE__);
  183. foreach ($_args as $key => $value) {
  184. if (is_bool($value))
  185. $value = $value ? 'true' : 'false';
  186. $arg_list[] = "'$key' => $value";
  187. }
  188. return '<?php echo $this->_run_insert(array(' . implode(', ', (array)$arg_list) . ')); ?>';
  189. break;
  190. case 'ldelim':
  191. return $this->left_tag;
  192. break;
  193. case 'rdelim':
  194. return $this->right_tag;
  195. break;
  196. case 'literal':
  197. list (,$literal) = each($this->_literal);
  198. $this->_linenum += substr_count($literal, "\n");
  199. return "<?php echo '" . str_replace("'", "\'", str_replace("\\", "\\\\", $literal)) . "'; ?>\n";
  200. break;
  201. case 'php':
  202. list (,$php_block) = each($this->_php_blocks);
  203. $this->_linenum += substr_count($php_block, "\n");
  204. return '<?php ' . $php_block . ' ?>';
  205. break;
  206. case 'foreach':
  207. array_push($this->_foreachelse_stack, false);
  208. $_args = $this->_parse_arguments($arguments);
  209. if (!isset($_args['from']))
  210. $this->trigger_error("missing 'from' attribute in 'foreach'", E_USER_ERROR, __FILE__, __LINE__);
  211. if (!isset($_args['value']) && !isset($_args['item']))
  212. $this->trigger_error("missing 'value' attribute in 'foreach'", E_USER_ERROR, __FILE__, __LINE__);
  213. if (isset($_args['value'])) {
  214. $_args['value'] = $this->_dequote($_args['value']);
  215. } elseif (isset($_args['item'])) {
  216. $_args['value'] = $this->_dequote($_args['item']);
  217. }
  218. isset($_args['key']) ? $_args['key'] = "\$this->_vars['".$this->_dequote($_args['key'])."'] => " : $_args['key'] = '';
  219. $_result = '<?php if (count((array)' . $_args['from'] . ')): foreach ((array)' . $_args['from'] . ' as ' . $_args['key'] . '$this->_vars[\'' . $_args['value'] . '\']): ?>';
  220. return $_result;
  221. break;
  222. case 'foreachelse':
  223. $this->_foreachelse_stack[count($this->_foreachelse_stack)-1] = true;
  224. return "<?php endforeach; else: ?>";
  225. break;
  226. case '/foreach':
  227. if (array_pop($this->_foreachelse_stack))
  228. return "<?php endif; ?>";
  229. else
  230. return "<?php endforeach; endif; ?>";
  231. break;
  232. case 'for':
  233. $this->_for_stack++;
  234. $_args = $this->_parse_arguments($arguments);
  235. if (!isset($_args['start']))
  236. $this->trigger_error("missing 'start' attribute in 'for'", E_USER_ERROR, __FILE__, __LINE__);
  237. if (!isset($_args['stop']))
  238. $this->trigger_error("missing 'stop' attribute in 'for'", E_USER_ERROR, __FILE__, __LINE__);
  239. if (!isset($_args['step']))
  240. $_args['step'] = 1;
  241. $_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'] . ')): ?>';
  242. if (isset($_args['value']))
  243. $_result .= '<?php $this->assign(\'' . $this->_dequote($_args['value']) . '\', $for' . $this->_for_stack . '); ?>';
  244. return $_result;
  245. break;
  246. case '/for':
  247. $this->_for_stack--;
  248. return "<?php endfor; ?>";
  249. break;
  250. case 'if':
  251. return $this->_compile_if($arguments);
  252. break;
  253. case 'else':
  254. return "<?php else: ?>";
  255. break;
  256. case 'elseif':
  257. return $this->_compile_if($arguments, true);
  258. break;
  259. case '/if':
  260. return "<?php endif; ?>";
  261. break;
  262. case 'assign':
  263. $_args = $this->_parse_arguments($arguments);
  264. if (!isset($_args['name']))
  265. $this->trigger_error("missing 'name' attribute in 'assign'", E_USER_ERROR, __FILE__, __LINE__);
  266. if (!isset($_args['value']))
  267. $this->trigger_error("missing 'value' attribute in 'assign'", E_USER_ERROR, __FILE__, __LINE__);
  268. return '<?php $this->assign(\'' . $this->_dequote($_args['name']) . '\', ' . $_args['value'] . '); ?>';
  269. break;
  270. case 'switch':
  271. $_args = $this->_parse_arguments($arguments);
  272. if (!isset($_args['from']))
  273. $this->trigger_error("missing 'from' attribute in 'switch'", E_USER_ERROR, __FILE__, __LINE__);
  274. array_push($this->_switch_stack, array("matched" => false, "var" => $this->_dequote($_args['from'])));
  275. return;
  276. break;
  277. case '/switch':
  278. array_pop($this->_switch_stack);
  279. return '<?php break; endswitch; ?>';
  280. break;
  281. case 'case':
  282. if (count($this->_switch_stack) > 0) {
  283. $_result = "<?php ";
  284. $_args = $this->_parse_arguments($arguments);
  285. $_index = count($this->_switch_stack) - 1;
  286. if (!$this->_switch_stack[$_index]["matched"]) {
  287. $_result .= 'switch(' . $this->_switch_stack[$_index]["var"] . '): ';
  288. $this->_switch_stack[$_index]["matched"] = true;
  289. } else {
  290. $_result .= 'break; ';
  291. }
  292. if (!empty($_args['value']))
  293. $_result .= 'case '.$_args['value'].': ';
  294. else
  295. $_result .= 'default: ';
  296. return $_result . ' ?>';
  297. } else {
  298. $this->trigger_error("unexpected 'case', 'case' can only be in a 'switch'", E_USER_ERROR, __FILE__, __LINE__);
  299. }
  300. break;
  301. case 'config_load':
  302. $_args = $this->_parse_arguments($arguments);
  303. if (empty($_args['file']))
  304. $this->trigger_error("missing 'file' attribute in 'config_load' tag", E_USER_ERROR, __FILE__, __LINE__);
  305. isset($_args['section']) ? null : $_args['section'] = 'null';
  306. isset($_args['var']) ? null : $_args['var'] = 'null';
  307. return '<?php $this->config_load(' . $_args['file'] . ', ' . $_args['section'] . ', ' . $_args['var'] . '); ?>';
  308. break;
  309. default:
  310. $_result = "";
  311. if ($this->_compile_custom_block($function, $modifiers, $arguments, $_result)) {
  312. return $_result;
  313. } elseif ($this->_compile_custom_function($function, $modifiers, $arguments, $_result)) {
  314. return $_result;
  315. } else {
  316. $this->trigger_error($function." function does not exist", E_USER_ERROR, __FILE__, __LINE__);
  317. }
  318. break;
  319. }
  320. }
  321. function _compile_custom_function($function, $modifiers, $arguments, &$_result) {
  322. if ($function = $this->_plugin_exists($function, "function")) {
  323. $_args = $this->_parse_arguments($arguments);
  324. foreach($_args as $key => $value) {
  325. if (is_bool($value))
  326. $value = $value ? 'true' : 'false';
  327. if (is_null($value))
  328. $value = 'null';
  329. $_args[$key] = "'$key' => $value";
  330. }
  331. $_result = '<?php echo ';
  332. if (!empty($modifiers)) {
  333. $_result .= $this->_parse_modifier($function . '(array(' . implode(',', (array)$_args) . '), $this)', $modifiers) . '; ';
  334. } else {
  335. $_result .= $function . '(array(' . implode(',', (array)$_args) . '), $this);';
  336. }
  337. $_result .= '?>';
  338. return true;
  339. } else {
  340. return false;
  341. }
  342. }
  343. function _compile_custom_block($function, $modifiers, $arguments, &$_result) {
  344. if ($function{0} == '/') {
  345. $start_tag = false;
  346. $function = substr($function, 1);
  347. } else {
  348. $start_tag = true;
  349. }
  350. if ($function = $this->_plugin_exists($function, "block")) {
  351. if ($start_tag) {
  352. $_args = $this->_parse_arguments($arguments);
  353. foreach($_args as $key => $value) {
  354. if (is_bool($value))
  355. $value = $value ? 'true' : 'false';
  356. if (is_null($value))
  357. $value = 'null';
  358. $_args[$key] = "'$key' => $value";
  359. }
  360. $_result = "<?php \$this->_tag_stack[] = array('$function', array(".implode(',', (array)$_args).")); ";
  361. $_result .= $function . '(array(' . implode(',', (array)$_args) .'), null, $this); ';
  362. $_result .= 'ob_start(); ?>';
  363. } else {
  364. $_result .= '<?php $this->_block_content = ob_get_contents(); ob_end_clean(); ';
  365. $_result .= '$this->_block_content = ' . $function . '($this->_tag_stack[count($this->_tag_stack) - 1][1], $this->_block_content, $this); ';
  366. if (!empty($modifiers)) {
  367. $_result .= '$this->_block_content = ' . $this->_parse_modifier('$this->_block_content', $modifiers) . '; ';
  368. }
  369. $_result .= 'echo $this->_block_content; array_pop($this->_tag_stack); ?>';
  370. }
  371. return true;
  372. } else {
  373. return false;
  374. }
  375. }
  376. function _compile_if($arguments, $elseif = false) {
  377. $_result = "";
  378. $_match = array();
  379. $_args = array();
  380. $_is_arg_stack = array();
  381. // extract arguments from the equation
  382. preg_match_all('/(?>(' . $this->_var_regexp . '|\/?' . $this->_func_regexp . ')(?:' . $this->_mod_regexp . '*)?|\-?0[xX][0-9a-fA-F]+|\-?\d+(?:\.\d+)?|\.\d+|!==|===|==|!=|<>|<<|>>|<=|>=|\&\&|\|\||\(|\)|,|\!|\^|=|\&|\~|<|>|\%|\+|\-|\/|\*|\@|\b\w+\b|\S+)/x', $arguments, $_match);
  383. $_args = $_match[0];
  384. // make sure we have balanced parenthesis
  385. $_args_count = array_count_values($_args);
  386. if(isset($_args_count['(']) && $_args_count['('] != $_args_count[')']) {
  387. $this->trigger_error("unbalanced parenthesis in if statement", E_USER_ERROR, __FILE__, __LINE__);
  388. }
  389. for ($i = 0, $for_max = count($_args); $i < $for_max; $i++) {
  390. $_arg = &$_args[$i];
  391. switch (strtolower($_arg)) {
  392. case '!':
  393. case '%':
  394. case '!==':
  395. case '==':
  396. case '===':
  397. case '>':
  398. case '<':
  399. case '!=':
  400. case '<>':
  401. case '<<':
  402. case '>>':
  403. case '<=':
  404. case '>=':
  405. case '&&':
  406. case '||':
  407. case '^':
  408. case '&':
  409. case '~':
  410. case ')':
  411. case ',':
  412. case '+':
  413. case '-':
  414. case '*':
  415. case '/':
  416. case '@':
  417. break;
  418. case 'eq':
  419. $_arg = '==';
  420. break;
  421. case 'ne':
  422. case 'neq':
  423. $_arg = '!=';
  424. break;
  425. case 'lt':
  426. $_arg = '<';
  427. break;
  428. case 'le':
  429. case 'lte':
  430. $_arg = '<=';
  431. break;
  432. case 'gt':
  433. $_arg = '>';
  434. break;
  435. case 'ge':
  436. case 'gte':
  437. $_arg = '>=';
  438. break;
  439. case 'and':
  440. $_arg = '&&';
  441. break;
  442. case 'or':
  443. $_arg = '||';
  444. break;
  445. case 'not':
  446. $_arg = '!';
  447. break;
  448. case 'mod':
  449. $_arg = '%';
  450. break;
  451. case '(':
  452. array_push($_is_arg_stack, $i);
  453. break;
  454. default:
  455. preg_match('/(?:(' . $this->_var_regexp . '|' . $this->_func_regexp . ')(' . $this->_mod_regexp . '*)(?:\s*[,\.]\s*)?)(?:\s+(.*))?/xs', $_arg, $_match);
  456. if ($_match[0]{0} == '$' || ($_match[0]{0} == '#' && $_match[0]{strlen($_match[0]) - 1} == '#') || $_match[0]{0} == "'" || $_match[0]{0} == '"') {
  457. // process a variable
  458. $_arg = $this->_parse_variables(array($_match[1]), array($_match[2]));
  459. } elseif (is_numeric($_arg)) {
  460. // pass the number through
  461. } elseif (function_exists($_match[0]) || $_match[0] == "empty" || $_match[0] == "isset" || $_match[0] == "unset" || strtolower($_match[0]) == "true" || strtolower($_match[0]) == "false" || strtolower($_match[0]) == "null") {
  462. // pass the function through
  463. } else {
  464. $this->trigger_error("unidentified token '$_arg'", E_USER_ERROR, __FILE__, __LINE__);
  465. }
  466. break;
  467. }
  468. }
  469. if ($elseif) {
  470. return '<?php elseif ('.implode(' ', $_args).'): ?>';
  471. } else {
  472. return '<?php if ('.implode(' ', $_args).'): ?>';
  473. }
  474. return $_result;
  475. }
  476. function _dequote($string) {
  477. if (($string{0} == "'" || $string{0} == '"') && $string{strlen($string)-1} == $string{0})
  478. return substr($string, 1, -1);
  479. else
  480. return $string;
  481. }
  482. function _parse_arguments($arguments) {
  483. $_match = array();
  484. $_result = array();
  485. $_variables = array();
  486. preg_match_all('/(?:' . $this->_qstr_regexp . ' | (?>[^"\'=\s]+))+|[=]/x', $arguments, $_match);
  487. /*
  488. Parse state:
  489. 0 - expecting attribute name
  490. 1 - expecting '='
  491. 2 - expecting attribute value (not '=')
  492. */
  493. $state = 0;
  494. foreach($_match[0] as $value) {
  495. switch($state) {
  496. case 0:
  497. // valid attribute name
  498. if (is_string($value)) {
  499. $a_name = $value;
  500. $state = 1;
  501. } else {
  502. $this->trigger_error("invalid attribute name: '$token'", E_USER_ERROR, __FILE__, __LINE__);
  503. }
  504. break;
  505. case 1:
  506. if ($value == '=') {
  507. $state = 2;
  508. } else {
  509. $this->trigger_error("expecting '=' after '$last_value'", E_USER_ERROR, __FILE__, __LINE__);
  510. }
  511. break;
  512. case 2:
  513. if ($value != '=') {
  514. if ($value == 'yes' || $value == 'on' || $value == 'true') {
  515. $value = true;
  516. } elseif ($value == 'no' || $value == 'off' || $value == 'false') {
  517. $value = false;
  518. } elseif ($value == 'null') {
  519. $value = null;
  520. }
  521. if(!preg_match_all('/(?:(' . $this->_var_regexp . ')(' . $this->_mod_regexp . '*))(?:\s+(.*))?/xs', $value, $_variables)) {
  522. $_result[$a_name] = $value;
  523. } else {
  524. $_result[$a_name] = $this->_parse_variables($_variables[1], $_variables[2]);
  525. }
  526. $state = 0;
  527. } else {
  528. $this->trigger_error("'=' cannot be an attribute value", E_USER_ERROR, __FILE__, __LINE__);
  529. }
  530. break;
  531. }
  532. $last_value = $value;
  533. }
  534. if($state != 0) {
  535. if($state == 1) {
  536. $this->trigger_error("expecting '=' after attribute name '$last_value'", E_USER_ERROR, __FILE__, __LINE__);
  537. } else {
  538. $this->trigger_error("missing attribute value", E_USER_ERROR, __FILE__, __LINE__);
  539. }
  540. }
  541. return $_result;
  542. }
  543. function _parse_variables($variables, $modifiers) {
  544. $_result = "";
  545. foreach($variables as $key => $value) {
  546. $tag_variable = trim($variables[$key]);
  547. if (empty($modifiers[$key])) {
  548. $_result .= $this->_parse_variable($tag_variable).'.';
  549. } else {
  550. $_result .= $this->_parse_modifier($this->_parse_variable($tag_variable), $modifiers[$key]).'.';
  551. }
  552. }
  553. return substr($_result, 0, -1);
  554. }
  555. function _parse_variable($variable) {
  556. // replace variable with value
  557. if ($variable{0} == "\$") {
  558. // replace the variable
  559. return $this->_compile_variable($variable);
  560. } elseif ($variable{0} == '#') {
  561. // replace the config variable
  562. return $this->_compile_config($variable);
  563. } elseif ($variable{0} == '"') {
  564. // expand the quotes to pull any variables out of it
  565. // fortunately variables inside of a quote aren't fancy, no modifiers, no quotes
  566. // just get everything from the $ to the ending space and parse it
  567. // if the $ is escaped, then we won't expand it
  568. $_result = "";
  569. preg_match_all('/(?:[^\\\]' . $this->_dvar_regexp . ')/', substr($variable, 1, -1), $_expand);
  570. $_expand = array_unique($_expand[0]);
  571. foreach($_expand as $key => $value) {
  572. $_expand[$key] = trim($value);
  573. if (strpos($_expand[$key], '$') > 0) {
  574. $_expand[$key] = substr($_expand[$key], strpos($_expand[$key], '$'));
  575. }
  576. }
  577. $_result = $variable;
  578. foreach($_expand as $value) {
  579. $value = trim($value);
  580. $_result = str_replace($value, '" . ' . $this->_parse_variable($value) . ' . "', $_result);
  581. }
  582. return $_result;
  583. } elseif ($variable{0} == "'") {
  584. // return the value just as it is
  585. return $variable;
  586. } else {
  587. // return it as is; i believe that there was a reason before that i did not just return it as is,
  588. // but i forgot what that reason is ...
  589. // the reason i return the variable 'as is' right now is so that unquoted literals are allowed
  590. return $variable;
  591. }
  592. }
  593. function _compile_variable($variable) {
  594. $_result = "";
  595. // remove the $
  596. $variable = substr($variable, 1);
  597. // get [foo] and .foo and (...) pieces
  598. preg_match_all('!(?:^\w+)|(?:' . $this->_var_bracket_regexp . ')|\.\$?\w+|\S+!', $variable, $_match);
  599. $variable = $_match[0];
  600. $var_name = array_shift($variable);
  601. if ($var_name == '_TPL') {
  602. if ($variable[0]{0} == '[') {
  603. switch($variable[0]) {
  604. case '[GET]':
  605. $_result = "\$_GET";
  606. break;
  607. case '[POST]':
  608. $_result = "\$_POST";
  609. break;
  610. case '[COOKIE]':
  611. $_result = "\$_COOKIE";
  612. break;
  613. case '[ENV]':
  614. $_result = "\$_ENV";
  615. break;
  616. case '[SERVER]':
  617. $_result = "\$_SERVER";
  618. break;
  619. case '[SESSION]':
  620. $_result = "\$_SESSION";
  621. break;
  622. case '[NOW]':
  623. $_result = "time()";
  624. break;
  625. default:
  626. $this->trigger_error('$' . $var_name.implode('', $variable) . ' is an invalid $_TPL reference', E_USER_ERROR, __FILE__, __LINE__);
  627. break;
  628. }
  629. array_shift($variable);
  630. } else {
  631. $this->trigger_error('$' . $var_name.implode('', $variable) . ' is an invalid $_TPL reference', E_USER_ERROR, __FILE__, __LINE__);
  632. }
  633. } else {
  634. $_result = "\$this->_vars['$var_name']";
  635. }
  636. foreach ($variable as $var) {
  637. if ($var{0} == '[') {
  638. $var = substr($var, 1, -1);
  639. if (is_numeric($var)) {
  640. $_result .= "[$var]";
  641. } elseif ($var{0} == '$') {
  642. $_result .= "[" . $this->_compile_variable($var) . "]";
  643. } elseif ($var{0} == '#') {
  644. $_result .= "[" . $this->_compile_config($var) . "]";
  645. } else {
  646. $_result .= "['$var']";
  647. }
  648. } else {
  649. $this->trigger_error('$' . $var_name.implode('', $variable) . ' is an invalid reference', E_USER_ERROR, __FILE__, __LINE__);
  650. }
  651. }
  652. return $_result;
  653. }
  654. function _compile_config($variable) {
  655. $_result = "";
  656. // remove the beginning and ending #
  657. $variable = substr($variable, 1, -1);
  658. // get [foo] and .foo and (...) pieces
  659. preg_match_all('!(?:^\w+)|(?:' . $this->_var_bracket_regexp . ')|\.\$?\w+|\S+!', $variable, $_match);
  660. $variable = $_match[0];
  661. $var_name = array_shift($variable);
  662. $_result = "\$this->_confs['$var_name']";
  663. foreach ($variable as $var) {
  664. if ($var{0} == '[') {
  665. $var = substr($var, 1, -1);
  666. if (is_numeric($var)) {
  667. $_result .= "[$var]";
  668. } elseif ($var{0} == '$') {
  669. $_result .= "[" . $this->_compile_variable($var) . "]";
  670. } elseif ($var{0} == '#') {
  671. $_result .= "[" . $this->_compile_config($var) . "]";
  672. } else {
  673. $_result .= "['$var']";
  674. }
  675. } else {
  676. $this->trigger_error('#' . $var_name.implode('', $variable) . '# is an invalid reference', E_USER_ERROR, __FILE__, __LINE__);
  677. }
  678. }
  679. return $_result;
  680. }
  681. function _parse_modifier($variable, $modifiers) {
  682. $_match = array();
  683. $_mods = array(); // stores all modifiers
  684. $_args = array(); // modifier arguments
  685. preg_match_all('!\|(@?\w+)((?>:(?:'. $this->_qstr_regexp . '|[^|]+))*)!', '|' . $modifiers, $_match);
  686. list(, $_mods, $_args) = $_match;
  687. for ($i = 0, $for_max = count($_mods); $i < $for_max; $i++) {
  688. preg_match_all('!:(' . $this->_qstr_regexp . '|[^:]+)!', $_args[$i], $_match);
  689. $_arg = $_match[1];
  690. if ($_mods[$i]{0} == '@') {
  691. $_mods[$i] = substr($_mods[$i], 1);
  692. $_map_array = 0;
  693. } else {
  694. $_map_array = 1;
  695. }
  696. foreach($_arg as $key => $value)
  697. $_arg[$key] = $this->_parse_variable($value);
  698. if ($this->_plugin_exists($_mods[$i], "modifier")) {
  699. if (count($_arg) > 0)
  700. $_arg = ', '.implode(', ', $_arg);
  701. else
  702. $_arg = '';
  703. $variable = "\$this->_run_modifier($variable, '$_mods[$i]', $_map_array$_arg)";
  704. } else {
  705. $variable = "\$this->trigger_error(\"'" . $_mods[$i] . "' modifier does not exist\", E_USER_NOTICE, __FILE__, __LINE__);";
  706. }
  707. }
  708. return $variable;
  709. }
  710. function _plugin_exists($function, $type) {
  711. // check for object functions
  712. 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]))
  713. return '$this->_plugins[\'' . $type . '\'][\'' . $function . '\'][0]->' . $this->_plugins[$type][$function][1];
  714. // check for standard functions
  715. if (isset($this->_plugins[$type][$function]) && function_exists($this->_plugins[$type][$function]))
  716. return $this->_plugins[$type][$function];
  717. // check for a plugin in the plugin directory
  718. if (file_exists($this->_get_plugin_dir() . $type . '.' . $function . '.php')) {
  719. require_once($this->_get_plugin_dir() . $type . '.' . $function . '.php');
  720. if (function_exists('tpl_' . $type . '_' . $function)) {
  721. $this->_require_stack[$type . '.' . $function . '.php'] = array($type, $function, 'tpl_' . $type . '_' . $function);
  722. return ('tpl_' . $type . '_' . $function);
  723. }
  724. }
  725. return false;
  726. }
  727. function _get_plugin_dir() {
  728. static $plugin_dir;
  729. if (isset($plugin_dir)) return $plugin_dir;
  730. $this->plugin_dir = $this->_get_dir($this->plugin_dir);
  731. if (!preg_match("/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/", $this->plugin_dir)) {
  732. // path is relative
  733. $plugin_dir = dirname(__FILE__).DIRECTORY_SEPARATOR.$this->plugin_dir;
  734. } else {
  735. // path is absolute
  736. $plugin_dir = str_replace('\\', '\\\\', $this->plugin_dir);
  737. }
  738. return $plugin_dir;
  739. }
  740. }
  741. ?>