PageRenderTime 59ms CodeModel.GetById 32ms RepoModel.GetById 1ms app.codeStats 0ms

/app/libraries/smarty/sysplugins/smarty_internal_templatecompilerbase.php

https://bitbucket.org/nanomites_webdev/heroframework
PHP | 429 lines | 308 code | 7 blank | 114 comment | 93 complexity | 62e5d47e1cc4d293f3cf83b45893ae70 MD5 | raw file
Possible License(s): LGPL-2.1, BSD-3-Clause, GPL-2.0
  1. <?php
  2. /**
  3. * Smarty Internal Plugin Smarty Template Compiler Base
  4. *
  5. * This file contains the basic classes and methodes for compiling Smarty templates with lexer/parser
  6. *
  7. * @package Smarty
  8. * @subpackage Compiler
  9. * @author Uwe Tews
  10. */
  11. /**
  12. * Main compiler class
  13. */
  14. class Smarty_Internal_TemplateCompilerBase {
  15. // hash for nocache sections
  16. private $nocache_hash = null;
  17. // suppress generation of nocache code
  18. public $suppressNocacheProcessing = false;
  19. // compile tag objects
  20. static $_tag_objects = array();
  21. // tag stack
  22. public $_tag_stack = array();
  23. // current template
  24. public $template = null;
  25. // optional log of tag/attributes
  26. public $used_tags = array();
  27. /**
  28. * Initialize compiler
  29. */
  30. public function __construct()
  31. {
  32. $this->nocache_hash = str_replace('.', '-', uniqid(rand(), true));
  33. }
  34. // abstract function doCompile($_content);
  35. /**
  36. * Methode to compile a Smarty template
  37. *
  38. * @param $template template object to compile
  39. * @return bool true if compiling succeeded, false if it failed
  40. */
  41. public function compileTemplate($template)
  42. {
  43. if (empty($template->properties['nocache_hash'])) {
  44. $template->properties['nocache_hash'] = $this->nocache_hash;
  45. } else {
  46. $this->nocache_hash = $template->properties['nocache_hash'];
  47. }
  48. // flag for nochache sections
  49. $this->nocache = false;
  50. $this->tag_nocache = false;
  51. // save template object in compiler class
  52. $this->template = $template;
  53. $this->smarty->_current_file = $this->template->getTemplateFilepath();
  54. // template header code
  55. $template_header = '';
  56. if (!$template->suppressHeader) {
  57. $template_header .= "<?php /* Smarty version " . Smarty::SMARTY_VERSION . ", created on " . strftime("%Y-%m-%d %H:%M:%S") . "\n";
  58. $template_header .= " compiled from \"" . $this->template->getTemplateFilepath() . "\" */ ?>\n";
  59. }
  60. do {
  61. // flag for aborting current and start recompile
  62. $this->abort_and_recompile = false;
  63. // get template source
  64. $_content = $template->getTemplateSource();
  65. // run prefilter if required
  66. if (isset($this->smarty->autoload_filters['pre']) || isset($this->smarty->registered_filters['pre'])) {
  67. $template->template_source = $_content = Smarty_Internal_Filter_Handler::runFilter('pre', $_content, $template);
  68. }
  69. // on empty template just return header
  70. if ($_content == '') {
  71. if ($template->suppressFileDependency) {
  72. $template->compiled_template = '';
  73. } else {
  74. $template->compiled_template = $template_header . $template->createPropertyHeader();
  75. }
  76. return true;
  77. }
  78. // call compiler
  79. $_compiled_code = $this->doCompile($_content);
  80. } while ($this->abort_and_recompile);
  81. // return compiled code to template object
  82. if ($template->suppressFileDependency) {
  83. $template->compiled_template = $_compiled_code;
  84. } else {
  85. $template->compiled_template = $template_header . $template->createPropertyHeader() . $_compiled_code;
  86. }
  87. // run postfilter if required
  88. if (isset($this->smarty->autoload_filters['post']) || isset($this->smarty->registered_filters['post'])) {
  89. $template->compiled_template = Smarty_Internal_Filter_Handler::runFilter('post', $template->compiled_template, $template);
  90. }
  91. }
  92. /**
  93. * Compile Tag
  94. *
  95. * This is a call back from the lexer/parser
  96. * It executes the required compile plugin for the Smarty tag
  97. *
  98. * @param string $tag tag name
  99. * @param array $args array with tag attributes
  100. * @param array $parameter array with compilation parameter
  101. * @return string compiled code
  102. */
  103. public function compileTag($tag, $args, $parameter = array())
  104. {
  105. // $args contains the attributes parsed and compiled by the lexer/parser
  106. // assume that tag does compile into code, but creates no HTML output
  107. $this->has_code = true;
  108. $this->has_output = false;
  109. // log tag/attributes
  110. if (isset($this->smarty->get_used_tags) && $this->smarty->get_used_tags) {
  111. $this->used_tags[] = array($tag,$args);
  112. }
  113. // check nocache option flag
  114. if (in_array("'nocache'",$args) || in_array(array('nocache'=>'true'),$args)
  115. || in_array(array('nocache'=>'"true"'),$args) || in_array(array('nocache'=>"'true'"),$args)) {
  116. $this->tag_nocache = true;
  117. }
  118. // compile the smarty tag (required compile classes to compile the tag are autoloaded)
  119. if (($_output = $this->callTagCompiler($tag, $args, $parameter)) === false) {
  120. if (isset($this->smarty->template_functions[$tag])) {
  121. // template defined by {template} tag
  122. $args['_attr']['name'] = "'" . $tag . "'";
  123. $_output = $this->callTagCompiler('call', $args, $parameter);
  124. }
  125. }
  126. if ($_output !== false) {
  127. if ($_output !== true) {
  128. // did we get compiled code
  129. if ($this->has_code) {
  130. // Does it create output?
  131. if ($this->has_output) {
  132. $_output .= "\n";
  133. }
  134. // return compiled code
  135. return $_output;
  136. }
  137. }
  138. // tag did not produce compiled code
  139. return '';
  140. } else {
  141. // map_named attributes
  142. if (isset($args['_attr'])) {
  143. foreach ($args['_attr'] as $key => $attribute) {
  144. if (is_array($attribute)) {
  145. $args = array_merge($args, $attribute);
  146. }
  147. }
  148. }
  149. // not an internal compiler tag
  150. if (strlen($tag) < 6 || substr($tag, -5) != 'close') {
  151. // check if tag is a registered object
  152. if (isset($this->smarty->registered_objects[$tag]) && isset($parameter['object_methode'])) {
  153. $methode = $parameter['object_methode'];
  154. if (!in_array($methode, $this->smarty->registered_objects[$tag][3]) &&
  155. (empty($this->smarty->registered_objects[$tag][1]) || in_array($methode, $this->smarty->registered_objects[$tag][1]))) {
  156. return $this->callTagCompiler('private_object_function', $args, $parameter, $tag, $methode);
  157. } elseif (in_array($methode, $this->smarty->registered_objects[$tag][3])) {
  158. return $this->callTagCompiler('private_object_block_function', $args, $parameter, $tag, $methode);
  159. } else {
  160. return $this->trigger_template_error ('unallowed methode "' . $methode . '" in registered object "' . $tag . '"', $this->lex->taglineno);
  161. }
  162. }
  163. // check if tag is registered
  164. foreach (array(Smarty::PLUGIN_COMPILER, Smarty::PLUGIN_FUNCTION, Smarty::PLUGIN_BLOCK) as $type) {
  165. if (isset($this->smarty->registered_plugins[$type][$tag])) {
  166. // if compiler function plugin call it now
  167. if ($type == Smarty::PLUGIN_COMPILER) {
  168. $new_args = array();
  169. foreach ($args as $mixed) {
  170. $new_args = array_merge($new_args, $mixed);
  171. }
  172. if (!$this->smarty->registered_plugins[$type][$tag][1]) {
  173. $this->tag_nocache = true;
  174. }
  175. $function = $this->smarty->registered_plugins[$type][$tag][0];
  176. if (!is_array($function)) {
  177. return $function($new_args, $this);
  178. } else if (is_object($function[0])) {
  179. return $this->smarty->registered_plugins[$type][$tag][0][0]->$function[1]($new_args, $this);
  180. } else {
  181. return call_user_func_array($this->smarty->registered_plugins[$type][$tag][0], array($new_args, $this));
  182. }
  183. }
  184. // compile registered function or block function
  185. if ($type == Smarty::PLUGIN_FUNCTION || $type == Smarty::PLUGIN_BLOCK) {
  186. return $this->callTagCompiler('private_registered_' . $type, $args, $parameter, $tag);
  187. }
  188. }
  189. }
  190. // check plugins from plugins folder
  191. foreach ($this->smarty->plugin_search_order as $plugin_type) {
  192. if ($plugin_type == Smarty::PLUGIN_BLOCK && $this->smarty->loadPlugin('smarty_compiler_' . $tag)) {
  193. $plugin = 'smarty_compiler_' . $tag;
  194. if (is_callable($plugin)) {
  195. return $plugin($args, $this->smarty);
  196. }
  197. if (class_exists($plugin, false)) {
  198. $plugin_object = new $plugin;
  199. if (method_exists($plugin_object, 'compile')) {
  200. return $plugin_object->compile($args, $this);
  201. }
  202. }
  203. throw new SmartyException("Plugin \"{$tag}\" not callable");
  204. } else {
  205. if ($function = $this->getPlugin($tag, $plugin_type)) {
  206. return $this->callTagCompiler('private_' . $plugin_type . '_plugin', $args, $parameter, $tag, $function);
  207. }
  208. }
  209. }
  210. } else {
  211. // compile closing tag of block function
  212. $base_tag = substr($tag, 0, -5);
  213. // check if closing tag is a registered object
  214. if (isset($this->smarty->registered_objects[$base_tag]) && isset($parameter['object_methode'])) {
  215. $methode = $parameter['object_methode'];
  216. if (in_array($methode, $this->smarty->registered_objects[$base_tag][3])) {
  217. return $this->callTagCompiler('private_object_block_function', $args, $parameter, $tag, $methode);
  218. } else {
  219. return $this->trigger_template_error ('unallowed closing tag methode "' . $methode . '" in registered object "' . $base_tag . '"', $this->lex->taglineno);
  220. }
  221. }
  222. // registered block tag ?
  223. if (isset($this->smarty->registered_plugins[Smarty::PLUGIN_BLOCK][$base_tag])) {
  224. return $this->callTagCompiler('private_registered_block', $args, $parameter, $tag);
  225. }
  226. // block plugin?
  227. if ($function = $this->getPlugin($base_tag, Smarty::PLUGIN_BLOCK)) {
  228. return $this->callTagCompiler('private_block_plugin', $args, $parameter, $tag, $function);
  229. }
  230. if ($this->smarty->loadPlugin('smarty_compiler_' . $tag)) {
  231. $plugin = 'smarty_compiler_' . $tag;
  232. if (is_callable($plugin)) {
  233. return $plugin($args, $this->smarty);
  234. }
  235. if (class_exists($plugin, false)) {
  236. $plugin_object = new $plugin;
  237. if (method_exists($plugin_object, 'compile')) {
  238. return $plugin_object->compile($args, $this);
  239. }
  240. }
  241. throw new SmartyException("Plugin \"{$tag}\" not callable");
  242. }
  243. }
  244. $this->trigger_template_error ("unknown tag \"" . $tag . "\"", $this->lex->taglineno);
  245. }
  246. }
  247. /**
  248. * lazy loads internal compile plugin for tag and calls the compile methode
  249. *
  250. * compile objects cached for reuse.
  251. * class name format: Smarty_Internal_Compile_TagName
  252. * plugin filename format: Smarty_Internal_Tagname.php
  253. *
  254. * @param $tag string tag name
  255. * @param $args array with tag attributes
  256. * @param $param1 optional parameter
  257. * @param $param2 optional parameter
  258. * @param $param3 optional parameter
  259. * @return string compiled code
  260. */
  261. public function callTagCompiler($tag, $args, $param1 = null, $param2 = null, $param3 = null)
  262. {
  263. // re-use object if already exists
  264. if (isset(self::$_tag_objects[$tag])) {
  265. // compile this tag
  266. return self::$_tag_objects[$tag]->compile($args, $this, $param1, $param2, $param3);
  267. }
  268. // lazy load internal compiler plugin
  269. $class_name = 'Smarty_Internal_Compile_' . $tag;
  270. if ($this->smarty->loadPlugin($class_name)) {
  271. // use plugin if found
  272. self::$_tag_objects[$tag] = new $class_name;
  273. // compile this tag
  274. return self::$_tag_objects[$tag]->compile($args, $this, $param1, $param2, $param3);
  275. }
  276. // no internal compile plugin for this tag
  277. return false;
  278. }
  279. /**
  280. * Check for plugins and return function name
  281. *
  282. * @param $pugin_name string name of plugin or function
  283. * @param $type string type of plugin
  284. * @return string call name of function
  285. */
  286. public function getPlugin($plugin_name, $type)
  287. {
  288. $function = null;
  289. if ($this->template->caching && ($this->nocache || $this->tag_nocache)) {
  290. if (isset($this->template->required_plugins['nocache'][$plugin_name][$type])) {
  291. $function = $this->template->required_plugins['nocache'][$plugin_name][$type]['function'];
  292. } else if (isset($this->template->required_plugins['compiled'][$plugin_name][$type])) {
  293. $this->template->required_plugins['nocache'][$plugin_name][$type] = $this->template->required_plugins['compiled'][$plugin_name][$type];
  294. $function = $this->template->required_plugins['nocache'][$plugin_name][$type]['function'];
  295. }
  296. } else {
  297. if (isset($this->template->required_plugins['compiled'][$plugin_name][$type])) {
  298. $function = $this->template->required_plugins['compiled'][$plugin_name][$type]['function'];
  299. } else if (isset($this->template->required_plugins['compiled'][$plugin_name][$type])) {
  300. $this->template->required_plugins['compiled'][$plugin_name][$type] = $this->template->required_plugins['nocache'][$plugin_name][$type];
  301. $function = $this->template->required_plugins['compiled'][$plugin_name][$type]['function'];
  302. }
  303. }
  304. if (isset($function)) {
  305. if ($type == 'modifier') {
  306. $this->template->saved_modifier[$plugin_name] = true;
  307. }
  308. return $function;
  309. }
  310. // loop through plugin dirs and find the plugin
  311. $function = 'smarty_' . $type . '_' . $plugin_name;
  312. $found = false;
  313. foreach((array)$this->smarty->plugins_dir as $_plugin_dir) {
  314. $file = rtrim($_plugin_dir, '/\\') . DS . $type . '.' . $plugin_name . '.php';
  315. if (file_exists($file)) {
  316. // require_once($file);
  317. $found = true;
  318. break;
  319. }
  320. }
  321. if ($found) {
  322. if ($this->template->caching && ($this->nocache || $this->tag_nocache)) {
  323. $this->template->required_plugins['nocache'][$plugin_name][$type]['file'] = $file;
  324. $this->template->required_plugins['nocache'][$plugin_name][$type]['function'] = $function;
  325. } else {
  326. $this->template->required_plugins['compiled'][$plugin_name][$type]['file'] = $file;
  327. $this->template->required_plugins['compiled'][$plugin_name][$type]['function'] = $function;
  328. }
  329. if ($type == 'modifier') {
  330. $this->template->saved_modifier[$plugin_name] = true;
  331. }
  332. return $function;
  333. }
  334. if (is_callable($function)) {
  335. // plugin function is defined in the script
  336. return $function;
  337. }
  338. return false;
  339. }
  340. /**
  341. * Inject inline code for nocache template sections
  342. *
  343. * This method gets the content of each template element from the parser.
  344. * If the content is compiled code and it should be not cached the code is injected
  345. * into the rendered output.
  346. *
  347. * @param string $content content of template element
  348. * @param boolean $tag_nocache true if the parser detected a nocache situation
  349. * @param boolean $is_code true if content is compiled code
  350. * @return string content
  351. */
  352. public function processNocacheCode ($content, $is_code)
  353. {
  354. // If the template is not evaluated and we have a nocache section and or a nocache tag
  355. if ($is_code && !empty($content)) {
  356. // generate replacement code
  357. if ((!$this->template->resource_object->isEvaluated || $this->template->forceNocache) && $this->template->caching && !$this->suppressNocacheProcessing &&
  358. ($this->nocache || $this->tag_nocache || $this->template->forceNocache == 2)) {
  359. $this->template->has_nocache_code = true;
  360. $_output = str_replace("'", "\'", $content);
  361. $_output = "<?php echo '/*%%SmartyNocache:{$this->nocache_hash}%%*/" . $_output . "/*/%%SmartyNocache:{$this->nocache_hash}%%*/';?>";
  362. // make sure we include modifer plugins for nocache code
  363. if (isset($this->template->saved_modifier)) {
  364. foreach ($this->template->saved_modifier as $plugin_name => $dummy) {
  365. if (isset($this->template->required_plugins['compiled'][$plugin_name]['modifier'])) {
  366. $this->template->required_plugins['nocache'][$plugin_name]['modifier'] = $this->template->required_plugins['compiled'][$plugin_name]['modifier'];
  367. }
  368. }
  369. $this->template->saved_modifier = null;
  370. }
  371. } else {
  372. $_output = $content;
  373. }
  374. } else {
  375. $_output = $content;
  376. }
  377. $this->suppressNocacheProcessing = false;
  378. $this->tag_nocache = false;
  379. return $_output;
  380. }
  381. /**
  382. * display compiler error messages without dying
  383. *
  384. * If parameter $args is empty it is a parser detected syntax error.
  385. * In this case the parser is called to obtain information about expected tokens.
  386. *
  387. * If parameter $args contains a string this is used as error message
  388. *
  389. * @param $args string individual error message or null
  390. */
  391. public function trigger_template_error($args = null, $line = null)
  392. {
  393. // get template source line which has error
  394. if (!isset($line)) {
  395. $line = $this->lex->line;
  396. }
  397. $match = preg_split("/\n/", $this->lex->data);
  398. $error_text = 'Syntax Error in template "' . $this->template->getTemplateFilepath() . '" on line ' . $line . ' "' . htmlspecialchars(trim(preg_replace('![\t\r\n]+!',' ',$match[$line-1]))) . '" ';
  399. if (isset($args)) {
  400. // individual error message
  401. $error_text .= $args;
  402. } else {
  403. // expected token from parser
  404. $error_text .= ' - Unexpected "' . $this->lex->value.'"';
  405. if (count($this->parser->yy_get_expected_tokens($this->parser->yymajor)) <= 4 ) {
  406. foreach ($this->parser->yy_get_expected_tokens($this->parser->yymajor) as $token) {
  407. $exp_token = $this->parser->yyTokenName[$token];
  408. if (isset($this->lex->smarty_token_names[$exp_token])) {
  409. // token type from lexer
  410. $expect[] = '"' . $this->lex->smarty_token_names[$exp_token] . '"';
  411. } else {
  412. // otherwise internal token name
  413. $expect[] = $this->parser->yyTokenName[$token];
  414. }
  415. }
  416. $error_text .= ', expected one of: ' . implode(' , ', $expect);
  417. }
  418. }
  419. throw new SmartyCompilerException($error_text);
  420. }
  421. }
  422. ?>