vendor/contao/core-bundle/src/Resources/contao/classes/FrontendTemplate.php line 41

Open in your IDE?
  1. <?php
  2. /*
  3. * This file is part of Contao.
  4. *
  5. * (c) Leo Feyer
  6. *
  7. * @license LGPL-3.0-or-later
  8. */
  9. namespace Contao;
  10. use Symfony\Component\HttpFoundation\Response;
  11. /**
  12. * Class FrontendTemplate
  13. *
  14. * @property integer $id
  15. * @property string $keywords
  16. * @property string $content
  17. * @property array $sections
  18. * @property array $positions
  19. * @property array $matches
  20. * @property string $tag
  21. */
  22. class FrontendTemplate extends Template
  23. {
  24. use FrontendTemplateTrait;
  25. /**
  26. * Unused $_GET check
  27. * @var boolean
  28. */
  29. protected $blnCheckRequest = false;
  30. /**
  31. * Add a hook to modify the template output
  32. *
  33. * @return string The template markup
  34. */
  35. public function parse()
  36. {
  37. $strBuffer = parent::parse();
  38. // HOOK: add custom parse filters
  39. if (isset($GLOBALS['TL_HOOKS']['parseFrontendTemplate']) && \is_array($GLOBALS['TL_HOOKS']['parseFrontendTemplate']))
  40. {
  41. foreach ($GLOBALS['TL_HOOKS']['parseFrontendTemplate'] as $callback)
  42. {
  43. $this->import($callback[0]);
  44. $strBuffer = $this->{$callback[0]}->{$callback[1]}($strBuffer, $this->strTemplate, $this);
  45. }
  46. }
  47. return $strBuffer;
  48. }
  49. /**
  50. * Send the response to the client
  51. *
  52. * @param bool $blnCheckRequest If true, check for unused $_GET parameters
  53. *
  54. * @deprecated Deprecated since Contao 4.0, to be removed in Contao 5.0.
  55. * Use FrontendTemplate::getResponse() instead.
  56. */
  57. public function output($blnCheckRequest=false)
  58. {
  59. $this->blnCheckRequest = $blnCheckRequest;
  60. parent::output();
  61. }
  62. /**
  63. * Return a response object
  64. *
  65. * @param bool $blnCheckRequest If true, check for unused $_GET parameters
  66. * @param bool $blnForceCacheHeaders
  67. *
  68. * @return Response The response object
  69. */
  70. public function getResponse($blnCheckRequest=false, $blnForceCacheHeaders=false)
  71. {
  72. $this->blnCheckRequest = $blnCheckRequest;
  73. $response = parent::getResponse();
  74. if ($blnForceCacheHeaders || 0 === strncmp('fe_', $this->strTemplate, 3))
  75. {
  76. return $this->setCacheHeaders($response);
  77. }
  78. return $response;
  79. }
  80. /**
  81. * Compile the template
  82. *
  83. * @throws UnusedArgumentsException If there are unused $_GET parameters
  84. *
  85. * @internal Do not call this method in your code. It will be made private in Contao 5.0.
  86. */
  87. protected function compile()
  88. {
  89. $this->keywords = '';
  90. // Backwards compatibility
  91. $arrKeywords = StringUtil::trimsplit(',', $GLOBALS['TL_KEYWORDS'] ?? '');
  92. // Add the meta keywords
  93. if (isset($arrKeywords[0]))
  94. {
  95. $this->keywords = str_replace(array("\n", "\r", '"'), array(' ', '', ''), implode(', ', array_unique($arrKeywords)));
  96. }
  97. // Parse the template
  98. $this->strBuffer = $this->parse();
  99. // HOOK: add custom output filters
  100. if (isset($GLOBALS['TL_HOOKS']['outputFrontendTemplate']) && \is_array($GLOBALS['TL_HOOKS']['outputFrontendTemplate']))
  101. {
  102. foreach ($GLOBALS['TL_HOOKS']['outputFrontendTemplate'] as $callback)
  103. {
  104. $this->import($callback[0]);
  105. $this->strBuffer = $this->{$callback[0]}->{$callback[1]}($this->strBuffer, $this->strTemplate);
  106. }
  107. }
  108. $this->strBuffer = System::getContainer()->get('contao.insert_tag.parser')->replace($this->strBuffer);
  109. $this->strBuffer = $this->replaceDynamicScriptTags($this->strBuffer); // see #4203
  110. // HOOK: allow to modify the compiled markup (see #4291)
  111. if (isset($GLOBALS['TL_HOOKS']['modifyFrontendPage']) && \is_array($GLOBALS['TL_HOOKS']['modifyFrontendPage']))
  112. {
  113. foreach ($GLOBALS['TL_HOOKS']['modifyFrontendPage'] as $callback)
  114. {
  115. $this->import($callback[0]);
  116. $this->strBuffer = $this->{$callback[0]}->{$callback[1]}($this->strBuffer, $this->strTemplate);
  117. }
  118. }
  119. // Check whether all $_GET parameters have been used (see #4277)
  120. if ($this->blnCheckRequest && Input::hasUnusedGet())
  121. {
  122. throw new UnusedArgumentsException('Unused arguments: ' . implode(', ', Input::getUnusedGet()));
  123. }
  124. /** @var PageModel|null $objPage */
  125. global $objPage;
  126. // Minify the markup
  127. if ($objPage !== null && $objPage->minifyMarkup)
  128. {
  129. $this->strBuffer = $this->minifyHtml($this->strBuffer);
  130. }
  131. // Replace literal insert tags (see #670, #3249)
  132. $this->strBuffer = preg_replace_callback(
  133. '/<script[^>]*>.*?<\/script[^>]*>|\[[{}]]/is',
  134. static function ($matches)
  135. {
  136. return $matches[0][0] === '<' ? $matches[0] : '&#' . \ord($matches[0][1]) . ';&#' . \ord($matches[0][1]) . ';';
  137. },
  138. $this->strBuffer
  139. );
  140. parent::compile();
  141. }
  142. /**
  143. * Set the cache headers according to the page settings.
  144. *
  145. * @param Response $response The response object
  146. *
  147. * @return Response The response object
  148. */
  149. private function setCacheHeaders(Response $response)
  150. {
  151. /** @var PageModel $objPage */
  152. global $objPage;
  153. // Do not cache the response if caching was not configured at all or disabled explicitly
  154. if (($objPage->cache === false || $objPage->cache < 1) && ($objPage->clientCache === false || $objPage->clientCache < 1))
  155. {
  156. $response->headers->set('Cache-Control', 'no-cache, no-store');
  157. return $response->setPrivate(); // Make sure the response is private
  158. }
  159. // Private cache
  160. if ($objPage->clientCache > 0)
  161. {
  162. $response->setMaxAge($objPage->clientCache);
  163. $response->setPrivate(); // Make sure the response is private
  164. }
  165. // Shared cache
  166. if ($objPage->cache > 0)
  167. {
  168. $response->setSharedMaxAge($objPage->cache); // Automatically sets the response to public
  169. // We vary on cookies if a response is cacheable by the shared
  170. // cache, so a reverse proxy does not load a response from cache if
  171. // the _request_ contains a cookie.
  172. //
  173. // This DOES NOT mean that we generate a cache entry for every
  174. // response containing a cookie! Responses with cookies will always
  175. // be private (@see Contao\CoreBundle\EventListener\MakeResponsePrivateListener).
  176. //
  177. // However, we want to be able to force the reverse proxy to load a
  178. // response from cache, even if the request contains a cookie – in
  179. // case the admin has configured to do so. A typical use case would
  180. // be serving public pages from cache to logged in members.
  181. if (!$objPage->alwaysLoadFromCache)
  182. {
  183. $response->setVary(array('Cookie'));
  184. }
  185. // Tag the page (see #2137)
  186. System::getContainer()->get('contao.cache.entity_tags')->tagWithModelInstance($objPage);
  187. }
  188. return $response;
  189. }
  190. }
  191. class_alias(FrontendTemplate::class, 'FrontendTemplate');