PageRenderTime 52ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

/interface/main/calendar/modules/PostCalendar/pnincludes/Smarty/Smarty_Compiler.class.php

http://openemr.codeplex.com
PHP | 1414 lines | 987 code | 223 blank | 204 comment | 193 complexity | ea9062b7cbb8fc37b8dcbee1f7b5476d MD5 | raw file
Possible License(s): LGPL-2.1, AGPL-1.0, LGPL-3.0, BSD-3-Clause, GPL-2.0, MPL-2.0, GPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /*
  3. * Project: Smarty: the PHP compiling template engine
  4. * File: Smarty_Compiler.class.php
  5. * Author: Monte Ohrt <monte@ispi.net>
  6. * Andrei Zmievski <andrei@php.net>
  7. *
  8. * Version: 2.3.1
  9. * Copyright: 2001,2002 ispi of Lincoln, Inc.
  10. *
  11. * This library is free software; you can redistribute it and/or
  12. * modify it under the terms of the GNU Lesser General Public
  13. * License as published by the Free Software Foundation; either
  14. * version 2.1 of the License, or (at your option) any later version.
  15. *
  16. * This library is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  19. * Lesser General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU Lesser General Public
  22. * License along with this library; if not, write to the Free Software
  23. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  24. *
  25. * You may contact the authors of Smarty by e-mail at:
  26. * monte@ispi.net
  27. * andrei@php.net
  28. *
  29. * Or, write to:
  30. * Monte Ohrt
  31. * Director of Technology, ispi
  32. * 237 S. 70th suite 220
  33. * Lincoln, NE 68510
  34. *
  35. * The latest version of Smarty can be obtained from:
  36. * http://www.phpinsider.com/
  37. *
  38. */
  39. class Smarty_Compiler extends Smarty {
  40. // internal vars
  41. var $_sectionelse_stack = array(); // keeps track of whether section had 'else' part
  42. var $_foreachelse_stack = array(); // keeps track of whether foreach had 'else' part
  43. var $_literal_blocks = array(); // keeps literal template blocks
  44. var $_php_blocks = array(); // keeps php code blocks
  45. var $_current_file = null; // the current template being compiled
  46. var $_current_line_no = 1; // line number for error messages
  47. var $_capture_stack = array(); // keeps track of nested capture buffers
  48. var $_plugin_info = array(); // keeps track of plugins to load
  49. var $_init_smarty_vars = false;
  50. /*======================================================================*\
  51. Function: _compile_file()
  52. Input: compile a template file
  53. \*======================================================================*/
  54. function _compile_file($tpl_file, $template_source, &$template_compiled)
  55. {
  56. if ($this->security) {
  57. // do not allow php syntax to be executed unless specified
  58. if ($this->php_handling == SMARTY_PHP_ALLOW &&
  59. !$this->security_settings['PHP_HANDLING']) {
  60. $this->php_handling = SMARTY_PHP_PASSTHRU;
  61. }
  62. }
  63. $this->_load_filters();
  64. $this->_current_file = $tpl_file;
  65. $this->_current_line_no = 1;
  66. $ldq = preg_quote($this->left_delimiter, '!');
  67. $rdq = preg_quote($this->right_delimiter, '!');
  68. // run template source through prefilter functions
  69. if (count($this->_plugins['prefilter']) > 0) {
  70. foreach ($this->_plugins['prefilter'] as $filter_name => $prefilter) {
  71. if ($prefilter === false) continue;
  72. if ($prefilter[3] || function_exists($prefilter[0])) {
  73. $template_source = $prefilter[0]($template_source, $this);
  74. $this->_plugins['prefilter'][$filter_name][3] = true;
  75. } else {
  76. $this->_trigger_plugin_error("Smarty plugin error: prefilter '$filter_name' is not implemented");
  77. }
  78. }
  79. }
  80. /* Annihilate the comments. */
  81. $template_source = preg_replace("!({$ldq})\*(.*?)\*({$rdq})!se",
  82. "'\\1*'.str_repeat(\"\n\", substr_count('\\2', \"\n\")) .'*\\3'",
  83. $template_source);
  84. /* Pull out the literal blocks. */
  85. preg_match_all("!{$ldq}literal{$rdq}(.*?){$ldq}/literal{$rdq}!s", $template_source, $match);
  86. $this->_literal_blocks = $match[1];
  87. $template_source = preg_replace("!{$ldq}literal{$rdq}(.*?){$ldq}/literal{$rdq}!s",
  88. $this->quote_replace($this->left_delimiter.'literal'.$this->right_delimiter), $template_source);
  89. /* Pull out the php code blocks. */
  90. preg_match_all("!{$ldq}php{$rdq}(.*?){$ldq}/php{$rdq}!s", $template_source, $match);
  91. $this->_php_blocks = $match[1];
  92. $template_source = preg_replace("!{$ldq}php{$rdq}(.*?){$ldq}/php{$rdq}!s",
  93. $this->quote_replace($this->left_delimiter.'php'.$this->right_delimiter), $template_source);
  94. /* Gather all template tags. */
  95. preg_match_all("!{$ldq}\s*(.*?)\s*{$rdq}!s", $template_source, $match);
  96. $template_tags = $match[1];
  97. /* Split content by template tags to obtain non-template content. */
  98. $text_blocks = preg_split("!{$ldq}.*?{$rdq}!s", $template_source);
  99. /* loop through text blocks */
  100. for ($curr_tb = 0, $for_max = count($text_blocks); $curr_tb < $for_max; $curr_tb++) {
  101. /* match anything within <?php ?> */
  102. if (preg_match_all('!(<\?[^?]*?\?>|<script\s+language\s*=\s*[\"\']?php[\"\']?\s*>)!is', $text_blocks[$curr_tb], $sp_match)) {
  103. /* found at least one match, loop through each one */
  104. for ($curr_sp = 0, $for_max2 = count($sp_match[0]); $curr_sp < $for_max2; $curr_sp++) {
  105. if (preg_match('!^(<\?(php\s|\s|=\s)|<script\s*language\s*=\s*[\"\']?php[\"\']?\s*>)!is', $sp_match[0][$curr_sp])) {
  106. /* php tag */
  107. if ($this->php_handling == SMARTY_PHP_PASSTHRU) {
  108. /* echo php contents */
  109. $text_blocks[$curr_tb] = str_replace($sp_match[0][$curr_sp], '<?php echo \''.str_replace("'", "\'", $sp_match[0][$curr_sp]).'\'; ?>'."\n", $text_blocks[$curr_tb]);
  110. } else if ($this->php_handling == SMARTY_PHP_QUOTE) {
  111. /* quote php tags */
  112. $text_blocks[$curr_tb] = str_replace($sp_match[0][$curr_sp], htmlspecialchars($sp_match[0][$curr_sp]), $text_blocks[$curr_tb]);
  113. } else if ($this->php_handling == SMARTY_PHP_REMOVE) {
  114. /* remove php tags */
  115. if (substr($sp_match[0][$curr_sp], 0, 2) == '<?')
  116. $text_blocks[$curr_tb] = str_replace($sp_match[0][$curr_sp], '', $text_blocks[$curr_tb]);
  117. else
  118. /* attempt to remove everything between <script ...> and </script> */
  119. $text_blocks[$curr_tb] = preg_replace('!'.preg_quote($sp_match[0][$curr_sp], '!').'.*?</script\s*>!is', '', $text_blocks[$curr_tb]);
  120. }
  121. } else
  122. /* echo the non-php tags */
  123. $text_blocks[$curr_tb] = str_replace($sp_match[0][$curr_sp], '<?php echo \''.str_replace("'", "\'", $sp_match[0][$curr_sp]).'\'; ?>'."\n", $text_blocks[$curr_tb]);
  124. }
  125. }
  126. }
  127. /* Compile the template tags into PHP code. */
  128. $compiled_tags = array();
  129. for ($i = 0, $for_max = count($template_tags); $i < $for_max; $i++) {
  130. $this->_current_line_no += substr_count($text_blocks[$i], "\n");
  131. $compiled_tags[] = $this->_compile_tag($template_tags[$i]);
  132. $this->_current_line_no += substr_count($template_tags[$i], "\n");
  133. }
  134. $template_compiled = '';
  135. /* Interleave the compiled contents and text blocks to get the final result. */
  136. for ($i = 0, $for_max = count($compiled_tags); $i < $for_max; $i++) {
  137. $template_compiled .= $text_blocks[$i].$compiled_tags[$i];
  138. }
  139. $template_compiled .= $text_blocks[$i];
  140. /* Reformat data between 'strip' and '/strip' tags, removing spaces, tabs and newlines. */
  141. if (preg_match_all("!{$ldq}strip{$rdq}.*?{$ldq}/strip{$rdq}!s", $template_compiled, $match)) {
  142. $strip_tags = $match[0];
  143. $strip_tags_modified = preg_replace("!{$ldq}/?strip{$rdq}|[\t ]+$|^[\t ]+!m", '', $strip_tags);
  144. $strip_tags_modified = preg_replace('![\r\n]+!m', '', $strip_tags_modified);
  145. for ($i = 0, $for_max = count($strip_tags); $i < $for_max; $i++)
  146. $template_compiled = preg_replace("!{$ldq}strip{$rdq}.*?{$ldq}/strip{$rdq}!s",
  147. $this->quote_replace($strip_tags_modified[$i]),
  148. $template_compiled, 1);
  149. }
  150. // remove \n from the end of the file, if any
  151. if ($template_compiled{strlen($template_compiled) - 1} == "\n" ) {
  152. $template_compiled = substr($template_compiled, 0, -1);
  153. }
  154. // run compiled template through postfilter functions
  155. if (count($this->_plugins['postfilter']) > 0) {
  156. foreach ($this->_plugins['postfilter'] as $filter_name => $postfilter) {
  157. if ($postfilter === false) continue;
  158. if ($postfilter[3] || function_exists($postfilter[0])) {
  159. $template_compiled = $postfilter[0]($template_compiled, $this);
  160. $this->_plugins['postfilter'][$filter_name][3] = true;
  161. } else {
  162. $this->_trigger_plugin_error("Smarty plugin error: postfilter '$filter_name' is not implemented");
  163. }
  164. }
  165. }
  166. // put header at the top of the compiled template
  167. $template_header = "<?php /* Smarty version ".$this->_version.", created on ".strftime("%Y-%m-%d %H:%M:%S")."\n";
  168. $template_header .= " compiled from ".$tpl_file." */ ?>\n";
  169. /* Emit code to load needed plugins. */
  170. if (count($this->_plugin_info)) {
  171. $plugins_code = '<?php $this->_load_plugins(array(';
  172. foreach ($this->_plugin_info as $plugin_type => $plugins) {
  173. foreach ($plugins as $plugin_name => $plugin_info) {
  174. $plugins_code .= "\narray('$plugin_type', '$plugin_name', '$plugin_info[0]', $plugin_info[1], ";
  175. $plugins_code .= $plugin_info[2] ? 'true),' : 'false),';
  176. }
  177. }
  178. $plugins_code .= ")); ?>";
  179. $template_header .= $plugins_code;
  180. $this->_plugin_info = array();
  181. }
  182. if ($this->_init_smarty_vars) {
  183. $template_header .= "<?php \$this->_assign_smarty_interface(); ?>\n";
  184. $this->_init_smarty_vars = false;
  185. }
  186. $template_compiled = $template_header . $template_compiled;
  187. return true;
  188. }
  189. /*======================================================================*\
  190. Function: _compile_tag
  191. Purpose: Compile a template tag
  192. \*======================================================================*/
  193. function _compile_tag($template_tag)
  194. {
  195. /* Matched comment. */
  196. if ($template_tag{0} == '*' && $template_tag{strlen($template_tag) - 1} == '*')
  197. return '';
  198. $qstr_regexp = '"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"|\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'';
  199. /* Split tag into two parts: command and the arguments. */
  200. preg_match('/^(
  201. (?: ' . $qstr_regexp . ' | (?>[^"\'\s]+))+
  202. )
  203. (?:\s+(.*))?
  204. /xs', $template_tag, $match);
  205. $tag_command = $match[1];
  206. $tag_args = isset($match[2]) ? $match[2] : '';
  207. /* If the tag name matches a variable or section property definition,
  208. we simply process it. */
  209. if (preg_match('!^\$\w+(?>(\[(\d+|\$\w+|\w+(\.\w+)?)\])|((\.|->)\$?\w+))*(?>\|@?\w+(:(?>' . $qstr_regexp . '|[^|]+))*)*$!', $tag_command) || // if a variable
  210. preg_match('!^#(\w+)#(?>\|@?\w+(:(?>' . $qstr_regexp . '|[^|]+))*)*$!', $tag_command) || // or a configuration variable
  211. preg_match('!^%\w+\.\w+%(?>\|@?\w+(:(?>' . $qstr_regexp . '|[^|]+))*)*$!', $tag_command)) { // or a section property
  212. settype($tag_command, 'array');
  213. $this->_parse_vars_props($tag_command);
  214. return "<?php echo $tag_command[0]; ?>\n";
  215. }
  216. switch ($tag_command) {
  217. case 'include':
  218. return $this->_compile_include_tag($tag_args);
  219. case 'include_php':
  220. return $this->_compile_include_php_tag($tag_args);
  221. case 'if':
  222. return $this->_compile_if_tag($tag_args);
  223. case 'else':
  224. return '<?php else: ?>';
  225. case 'elseif':
  226. return $this->_compile_if_tag($tag_args, true);
  227. case '/if':
  228. return '<?php endif; ?>';
  229. case 'capture':
  230. return $this->_compile_capture_tag(true, $tag_args);
  231. case '/capture':
  232. return $this->_compile_capture_tag(false);
  233. case 'ldelim':
  234. return $this->left_delimiter;
  235. case 'rdelim':
  236. return $this->right_delimiter;
  237. case 'section':
  238. array_push($this->_sectionelse_stack, false);
  239. return $this->_compile_section_start($tag_args);
  240. case 'sectionelse':
  241. $this->_sectionelse_stack[count($this->_sectionelse_stack)-1] = true;
  242. return "<?php endfor; else: ?>";
  243. case '/section':
  244. if (array_pop($this->_sectionelse_stack))
  245. return "<?php endif; ?>";
  246. else
  247. return "<?php endfor; endif; ?>";
  248. case 'foreach':
  249. array_push($this->_foreachelse_stack, false);
  250. return $this->_compile_foreach_start($tag_args);
  251. break;
  252. case 'foreachelse':
  253. $this->_foreachelse_stack[count($this->_foreachelse_stack)-1] = true;
  254. return "<?php endforeach; else: ?>";
  255. case '/foreach':
  256. if (array_pop($this->_foreachelse_stack))
  257. return "<?php endif; ?>";
  258. else
  259. return "<?php endforeach; endif; ?>";
  260. case 'config_load':
  261. return $this->_compile_config_load_tag($tag_args);
  262. case 'strip':
  263. case '/strip':
  264. return $this->left_delimiter.$tag_command.$this->right_delimiter;
  265. case 'literal':
  266. list (,$literal_block) = each($this->_literal_blocks);
  267. $this->_current_line_no += substr_count($literal_block, "\n");
  268. return "<?php echo '".str_replace("'", "\'", str_replace("\\", "\\\\", $literal_block))."'; ?>\n";
  269. case 'php':
  270. if ($this->security && !$this->security_settings['PHP_TAGS']) {
  271. $this->_syntax_error("(secure mode) php tags not permitted", E_USER_WARNING);
  272. return;
  273. }
  274. list (,$php_block) = each($this->_php_blocks);
  275. $this->_current_line_no += substr_count($php_block, "\n");
  276. return '<?php '.$php_block.' ?>';
  277. case 'insert':
  278. return $this->_compile_insert_tag($tag_args);
  279. default:
  280. if ($this->_compile_compiler_tag($tag_command, $tag_args, $output)) {
  281. return $output;
  282. } else if ($this->_compile_block_tag($tag_command, $tag_args, $output)) {
  283. return $output;
  284. } else {
  285. return $this->_compile_custom_tag($tag_command, $tag_args);
  286. }
  287. }
  288. }
  289. /*======================================================================*\
  290. Function: _compile_compiler_tag
  291. Purpose: compile the custom compiler tag
  292. \*======================================================================*/
  293. function _compile_compiler_tag($tag_command, $tag_args, &$output)
  294. {
  295. $found = false;
  296. $have_function = true;
  297. /*
  298. * First we check if the compiler function has already been registered
  299. * or loaded from a plugin file.
  300. */
  301. if (isset($this->_plugins['compiler'][$tag_command])) {
  302. $found = true;
  303. $plugin_func = $this->_plugins['compiler'][$tag_command][0];
  304. if (!function_exists($plugin_func)) {
  305. $message = "compiler function '$tag_command' is not implemented";
  306. $have_function = false;
  307. }
  308. }
  309. /*
  310. * Otherwise we need to load plugin file and look for the function
  311. * inside it.
  312. */
  313. else if ($plugin_file = $this->_get_plugin_filepath('compiler', $tag_command)) {
  314. $found = true;
  315. include_once $plugin_file;
  316. $plugin_func = 'smarty_compiler_' . $tag_command;
  317. if (!function_exists($plugin_func)) {
  318. $message = "plugin function $plugin_func() not found in $plugin_file\n";
  319. $have_function = false;
  320. } else {
  321. $this->_plugins['compiler'][$tag_command] = array($plugin_func, null, null);
  322. }
  323. }
  324. /*
  325. * True return value means that we either found a plugin or a
  326. * dynamically registered function. False means that we didn't and the
  327. * compiler should now emit code to load custom function plugin for this
  328. * tag.
  329. */
  330. if ($found) {
  331. if ($have_function) {
  332. $output = '<?php ' . $plugin_func($tag_args, $this) . ' ?>';
  333. } else {
  334. $this->_syntax_error($message, E_USER_WARNING);
  335. }
  336. return true;
  337. } else {
  338. return false;
  339. }
  340. }
  341. /*======================================================================*\
  342. Function: _compile_block_tag
  343. Purpose: compile block function tag
  344. \*======================================================================*/
  345. function _compile_block_tag($tag_command, $tag_args, &$output)
  346. {
  347. if ($tag_command{0} == '/') {
  348. $start_tag = false;
  349. $tag_command = substr($tag_command, 1);
  350. } else
  351. $start_tag = true;
  352. $found = false;
  353. $have_function = true;
  354. /*
  355. * First we check if the block function has already been registered
  356. * or loaded from a plugin file.
  357. */
  358. if (isset($this->_plugins['block'][$tag_command])) {
  359. $found = true;
  360. $plugin_func = $this->_plugins['block'][$tag_command][0];
  361. if (!function_exists($plugin_func)) {
  362. $message = "block function '$tag_command' is not implemented";
  363. $have_function = false;
  364. }
  365. }
  366. /*
  367. * Otherwise we need to load plugin file and look for the function
  368. * inside it.
  369. */
  370. else if ($plugin_file = $this->_get_plugin_filepath('block', $tag_command)) {
  371. $found = true;
  372. include_once $plugin_file;
  373. $plugin_func = 'smarty_block_' . $tag_command;
  374. if (!function_exists($plugin_func)) {
  375. $message = "plugin function $plugin_func() not found in $plugin_file\n";
  376. $have_function = false;
  377. } else {
  378. $this->_plugins['block'][$tag_command] = array($plugin_func, null, null);
  379. }
  380. }
  381. if (!$found) {
  382. return false;
  383. } else if (!$have_function) {
  384. $this->_syntax_error($message, E_USER_WARNING);
  385. return true;
  386. }
  387. /*
  388. * Even though we've located the plugin function, compilation
  389. * happens only once, so the plugin will still need to be loaded
  390. * at runtime for future requests.
  391. */
  392. $this->_add_plugin('block', $tag_command);
  393. if ($start_tag) {
  394. $arg_list = array();
  395. $attrs = $this->_parse_attrs($tag_args);
  396. foreach ($attrs as $arg_name => $arg_value) {
  397. if (is_bool($arg_value))
  398. $arg_value = $arg_value ? 'true' : 'false';
  399. $arg_list[] = "'$arg_name' => $arg_value";
  400. }
  401. $output = "<?php \$this->_tag_stack[] = array('$tag_command', array(".implode(',', (array)$arg_list).")); \$this->_plugins['block']['$tag_command'][0](array(".implode(',', (array)$arg_list)."), null, \$this); ob_start(); ?>";
  402. } else {
  403. $output = "<?php \$this->_block_content = ob_get_contents(); ob_end_clean(); \$this->_plugins['block']['$tag_command'][0](\$this->_tag_stack[count(\$this->_tag_stack)-1][1], \$this->_block_content, \$this); array_pop(\$this->_tag_stack); ?>";
  404. }
  405. return true;
  406. }
  407. /*======================================================================*\
  408. Function: _compile_custom_tag
  409. Purpose: compile custom function tag
  410. \*======================================================================*/
  411. function _compile_custom_tag($tag_command, $tag_args)
  412. {
  413. $this->_add_plugin('function', $tag_command);
  414. $arg_list = array();
  415. $attrs = $this->_parse_attrs($tag_args);
  416. foreach ($attrs as $arg_name => $arg_value) {
  417. if (is_bool($arg_value))
  418. $arg_value = $arg_value ? 'true' : 'false';
  419. $arg_list[] = "'$arg_name' => $arg_value";
  420. }
  421. return "<?php \$this->_plugins['function']['$tag_command'][0](array(".implode(',', (array)$arg_list)."), \$this); if(\$this->_extract) { extract(\$this->_tpl_vars); \$this->_extract=false; } ?>";
  422. }
  423. /*======================================================================*\
  424. Function: _compile_insert_tag
  425. Purpose: Compile {insert ...} tag
  426. \*======================================================================*/
  427. function _compile_insert_tag($tag_args)
  428. {
  429. $attrs = $this->_parse_attrs($tag_args);
  430. $name = $this->_dequote($attrs['name']);
  431. if (empty($name)) {
  432. $this->_syntax_error("missing insert name");
  433. }
  434. if (!empty($attrs['script'])) {
  435. $delayed_loading = true;
  436. }
  437. foreach ($attrs as $arg_name => $arg_value) {
  438. if (is_bool($arg_value))
  439. $arg_value = $arg_value ? 'true' : 'false';
  440. $arg_list[] = "'$arg_name' => $arg_value";
  441. }
  442. $this->_add_plugin('insert', $name, $delayed_loading);
  443. return "<?php echo \$this->_run_insert_handler(array(".implode(', ', (array)$arg_list).")); ?>\n";
  444. }
  445. /*======================================================================*\
  446. Function: _compile_config_load_tag
  447. Purpose: Compile {config_load ...} tag
  448. \*======================================================================*/
  449. function _compile_config_load_tag($tag_args)
  450. {
  451. $attrs = $this->_parse_attrs($tag_args);
  452. if (empty($attrs['file'])) {
  453. $this->_syntax_error("missing 'file' attribute in config_load tag");
  454. }
  455. if (empty($attrs['section'])) {
  456. $attrs['section'] = 'null';
  457. }
  458. $scope = @$this->_dequote($attrs['scope']);
  459. if (!empty($scope)) {
  460. if ($scope != 'local' &&
  461. $scope != 'parent' &&
  462. $scope != 'global') {
  463. $this->_syntax_error("invalid 'scope' attribute value");
  464. }
  465. } else {
  466. if (!empty($attrs['global']) && $attrs['global'])
  467. $scope = 'parent';
  468. else
  469. $scope = 'local';
  470. }
  471. $output = '<?php $this->_config_load(' . $attrs['file'] . ', ' . $attrs['section'] . ", '$scope'); ?>";
  472. return $output;
  473. }
  474. /*======================================================================*\
  475. Function: _compile_include_tag
  476. Purpose: Compile {include ...} tag
  477. \*======================================================================*/
  478. function _compile_include_tag($tag_args)
  479. {
  480. $attrs = $this->_parse_attrs($tag_args);
  481. $arg_list = array();
  482. if (empty($attrs['file'])) {
  483. $this->_syntax_error("missing 'file' attribute in include tag");
  484. }
  485. foreach ($attrs as $arg_name => $arg_value) {
  486. if ($arg_name == 'file') {
  487. $include_file = $arg_value;
  488. continue;
  489. } else if ($arg_name == 'assign') {
  490. $assign_var = $arg_value;
  491. continue;
  492. }
  493. if (is_bool($arg_value))
  494. $arg_value = $arg_value ? 'true' : 'false';
  495. $arg_list[] = "'$arg_name' => $arg_value";
  496. }
  497. $output = '<?php ';
  498. if (isset($assign_var)) {
  499. $output .= "ob_start();\n";
  500. }
  501. $output .=
  502. "\$_smarty_tpl_vars = \$this->_tpl_vars;\n" .
  503. "\$this->_smarty_include(".$include_file.", array(".implode(',', (array)$arg_list)."));\n" .
  504. "\$this->_tpl_vars = \$_smarty_tpl_vars;\n" .
  505. "unset(\$_smarty_tpl_vars);\n";
  506. if (isset($assign_var)) {
  507. $output .= "\$this->assign(" . $assign_var . ", ob_get_contents()); ob_end_clean();\n";
  508. }
  509. $output .= ' ?>';
  510. return $output;
  511. }
  512. /*======================================================================*\
  513. Function: _compile_include_php_tag
  514. Purpose: Compile {include ...} tag
  515. \*======================================================================*/
  516. function _compile_include_php_tag($tag_args)
  517. {
  518. $attrs = $this->_parse_attrs($tag_args);
  519. if (empty($attrs['file'])) {
  520. $this->_syntax_error("missing 'file' attribute in include_php tag");
  521. }
  522. $assign_var = $this->_dequote($attrs['assign']);
  523. $once_var = ( $attrs['once'] === false ) ? 'false' : 'true';
  524. return "<?php \$this->_smarty_include_php($attrs[file], '$assign_var', $once_var); ?>";
  525. }
  526. /*======================================================================*\
  527. Function: _compile_section_start
  528. Purpose: Compile {section ...} tag
  529. \*======================================================================*/
  530. function _compile_section_start($tag_args)
  531. {
  532. $attrs = $this->_parse_attrs($tag_args);
  533. $arg_list = array();
  534. $output = "<?php ";
  535. $section_name = $attrs['name'];
  536. if (empty($section_name)) {
  537. $this->_syntax_error("missing section name");
  538. }
  539. $output .= "if (isset(\$this->_sections[$section_name])) unset(\$this->_sections[$section_name]);\n";
  540. $section_props = "\$this->_sections[$section_name]";
  541. foreach ($attrs as $attr_name => $attr_value) {
  542. switch ($attr_name) {
  543. case 'loop':
  544. $output .= "{$section_props}['loop'] = is_array($attr_value) ? count($attr_value) : max(0, (int)$attr_value);\n";
  545. break;
  546. case 'show':
  547. if (is_bool($attr_value))
  548. $show_attr_value = $attr_value ? 'true' : 'false';
  549. else
  550. $show_attr_value = "(bool)$attr_value";
  551. $output .= "{$section_props}['show'] = $show_attr_value;\n";
  552. break;
  553. case 'name':
  554. $output .= "{$section_props}['$attr_name'] = $attr_value;\n";
  555. break;
  556. case 'max':
  557. case 'start':
  558. $output .= "{$section_props}['$attr_name'] = (int)$attr_value;\n";
  559. break;
  560. case 'step':
  561. $output .= "{$section_props}['$attr_name'] = ((int)$attr_value) == 0 ? 1 : (int)$attr_value;\n";
  562. break;
  563. default:
  564. $this->_syntax_error("unknown section attribute - '$attr_name'");
  565. break;
  566. }
  567. }
  568. if (!isset($attrs['show']))
  569. $output .= "{$section_props}['show'] = true;\n";
  570. if (!isset($attrs['loop']))
  571. $output .= "{$section_props}['loop'] = 1;\n";
  572. if (!isset($attrs['max']))
  573. $output .= "{$section_props}['max'] = {$section_props}['loop'];\n";
  574. else
  575. $output .= "if ({$section_props}['max'] < 0)\n" .
  576. " {$section_props}['max'] = {$section_props}['loop'];\n";
  577. if (!isset($attrs['step']))
  578. $output .= "{$section_props}['step'] = 1;\n";
  579. if (!isset($attrs['start']))
  580. $output .= "{$section_props}['start'] = {$section_props}['step'] > 0 ? 0 : {$section_props}['loop']-1;\n";
  581. else {
  582. $output .= "if ({$section_props}['start'] < 0)\n" .
  583. " {$section_props}['start'] = max({$section_props}['step'] > 0 ? 0 : -1, {$section_props}['loop'] + {$section_props}['start']);\n" .
  584. "else\n" .
  585. " {$section_props}['start'] = min({$section_props}['start'], {$section_props}['step'] > 0 ? {$section_props}['loop'] : {$section_props}['loop']-1);\n";
  586. }
  587. $output .= "if ({$section_props}['show']) {\n";
  588. if (!isset($attrs['start']) && !isset($attrs['step']) && !isset($attrs['max'])) {
  589. $output .= " {$section_props}['total'] = {$section_props}['loop'];\n";
  590. } else {
  591. $output .= " {$section_props}['total'] = min(ceil(({$section_props}['step'] > 0 ? {$section_props}['loop'] - {$section_props}['start'] : {$section_props}['start']+1)/abs({$section_props}['step'])), {$section_props}['max']);\n";
  592. }
  593. $output .= " if ({$section_props}['total'] == 0)\n" .
  594. " {$section_props}['show'] = false;\n" .
  595. "} else\n" .
  596. " {$section_props}['total'] = 0;\n";
  597. $output .= "if ({$section_props}['show']):\n";
  598. $output .= "
  599. for ({$section_props}['index'] = {$section_props}['start'], {$section_props}['iteration'] = 1;
  600. {$section_props}['iteration'] <= {$section_props}['total'];
  601. {$section_props}['index'] += {$section_props}['step'], {$section_props}['iteration']++):\n";
  602. $output .= "{$section_props}['rownum'] = {$section_props}['iteration'];\n";
  603. $output .= "{$section_props}['index_prev'] = {$section_props}['index'] - {$section_props}['step'];\n";
  604. $output .= "{$section_props}['index_next'] = {$section_props}['index'] + {$section_props}['step'];\n";
  605. $output .= "{$section_props}['first'] = ({$section_props}['iteration'] == 1);\n";
  606. $output .= "{$section_props}['last'] = ({$section_props}['iteration'] == {$section_props}['total']);\n";
  607. $output .= "?>";
  608. return $output;
  609. }
  610. /*======================================================================*\
  611. Function: _compile_foreach_start
  612. Purpose: Compile {foreach ...} tag
  613. \*======================================================================*/
  614. function _compile_foreach_start($tag_args)
  615. {
  616. $attrs = $this->_parse_attrs($tag_args);
  617. $arg_list = array();
  618. if (empty($attrs['from'])) {
  619. $this->_syntax_error("missing 'from' attribute");
  620. }
  621. if (empty($attrs['item'])) {
  622. $this->_syntax_error("missing 'item' attribute");
  623. }
  624. $from = $attrs['from'];
  625. $item = $this->_dequote($attrs['item']);
  626. if (isset($attrs['name']))
  627. $name = $attrs['name'];
  628. $output = '<?php ';
  629. if (isset($name)) {
  630. $output .= "if (isset(\$this->_foreach[$name])) unset(\$this->_foreach[$name]);\n";
  631. $foreach_props = "\$this->_foreach[$name]";
  632. }
  633. $key_part = '';
  634. foreach ($attrs as $attr_name => $attr_value) {
  635. switch ($attr_name) {
  636. case 'key':
  637. $key = $this->_dequote($attrs['key']);
  638. $key_part = "\$this->_tpl_vars['$key'] => ";
  639. break;
  640. case 'name':
  641. $output .= "{$foreach_props}['$attr_name'] = $attr_value;\n";
  642. break;
  643. }
  644. }
  645. if (isset($name)) {
  646. $output .= "{$foreach_props}['total'] = count((array)$from);\n";
  647. $output .= "{$foreach_props}['show'] = {$foreach_props}['total'] > 0;\n";
  648. $output .= "if ({$foreach_props}['show']):\n";
  649. $output .= "{$foreach_props}['iteration'] = 0;\n";
  650. $output .= " foreach ((array)$from as $key_part\$this->_tpl_vars['$item']):\n";
  651. $output .= " {$foreach_props}['iteration']++;\n";
  652. $output .= " {$foreach_props}['first'] = ({$foreach_props}['iteration'] == 1);\n";
  653. $output .= " {$foreach_props}['last'] = ({$foreach_props}['iteration'] == {$foreach_props}['total']);\n";
  654. } else {
  655. $output .= "if (count((array)$from)):\n";
  656. $output .= " foreach ((array)$from as $key_part\$this->_tpl_vars['$item']):\n";
  657. }
  658. $output .= '?>';
  659. return $output;
  660. }
  661. /*======================================================================*\
  662. Function: _compile_capture_tag
  663. Purpose: Compile {capture} .. {/capture} tags
  664. \*======================================================================*/
  665. function _compile_capture_tag($start, $tag_args = '')
  666. {
  667. $attrs = $this->_parse_attrs($tag_args);
  668. if ($start) {
  669. if (isset($attrs['name']))
  670. $buffer = $attrs['name'];
  671. else
  672. $buffer = "'default'";
  673. $output = "<?php ob_start(); ?>";
  674. $this->_capture_stack[] = $buffer;
  675. } else {
  676. $buffer = array_pop($this->_capture_stack);
  677. $output = "<?php \$this->_smarty_vars['capture'][$buffer] = ob_get_contents(); ob_end_clean(); ?>";
  678. }
  679. return $output;
  680. }
  681. /*======================================================================*\
  682. Function: _compile_if_tag
  683. Purpose: Compile {if ...} tag
  684. \*======================================================================*/
  685. function _compile_if_tag($tag_args, $elseif = false)
  686. {
  687. /* Tokenize args for 'if' tag. */
  688. preg_match_all('/(?:
  689. "[^"\\\\]*(?:\\\\.[^"\\\\]*)*" | # match all double quoted strings allowing escaped double quotes
  690. \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\' | # match all single quoted strings allowing escaped single quotes
  691. [(),] | # match parentheses and commas
  692. [^\s(),]+ # match any other token that is not any of the above
  693. )/x', $tag_args, $match);
  694. $tokens = $match[0];
  695. $this->_parse_vars_props($tokens);
  696. $is_arg_stack = array();
  697. for ($i = 0, $for_max = count($tokens); $i < $for_max; $i++) {
  698. $token = &$tokens[$i];
  699. switch ($token) {
  700. case 'eq':
  701. $token = '==';
  702. break;
  703. case 'ne':
  704. case 'neq':
  705. $token = '!=';
  706. break;
  707. case 'lt':
  708. $token = '<';
  709. break;
  710. case 'le':
  711. case 'lte':
  712. $token = '<=';
  713. break;
  714. case 'gt':
  715. $token = '>';
  716. break;
  717. case 'ge':
  718. case 'gte':
  719. $token = '>=';
  720. break;
  721. case 'and':
  722. $token = '&&';
  723. break;
  724. case 'or':
  725. $token = '||';
  726. break;
  727. case 'not':
  728. $token = '!';
  729. break;
  730. case 'mod':
  731. $token = '%';
  732. break;
  733. case '(':
  734. array_push($is_arg_stack, $i);
  735. break;
  736. case 'is':
  737. /* If last token was a ')', we operate on the parenthesized
  738. expression. The start of the expression is on the stack.
  739. Otherwise, we operate on the last encountered token. */
  740. if ($tokens[$i-1] == ')')
  741. $is_arg_start = array_pop($is_arg_stack);
  742. else
  743. $is_arg_start = $i-1;
  744. /* Construct the argument for 'is' expression, so it knows
  745. what to operate on. */
  746. $is_arg = implode(' ', array_slice($tokens, $is_arg_start, $i - $is_arg_start));
  747. /* Pass all tokens from next one until the end to the
  748. 'is' expression parsing function. The function will
  749. return modified tokens, where the first one is the result
  750. of the 'is' expression and the rest are the tokens it
  751. didn't touch. */
  752. $new_tokens = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1));
  753. /* Replace the old tokens with the new ones. */
  754. array_splice($tokens, $is_arg_start, count($tokens), $new_tokens);
  755. /* Adjust argument start so that it won't change from the
  756. current position for the next iteration. */
  757. $i = $is_arg_start;
  758. break;
  759. default:
  760. if($this->security &&
  761. $i+1 < count($tokens) &&
  762. $tokens[$i+1] == '(' &&
  763. preg_match('!^[a-zA-Z_]\w+$!', $tokens[$i]) &&
  764. !in_array($tokens[$i], $this->security_settings['IF_FUNCS'])) {
  765. $this->_syntax_error("(secure mode) '".$tokens[$i]."' not allowed in if statement");
  766. }
  767. break;
  768. }
  769. }
  770. if ($elseif)
  771. return '<?php elseif ('.implode(' ', $tokens).'): ?>';
  772. else
  773. return '<?php if ('.implode(' ', $tokens).'): ?>';
  774. }
  775. /*======================================================================*\
  776. Function: _parse_is_expr
  777. Purpose: Parse is expression
  778. \*======================================================================*/
  779. function _parse_is_expr($is_arg, $tokens)
  780. {
  781. $expr_end = 0;
  782. $negate_expr = false;
  783. if (($first_token = array_shift($tokens)) == 'not') {
  784. $negate_expr = true;
  785. $expr_type = array_shift($tokens);
  786. } else
  787. $expr_type = $first_token;
  788. switch ($expr_type) {
  789. case 'even':
  790. if (@$tokens[$expr_end] == 'by') {
  791. $expr_end++;
  792. $expr_arg = $tokens[$expr_end++];
  793. $expr = "!(($is_arg / $expr_arg) % $expr_arg)";
  794. } else
  795. $expr = "!($is_arg % 2)";
  796. break;
  797. case 'odd':
  798. if (@$tokens[$expr_end] == 'by') {
  799. $expr_end++;
  800. $expr_arg = $tokens[$expr_end++];
  801. $expr = "(($is_arg / $expr_arg) % $expr_arg)";
  802. } else
  803. $expr = "($is_arg % 2)";
  804. break;
  805. case 'div':
  806. if (@$tokens[$expr_end] == 'by') {
  807. $expr_end++;
  808. $expr_arg = $tokens[$expr_end++];
  809. $expr = "!($is_arg % $expr_arg)";
  810. } else {
  811. $this->_syntax_error("expecting 'by' after 'div'");
  812. }
  813. break;
  814. default:
  815. $this->_syntax_error("unknown 'is' expression - '$expr_type'");
  816. break;
  817. }
  818. if ($negate_expr) {
  819. $expr = "!($expr)";
  820. }
  821. array_splice($tokens, 0, $expr_end, $expr);
  822. return $tokens;
  823. }
  824. /*======================================================================*\
  825. Function: _parse_attrs
  826. Purpose: Parse attribute string
  827. \*======================================================================*/
  828. function _parse_attrs($tag_args, $quote = true)
  829. {
  830. /* Tokenize tag attributes. */
  831. preg_match_all('/(?:"[^"\\\\]*(?:\\\\.[^"\\\\]*)*" |
  832. \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\' | (?>[^"\'=\s]+)
  833. )+ |
  834. [=]
  835. /x', $tag_args, $match);
  836. $tokens = $match[0];
  837. $var_delims = array('$', '#', '%');
  838. $attrs = array();
  839. /* Parse state:
  840. 0 - expecting attribute name
  841. 1 - expecting '='
  842. 2 - expecting attribute value (not '=') */
  843. $state = 0;
  844. foreach ($tokens as $token) {
  845. switch ($state) {
  846. case 0:
  847. /* If the token is a valid identifier, we set attribute name
  848. and go to state 1. */
  849. if (preg_match('!^\w+$!', $token)) {
  850. $attr_name = $token;
  851. $state = 1;
  852. } else
  853. $this->_syntax_error("invalid attribute name - '$token'");
  854. break;
  855. case 1:
  856. /* If the token is '=', then we go to state 2. */
  857. if ($token == '=') {
  858. $state = 2;
  859. } else
  860. $this->_syntax_error("expecting '=' after attribute name");
  861. break;
  862. case 2:
  863. /* If token is not '=', we set the attribute value and go to
  864. state 0. */
  865. if ($token != '=') {
  866. /* We booleanize the token if it's a non-quoted possible
  867. boolean value. */
  868. if (preg_match('!^(on|yes|true)$!', $token))
  869. $token = true;
  870. else if (preg_match('!^(off|no|false)$!', $token))
  871. $token = false;
  872. /* If the token is not variable (doesn't start with
  873. '$', '#', or '%') and not enclosed in single or
  874. double quotes we single-quote it. */
  875. else if ($quote && !in_array($token{0}, $var_delims) &&
  876. !(($token{0} == '"' || $token{0} == "'") &&
  877. $token{strlen($token)-1} == $token{0}))
  878. $token = '"'.$token.'"';
  879. $attrs[$attr_name] = $token;
  880. $state = 0;
  881. } else
  882. $this->_syntax_error("'=' cannot be an attribute value");
  883. break;
  884. }
  885. }
  886. $this->_parse_vars_props($attrs);
  887. return $attrs;
  888. }
  889. /*======================================================================*\
  890. Function: _parse_vars_props
  891. Purpose: compile variables and section properties tokens into
  892. PHP code
  893. \*======================================================================*/
  894. function _parse_vars_props(&$tokens)
  895. {
  896. $qstr_regexp = '"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"|\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'';
  897. $var_exprs = preg_grep('!^\$\w+(?>(\[(\d+|\$\w+|\w+(\.\w+)?)\])|((\.|->)\$?\w+))*(?>\|@?\w+(:(?>' . $qstr_regexp . '|[^|]+))*)*$!', $tokens);
  898. $conf_var_exprs = preg_grep('!^#(\w+)#(?>\|@?\w+(:(?>' . $qstr_regexp . '|[^|]+))*)*$!', $tokens);
  899. $sect_prop_exprs = preg_grep('!^%\w+\.\w+%(?>\|@?\w+(:(?>' . $qstr_regexp . '|[^|]+))*)*$!', $tokens);
  900. if (count($var_exprs)) {
  901. foreach ($var_exprs as $expr_index => $var_expr) {
  902. $tokens[$expr_index] = $this->_parse_var($var_expr);
  903. }
  904. }
  905. if (count($conf_var_exprs)) {
  906. foreach ($conf_var_exprs as $expr_index => $var_expr) {
  907. $tokens[$expr_index] = $this->_parse_conf_var($var_expr);
  908. }
  909. }
  910. if (count($sect_prop_exprs)) {
  911. foreach ($sect_prop_exprs as $expr_index => $section_prop_expr) {
  912. $tokens[$expr_index] = $this->_parse_section_prop($section_prop_expr);
  913. }
  914. }
  915. }
  916. /*======================================================================*\
  917. Function: _parse_var
  918. Purpose: parse variable expression into PHP code
  919. \*======================================================================*/
  920. function _parse_var($var_expr)
  921. {
  922. $parts = explode('|', substr($var_expr, 1), 2);
  923. $var_ref = $parts[0];
  924. $modifiers = isset($parts[1]) ? $parts[1] : '';
  925. if(!empty($this->default_modifiers) && !preg_match('!(^|\|)smarty:nodefaults($|\|)!',$modifiers)) {
  926. $_default_mod_string = implode('|',(array)$this->default_modifiers);
  927. $modifiers = empty($modifiers) ? $_default_mod_string : $_default_mod_string . '|' . $modifiers;
  928. }
  929. preg_match_all('!\[(?:\$\w+|\w+(\.\w+)?)\]|(->|\.)\$?\w+|^\w+!', $var_ref, $match);
  930. $indexes = $match[0];
  931. $var_name = array_shift($indexes);
  932. /* Handle $smarty.* variable references as a special case. */
  933. if ($var_name == 'smarty') {
  934. /*
  935. * If the reference could be compiled, use the compiled output;
  936. * otherwise, fall back on the $smarty variable generated at
  937. * run-time.
  938. */
  939. if (($smarty_ref = $this->_compile_smarty_ref($indexes)) !== null) {
  940. $output = $smarty_ref;
  941. } else {
  942. $var_name = substr(array_shift($indexes), 1);
  943. $output = "\$this->_smarty_vars['$var_name']";
  944. }
  945. } else {
  946. $output = "\$this->_tpl_vars['$var_name']";
  947. }
  948. foreach ($indexes as $index) {
  949. if ($index{0} == '[') {
  950. $index = substr($index, 1, -1);
  951. if (is_numeric($index)) {
  952. $output .= "[$index]";
  953. } elseif ($index{0} == '$') {
  954. $output .= "[\$this->_tpl_vars['" . substr($index, 1) . "']]";
  955. } else {
  956. $parts = explode('.', $index);
  957. $section = $parts[0];
  958. $section_prop = isset($parts[1]) ? $parts[1] : 'index';
  959. $output .= "[\$this->_sections['$section']['$section_prop']]";
  960. }
  961. } else if ($index{0} == '.') {
  962. if ($index{1} == '$')
  963. $output .= "[\$this->_tpl_vars['" . substr($index, 2) . "']]";
  964. else
  965. $output .= "['" . substr($index, 1) . "']";
  966. } else {
  967. $output .= $index;
  968. }
  969. }
  970. $this->_parse_modifiers($output, $modifiers);
  971. return $output;
  972. }
  973. /*======================================================================*\
  974. Function: _parse_conf_var
  975. Purpose: parse configuration variable expression into PHP code
  976. \*======================================================================*/
  977. function _parse_conf_var($conf_var_expr)
  978. {
  979. $parts = explode('|', $conf_var_expr, 2);
  980. $var_ref = $parts[0];
  981. $modifiers = isset($parts[1]) ? $parts[1] : '';
  982. $var_name = substr($var_ref, 1, -1);
  983. $output = "\$this->_config[0]['vars']['$var_name']";
  984. $this->_parse_modifiers($output, $modifiers);
  985. return $output;
  986. }
  987. /*======================================================================*\
  988. Function: _parse_section_prop
  989. Purpose: parse section property expression into PHP code
  990. \*======================================================================*/
  991. function _parse_section_prop($section_prop_expr)
  992. {
  993. $parts = explode('|', $section_prop_expr, 2);
  994. $var_ref = $parts[0];
  995. $modifiers = isset($parts[1]) ? $parts[1] : '';
  996. preg_match('!%(\w+)\.(\w+)%!', $var_ref, $match);
  997. $section_name = $match[1];
  998. $prop_name = $match[2];
  999. $output = "\$this->_sections['$section_name']['$prop_name']";
  1000. $this->_parse_modifiers($output, $modifiers);
  1001. return $output;
  1002. }
  1003. /*======================================================================*\
  1004. Function: _parse_modifiers
  1005. Purpose: parse modifier chain into PHP code
  1006. \*======================================================================*/
  1007. function _parse_modifiers(&$output, $modifier_string)
  1008. {
  1009. $qstr_regexp = '"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"|\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'';
  1010. preg_match_all('!\|(@?\w+)((?>:(?:'. $qstr_regexp . '|[^|]+))*)!', '|' . $modifier_string, $match);
  1011. list(, $modifiers, $modifier_arg_strings) = $match;
  1012. for ($i = 0, $for_max = count($modifiers); $i < $for_max; $i++) {
  1013. $modifier_name = $modifiers[$i];
  1014. if($modifier_name == 'smarty') {
  1015. // skip smarty modifier
  1016. continue;
  1017. }
  1018. preg_match_all('!:(' . $qstr_regexp . '|[^:]+)!', $modifier_arg_strings[$i], $match);
  1019. $modifier_args = $match[1];
  1020. if ($modifier_name{0} == '@') {
  1021. $map_array = 'false';
  1022. $modifier_name = substr($modifier_name, 1);
  1023. } else {
  1024. $map_array = 'true';
  1025. }
  1026. $this->_add_plugin('modifier', $modifier_name);
  1027. $this->_parse_vars_props($modifier_args);
  1028. if (count($modifi

Large files files are truncated, but you can click here to view the full file