Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

smarty_internal_compile_include.php 15KB

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