‪TYPO3CMS  9.5
RequestHandler.php
Go to the documentation of this file.
1 <?php
2 declare(strict_types = 1);
3 
5 
6 /*
7  * This file is part of the TYPO3 CMS project.
8  *
9  * It is free software; you can redistribute it and/or modify it under
10  * the terms of the GNU General Public License, either version 2
11  * of the License, or any later version.
12  *
13  * For the full copyright and license information, please read the
14  * LICENSE.txt file that was distributed with this source code.
15  *
16  * The TYPO3 project - inspiring people to share!
17  */
18 
19 use Psr\Http\Message\ResponseInterface;
20 use Psr\Http\Message\ServerRequestInterface;
21 use Psr\Http\Server\RequestHandlerInterface as PsrRequestHandlerInterface;
37 
59 class ‪RequestHandler implements ‪RequestHandlerInterface, PsrRequestHandlerInterface
60 {
65  protected ‪$timeTracker;
66 
73  public function ‪handleRequest(ServerRequestInterface $request): ResponseInterface
74  {
75  return $this->‪handle($request);
76  }
77 
85  protected function ‪addModifiedGlobalsToIncomingRequest(ServerRequestInterface $request): ServerRequestInterface
86  {
87  $originalGetParameters = $request->getAttribute('_originalGetParameters', null);
88  if ($originalGetParameters !== null && !empty($_GET) && $_GET !== $originalGetParameters) {
89  // Find out what has been changed.
90  $modifiedGetParameters = ‪ArrayUtility::arrayDiffAssocRecursive($_GET ?? [], $originalGetParameters);
91  if (!empty($modifiedGetParameters)) {
92  $queryParams = array_replace_recursive($modifiedGetParameters, $request->getQueryParams());
93  $request = $request->withQueryParams($queryParams);
94  ‪$GLOBALS['TYPO3_REQUEST'] = $request;
95  $this->timeTracker->setTSlogMessage('GET parameters have been modified during Request building in a hook.');
96  }
97  }
98  // do same for $_POST if the request is a POST request
99  $originalPostParameters = $request->getAttribute('_originalPostParameters', null);
100  if ($request->getMethod() === 'POST' && $originalPostParameters !== null && !empty($_POST) && $_POST !== $originalPostParameters) {
101  // Find out what has been changed
102  $modifiedPostParameters = ‪ArrayUtility::arrayDiffAssocRecursive($_POST ?? [], $originalPostParameters);
103  if (!empty($modifiedPostParameters)) {
104  $parsedBody = array_replace_recursive($modifiedPostParameters, $request->getParsedBody());
105  $request = $request->withParsedBody($parsedBody);
106  ‪$GLOBALS['TYPO3_REQUEST'] = $request;
107  $this->timeTracker->setTSlogMessage('POST parameters have been modified during Request building in a hook.');
108  }
109  }
110  return $request;
111  }
112 
122  protected function ‪resetGlobalsToCurrentRequest(ServerRequestInterface $request)
123  {
124  if ($request->getQueryParams() !== $_GET) {
125  $queryParams = $request->getQueryParams();
126  $_GET = $queryParams;
127  ‪$GLOBALS['HTTP_GET_VARS'] = $_GET;
128  }
129  if ($request->getMethod() === 'POST') {
130  $parsedBody = $request->getParsedBody();
131  if (is_array($parsedBody) && $parsedBody !== $_POST) {
132  $_POST = $parsedBody;
133  ‪$GLOBALS['HTTP_POST_VARS'] = $_POST;
134  }
135  }
136  }
143  public function ‪handle(ServerRequestInterface $request): ResponseInterface
144  {
145  // Fetch the initialized time tracker object
146  $this->timeTracker = GeneralUtility::makeInstance(TimeTracker::class);
148  $controller = ‪$GLOBALS['TSFE'];
149 
150  // safety net, will be removed in TYPO3 v10.0. Aligns $_GET/$_POST to the incoming request.
151  $request = $this->‪addModifiedGlobalsToIncomingRequest($request);
152  $this->‪resetGlobalsToCurrentRequest($request);
153 
154  // Generate page
155  if ($controller->isGeneratePage()) {
156  $this->timeTracker->push('Page generation');
157  $controller->generatePage_preProcessing();
158  $controller->preparePageContentGeneration($request);
159 
160  // Content generation
161  $this->timeTracker->incStackPointer();
162  $this->timeTracker->push($controller->sPre, 'PAGE');
163 
164  // If 'disableAllHeaderCode' is set, all the header-code is discarded
165  if ($controller->config['config']['disableAllHeaderCode'] ?? false) {
166  $controller->content = $this->‪generatePageContent($controller);
167  } else {
168  $controller->content = $this->‪generatePageContentWithHeader($controller, $request->getAttribute('language', null));
169  }
170 
171  $this->timeTracker->pull($this->timeTracker->LR ? $controller->content : '');
172  $this->timeTracker->decStackPointer();
173 
174  $controller->setAbsRefPrefix();
175  $controller->generatePage_postProcessing();
176  $this->timeTracker->pull();
177  }
178  $controller->releaseLocks();
179 
180  // Render non-cached page parts by replacing placeholders which are taken from cache or added during page generation
181  if ($controller->isINTincScript()) {
182  if (!$controller->isGeneratePage()) {
183  // When page was generated, this was already called. Avoid calling this twice.
184  $controller->preparePageContentGeneration($request);
185  }
186  $this->timeTracker->push('Non-cached objects');
187  $controller->INTincScript();
188  $this->timeTracker->pull();
189  }
190 
191  // Create a Response object when sending content
192  $response = new ‪Response();
193 
194  // Output content
195  $isOutputting = $controller->isOutputting();
196  if ($isOutputting) {
197  $this->timeTracker->push('Print Content');
198  $response = $controller->applyHttpHeadersToResponse($response);
199  $controller->processContentForOutput();
200  $this->timeTracker->pull();
201  }
202  // Store session data for fe_users
203  $controller->fe_user->storeSessionData();
204 
205  // @deprecated since TYPO3 v9.3, will be removed in TYPO3 v10.0.
206  $redirectResponse = $controller->redirectToExternalUrl(true);
207  if ($redirectResponse instanceof ResponseInterface) {
208  $controller->sendHttpHeadersDirectly();
209  return $redirectResponse;
210  }
211 
212  // Statistics
213  ‪$GLOBALS['TYPO3_MISC']['microtime_end'] = microtime(true);
214  if ($isOutputting && ($controller->config['config']['debug'] ?? !empty(‪$GLOBALS['TYPO3_CONF_VARS']['FE']['debug']))) {
215  $response = $response->withHeader('X-TYPO3-Parsetime', $this->timeTracker->getParseTime() . 'ms');
216  }
217 
218  // Preview info
219  // @deprecated since TYPO3 v9.4, will be removed in TYPO3 v10.0.
220  $controller->previewInfo(true);
221 
222  // Hook for "end-of-frontend"
223  $_params = ['pObj' => &$controller];
224  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['hook_eofe'] ?? [] as $_funcRef) {
225  GeneralUtility::callUserFunction($_funcRef, $_params, $controller);
226  }
227 
228  // Finish time tracking (started in TYPO3\CMS\Frontend\Middleware\TimeTrackerInitialization)
229  $this->timeTracker->pull();
230 
231  if ($isOutputting) {
232  $response->getBody()->write($controller->content);
233  }
234 
235  return $isOutputting ? $response : new ‪NullResponse();
236  }
237 
244  protected function ‪generatePageContent(‪TypoScriptFrontendController $controller): string
245  {
246  $pageContent = $controller->cObj->cObjGet($controller->pSetup) ?: '';
247  if ($controller->pSetup['wrap'] ?? false) {
248  $pageContent = $controller->cObj->wrap($pageContent, $controller->pSetup['wrap']);
249  }
250  if ($controller->pSetup['stdWrap.'] ?? false) {
251  $pageContent = $controller->cObj->stdWrap($pageContent, $controller->pSetup['stdWrap.']);
252  }
253  return $pageContent;
254  }
255 
265  protected function ‪generatePageContentWithHeader(‪TypoScriptFrontendController $controller, ?‪SiteLanguage $siteLanguage): string
266  {
267  // Generate the page content, this has to be first, as some additional TSFE-related code could have been written
268  $pageContent = $this->‪generatePageContent($controller);
269  $pageRenderer = $this->‪getPageRenderer();
270  if ($controller->config['config']['moveJsFromHeaderToFooter'] ?? false) {
271  $pageRenderer->enableMoveJsFromHeaderToFooter();
272  }
273  if ($controller->config['config']['pageRendererTemplateFile'] ?? false) {
274  try {
275  $file = GeneralUtility::makeInstance(FilePathSanitizer::class)->sanitize($controller->config['config']['pageRendererTemplateFile']);
276  $pageRenderer->setTemplateFile($file);
277  } catch (\‪TYPO3\CMS\Core\Resource\‪Exception $e) {
278  // do nothing
279  }
280  }
281  $headerComment = trim($controller->config['config']['headerComment'] ?? '');
282  if ($headerComment) {
283  $pageRenderer->addInlineComment("\t" . str_replace(LF, LF . "\t", $headerComment) . LF);
284  }
285  // Setting charset:
286  $theCharset = $controller->metaCharset;
287  // Reset the content variables:
288  $controller->content = '';
289  $htmlTagAttributes = [];
290  $htmlLang = $controller->config['config']['htmlTag_langKey'] ?? ($controller->sys_language_isocode ?: 'en');
291  $direction = $controller->config['config']['htmlTag_dir'] ?? null;
292  if ($siteLanguage !== null) {
293  $direction = $siteLanguage->‪getDirection();
294  $htmlLang = $siteLanguage->‪getHreflang();
295  }
296 
297  if ($direction) {
298  $htmlTagAttributes['dir'] = htmlspecialchars($direction);
299  }
300  // Setting document type:
301  $docTypeParts = [];
302  $xmlDocument = true;
303  // Part 1: XML prologue
304  switch ((string)($controller->config['config']['xmlprologue'] ?? '')) {
305  case 'none':
306  $xmlDocument = false;
307  break;
308  case 'xml_10':
309  $docTypeParts[] = '<?xml version="1.0" encoding="' . $theCharset . '"?>';
310  break;
311  case 'xml_11':
312  $docTypeParts[] = '<?xml version="1.1" encoding="' . $theCharset . '"?>';
313  break;
314  case '':
315  if ($controller->xhtmlVersion) {
316  $docTypeParts[] = '<?xml version="1.0" encoding="' . $theCharset . '"?>';
317  } else {
318  $xmlDocument = false;
319  }
320  break;
321  default:
322  $docTypeParts[] = $controller->config['config']['xmlprologue'];
323  }
324  // Part 2: DTD
325  $doctype = $controller->config['config']['doctype'] ?? null;
326  if ($doctype) {
327  switch ($doctype) {
328  case 'xhtml_trans':
329  $docTypeParts[] = '<!DOCTYPE html
330  PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
331  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">';
332  break;
333  case 'xhtml_strict':
334  $docTypeParts[] = '<!DOCTYPE html
335  PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
336  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
337  break;
338  case 'xhtml_basic':
339  $docTypeParts[] = '<!DOCTYPE html
340  PUBLIC "-//W3C//DTD XHTML Basic 1.0//EN"
341  "http://www.w3.org/TR/xhtml-basic/xhtml-basic10.dtd">';
342  break;
343  case 'xhtml_11':
344  $docTypeParts[] = '<!DOCTYPE html
345  PUBLIC "-//W3C//DTD XHTML 1.1//EN"
346  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">';
347  break;
348  case 'xhtml+rdfa_10':
349  $docTypeParts[] = '<!DOCTYPE html
350  PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN"
351  "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd">';
352  break;
353  case 'html5':
354  $docTypeParts[] = '<!DOCTYPE html>';
355  if ($xmlDocument) {
356  $pageRenderer->setMetaCharsetTag('<meta charset="|" />');
357  } else {
358  $pageRenderer->setMetaCharsetTag('<meta charset="|">');
359  }
360  break;
361  case 'none':
362  break;
363  default:
364  $docTypeParts[] = $doctype;
365  }
366  } else {
367  $docTypeParts[] = '<!DOCTYPE html>';
368  if ($xmlDocument) {
369  $pageRenderer->setMetaCharsetTag('<meta charset="|" />');
370  } else {
371  $pageRenderer->setMetaCharsetTag('<meta charset="|">');
372  }
373  }
374  if ($controller->xhtmlVersion) {
375  $htmlTagAttributes['xml:lang'] = $htmlLang;
376  }
377  if ($controller->xhtmlVersion < 110 || $doctype === 'html5') {
378  $htmlTagAttributes['lang'] = $htmlLang;
379  }
380  if ($controller->xhtmlVersion || $doctype === 'html5' && $xmlDocument) {
381  // We add this to HTML5 to achieve a slightly better backwards compatibility
382  $htmlTagAttributes['xmlns'] = 'http://www.w3.org/1999/xhtml';
383  if (is_array($controller->config['config']['namespaces.'])) {
384  foreach ($controller->config['config']['namespaces.'] as $prefix => $uri) {
385  // $uri gets htmlspecialchared later
386  $htmlTagAttributes['xmlns:' . htmlspecialchars($prefix)] = $uri;
387  }
388  }
389  }
390  // Swap XML and doctype order around (for MSIE / Opera standards compliance)
391  if ($controller->config['config']['doctypeSwitch'] ?? false) {
392  $docTypeParts = array_reverse($docTypeParts);
393  }
394  // Adding doctype parts:
395  if (!empty($docTypeParts)) {
396  $pageRenderer->setXmlPrologAndDocType(implode(LF, $docTypeParts));
397  }
398  // Begin header section:
399  $htmlTag = $this->‪generateHtmlTag($htmlTagAttributes, $controller->config['config'] ?? [], $controller->cObj);
400  $pageRenderer->setHtmlTag($htmlTag);
401  // Head tag:
402  $headTag = $controller->pSetup['headTag'] ?? '<head>';
403  if (isset($controller->pSetup['headTag.'])) {
404  $headTag = $controller->cObj->stdWrap($headTag, $controller->pSetup['headTag.']);
405  }
406  $pageRenderer->setHeadTag($headTag);
407  // Setting charset meta tag:
408  $pageRenderer->setCharSet($theCharset);
409  $pageRenderer->addInlineComment(' This website is powered by TYPO3 - inspiring people to share!
410  TYPO3 is a free open source Content Management Framework initially created by Kasper Skaarhoj and licensed under GNU/GPL.
411  TYPO3 is copyright ' . TYPO3_copyright_year . ' of Kasper Skaarhoj. Extensions are copyright of their respective owners.
412  Information and contribution at ' . TYPO3_URL_GENERAL . '
413 ');
414  if ($controller->baseUrl) {
415  $pageRenderer->setBaseUrl($controller->baseUrl);
416  }
417  if ($controller->pSetup['shortcutIcon'] ?? false) {
418  try {
419  $favIcon = GeneralUtility::makeInstance(FilePathSanitizer::class)->sanitize($controller->pSetup['shortcutIcon']);
420  $iconFileInfo = GeneralUtility::makeInstance(ImageInfo::class, ‪Environment::getPublicPath() . '/' . $favIcon);
421  if ($iconFileInfo->isFile()) {
422  $iconMimeType = $iconFileInfo->getMimeType();
423  if ($iconMimeType) {
424  $iconMimeType = ' type="' . $iconMimeType . '"';
425  $pageRenderer->setIconMimeType($iconMimeType);
426  }
427  $pageRenderer->setFavIcon(‪PathUtility::getAbsoluteWebPath($controller->absRefPrefix . $favIcon));
428  }
429  } catch (\‪TYPO3\CMS\Core\Resource\‪Exception $e) {
430  // do nothing
431  }
432  }
433  // Including CSS files
434  if (isset($controller->tmpl->setup['plugin.']) && is_array($controller->tmpl->setup['plugin.'])) {
435  $stylesFromPlugins = '';
436  foreach ($controller->tmpl->setup['plugin.'] as $key => $iCSScode) {
437  if (is_array($iCSScode)) {
438  if ($iCSScode['_CSS_DEFAULT_STYLE'] && empty($controller->config['config']['removeDefaultCss'])) {
439  if (isset($iCSScode['_CSS_DEFAULT_STYLE.'])) {
440  $cssDefaultStyle = $controller->cObj->stdWrap($iCSScode['_CSS_DEFAULT_STYLE'], $iCSScode['_CSS_DEFAULT_STYLE.']);
441  } else {
442  $cssDefaultStyle = $iCSScode['_CSS_DEFAULT_STYLE'];
443  }
444  $stylesFromPlugins .= '/* default styles for extension "' . substr($key, 0, -1) . '" */' . LF . $cssDefaultStyle . LF;
445  }
446  if ($iCSScode['_CSS_PAGE_STYLE'] && empty($controller->config['config']['removePageCss'])) {
447  $cssPageStyle = implode(LF, $iCSScode['_CSS_PAGE_STYLE']);
448  if (isset($iCSScode['_CSS_PAGE_STYLE.'])) {
449  $cssPageStyle = $controller->cObj->stdWrap($cssPageStyle, $iCSScode['_CSS_PAGE_STYLE.']);
450  }
451  $cssPageStyle = '/* specific page styles for extension "' . substr($key, 0, -1) . '" */' . LF . $cssPageStyle;
452  $this->‪addCssToPageRenderer($controller, $cssPageStyle, true, 'InlinePageCss');
453  }
454  }
455  }
456  if (!empty($stylesFromPlugins)) {
457  $this->‪addCssToPageRenderer($controller, $stylesFromPlugins, false, 'InlineDefaultCss');
458  }
459  }
460  /**********************************************************************/
461  /* config.includeCSS / config.includeCSSLibs
462  /**********************************************************************/
463  if (isset($controller->pSetup['includeCSS.']) && is_array($controller->pSetup['includeCSS.'])) {
464  foreach ($controller->pSetup['includeCSS.'] as $key => $CSSfile) {
465  if (!is_array($CSSfile)) {
466  $cssFileConfig = &$controller->pSetup['includeCSS.'][$key . '.'];
467  if (isset($cssFileConfig['if.']) && !$controller->cObj->checkIf($cssFileConfig['if.'])) {
468  continue;
469  }
470  if ($cssFileConfig['external']) {
471  $ss = $CSSfile;
472  } else {
473  try {
474  $ss = GeneralUtility::makeInstance(FilePathSanitizer::class)->sanitize($CSSfile);
475  } catch (\‪TYPO3\CMS\Core\Resource\‪Exception $e) {
476  $ss = null;
477  }
478  }
479  if ($ss) {
480  if ($cssFileConfig['import']) {
481  if (!$cssFileConfig['external'] && $ss[0] !== '/') {
482  // To fix MSIE 6 that cannot handle these as relative paths (according to Ben v Ende)
483  $ss = GeneralUtility::dirname(GeneralUtility::getIndpEnv('SCRIPT_NAME')) . '/' . $ss;
484  }
485  $cssMedia = !empty($cssFileConfig['media']) ? ' ' . htmlspecialchars($cssFileConfig['media']) : '';
486  $pageRenderer->addCssInlineBlock('import_' . $key, '@import url("' . htmlspecialchars($ss) . '")' . $cssMedia . ';', empty($cssFileConfig['disableCompression']), (bool)$cssFileConfig['forceOnTop']);
487  } else {
488  $pageRenderer->addCssFile(
489  $ss,
490  $cssFileConfig['alternate'] ? 'alternate stylesheet' : 'stylesheet',
491  $cssFileConfig['media'] ?: 'all',
492  $cssFileConfig['title'] ?: '',
493  $cssFileConfig['external'] || (bool)$cssFileConfig['inline'] ? false : empty($cssFileConfig['disableCompression']),
494  (bool)$cssFileConfig['forceOnTop'],
495  $cssFileConfig['allWrap'],
496  (bool)$cssFileConfig['excludeFromConcatenation'] || (bool)$cssFileConfig['inline'],
497  $cssFileConfig['allWrap.']['splitChar'],
498  $cssFileConfig['inline']
499  );
500  unset($cssFileConfig);
501  }
502  }
503  }
504  }
505  }
506  if (isset($controller->pSetup['includeCSSLibs.']) && is_array($controller->pSetup['includeCSSLibs.'])) {
507  foreach ($controller->pSetup['includeCSSLibs.'] as $key => $CSSfile) {
508  if (!is_array($CSSfile)) {
509  $cssFileConfig = &$controller->pSetup['includeCSSLibs.'][$key . '.'];
510  if (isset($cssFileConfig['if.']) && !$controller->cObj->checkIf($cssFileConfig['if.'])) {
511  continue;
512  }
513  if ($cssFileConfig['external']) {
514  $ss = $CSSfile;
515  } else {
516  try {
517  $ss = GeneralUtility::makeInstance(FilePathSanitizer::class)->sanitize($CSSfile);
518  } catch (\‪TYPO3\CMS\Core\Resource\‪Exception $e) {
519  $ss = null;
520  }
521  }
522  if ($ss) {
523  if ($cssFileConfig['import']) {
524  if (!$cssFileConfig['external'] && $ss[0] !== '/') {
525  // To fix MSIE 6 that cannot handle these as relative paths (according to Ben v Ende)
526  $ss = GeneralUtility::dirname(GeneralUtility::getIndpEnv('SCRIPT_NAME')) . '/' . $ss;
527  }
528  $cssMedia = !empty($cssFileConfig['media']) ? ' ' . htmlspecialchars($cssFileConfig['media']) : '';
529  $pageRenderer->addCssInlineBlock('import_' . $key, '@import url("' . htmlspecialchars($ss) . '")' . $cssMedia . ';', empty($cssFileConfig['disableCompression']), (bool)$cssFileConfig['forceOnTop']);
530  } else {
531  $pageRenderer->addCssLibrary(
532  $ss,
533  $cssFileConfig['alternate'] ? 'alternate stylesheet' : 'stylesheet',
534  $cssFileConfig['media'] ?: 'all',
535  $cssFileConfig['title'] ?: '',
536  $cssFileConfig['external'] || (bool)$cssFileConfig['inline'] ? false : empty($cssFileConfig['disableCompression']),
537  (bool)$cssFileConfig['forceOnTop'],
538  $cssFileConfig['allWrap'],
539  (bool)$cssFileConfig['excludeFromConcatenation'] || (bool)$cssFileConfig['inline'],
540  $cssFileConfig['allWrap.']['splitChar'],
541  $cssFileConfig['inline']
542  );
543  unset($cssFileConfig);
544  }
545  }
546  }
547  }
548  }
549 
550  // CSS_inlineStyle from TS
551  $style = trim($controller->pSetup['CSS_inlineStyle'] ?? '');
552  $style .= $controller->cObj->cObjGet($controller->pSetup['cssInline.'] ?? null, 'cssInline.');
553  if (trim($style)) {
554  $this->‪addCssToPageRenderer($controller, $style, true, 'additionalTSFEInlineStyle');
555  }
556  // Javascript Libraries
557  if (isset($controller->pSetup['javascriptLibs.']) && is_array($controller->pSetup['javascriptLibs.'])) {
558  // @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0, the setting page.javascriptLibs has been deprecated and will be removed in TYPO3 v10.0.
559  trigger_error('The setting page.javascriptLibs will be removed in TYPO3 v10.0.', E_USER_DEPRECATED);
560 
561  // Include jQuery into the page renderer
562  if (!empty($controller->pSetup['javascriptLibs.']['jQuery'])) {
563  // @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0, the setting page.javascriptLibs.jQuery has been deprecated and will be removed in TYPO3 v10.0.
564  trigger_error('The setting page.javascriptLibs.jQuery will be removed in TYPO3 v10.0.', E_USER_DEPRECATED);
565 
566  $jQueryTS = $controller->pSetup['javascriptLibs.']['jQuery.'];
567  // Check if version / source is set, if not set variable to "NULL" to use the default of the page renderer
568  $version = $jQueryTS['version'] ?? null;
569  $source = $jQueryTS['source'] ?? null;
570  // When "noConflict" is not set or "1" enable the default jQuery noConflict mode, otherwise disable the namespace
571  if (!isset($jQueryTS['noConflict']) || !empty($jQueryTS['noConflict'])) {
572  $namespace = 'noConflict';
573  } else {
575  }
576  $pageRenderer->loadJquery($version, $source, $namespace, true);
577  }
578  }
579  // JavaScript library files
580  if (isset($controller->pSetup['includeJSLibs.']) && is_array($controller->pSetup['includeJSLibs.'])) {
581  foreach ($controller->pSetup['includeJSLibs.'] as $key => $JSfile) {
582  if (!is_array($JSfile)) {
583  if (isset($controller->pSetup['includeJSLibs.'][$key . '.']['if.']) && !$controller->cObj->checkIf($controller->pSetup['includeJSLibs.'][$key . '.']['if.'])) {
584  continue;
585  }
586  if ($controller->pSetup['includeJSLibs.'][$key . '.']['external']) {
587  $ss = $JSfile;
588  } else {
589  try {
590  $ss = GeneralUtility::makeInstance(FilePathSanitizer::class)->sanitize($JSfile);
591  } catch (\‪TYPO3\CMS\Core\Resource\‪Exception $e) {
592  $ss = null;
593  }
594  }
595  if ($ss) {
596  $jsFileConfig = &$controller->pSetup['includeJSLibs.'][$key . '.'];
597  $type = $jsFileConfig['type'];
598  if (!$type) {
599  $type = 'text/javascript';
600  }
601  $crossOrigin = $jsFileConfig['crossorigin'];
602  if (!$crossOrigin && $jsFileConfig['integrity'] && $jsFileConfig['external']) {
603  $crossOrigin = 'anonymous';
604  }
605  $pageRenderer->addJsLibrary(
606  $key,
607  $ss,
608  $type,
609  $jsFileConfig['external'] ? false : empty($jsFileConfig['disableCompression']),
610  (bool)$jsFileConfig['forceOnTop'],
611  $jsFileConfig['allWrap'],
612  (bool)$jsFileConfig['excludeFromConcatenation'],
613  $jsFileConfig['allWrap.']['splitChar'],
614  (bool)$jsFileConfig['async'],
615  $jsFileConfig['integrity'],
616  (bool)$jsFileConfig['defer'],
617  $crossOrigin
618  );
619  unset($jsFileConfig);
620  }
621  }
622  }
623  }
624  if (isset($controller->pSetup['includeJSFooterlibs.']) && is_array($controller->pSetup['includeJSFooterlibs.'])) {
625  foreach ($controller->pSetup['includeJSFooterlibs.'] as $key => $JSfile) {
626  if (!is_array($JSfile)) {
627  if (isset($controller->pSetup['includeJSFooterlibs.'][$key . '.']['if.']) && !$controller->cObj->checkIf($controller->pSetup['includeJSFooterlibs.'][$key . '.']['if.'])) {
628  continue;
629  }
630  if ($controller->pSetup['includeJSFooterlibs.'][$key . '.']['external']) {
631  $ss = $JSfile;
632  } else {
633  try {
634  $ss = GeneralUtility::makeInstance(FilePathSanitizer::class)->sanitize($JSfile);
635  } catch (\‪TYPO3\CMS\Core\Resource\‪Exception $e) {
636  $ss = null;
637  }
638  }
639  if ($ss) {
640  $jsFileConfig = &$controller->pSetup['includeJSFooterlibs.'][$key . '.'];
641  $type = $jsFileConfig['type'];
642  if (!$type) {
643  $type = 'text/javascript';
644  }
645  $crossorigin = $jsFileConfig['crossorigin'];
646  if (!$crossorigin && $jsFileConfig['integrity'] && $jsFileConfig['external']) {
647  $crossorigin = 'anonymous';
648  }
649  $pageRenderer->addJsFooterLibrary(
650  $key,
651  $ss,
652  $type,
653  $jsFileConfig['external'] ? false : empty($jsFileConfig['disableCompression']),
654  (bool)$jsFileConfig['forceOnTop'],
655  $jsFileConfig['allWrap'],
656  (bool)$jsFileConfig['excludeFromConcatenation'],
657  $jsFileConfig['allWrap.']['splitChar'],
658  (bool)$jsFileConfig['async'],
659  $jsFileConfig['integrity'],
660  (bool)$jsFileConfig['defer'],
661  $crossorigin
662  );
663  unset($jsFileConfig);
664  }
665  }
666  }
667  }
668  // JavaScript files
669  if (isset($controller->pSetup['includeJS.']) && is_array($controller->pSetup['includeJS.'])) {
670  foreach ($controller->pSetup['includeJS.'] as $key => $JSfile) {
671  if (!is_array($JSfile)) {
672  if (isset($controller->pSetup['includeJS.'][$key . '.']['if.']) && !$controller->cObj->checkIf($controller->pSetup['includeJS.'][$key . '.']['if.'])) {
673  continue;
674  }
675  if ($controller->pSetup['includeJS.'][$key . '.']['external']) {
676  $ss = $JSfile;
677  } else {
678  try {
679  $ss = GeneralUtility::makeInstance(FilePathSanitizer::class)->sanitize($JSfile);
680  } catch (\‪TYPO3\CMS\Core\Resource\‪Exception $e) {
681  $ss = null;
682  }
683  }
684  if ($ss) {
685  $jsConfig = &$controller->pSetup['includeJS.'][$key . '.'];
686  $type = $jsConfig['type'];
687  if (!$type) {
688  $type = 'text/javascript';
689  }
690  $crossorigin = $jsConfig['crossorigin'];
691  if (!$crossorigin && $jsConfig['integrity'] && $jsConfig['external']) {
692  $crossorigin = 'anonymous';
693  }
694  $pageRenderer->addJsFile(
695  $ss,
696  $type,
697  $jsConfig['external'] ? false : empty($jsConfig['disableCompression']),
698  (bool)$jsConfig['forceOnTop'],
699  $jsConfig['allWrap'],
700  (bool)$jsConfig['excludeFromConcatenation'],
701  $jsConfig['allWrap.']['splitChar'],
702  (bool)$jsConfig['async'],
703  $jsConfig['integrity'],
704  (bool)$jsConfig['defer'],
705  $crossorigin
706  );
707  unset($jsConfig);
708  }
709  }
710  }
711  }
712  if (isset($controller->pSetup['includeJSFooter.']) && is_array($controller->pSetup['includeJSFooter.'])) {
713  foreach ($controller->pSetup['includeJSFooter.'] as $key => $JSfile) {
714  if (!is_array($JSfile)) {
715  if (isset($controller->pSetup['includeJSFooter.'][$key . '.']['if.']) && !$controller->cObj->checkIf($controller->pSetup['includeJSFooter.'][$key . '.']['if.'])) {
716  continue;
717  }
718  if ($controller->pSetup['includeJSFooter.'][$key . '.']['external']) {
719  $ss = $JSfile;
720  } else {
721  try {
722  $ss = GeneralUtility::makeInstance(FilePathSanitizer::class)->sanitize($JSfile);
723  } catch (\‪TYPO3\CMS\Core\Resource\‪Exception $e) {
724  $ss = null;
725  }
726  }
727  if ($ss) {
728  $jsConfig = &$controller->pSetup['includeJSFooter.'][$key . '.'];
729  $type = $jsConfig['type'];
730  if (!$type) {
731  $type = 'text/javascript';
732  }
733  $crossorigin = $jsConfig['crossorigin'];
734  if (!$crossorigin && $jsConfig['integrity'] && $jsConfig['external']) {
735  $crossorigin = 'anonymous';
736  }
737  $pageRenderer->addJsFooterFile(
738  $ss,
739  $type,
740  $jsConfig['external'] ? false : empty($jsConfig['disableCompression']),
741  (bool)$jsConfig['forceOnTop'],
742  $jsConfig['allWrap'],
743  (bool)$jsConfig['excludeFromConcatenation'],
744  $jsConfig['allWrap.']['splitChar'],
745  (bool)$jsConfig['async'],
746  $jsConfig['integrity'],
747  (bool)$jsConfig['defer'],
748  $crossorigin
749  );
750  unset($jsConfig);
751  }
752  }
753  }
754  }
755  // Headerdata
756  if (isset($controller->pSetup['headerData.']) && is_array($controller->pSetup['headerData.'])) {
757  $pageRenderer->addHeaderData($controller->cObj->cObjGet($controller->pSetup['headerData.'], 'headerData.'));
758  }
759  // Footerdata
760  if (isset($controller->pSetup['footerData.']) && is_array($controller->pSetup['footerData.'])) {
761  $pageRenderer->addFooterData($controller->cObj->cObjGet($controller->pSetup['footerData.'], 'footerData.'));
762  }
763  $controller->‪generatePageTitle();
764 
765  // @internal hook for EXT:seo, will be gone soon, do not use it in your own extensions
766  $_params = ['page' => $controller->page];
767  $_ref = '';
768  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['TYPO3\CMS\Frontend\Page\PageGenerator']['generateMetaTags'] ?? [] as $_funcRef) {
769  GeneralUtility::callUserFunction($_funcRef, $_params, $_ref);
770  }
771 
772  $this->‪generateMetaTagHtml(
773  $controller->pSetup['meta.'] ?? [],
774  $controller->cObj
775  );
776 
777  unset($controller->additionalHeaderData['JSCode']);
778  if (isset($controller->config['INTincScript']) && is_array($controller->config['INTincScript'])) {
779  $controller->additionalHeaderData['JSCode'] = $controller->JSCode;
780  // Storing the JSCode vars...
781  $controller->config['INTincScript_ext']['divKey'] = $controller->‪uniqueHash();
782  $controller->config['INTincScript_ext']['additionalHeaderData'] = $controller->additionalHeaderData;
783  // Storing the header-data array
784  $controller->config['INTincScript_ext']['additionalFooterData'] = $controller->additionalFooterData;
785  // Storing the footer-data array
786  $controller->config['INTincScript_ext']['additionalJavaScript'] = $controller->additionalJavaScript;
787  // Storing the JS-data array
788  $controller->config['INTincScript_ext']['additionalCSS'] = $controller->additionalCSS;
789  // Storing the Style-data array
790  $controller->additionalHeaderData = ['<!--HD_' . $controller->config['INTincScript_ext']['divKey'] . '-->'];
791  // Clearing the array
792  $controller->additionalFooterData = ['<!--FD_' . $controller->config['INTincScript_ext']['divKey'] . '-->'];
793  // Clearing the array
794  $controller->divSection .= '<!--TDS_' . $controller->config['INTincScript_ext']['divKey'] . '-->';
795  } else {
796  $controller->‪INTincScript_loadJSCode();
797  }
798  $scriptJsCode = '';
799 
800  if ($controller->spamProtectEmailAddresses && $controller->spamProtectEmailAddresses !== 'ascii') {
801  $scriptJsCode = '
802  /* decrypt helper function */
803  function decryptCharcode(n,start,end,offset) {
804  n = n + offset;
805  if (offset > 0 && n > end) {
806  n = start + (n - end - 1);
807  } else if (offset < 0 && n < start) {
808  n = end - (start - n - 1);
809  }
810  return String.fromCharCode(n);
811  }
812  /* decrypt string */
813  function decryptString(enc,offset) {
814  var dec = "";
815  var len = enc.length;
816  for(var i=0; i < len; i++) {
817  var n = enc.charCodeAt(i);
818  if (n >= 0x2B && n <= 0x3A) {
819  dec += decryptCharcode(n,0x2B,0x3A,offset); /* 0-9 . , - + / : */
820  } else if (n >= 0x40 && n <= 0x5A) {
821  dec += decryptCharcode(n,0x40,0x5A,offset); /* A-Z @ */
822  } else if (n >= 0x61 && n <= 0x7A) {
823  dec += decryptCharcode(n,0x61,0x7A,offset); /* a-z */
824  } else {
825  dec += enc.charAt(i);
826  }
827  }
828  return dec;
829  }
830  /* decrypt spam-protected emails */
831  function linkTo_UnCryptMailto(s) {
832  location.href = decryptString(s,' . $controller->spamProtectEmailAddresses * -1 . ');
833  }
834  ';
835  }
836  // Add inline JS
837  $inlineJS = '';
838  // defined in php
839  if (is_array($controller->inlineJS)) {
840  foreach ($controller->inlineJS as $key => $val) {
841  if (!is_array($val)) {
842  $inlineJS .= LF . $val . LF;
843  }
844  }
845  }
846  // defined in TS with page.inlineJS
847  // Javascript inline code
848  $inline = $controller->cObj->cObjGet($controller->pSetup['jsInline.'] ?? null, 'jsInline.');
849  if ($inline) {
850  $inlineJS .= LF . $inline . LF;
851  }
852  // Javascript inline code for Footer
853  $inlineFooterJs = $controller->cObj->cObjGet($controller->pSetup['jsFooterInline.'] ?? null, 'jsFooterInline.');
854  // Should minify?
855  if ($controller->config['config']['compressJs'] ?? false) {
856  $pageRenderer->enableCompressJavascript();
857  $minifyErrorScript = ($minifyErrorInline = '');
858  $scriptJsCode = GeneralUtility::minifyJavaScript($scriptJsCode, $minifyErrorScript);
859  if ($minifyErrorScript) {
860  $this->timeTracker->setTSlogMessage($minifyErrorScript, 3);
861  }
862  if ($inlineJS) {
863  $inlineJS = GeneralUtility::minifyJavaScript($inlineJS, $minifyErrorInline);
864  if ($minifyErrorInline) {
865  $this->timeTracker->setTSlogMessage($minifyErrorInline, 3);
866  }
867  }
868  if ($inlineFooterJs) {
869  $inlineFooterJs = GeneralUtility::minifyJavaScript($inlineFooterJs, $minifyErrorInline);
870  if ($minifyErrorInline) {
871  $this->timeTracker->setTSlogMessage($minifyErrorInline, 3);
872  }
873  }
874  }
875  if (!isset($controller->config['config']['removeDefaultJS']) || !$controller->config['config']['removeDefaultJS']) {
876  // include default and inlineJS
877  if ($scriptJsCode) {
878  $pageRenderer->addJsInlineCode('_scriptCode', $scriptJsCode, $controller->config['config']['compressJs']);
879  }
880  if ($inlineJS) {
881  $pageRenderer->addJsInlineCode('TS_inlineJS', $inlineJS, $controller->config['config']['compressJs']);
882  }
883  if ($inlineFooterJs) {
884  $pageRenderer->addJsFooterInlineCode('TS_inlineFooter', $inlineFooterJs, $controller->config['config']['compressJs']);
885  }
886  } elseif ($controller->config['config']['removeDefaultJS'] === 'external') {
887  /*
888  * This keeps inlineJS from *_INT Objects from being moved to external files.
889  * At this point in frontend rendering *_INT Objects only have placeholders instead
890  * of actual content so moving these placeholders to external files would
891  * a) break the JS file (syntax errors due to the placeholders)
892  * b) the needed JS would never get included to the page
893  * Therefore inlineJS from *_INT Objects must not be moved to external files but
894  * kept internal.
895  */
896  $inlineJSint = '';
897  $this->‪stripIntObjectPlaceholder($inlineJS, $inlineJSint);
898  if ($inlineJSint) {
899  $pageRenderer->addJsInlineCode('TS_inlineJSint', $inlineJSint, $controller->config['config']['compressJs']);
900  }
901  if (trim($scriptJsCode . $inlineJS)) {
902  $pageRenderer->addJsFile(GeneralUtility::writeJavaScriptContentToTemporaryFile($scriptJsCode . $inlineJS), 'text/javascript', $controller->config['config']['compressJs']);
903  }
904  if ($inlineFooterJs) {
905  $inlineFooterJSint = '';
906  $this->‪stripIntObjectPlaceholder($inlineFooterJs, $inlineFooterJSint);
907  if ($inlineFooterJSint) {
908  $pageRenderer->addJsFooterInlineCode('TS_inlineFooterJSint', $inlineFooterJSint, $controller->config['config']['compressJs']);
909  }
910  $pageRenderer->addJsFooterFile(GeneralUtility::writeJavaScriptContentToTemporaryFile($inlineFooterJs), 'text/javascript', $controller->config['config']['compressJs']);
911  }
912  } else {
913  // Include only inlineJS
914  if ($inlineJS) {
915  $pageRenderer->addJsInlineCode('TS_inlineJS', $inlineJS, $controller->config['config']['compressJs']);
916  }
917  if ($inlineFooterJs) {
918  $pageRenderer->addJsFooterInlineCode('TS_inlineFooter', $inlineFooterJs, $controller->config['config']['compressJs']);
919  }
920  }
921  if (isset($controller->pSetup['inlineLanguageLabelFiles.']) && is_array($controller->pSetup['inlineLanguageLabelFiles.'])) {
922  foreach ($controller->pSetup['inlineLanguageLabelFiles.'] as $key => $languageFile) {
923  if (is_array($languageFile)) {
924  continue;
925  }
926  $languageFileConfig = &$controller->pSetup['inlineLanguageLabelFiles.'][$key . '.'];
927  if (isset($languageFileConfig['if.']) && !$controller->cObj->checkIf($languageFileConfig['if.'])) {
928  continue;
929  }
930  $pageRenderer->addInlineLanguageLabelFile(
931  $languageFile,
932  $languageFileConfig['selectionPrefix'] ?: '',
933  $languageFileConfig['stripFromSelectionName'] ?: ''
934  );
935  }
936  }
937  if (isset($controller->pSetup['inlineSettings.']) && is_array($controller->pSetup['inlineSettings.'])) {
938  $pageRenderer->addInlineSettingArray('TS', $controller->pSetup['inlineSettings.']);
939  }
940  // Compression and concatenate settings
941  if ($controller->config['config']['compressCss'] ?? false) {
942  $pageRenderer->enableCompressCss();
943  }
944  if ($controller->config['config']['compressJs'] ?? false) {
945  $pageRenderer->enableCompressJavascript();
946  }
947  if ($controller->config['config']['concatenateCss'] ?? false) {
948  $pageRenderer->enableConcatenateCss();
949  }
950  if ($controller->config['config']['concatenateJs'] ?? false) {
951  $pageRenderer->enableConcatenateJavascript();
952  }
953  // Backward compatibility for old configuration
954  // @deprecated - remove this option in TYPO3 v10.0.
955  if ($controller->config['config']['concatenateJsAndCss'] ?? false) {
956  trigger_error('Setting config.concatenateJsAndCss is deprecated in favor of config.concatenateJs and config.concatenateCss, and will have no effect anymore in TYPO3 v10.0.', E_USER_DEPRECATED);
957  $pageRenderer->enableConcatenateCss();
958  $pageRenderer->enableConcatenateJavascript();
959  }
960  // Add header data block
961  if ($controller->additionalHeaderData) {
962  $pageRenderer->addHeaderData(implode(LF, $controller->additionalHeaderData));
963  }
964  // Add footer data block
965  if ($controller->additionalFooterData) {
966  $pageRenderer->addFooterData(implode(LF, $controller->additionalFooterData));
967  }
968  // Header complete, now add content
969  // Bodytag:
970  if ($controller->config['config']['disableBodyTag'] ?? false) {
971  $bodyTag = '';
972  } else {
973  $defBT = (isset($controller->pSetup['bodyTagCObject']) && $controller->pSetup['bodyTagCObject'])
974  ? $controller->cObj->cObjGetSingle($controller->pSetup['bodyTagCObject'], $controller->pSetup['bodyTagCObject.'], 'bodyTagCObject')
975  : '<body>';
976  $bodyTag = (isset($controller->pSetup['bodyTag']) && $controller->pSetup['bodyTag'])
977  ? $controller->pSetup['bodyTag']
978  : $defBT;
979  if (trim($controller->pSetup['bodyTagAdd'] ?? '')) {
980  $bodyTag = preg_replace('/>$/', '', trim($bodyTag)) . ' ' . trim($controller->pSetup['bodyTagAdd']) . '>';
981  }
982  }
983  $pageRenderer->addBodyContent(LF . $bodyTag);
984  // Div-sections
985  if ($controller->divSection) {
986  $pageRenderer->addBodyContent(LF . $controller->divSection);
987  }
988  // Page content
989  $pageRenderer->addBodyContent(LF . $pageContent);
990  if (!empty($controller->config['INTincScript']) && is_array($controller->config['INTincScript'])) {
991  // Store the serialized pageRenderer in configuration
992  $controller->config['INTincScript_ext']['pageRenderer'] = serialize($pageRenderer);
993  // Render complete page, keep placeholders for JavaScript and CSS
994  $pageContent = $pageRenderer->renderPageWithUncachedObjects($controller->config['INTincScript_ext']['divKey']);
995  } else {
996  // Render complete page
997  $pageContent = $pageRenderer->render();
998  }
999  return $pageContent ?: '';
1000  }
1001 
1002  /*************************
1003  *
1004  * Helper functions
1005  *
1006  *************************/
1007 
1015  protected function ‪stripIntObjectPlaceholder(&$searchString, &$intObjects)
1016  {
1017  $tempArray = [];
1018  preg_match_all('/\\<\\!--INT_SCRIPT.[a-z0-9]*--\\>/', $searchString, $tempArray);
1019  $searchString = preg_replace('/\\<\\!--INT_SCRIPT.[a-z0-9]*--\\>/', '', $searchString);
1020  $intObjects = implode('', $tempArray[0]);
1021  }
1022 
1029  protected function ‪generateMetaTagHtml(array $metaTagTypoScript, ‪ContentObjectRenderer $cObj)
1030  {
1031  $pageRenderer = $this->‪getPageRenderer();
1032 
1033  $typoScriptService = GeneralUtility::makeInstance(TypoScriptService::class);
1034  $conf = $typoScriptService->convertTypoScriptArrayToPlainArray($metaTagTypoScript);
1035  foreach ($conf as $key => $properties) {
1036  $replace = false;
1037  if (is_array($properties)) {
1038  $nodeValue = $properties['_typoScriptNodeValue'] ?? '';
1039  $value = trim((string)$cObj->‪stdWrap($nodeValue, $metaTagTypoScript[$key . '.']));
1040  if ($value === '' && !empty($properties['value'])) {
1041  $value = $properties['value'];
1042  $replace = false;
1043  }
1044  } else {
1045  $value = $properties;
1046  }
1047 
1048  $attribute = 'name';
1049  if ((is_array($properties) && !empty($properties['httpEquivalent'])) || strtolower($key) === 'refresh') {
1050  $attribute = 'http-equiv';
1051  }
1052  if (is_array($properties) && !empty($properties['attribute'])) {
1053  $attribute = $properties['attribute'];
1054  }
1055  if (is_array($properties) && !empty($properties['replace'])) {
1056  $replace = true;
1057  }
1058 
1059  if (!is_array($value)) {
1060  $value = (array)$value;
1061  }
1062  foreach ($value as $subValue) {
1063  if (trim($subValue ?? '') !== '') {
1064  $pageRenderer->setMetaTag($attribute, $key, $subValue, [], $replace);
1065  }
1066  }
1067  }
1068  }
1069 
1073  protected function ‪getPageRenderer(): ‪PageRenderer
1074  {
1075  return GeneralUtility::makeInstance(PageRenderer::class);
1076  }
1077 
1086  protected function ‪addCssToPageRenderer(‪TypoScriptFrontendController $controller, string $cssStyles, bool $excludeFromConcatenation, string $inlineBlockName)
1087  {
1088  if (empty($controller->config['config']['inlineStyle2TempFile'] ?? false)) {
1089  $this->‪getPageRenderer()->‪addCssInlineBlock($inlineBlockName, $cssStyles, !empty($controller->config['config']['compressCss'] ?? false));
1090  } else {
1092  GeneralUtility::writeStyleSheetContentToTemporaryFile($cssStyles),
1093  'stylesheet',
1094  'all',
1095  '',
1096  (bool)($controller->config['config']['compressCss'] ?? false),
1097  false,
1098  '',
1099  $excludeFromConcatenation
1100  );
1101  }
1102  }
1103 
1123  protected function ‪generateHtmlTag(array $htmlTagAttributes, array $configuration, ‪ContentObjectRenderer $cObj): string
1124  {
1125  if (is_array($configuration['htmlTag.']['attributes.'] ?? null)) {
1126  $attributeString = '';
1127  foreach ($configuration['htmlTag.']['attributes.'] as $attributeName => $value) {
1128  $attributeString .= ' ' . htmlspecialchars($attributeName) . ($value !== '' ? '="' . htmlspecialchars((string)$value) . '"' : '');
1129  // If e.g. "htmlTag.attributes.dir" is set, make sure it is not added again with "implodeAttributes()"
1130  if (isset($htmlTagAttributes[$attributeName])) {
1131  unset($htmlTagAttributes[$attributeName]);
1132  }
1133  }
1134  $attributeString = ltrim(GeneralUtility::implodeAttributes($htmlTagAttributes) . $attributeString);
1135  } elseif (($configuration['htmlTag_setParams'] ?? '') === 'none') {
1136  $attributeString = '';
1137  } elseif (isset($configuration['htmlTag_setParams'])) {
1138  $attributeString = $configuration['htmlTag_setParams'];
1139  } else {
1140  $attributeString = GeneralUtility::implodeAttributes($htmlTagAttributes);
1141  }
1142  $htmlTag = '<html' . ($attributeString ? ' ' . $attributeString : '') . '>';
1143  if (isset($configuration['htmlTag_stdWrap.'])) {
1144  $htmlTag = $cObj->‪stdWrap($htmlTag, $configuration['htmlTag_stdWrap.']);
1145  }
1146  return $htmlTag;
1147  }
1148 
1155  public function ‪canHandleRequest(ServerRequestInterface $request): bool
1156  {
1157  return true;
1158  }
1159 
1166  public function ‪getPriority(): int
1167  {
1168  return 50;
1169  }
1170 }
‪TYPO3\CMS\Frontend\Http\RequestHandler\$timeTracker
‪TimeTracker $timeTracker
Definition: RequestHandler.php:64
‪TYPO3\CMS\Frontend\Http\RequestHandler\handle
‪ResponseInterface null handle(ServerRequestInterface $request)
Definition: RequestHandler.php:142
‪TYPO3\CMS\Core\Utility\PathUtility
Definition: PathUtility.php:23
‪TYPO3\CMS\Core\Core\Environment\getPublicPath
‪static string getPublicPath()
Definition: Environment.php:153
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap
‪string stdWrap($content='', $conf=[])
Definition: ContentObjectRenderer.php:1542
‪TYPO3\CMS\Core\Exception
Definition: Exception.php:21
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\generatePageTitle
‪string generatePageTitle()
Definition: TypoScriptFrontendController.php:3570
‪TYPO3\CMS\Frontend\Http\RequestHandler\getPriority
‪int getPriority()
Definition: RequestHandler.php:1165
‪TYPO3\CMS\Frontend\Http
Definition: Application.php:3
‪TYPO3
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\uniqueHash
‪string uniqueHash($str='')
Definition: TypoScriptFrontendController.php:4388
‪TYPO3\CMS\Frontend\Resource\FilePathSanitizer
Definition: FilePathSanitizer.php:37
‪TYPO3\CMS\Core\Page\PageRenderer\addCssInlineBlock
‪addCssInlineBlock($name, $block, $compress=false, $forceOnTop=false)
Definition: PageRenderer.php:1330
‪TYPO3\CMS\Core\Site\Entity\SiteLanguage\getDirection
‪string getDirection()
Definition: SiteLanguage.php:266
‪TYPO3\CMS\Core\Http\NullResponse
Definition: NullResponse.php:24
‪TYPO3\CMS\Frontend\Http\RequestHandler\handleRequest
‪ResponseInterface handleRequest(ServerRequestInterface $request)
Definition: RequestHandler.php:72
‪TYPO3\CMS\Frontend\Http\RequestHandler\addModifiedGlobalsToIncomingRequest
‪ServerRequestInterface addModifiedGlobalsToIncomingRequest(ServerRequestInterface $request)
Definition: RequestHandler.php:84
‪TYPO3\CMS\Core\Site\Entity\SiteLanguage
Definition: SiteLanguage.php:25
‪TYPO3\CMS\Core\Page\PageRenderer
Definition: PageRenderer.php:35
‪TYPO3\CMS\Core\Http\RequestHandlerInterface
Definition: RequestHandlerInterface.php:28
‪TYPO3\CMS\Core\Page\PageRenderer\addCssFile
‪addCssFile($file, $rel='stylesheet', $media='all', $title='', $compress=true, $forceOnTop=false, $allWrap='', $excludeFromConcatenation=false, $splitChar='|', $inline=false)
Definition: PageRenderer.php:1272
‪TYPO3\CMS\Core\Http\Response
Definition: Response.php:28
‪TYPO3\CMS\Frontend\Http\RequestHandler\addCssToPageRenderer
‪addCssToPageRenderer(TypoScriptFrontendController $controller, string $cssStyles, bool $excludeFromConcatenation, string $inlineBlockName)
Definition: RequestHandler.php:1085
‪TYPO3\CMS\Frontend\Http\RequestHandler\stripIntObjectPlaceholder
‪stripIntObjectPlaceholder(&$searchString, &$intObjects)
Definition: RequestHandler.php:1014
‪TYPO3\CMS\Core\Page\PageRenderer\JQUERY_NAMESPACE_NONE
‪const JQUERY_NAMESPACE_NONE
Definition: PageRenderer.php:45
‪TYPO3\CMS\Frontend\Http\RequestHandler\canHandleRequest
‪bool canHandleRequest(ServerRequestInterface $request)
Definition: RequestHandler.php:1154
‪TYPO3\CMS\Frontend\Http\RequestHandler\generatePageContent
‪string generatePageContent(TypoScriptFrontendController $controller)
Definition: RequestHandler.php:243
‪TYPO3\CMS\Core\Type\File\ImageInfo
Definition: ImageInfo.php:25
‪TYPO3\CMS\Core\TypoScript\TypoScriptService
Definition: TypoScriptService.php:23
‪TYPO3\CMS\Frontend\Http\RequestHandler
Definition: RequestHandler.php:60
‪TYPO3\CMS\Core\Site\Entity\SiteLanguage\getHreflang
‪string getHreflang()
Definition: SiteLanguage.php:256
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController
Definition: TypoScriptFrontendController.php:97
‪TYPO3\CMS\Core\Utility\ArrayUtility
Definition: ArrayUtility.php:23
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Frontend\Http\RequestHandler\generateHtmlTag
‪string generateHtmlTag(array $htmlTagAttributes, array $configuration, ContentObjectRenderer $cObj)
Definition: RequestHandler.php:1122
‪TYPO3\CMS\Core\Core\Environment
Definition: Environment.php:39
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\INTincScript_loadJSCode
‪INTincScript_loadJSCode()
Definition: TypoScriptFrontendController.php:3774
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
Definition: ContentObjectRenderer.php:91
‪TYPO3\CMS\Frontend\Http\RequestHandler\getPageRenderer
‪PageRenderer getPageRenderer()
Definition: RequestHandler.php:1072
‪TYPO3\CMS\Frontend\Http\RequestHandler\generatePageContentWithHeader
‪string generatePageContentWithHeader(TypoScriptFrontendController $controller, ?SiteLanguage $siteLanguage)
Definition: RequestHandler.php:264
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:45
‪TYPO3\CMS\Frontend\Http\RequestHandler\generateMetaTagHtml
‪generateMetaTagHtml(array $metaTagTypoScript, ContentObjectRenderer $cObj)
Definition: RequestHandler.php:1028
‪TYPO3\CMS\Core\Utility\PathUtility\getAbsoluteWebPath
‪static string getAbsoluteWebPath($targetPath)
Definition: PathUtility.php:42
‪TYPO3\CMS\Core\TimeTracker\TimeTracker
Definition: TimeTracker.php:27
‪TYPO3\CMS\Core\Utility\ArrayUtility\arrayDiffAssocRecursive
‪static array arrayDiffAssocRecursive(array $array1, array $array2)
Definition: ArrayUtility.php:728
‪TYPO3\CMS\Frontend\Http\RequestHandler\resetGlobalsToCurrentRequest
‪resetGlobalsToCurrentRequest(ServerRequestInterface $request)
Definition: RequestHandler.php:121