smarty_internal_compile_include.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. <?php
  2. /**
  3. * Smarty Internal Plugin Compile Include
  4. * Compiles the {include} tag
  5. *
  6. * @package Smarty
  7. * @subpackage Compiler
  8. * @author Uwe Tews
  9. */
  10. /**
  11. * Smarty Internal Plugin Compile Include Class
  12. *
  13. * @package Smarty
  14. * @subpackage Compiler
  15. */
  16. class Smarty_Internal_Compile_Include extends Smarty_Internal_CompileBase
  17. {
  18. /**
  19. * caching mode to create nocache code but no cache file
  20. */
  21. const CACHING_NOCACHE_CODE = 9999;
  22. /**
  23. * Attribute definition: Overwrites base class.
  24. *
  25. * @var array
  26. * @see Smarty_Internal_CompileBase
  27. */
  28. public $required_attributes = array('file');
  29. /**
  30. * Attribute definition: Overwrites base class.
  31. *
  32. * @var array
  33. * @see Smarty_Internal_CompileBase
  34. */
  35. public $shorttag_order = array('file');
  36. /**
  37. * Attribute definition: Overwrites base class.
  38. *
  39. * @var array
  40. * @see Smarty_Internal_CompileBase
  41. */
  42. public $option_flags = array('nocache', 'inline', 'caching');
  43. /**
  44. * Attribute definition: Overwrites base class.
  45. *
  46. * @var array
  47. * @see Smarty_Internal_CompileBase
  48. */
  49. public $optional_attributes = array('_any');
  50. /**
  51. * Valid scope names
  52. *
  53. * @var array
  54. */
  55. public $valid_scopes = array('parent' => Smarty::SCOPE_PARENT, 'root' => Smarty::SCOPE_ROOT,
  56. 'global' => Smarty::SCOPE_GLOBAL, 'tpl_root' => Smarty::SCOPE_TPL_ROOT,
  57. 'smarty' => Smarty::SCOPE_SMARTY);
  58. /**
  59. * Compiles code for the {include} tag
  60. *
  61. * @param array $args array with attributes from parser
  62. * @param Smarty_Internal_SmartyTemplateCompiler $compiler compiler object
  63. * @param array $parameter array with compilation parameter
  64. *
  65. * @throws SmartyCompilerException
  66. * @return string compiled code
  67. */
  68. public function compile($args, Smarty_Internal_SmartyTemplateCompiler $compiler, $parameter)
  69. {
  70. $uid = $t_hash = null;
  71. // check and get attributes
  72. $_attr = $this->getAttributes($compiler, $args);
  73. $fullResourceName = $source_resource = $_attr[ 'file' ];
  74. $variable_template = false;
  75. $cache_tpl = false;
  76. // parse resource_name
  77. if (preg_match('/^([\'"])(([A-Za-z0-9_\-]{2,})[:])?(([^$()]+)|(.+))\1$/', $source_resource, $match)) {
  78. $type = !empty($match[ 3 ]) ? $match[ 3 ] : $compiler->template->smarty->default_resource_type;
  79. $name = !empty($match[ 5 ]) ? $match[ 5 ] : $match[ 6 ];
  80. $handler = Smarty_Resource::load($compiler->smarty, $type);
  81. if ($handler->recompiled || $handler->uncompiled) {
  82. $variable_template = true;
  83. }
  84. if (!$variable_template) {
  85. if ($type != 'string') {
  86. $fullResourceName = "{$type}:{$name}";
  87. $compiled = $compiler->parent_compiler->template->compiled;
  88. if (isset($compiled->includes[ $fullResourceName ])) {
  89. $compiled->includes[ $fullResourceName ] ++;
  90. $cache_tpl = true;
  91. } else {
  92. if ("{$compiler->template->source->type}:{$compiler->template->source->name}" ==
  93. $fullResourceName
  94. ) {
  95. // recursive call of current template
  96. $compiled->includes[ $fullResourceName ] = 2;
  97. $cache_tpl = true;
  98. } else {
  99. $compiled->includes[ $fullResourceName ] = 1;
  100. }
  101. }
  102. $fullResourceName = $match[ 1 ] . $fullResourceName . $match[ 1 ];
  103. }
  104. }
  105. if (empty($match[ 5 ])) {
  106. $variable_template = true;
  107. }
  108. } else {
  109. $variable_template = true;
  110. }
  111. // scope setup
  112. $_scope = $compiler->convertScope($_attr, $this->valid_scopes);
  113. // set flag to cache subtemplate object when called within loop or template name is variable.
  114. if ($cache_tpl || $variable_template || $compiler->loopNesting > 0) {
  115. $_cache_tpl = 'true';
  116. } else {
  117. $_cache_tpl = 'false';
  118. }
  119. // assume caching is off
  120. $_caching = Smarty::CACHING_OFF;
  121. $call_nocache = $compiler->tag_nocache || $compiler->nocache;
  122. // caching was on and {include} is not in nocache mode
  123. if ($compiler->template->caching && !$compiler->nocache && !$compiler->tag_nocache) {
  124. $_caching = self::CACHING_NOCACHE_CODE;
  125. }
  126. // flag if included template code should be merged into caller
  127. $merge_compiled_includes = ($compiler->smarty->merge_compiled_includes || $_attr[ 'inline' ] === true) &&
  128. !$compiler->template->source->handler->recompiled;
  129. if ($merge_compiled_includes) {
  130. // variable template name ?
  131. if ($variable_template) {
  132. $merge_compiled_includes = false;
  133. }
  134. // variable compile_id?
  135. if (isset($_attr[ 'compile_id' ]) && $compiler->isVariable($_attr[ 'compile_id' ])) {
  136. $merge_compiled_includes = false;
  137. }
  138. }
  139. /*
  140. * if the {include} tag provides individual parameter for caching or compile_id
  141. * the subtemplate must not be included into the common cache file and is treated like
  142. * a call in nocache mode.
  143. *
  144. */
  145. if ($_attr[ 'nocache' ] !== true && $_attr[ 'caching' ]) {
  146. $_caching = $_new_caching = (int) $_attr[ 'caching' ];
  147. $call_nocache = true;
  148. } else {
  149. $_new_caching = Smarty::CACHING_LIFETIME_CURRENT;
  150. }
  151. if (isset($_attr[ 'cache_lifetime' ])) {
  152. $_cache_lifetime = $_attr[ 'cache_lifetime' ];
  153. $call_nocache = true;
  154. $_caching = $_new_caching;
  155. } else {
  156. $_cache_lifetime = '$_smarty_tpl->cache_lifetime';
  157. }
  158. if (isset($_attr[ 'cache_id' ])) {
  159. $_cache_id = $_attr[ 'cache_id' ];
  160. $call_nocache = true;
  161. $_caching = $_new_caching;
  162. } else {
  163. $_cache_id = '$_smarty_tpl->cache_id';
  164. }
  165. if (isset($_attr[ 'compile_id' ])) {
  166. $_compile_id = $_attr[ 'compile_id' ];
  167. } else {
  168. $_compile_id = '$_smarty_tpl->compile_id';
  169. }
  170. // if subtemplate will be called in nocache mode do not merge
  171. if ($compiler->template->caching && $call_nocache) {
  172. $merge_compiled_includes = false;
  173. }
  174. // assign attribute
  175. if (isset($_attr[ 'assign' ])) {
  176. // output will be stored in a smarty variable instead of being displayed
  177. if ($_assign = $compiler->getId($_attr[ 'assign' ])) {
  178. $_assign = "'{$_assign}'";
  179. if ($compiler->tag_nocache || $compiler->nocache || $call_nocache) {
  180. // create nocache var to make it know for further compiling
  181. $compiler->setNocacheInVariable($_attr[ 'assign' ]);
  182. }
  183. } else {
  184. $_assign = $_attr[ 'assign' ];
  185. }
  186. }
  187. $has_compiled_template = false;
  188. if ($merge_compiled_includes) {
  189. $c_id = isset($_attr[ 'compile_id' ]) ? $_attr[ 'compile_id' ] : $compiler->template->compile_id;
  190. // we must observe different compile_id and caching
  191. $t_hash = sha1($c_id . ($_caching ? '--caching' : '--nocaching'));
  192. $compiler->smarty->allow_ambiguous_resources = true;
  193. /* @var Smarty_Internal_Template $tpl */
  194. $tpl = new $compiler->smarty->template_class (trim($fullResourceName, '"\''), $compiler->smarty,
  195. $compiler->template, $compiler->template->cache_id, $c_id,
  196. $_caching);
  197. $uid = $tpl->source->type . $tpl->source->uid;
  198. if (!isset($compiler->parent_compiler->mergedSubTemplatesData[ $uid ][ $t_hash ])) {
  199. $has_compiled_template = $this->compileInlineTemplate($compiler, $tpl, $t_hash);
  200. } else {
  201. $has_compiled_template = true;
  202. }
  203. unset($tpl);
  204. }
  205. // delete {include} standard attributes
  206. unset($_attr[ 'file' ], $_attr[ 'assign' ], $_attr[ 'cache_id' ], $_attr[ 'compile_id' ], $_attr[ 'cache_lifetime' ], $_attr[ 'nocache' ], $_attr[ 'caching' ], $_attr[ 'scope' ], $_attr[ 'inline' ]);
  207. // remaining attributes must be assigned as smarty variable
  208. $_vars = 'array()';
  209. if (!empty($_attr)) {
  210. $_pairs = array();
  211. // create variables
  212. foreach ($_attr as $key => $value) {
  213. $_pairs[] = "'$key'=>$value";
  214. }
  215. $_vars = 'array(' . join(',', $_pairs) . ')';
  216. }
  217. $update_compile_id = $compiler->template->caching && !$compiler->tag_nocache && !$compiler->nocache &&
  218. $_compile_id != '$_smarty_tpl->compile_id';
  219. if ($has_compiled_template && !$call_nocache) {
  220. $_output = "<?php\n";
  221. if ($update_compile_id) {
  222. $_output .= $compiler->makeNocacheCode("\$_compile_id_save[] = \$_smarty_tpl->compile_id;\n\$_smarty_tpl->compile_id = {$_compile_id};\n");
  223. }
  224. if (!empty($_attr) && $_caching == 9999 && $compiler->template->caching) {
  225. $_vars_nc = "foreach ($_vars as \$ik => \$iv) {\n";
  226. $_vars_nc .= "\$_smarty_tpl->tpl_vars[\$ik] = new Smarty_Variable(\$iv);\n";
  227. $_vars_nc .= "}\n";
  228. $_output .= substr($compiler->processNocacheCode('<?php ' . $_vars_nc . "?>\n", true), 6, - 3);
  229. }
  230. if (isset($_assign)) {
  231. $_output .= "ob_start();\n";
  232. }
  233. $_output .= "\$_smarty_tpl->_subTemplateRender({$fullResourceName}, {$_cache_id}, {$_compile_id}, {$_caching}, {$_cache_lifetime}, {$_vars}, {$_scope}, {$_cache_tpl}, '{$compiler->parent_compiler->mergedSubTemplatesData[$uid][$t_hash]['uid']}', '{$compiler->parent_compiler->mergedSubTemplatesData[$uid][$t_hash]['func']}');\n";
  234. if (isset($_assign)) {
  235. $_output .= "\$_smarty_tpl->assign({$_assign}, ob_get_clean());\n";
  236. }
  237. if ($update_compile_id) {
  238. $_output .= $compiler->makeNocacheCode("\$_smarty_tpl->compile_id = array_pop(\$_compile_id_save);\n");
  239. }
  240. $_output .= "?>\n";
  241. return $_output;
  242. }
  243. if ($call_nocache) {
  244. $compiler->tag_nocache = true;
  245. }
  246. $_output = "<?php ";
  247. if ($update_compile_id) {
  248. $_output .= "\$_compile_id_save[] = \$_smarty_tpl->compile_id;\n\$_smarty_tpl->compile_id = {$_compile_id};\n";
  249. }
  250. // was there an assign attribute
  251. if (isset($_assign)) {
  252. $_output .= "ob_start();\n";
  253. }
  254. $_output .= "\$_smarty_tpl->_subTemplateRender({$fullResourceName}, $_cache_id, $_compile_id, $_caching, $_cache_lifetime, $_vars, $_scope, {$_cache_tpl});\n";
  255. if (isset($_assign)) {
  256. $_output .= "\$_smarty_tpl->assign({$_assign}, ob_get_clean());\n";
  257. }
  258. if ($update_compile_id) {
  259. $_output .= "\$_smarty_tpl->compile_id = array_pop(\$_compile_id_save);\n";
  260. }
  261. $_output .= "?>\n";
  262. return $_output;
  263. }
  264. /**
  265. * Compile inline sub template
  266. *
  267. * @param \Smarty_Internal_SmartyTemplateCompiler $compiler
  268. * @param \Smarty_Internal_Template $tpl
  269. * @param string $t_hash
  270. *
  271. * @return bool
  272. */
  273. public function compileInlineTemplate(Smarty_Internal_SmartyTemplateCompiler $compiler,
  274. Smarty_Internal_Template $tpl, $t_hash)
  275. {
  276. $uid = $tpl->source->type . $tpl->source->uid;
  277. if (!($tpl->source->handler->uncompiled) && $tpl->source->exists) {
  278. $compiler->parent_compiler->mergedSubTemplatesData[ $uid ][ $t_hash ][ 'uid' ] = $tpl->source->uid;
  279. if (isset($compiler->template->inheritance)) {
  280. $tpl->inheritance = clone $compiler->template->inheritance;
  281. }
  282. $tpl->compiled = new Smarty_Template_Compiled();
  283. $tpl->compiled->nocache_hash = $compiler->parent_compiler->template->compiled->nocache_hash;
  284. $tpl->loadCompiler();
  285. // save unique function name
  286. $compiler->parent_compiler->mergedSubTemplatesData[ $uid ][ $t_hash ][ 'func' ] =
  287. $tpl->compiled->unifunc = 'content_' . str_replace(array('.', ','), '_', uniqid('', true));
  288. // make sure whole chain gets compiled
  289. $tpl->mustCompile = true;
  290. $compiler->parent_compiler->mergedSubTemplatesData[ $uid ][ $t_hash ][ 'nocache_hash' ] =
  291. $tpl->compiled->nocache_hash;
  292. if ($compiler->template->source->type == 'file') {
  293. $sourceInfo = $compiler->template->source->filepath;
  294. } else {
  295. $basename = $compiler->template->source->handler->getBasename($compiler->template->source);
  296. $sourceInfo = $compiler->template->source->type . ':' .
  297. ($basename ? $basename : $compiler->template->source->name);
  298. }
  299. // get compiled code
  300. $compiled_code = "<?php\n\n";
  301. $compiled_code .= "/* Start inline template \"{$sourceInfo}\" =============================*/\n";
  302. $compiled_code .= "function {$tpl->compiled->unifunc} (\$_smarty_tpl) {\n";
  303. $compiled_code .= "?>\n" . $tpl->compiler->compileTemplateSource($tpl, null, $compiler->parent_compiler);
  304. $compiled_code .= "<?php\n";
  305. $compiled_code .= "}\n?>\n";
  306. $compiled_code .= $tpl->compiler->postFilter($tpl->compiler->blockOrFunctionCode);
  307. $compiled_code .= "<?php\n\n";
  308. $compiled_code .= "/* End inline template \"{$sourceInfo}\" =============================*/\n";
  309. $compiled_code .= "?>";
  310. unset($tpl->compiler);
  311. if ($tpl->compiled->has_nocache_code) {
  312. // replace nocache_hash
  313. $compiled_code =
  314. str_replace("{$tpl->compiled->nocache_hash}", $compiler->template->compiled->nocache_hash,
  315. $compiled_code);
  316. $compiler->template->compiled->has_nocache_code = true;
  317. }
  318. $compiler->parent_compiler->mergedSubTemplatesCode[ $tpl->compiled->unifunc ] = $compiled_code;
  319. return true;
  320. } else {
  321. return false;
  322. }
  323. }
  324. }