[TASK] Deprecate PageRenderer->loadJQuery()
[Packages/TYPO3.CMS.git] / typo3 / sysext / frontend / Classes / Page / PageGenerator.php
1 <?php
2 namespace TYPO3\CMS\Frontend\Page;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use Psr\Http\Message\ServerRequestInterface;
18 use TYPO3\CMS\Core\Core\Environment;
19 use TYPO3\CMS\Core\Page\PageRenderer;
20 use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
21 use TYPO3\CMS\Core\TimeTracker\TimeTracker;
22 use TYPO3\CMS\Core\Type\File\ImageInfo;
23 use TYPO3\CMS\Core\TypoScript\TypoScriptService;
24 use TYPO3\CMS\Core\Utility\GeneralUtility;
25 use TYPO3\CMS\Core\Utility\MathUtility;
26 use TYPO3\CMS\Core\Utility\PathUtility;
27 use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
28 use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
29 use TYPO3\CMS\Frontend\Resource\FilePathSanitizer;
30
31 /**
32 * Class for starting TypoScript page generation
33 *
34 * The class is not instantiated as an objects but called directly with the "::" operator.
35 * @deprecated this class will be removed in TYPO3 v10.0, as all functionality has been built in RequestHandler already.
36 */
37 class PageGenerator
38 {
39 /**
40 * Do not render title tag
41 * Typoscript setting: [config][noPageTitle]
42 * @deprecated will not be used anymore, and will be removed in TYPO3 v10.
43 */
44 const NO_PAGE_TITLE = 2;
45
46 /**
47 * Rendering the page content
48 * @deprecated since TYPO3 v9.4 will be removed in TYPO3 v10.0. This functionality is now within RequestHandler.
49 */
50 public static function renderContent()
51 {
52 trigger_error('PageGenerator::renderContent() will be removed in TYPO3 v10.0. This logic is now built in TYPO3s Frontend RequestHandler.', E_USER_DEPRECATED);
53 /** @var TypoScriptFrontendController $tsfe */
54 $tsfe = $GLOBALS['TSFE'];
55
56 /** @var TimeTracker $timeTracker */
57 $timeTracker = GeneralUtility::makeInstance(TimeTracker::class);
58
59 // PAGE CONTENT
60 $timeTracker->incStackPointer();
61 $timeTracker->push($tsfe->sPre, 'PAGE');
62 $pageContent = $tsfe->cObj->cObjGet($tsfe->pSetup);
63 if ($tsfe->pSetup['wrap']) {
64 $pageContent = $tsfe->cObj->wrap($pageContent, $tsfe->pSetup['wrap']);
65 }
66 if ($tsfe->pSetup['stdWrap.']) {
67 $pageContent = $tsfe->cObj->stdWrap($pageContent, $tsfe->pSetup['stdWrap.']);
68 }
69 // PAGE HEADER (after content - maybe JS is inserted!
70 // if 'disableAllHeaderCode' is set, all the header-code is discarded!
71 if ($tsfe->config['config']['disableAllHeaderCode']) {
72 $tsfe->content = $pageContent;
73 } else {
74 self::renderContentWithHeader($pageContent);
75 }
76 $timeTracker->pull($timeTracker->LR ? $tsfe->content : '');
77 $timeTracker->decStackPointer();
78 }
79
80 /**
81 * Rendering normal HTML-page with header by wrapping the generated content ($pageContent) in body-tags and setting the header accordingly.
82 *
83 * @param string $pageContent The page content which TypoScript objects has generated
84 * @deprecated since TYPO3 v9.4, will be removed in TYPO3 v10.0. This functionality is now within TYPO3's Frontend Request Handler.
85 */
86 public static function renderContentWithHeader($pageContent)
87 {
88 trigger_error('PageGenerator::renderContentWithHeader() will be removed in TYPO3 v10.0. This logic is now built in TYPO3s Frontend RequestHandler.', E_USER_DEPRECATED);
89 /** @var TypoScriptFrontendController $tsfe */
90 $tsfe = $GLOBALS['TSFE'];
91
92 /** @var TimeTracker $timeTracker */
93 $timeTracker = GeneralUtility::makeInstance(TimeTracker::class);
94
95 $pageRenderer = static::getPageRenderer();
96 if ($tsfe->config['config']['moveJsFromHeaderToFooter'] ?? false) {
97 $pageRenderer->enableMoveJsFromHeaderToFooter();
98 }
99 if ($tsfe->config['config']['pageRendererTemplateFile'] ?? false) {
100 try {
101 $file = GeneralUtility::makeInstance(FilePathSanitizer::class)->sanitize($tsfe->config['config']['pageRendererTemplateFile']);
102 $pageRenderer->setTemplateFile($file);
103 } catch (\TYPO3\CMS\Core\Resource\Exception $e) {
104 // do nothing
105 }
106 }
107 $headerComment = $tsfe->config['config']['headerComment'] ?? null;
108 if (trim($headerComment)) {
109 $pageRenderer->addInlineComment("\t" . str_replace(LF, LF . "\t", trim($headerComment)) . LF);
110 }
111 // Setting charset:
112 $theCharset = $tsfe->metaCharset;
113 // Reset the content variables:
114 $tsfe->content = '';
115 $htmlTagAttributes = [];
116 $htmlLang = $tsfe->config['config']['htmlTag_langKey'] ?? ($tsfe->sys_language_isocode ?: 'en');
117 // Set content direction
118 // More info: http://www.tau.ac.il/~danon/Hebrew/HTML_and_Hebrew.html)
119 $direction = $tsfe->config['config']['htmlTag_dir'] ?? null;
120 if (self::getCurrentSiteLanguage()) {
121 $direction = self::getCurrentSiteLanguage()->getDirection();
122 $htmlLang = self::getCurrentSiteLanguage()->getTwoLetterIsoCode();
123 }
124 if ($direction) {
125 $htmlTagAttributes['dir'] = htmlspecialchars($direction);
126 }
127 // Setting document type:
128 $docTypeParts = [];
129 $xmlDocument = true;
130 // Part 1: XML prologue
131 switch ((string)($tsfe->config['config']['xmlprologue'] ?? '')) {
132 case 'none':
133 $xmlDocument = false;
134 break;
135 case 'xml_10':
136 $docTypeParts[] = '<?xml version="1.0" encoding="' . $theCharset . '"?>';
137 break;
138 case 'xml_11':
139 $docTypeParts[] = '<?xml version="1.1" encoding="' . $theCharset . '"?>';
140 break;
141 case '':
142 if ($tsfe->xhtmlVersion) {
143 $docTypeParts[] = '<?xml version="1.0" encoding="' . $theCharset . '"?>';
144 } else {
145 $xmlDocument = false;
146 }
147 break;
148 default:
149 $docTypeParts[] = $tsfe->config['config']['xmlprologue'];
150 }
151 // Part 2: DTD
152 $doctype = $tsfe->config['config']['doctype'] ?? null;
153 if ($doctype) {
154 switch ($doctype) {
155 case 'xhtml_trans':
156 $docTypeParts[] = '<!DOCTYPE html
157 PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
158 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">';
159 break;
160 case 'xhtml_strict':
161 $docTypeParts[] = '<!DOCTYPE html
162 PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
163 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
164 break;
165 case 'xhtml_basic':
166 $docTypeParts[] = '<!DOCTYPE html
167 PUBLIC "-//W3C//DTD XHTML Basic 1.0//EN"
168 "http://www.w3.org/TR/xhtml-basic/xhtml-basic10.dtd">';
169 break;
170 case 'xhtml_11':
171 $docTypeParts[] = '<!DOCTYPE html
172 PUBLIC "-//W3C//DTD XHTML 1.1//EN"
173 "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">';
174 break;
175 case 'xhtml+rdfa_10':
176 $docTypeParts[] = '<!DOCTYPE html
177 PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN"
178 "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd">';
179 break;
180 case 'html5':
181 $docTypeParts[] = '<!DOCTYPE html>';
182 if ($xmlDocument) {
183 $pageRenderer->setMetaCharsetTag('<meta charset="|" />');
184 } else {
185 $pageRenderer->setMetaCharsetTag('<meta charset="|">');
186 }
187 break;
188 case 'none':
189 break;
190 default:
191 $docTypeParts[] = $doctype;
192 }
193 } else {
194 $docTypeParts[] = '<!DOCTYPE html>';
195 if ($xmlDocument) {
196 $pageRenderer->setMetaCharsetTag('<meta charset="|" />');
197 } else {
198 $pageRenderer->setMetaCharsetTag('<meta charset="|">');
199 }
200 }
201 if ($tsfe->xhtmlVersion) {
202 $htmlTagAttributes['xml:lang'] = $htmlLang;
203 }
204 if ($tsfe->xhtmlVersion < 110 || $doctype === 'html5') {
205 $htmlTagAttributes['lang'] = $htmlLang;
206 }
207 if ($tsfe->xhtmlVersion || $doctype === 'html5' && $xmlDocument) {
208 // We add this to HTML5 to achieve a slightly better backwards compatibility
209 $htmlTagAttributes['xmlns'] = 'http://www.w3.org/1999/xhtml';
210 if (is_array($tsfe->config['config']['namespaces.'])) {
211 foreach ($tsfe->config['config']['namespaces.'] as $prefix => $uri) {
212 // $uri gets htmlspecialchared later
213 $htmlTagAttributes['xmlns:' . htmlspecialchars($prefix)] = $uri;
214 }
215 }
216 }
217 // Swap XML and doctype order around (for MSIE / Opera standards compliance)
218 if ($tsfe->config['config']['doctypeSwitch'] ?? false) {
219 $docTypeParts = array_reverse($docTypeParts);
220 }
221 // Adding doctype parts:
222 if (!empty($docTypeParts)) {
223 $pageRenderer->setXmlPrologAndDocType(implode(LF, $docTypeParts));
224 }
225 // Begin header section:
226 if (($tsfe->config['config']['htmlTag_setParams'] ?? '') !== 'none') {
227 $_attr = $tsfe->config['config']['htmlTag_setParams'] ?? GeneralUtility::implodeAttributes($htmlTagAttributes);
228 } else {
229 $_attr = '';
230 }
231 $htmlTag = '<html' . ($_attr ? ' ' . $_attr : '') . '>';
232 if (isset($tsfe->config['config']['htmlTag_stdWrap.'])) {
233 $htmlTag = $tsfe->cObj->stdWrap($htmlTag, $tsfe->config['config']['htmlTag_stdWrap.']);
234 }
235 $pageRenderer->setHtmlTag($htmlTag);
236 // Head tag:
237 $headTag = $tsfe->pSetup['headTag'] ?? '<head>';
238 if (isset($tsfe->pSetup['headTag.'])) {
239 $headTag = $tsfe->cObj->stdWrap($headTag, $tsfe->pSetup['headTag.']);
240 }
241 $pageRenderer->setHeadTag($headTag);
242 // Setting charset meta tag:
243 $pageRenderer->setCharSet($theCharset);
244 $pageRenderer->addInlineComment(' This website is powered by TYPO3 - inspiring people to share!
245 TYPO3 is a free open source Content Management Framework initially created by Kasper Skaarhoj and licensed under GNU/GPL.
246 TYPO3 is copyright ' . TYPO3_copyright_year . ' of Kasper Skaarhoj. Extensions are copyright of their respective owners.
247 Information and contribution at ' . TYPO3_URL_GENERAL . '
248 ');
249 if ($tsfe->baseUrl) {
250 $pageRenderer->setBaseUrl($tsfe->baseUrl);
251 }
252 if ($tsfe->pSetup['shortcutIcon'] ?? false) {
253 try {
254 $favIcon = GeneralUtility::makeInstance(FilePathSanitizer::class)->sanitize($tsfe->pSetup['shortcutIcon']);
255 $iconFileInfo = GeneralUtility::makeInstance(ImageInfo::class, Environment::getPublicPath() . '/' . $favIcon);
256 if ($iconFileInfo->isFile()) {
257 $iconMimeType = $iconFileInfo->getMimeType();
258 if ($iconMimeType) {
259 $iconMimeType = ' type="' . $iconMimeType . '"';
260 $pageRenderer->setIconMimeType($iconMimeType);
261 }
262 $pageRenderer->setFavIcon(PathUtility::getAbsoluteWebPath($tsfe->absRefPrefix . $favIcon));
263 }
264 } catch (\TYPO3\CMS\Core\Resource\Exception $e) {
265 // do nothing
266 }
267 }
268 // Including CSS files
269 if (isset($tsfe->tmpl->setup['plugin.']) && is_array($tsfe->tmpl->setup['plugin.'])) {
270 $stylesFromPlugins = '';
271 foreach ($tsfe->tmpl->setup['plugin.'] as $key => $iCSScode) {
272 if (is_array($iCSScode)) {
273 if ($iCSScode['_CSS_DEFAULT_STYLE'] && empty($tsfe->config['config']['removeDefaultCss'])) {
274 if (isset($iCSScode['_CSS_DEFAULT_STYLE.'])) {
275 $cssDefaultStyle = $tsfe->cObj->stdWrap($iCSScode['_CSS_DEFAULT_STYLE'], $iCSScode['_CSS_DEFAULT_STYLE.']);
276 } else {
277 $cssDefaultStyle = $iCSScode['_CSS_DEFAULT_STYLE'];
278 }
279 $stylesFromPlugins .= '/* default styles for extension "' . substr($key, 0, -1) . '" */' . LF . $cssDefaultStyle . LF;
280 }
281 if ($iCSScode['_CSS_PAGE_STYLE'] && empty($tsfe->config['config']['removePageCss'])) {
282 $cssPageStyle = implode(LF, $iCSScode['_CSS_PAGE_STYLE']);
283 if (isset($iCSScode['_CSS_PAGE_STYLE.'])) {
284 $cssPageStyle = $tsfe->cObj->stdWrap($cssPageStyle, $iCSScode['_CSS_PAGE_STYLE.']);
285 }
286 $cssPageStyle = '/* specific page styles for extension "' . substr($key, 0, -1) . '" */' . LF . $cssPageStyle;
287 self::addCssToPageRenderer($cssPageStyle, true, 'InlinePageCss');
288 }
289 }
290 }
291 if (!empty($stylesFromPlugins)) {
292 self::addCssToPageRenderer($stylesFromPlugins, false, 'InlineDefaultCss');
293 }
294 }
295 /**********************************************************************/
296 /* config.includeCSS / config.includeCSSLibs
297 /**********************************************************************/
298 if (isset($tsfe->pSetup['includeCSS.']) && is_array($tsfe->pSetup['includeCSS.'])) {
299 foreach ($tsfe->pSetup['includeCSS.'] as $key => $CSSfile) {
300 if (!is_array($CSSfile)) {
301 $cssFileConfig = &$tsfe->pSetup['includeCSS.'][$key . '.'];
302 if (isset($cssFileConfig['if.']) && !$tsfe->cObj->checkIf($cssFileConfig['if.'])) {
303 continue;
304 }
305 if ($cssFileConfig['external']) {
306 $ss = $CSSfile;
307 } else {
308 try {
309 $ss = GeneralUtility::makeInstance(FilePathSanitizer::class)->sanitize($CSSfile);
310 } catch (\TYPO3\CMS\Core\Resource\Exception $e) {
311 $ss = null;
312 }
313 }
314 if ($ss) {
315 if ($cssFileConfig['import']) {
316 if (!$cssFileConfig['external'] && $ss[0] !== '/') {
317 // To fix MSIE 6 that cannot handle these as relative paths (according to Ben v Ende)
318 $ss = GeneralUtility::dirname(GeneralUtility::getIndpEnv('SCRIPT_NAME')) . '/' . $ss;
319 }
320 $pageRenderer->addCssInlineBlock('import_' . $key, '@import url("' . htmlspecialchars($ss) . '") ' . htmlspecialchars($cssFileConfig['media']) . ';', empty($cssFileConfig['disableCompression']), (bool)$cssFileConfig['forceOnTop']);
321 } else {
322 $pageRenderer->addCssFile(
323 $ss,
324 $cssFileConfig['alternate'] ? 'alternate stylesheet' : 'stylesheet',
325 $cssFileConfig['media'] ?: 'all',
326 $cssFileConfig['title'] ?: '',
327 empty($cssFileConfig['disableCompression']),
328 (bool)$cssFileConfig['forceOnTop'],
329 $cssFileConfig['allWrap'],
330 (bool)$cssFileConfig['excludeFromConcatenation'] || (bool)$cssFileConfig['inline'],
331 $cssFileConfig['allWrap.']['splitChar'],
332 $cssFileConfig['inline']
333 );
334 unset($cssFileConfig);
335 }
336 }
337 }
338 }
339 }
340 if (isset($tsfe->pSetup['includeCSSLibs.']) && is_array($tsfe->pSetup['includeCSSLibs.'])) {
341 foreach ($tsfe->pSetup['includeCSSLibs.'] as $key => $CSSfile) {
342 if (!is_array($CSSfile)) {
343 $cssFileConfig = &$tsfe->pSetup['includeCSSLibs.'][$key . '.'];
344 if (isset($cssFileConfig['if.']) && !$tsfe->cObj->checkIf($cssFileConfig['if.'])) {
345 continue;
346 }
347 if ($cssFileConfig['external']) {
348 $ss = $CSSfile;
349 } else {
350 try {
351 $ss = GeneralUtility::makeInstance(FilePathSanitizer::class)->sanitize($CSSfile);
352 } catch (\TYPO3\CMS\Core\Resource\Exception $e) {
353 $ss = null;
354 }
355 }
356 if ($ss) {
357 if ($cssFileConfig['import']) {
358 if (!$cssFileConfig['external'] && $ss[0] !== '/') {
359 // To fix MSIE 6 that cannot handle these as relative paths (according to Ben v Ende)
360 $ss = GeneralUtility::dirname(GeneralUtility::getIndpEnv('SCRIPT_NAME')) . '/' . $ss;
361 }
362 $pageRenderer->addCssInlineBlock('import_' . $key, '@import url("' . htmlspecialchars($ss) . '") ' . htmlspecialchars($cssFileConfig['media']) . ';', empty($cssFileConfig['disableCompression']), (bool)$cssFileConfig['forceOnTop']);
363 } else {
364 $pageRenderer->addCssLibrary(
365 $ss,
366 $cssFileConfig['alternate'] ? 'alternate stylesheet' : 'stylesheet',
367 $cssFileConfig['media'] ?: 'all',
368 $cssFileConfig['title'] ?: '',
369 empty($cssFileConfig['disableCompression']),
370 (bool)$cssFileConfig['forceOnTop'],
371 $cssFileConfig['allWrap'],
372 (bool)$cssFileConfig['excludeFromConcatenation'] || (bool)$cssFileConfig['inline'],
373 $cssFileConfig['allWrap.']['splitChar'],
374 $cssFileConfig['inline']
375 );
376 unset($cssFileConfig);
377 }
378 }
379 }
380 }
381 }
382
383 // CSS_inlineStyle from TS
384 $style = trim($tsfe->pSetup['CSS_inlineStyle'] ?? '');
385 $style .= $tsfe->cObj->cObjGet($tsfe->pSetup['cssInline.'] ?? null, 'cssInline.');
386 if (trim($style)) {
387 self::addCssToPageRenderer($style, true, 'additionalTSFEInlineStyle');
388 }
389 // Javascript Libraries
390 if (isset($tsfe->pSetup['javascriptLibs.']) && is_array($tsfe->pSetup['javascriptLibs.'])) {
391 // @deprecated since TYPO3 v9, will be removed in TYPO3 v10, the setting page.javascriptLibs has been deprecated and will be removed in TYPO3 CMS 10.
392 trigger_error('The setting page.javascriptLibs has been deprecated and will be removed in TYPO3 CMS 10', E_USER_DEPRECATED);
393
394 // Include jQuery into the page renderer
395 if (!empty($tsfe->pSetup['javascriptLibs.']['jQuery'])) {
396 // @deprecated since TYPO3 v9, will be removed in TYPO3 v10, the setting page.javascriptLibs.jQuery has been deprecated and will be removed in TYPO3 CMS 10.
397 trigger_error('The setting page.javascriptLibs.jQuery has been deprecated and will be removed in TYPO3 CMS 10', E_USER_DEPRECATED);
398
399 $jQueryTS = $tsfe->pSetup['javascriptLibs.']['jQuery.'];
400 // Check if version / source is set, if not set variable to "NULL" to use the default of the page renderer
401 $version = $jQueryTS['version'] ?? null;
402 $source = $jQueryTS['source'] ?? null;
403 // When "noConflict" is not set or "1" enable the default jQuery noConflict mode, otherwise disable the namespace
404 if (!isset($jQueryTS['noConflict']) || !empty($jQueryTS['noConflict'])) {
405 $namespace = 'noConflict';
406 } else {
407 $namespace = PageRenderer::JQUERY_NAMESPACE_NONE;
408 }
409 $pageRenderer->loadJquery($version, $source, $namespace, true);
410 }
411 }
412 // JavaScript library files
413 if (isset($tsfe->pSetup['includeJSLibs.']) && is_array($tsfe->pSetup['includeJSLibs.'])) {
414 foreach ($tsfe->pSetup['includeJSLibs.'] as $key => $JSfile) {
415 if (!is_array($JSfile)) {
416 if (isset($tsfe->pSetup['includeJSLibs.'][$key . '.']['if.']) && !$tsfe->cObj->checkIf($tsfe->pSetup['includeJSLibs.'][$key . '.']['if.'])) {
417 continue;
418 }
419 if ($tsfe->pSetup['includeJSLibs.'][$key . '.']['external']) {
420 $ss = $JSfile;
421 } else {
422 try {
423 $ss = GeneralUtility::makeInstance(FilePathSanitizer::class)->sanitize($JSfile);
424 } catch (\TYPO3\CMS\Core\Resource\Exception $e) {
425 $ss = null;
426 }
427 }
428 if ($ss) {
429 $jsFileConfig = &$tsfe->pSetup['includeJSLibs.'][$key . '.'];
430 $type = $jsFileConfig['type'];
431 if (!$type) {
432 $type = 'text/javascript';
433 }
434 $crossorigin = $jsFileConfig['crossorigin'];
435 if (!$crossorigin && $jsFileConfig['integrity'] && $jsFileConfig['external']) {
436 $crossorigin = 'anonymous';
437 }
438 $pageRenderer->addJsLibrary(
439 $key,
440 $ss,
441 $type,
442 empty($jsFileConfig['disableCompression']),
443 (bool)$jsFileConfig['forceOnTop'],
444 $jsFileConfig['allWrap'],
445 (bool)$jsFileConfig['excludeFromConcatenation'],
446 $jsFileConfig['allWrap.']['splitChar'],
447 (bool)$jsFileConfig['async'],
448 $jsFileConfig['integrity'],
449 (bool)$jsFileConfig['defer'],
450 $crossorigin
451 );
452 unset($jsFileConfig);
453 }
454 }
455 }
456 }
457 if (isset($tsfe->pSetup['includeJSFooterlibs.']) && is_array($tsfe->pSetup['includeJSFooterlibs.'])) {
458 foreach ($tsfe->pSetup['includeJSFooterlibs.'] as $key => $JSfile) {
459 if (!is_array($JSfile)) {
460 if (isset($tsfe->pSetup['includeJSFooterlibs.'][$key . '.']['if.']) && !$tsfe->cObj->checkIf($tsfe->pSetup['includeJSFooterlibs.'][$key . '.']['if.'])) {
461 continue;
462 }
463 if ($tsfe->pSetup['includeJSFooterlibs.'][$key . '.']['external']) {
464 $ss = $JSfile;
465 } else {
466 try {
467 $ss = GeneralUtility::makeInstance(FilePathSanitizer::class)->sanitize($JSfile);
468 } catch (\TYPO3\CMS\Core\Resource\Exception $e) {
469 $ss = null;
470 }
471 }
472 if ($ss) {
473 $jsFileConfig = &$tsfe->pSetup['includeJSFooterlibs.'][$key . '.'];
474 $type = $jsFileConfig['type'];
475 if (!$type) {
476 $type = 'text/javascript';
477 }
478 $crossorigin = $jsFileConfig['crossorigin'];
479 if (!$crossorigin && $jsFileConfig['integrity'] && $jsFileConfig['external']) {
480 $crossorigin = 'anonymous';
481 }
482 $pageRenderer->addJsFooterLibrary(
483 $key,
484 $ss,
485 $type,
486 empty($jsFileConfig['disableCompression']),
487 (bool)$jsFileConfig['forceOnTop'],
488 $jsFileConfig['allWrap'],
489 (bool)$jsFileConfig['excludeFromConcatenation'],
490 $jsFileConfig['allWrap.']['splitChar'],
491 (bool)$jsFileConfig['async'],
492 $jsFileConfig['integrity'],
493 (bool)$jsFileConfig['defer'],
494 $crossorigin
495 );
496 unset($jsFileConfig);
497 }
498 }
499 }
500 }
501 // JavaScript files
502 if (isset($tsfe->pSetup['includeJS.']) && is_array($tsfe->pSetup['includeJS.'])) {
503 foreach ($tsfe->pSetup['includeJS.'] as $key => $JSfile) {
504 if (!is_array($JSfile)) {
505 if (isset($tsfe->pSetup['includeJS.'][$key . '.']['if.']) && !$tsfe->cObj->checkIf($tsfe->pSetup['includeJS.'][$key . '.']['if.'])) {
506 continue;
507 }
508 if ($tsfe->pSetup['includeJS.'][$key . '.']['external']) {
509 $ss = $JSfile;
510 } else {
511 try {
512 $ss = GeneralUtility::makeInstance(FilePathSanitizer::class)->sanitize($JSfile);
513 } catch (\TYPO3\CMS\Core\Resource\Exception $e) {
514 $ss = null;
515 }
516 }
517 if ($ss) {
518 $jsConfig = &$tsfe->pSetup['includeJS.'][$key . '.'];
519 $type = $jsConfig['type'];
520 if (!$type) {
521 $type = 'text/javascript';
522 }
523 $crossorigin = $jsConfig['crossorigin'];
524 if (!$crossorigin && $jsConfig['integrity'] && $jsConfig['external']) {
525 $crossorigin = 'anonymous';
526 }
527 $pageRenderer->addJsFile(
528 $ss,
529 $type,
530 empty($jsConfig['disableCompression']),
531 (bool)$jsConfig['forceOnTop'],
532 $jsConfig['allWrap'],
533 (bool)$jsConfig['excludeFromConcatenation'],
534 $jsConfig['allWrap.']['splitChar'],
535 (bool)$jsConfig['async'],
536 $jsConfig['integrity'],
537 (bool)$jsConfig['defer'],
538 $crossorigin
539 );
540 unset($jsConfig);
541 }
542 }
543 }
544 }
545 if (isset($tsfe->pSetup['includeJSFooter.']) && is_array($tsfe->pSetup['includeJSFooter.'])) {
546 foreach ($tsfe->pSetup['includeJSFooter.'] as $key => $JSfile) {
547 if (!is_array($JSfile)) {
548 if (isset($tsfe->pSetup['includeJSFooter.'][$key . '.']['if.']) && !$tsfe->cObj->checkIf($tsfe->pSetup['includeJSFooter.'][$key . '.']['if.'])) {
549 continue;
550 }
551 if ($tsfe->pSetup['includeJSFooter.'][$key . '.']['external']) {
552 $ss = $JSfile;
553 } else {
554 try {
555 $ss = GeneralUtility::makeInstance(FilePathSanitizer::class)->sanitize($JSfile);
556 } catch (\TYPO3\CMS\Core\Resource\Exception $e) {
557 $ss = null;
558 }
559 }
560 if ($ss) {
561 $jsConfig = &$tsfe->pSetup['includeJSFooter.'][$key . '.'];
562 $type = $jsConfig['type'];
563 if (!$type) {
564 $type = 'text/javascript';
565 }
566 $crossorigin = $jsConfig['crossorigin'];
567 if (!$crossorigin && $jsConfig['integrity'] && $jsConfig['external']) {
568 $crossorigin = 'anonymous';
569 }
570 $pageRenderer->addJsFooterFile(
571 $ss,
572 $type,
573 empty($jsConfig['disableCompression']),
574 (bool)$jsConfig['forceOnTop'],
575 $jsConfig['allWrap'],
576 (bool)$jsConfig['excludeFromConcatenation'],
577 $jsConfig['allWrap.']['splitChar'],
578 (bool)$jsConfig['async'],
579 $jsConfig['integrity'],
580 (bool)$jsConfig['defer'],
581 $crossorigin
582 );
583 unset($jsConfig);
584 }
585 }
586 }
587 }
588 // Headerdata
589 if (isset($tsfe->pSetup['headerData.']) && is_array($tsfe->pSetup['headerData.'])) {
590 $pageRenderer->addHeaderData($tsfe->cObj->cObjGet($tsfe->pSetup['headerData.'], 'headerData.'));
591 }
592 // Footerdata
593 if (isset($tsfe->pSetup['footerData.']) && is_array($tsfe->pSetup['footerData.'])) {
594 $pageRenderer->addFooterData($tsfe->cObj->cObjGet($tsfe->pSetup['footerData.'], 'footerData.'));
595 }
596 $tsfe->generatePageTitle();
597
598 // @internal hook for EXT:seo, will be gone soon, do not use it in your own extensions
599 $_params = ['page' => $tsfe->page];
600 $_ref = '';
601 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['TYPO3\CMS\Frontend\Page\PageGenerator']['generateMetaTags'] ?? [] as $_funcRef) {
602 GeneralUtility::callUserFunction($_funcRef, $_params, $_ref);
603 }
604
605 static::generateMetaTagHtml(
606 $tsfe->pSetup['meta.'] ?? [],
607 $tsfe->cObj
608 );
609
610 unset($tsfe->additionalHeaderData['JSCode']);
611 if (isset($tsfe->config['INTincScript']) && is_array($tsfe->config['INTincScript'])) {
612 $tsfe->additionalHeaderData['JSCode'] = $tsfe->JSCode;
613 // Storing the JSCode vars...
614 $tsfe->config['INTincScript_ext']['divKey'] = $tsfe->uniqueHash();
615 $tsfe->config['INTincScript_ext']['additionalHeaderData'] = $tsfe->additionalHeaderData;
616 // Storing the header-data array
617 $tsfe->config['INTincScript_ext']['additionalFooterData'] = $tsfe->additionalFooterData;
618 // Storing the footer-data array
619 $tsfe->config['INTincScript_ext']['additionalJavaScript'] = $tsfe->additionalJavaScript;
620 // Storing the JS-data array
621 $tsfe->config['INTincScript_ext']['additionalCSS'] = $tsfe->additionalCSS;
622 // Storing the Style-data array
623 $tsfe->additionalHeaderData = ['<!--HD_' . $tsfe->config['INTincScript_ext']['divKey'] . '-->'];
624 // Clearing the array
625 $tsfe->additionalFooterData = ['<!--FD_' . $tsfe->config['INTincScript_ext']['divKey'] . '-->'];
626 // Clearing the array
627 $tsfe->divSection .= '<!--TDS_' . $tsfe->config['INTincScript_ext']['divKey'] . '-->';
628 } else {
629 $tsfe->INTincScript_loadJSCode();
630 }
631 $scriptJsCode = '';
632
633 if ($tsfe->spamProtectEmailAddresses && $tsfe->spamProtectEmailAddresses !== 'ascii') {
634 $scriptJsCode = '
635 // decrypt helper function
636 function decryptCharcode(n,start,end,offset) {
637 n = n + offset;
638 if (offset > 0 && n > end) {
639 n = start + (n - end - 1);
640 } else if (offset < 0 && n < start) {
641 n = end - (start - n - 1);
642 }
643 return String.fromCharCode(n);
644 }
645 // decrypt string
646 function decryptString(enc,offset) {
647 var dec = "";
648 var len = enc.length;
649 for(var i=0; i < len; i++) {
650 var n = enc.charCodeAt(i);
651 if (n >= 0x2B && n <= 0x3A) {
652 dec += decryptCharcode(n,0x2B,0x3A,offset); // 0-9 . , - + / :
653 } else if (n >= 0x40 && n <= 0x5A) {
654 dec += decryptCharcode(n,0x40,0x5A,offset); // A-Z @
655 } else if (n >= 0x61 && n <= 0x7A) {
656 dec += decryptCharcode(n,0x61,0x7A,offset); // a-z
657 } else {
658 dec += enc.charAt(i);
659 }
660 }
661 return dec;
662 }
663 // decrypt spam-protected emails
664 function linkTo_UnCryptMailto(s) {
665 location.href = decryptString(s,' . $tsfe->spamProtectEmailAddresses * -1 . ');
666 }
667 ';
668 }
669 // Add inline JS
670 $inlineJS = '';
671 // defined in php
672 if (is_array($tsfe->inlineJS)) {
673 foreach ($tsfe->inlineJS as $key => $val) {
674 if (!is_array($val)) {
675 $inlineJS .= LF . $val . LF;
676 }
677 }
678 }
679 // defined in TS with page.inlineJS
680 // Javascript inline code
681 $inline = $tsfe->cObj->cObjGet($tsfe->pSetup['jsInline.'] ?? null, 'jsInline.');
682 if ($inline) {
683 $inlineJS .= LF . $inline . LF;
684 }
685 // Javascript inline code for Footer
686 $inlineFooterJs = $tsfe->cObj->cObjGet($tsfe->pSetup['jsFooterInline.'] ?? null, 'jsFooterInline.');
687 // Should minify?
688 if ($tsfe->config['config']['compressJs'] ?? false) {
689 $pageRenderer->enableCompressJavascript();
690 $minifyErrorScript = ($minifyErrorInline = '');
691 $scriptJsCode = GeneralUtility::minifyJavaScript($scriptJsCode, $minifyErrorScript);
692 if ($minifyErrorScript) {
693 $timeTracker->setTSlogMessage($minifyErrorScript, 3);
694 }
695 if ($inlineJS) {
696 $inlineJS = GeneralUtility::minifyJavaScript($inlineJS, $minifyErrorInline);
697 if ($minifyErrorInline) {
698 $timeTracker->setTSlogMessage($minifyErrorInline, 3);
699 }
700 }
701 if ($inlineFooterJs) {
702 $inlineFooterJs = GeneralUtility::minifyJavaScript($inlineFooterJs, $minifyErrorInline);
703 if ($minifyErrorInline) {
704 $timeTracker->setTSlogMessage($minifyErrorInline, 3);
705 }
706 }
707 }
708 if (!isset($tsfe->config['config']['removeDefaultJS']) || !$tsfe->config['config']['removeDefaultJS']) {
709 // include default and inlineJS
710 if ($scriptJsCode) {
711 $pageRenderer->addJsInlineCode('_scriptCode', $scriptJsCode, $tsfe->config['config']['compressJs']);
712 }
713 if ($inlineJS) {
714 $pageRenderer->addJsInlineCode('TS_inlineJS', $inlineJS, $tsfe->config['config']['compressJs']);
715 }
716 if ($inlineFooterJs) {
717 $pageRenderer->addJsFooterInlineCode('TS_inlineFooter', $inlineFooterJs, $tsfe->config['config']['compressJs']);
718 }
719 } elseif ($tsfe->config['config']['removeDefaultJS'] === 'external') {
720 /*
721 * This keeps inlineJS from *_INT Objects from being moved to external files.
722 * At this point in frontend rendering *_INT Objects only have placeholders instead
723 * of actual content so moving these placeholders to external files would
724 * a) break the JS file (syntax errors due to the placeholders)
725 * b) the needed JS would never get included to the page
726 * Therefore inlineJS from *_INT Objects must not be moved to external files but
727 * kept internal.
728 */
729 $inlineJSint = '';
730 self::stripIntObjectPlaceholder($inlineJS, $inlineJSint);
731 if ($inlineJSint) {
732 $pageRenderer->addJsInlineCode('TS_inlineJSint', $inlineJSint, $tsfe->config['config']['compressJs']);
733 }
734 if (trim($scriptJsCode . $inlineJS)) {
735 $pageRenderer->addJsFile(self::inline2TempFile($scriptJsCode . $inlineJS, 'js'), 'text/javascript', $tsfe->config['config']['compressJs']);
736 }
737 if ($inlineFooterJs) {
738 $inlineFooterJSint = '';
739 self::stripIntObjectPlaceholder($inlineFooterJs, $inlineFooterJSint);
740 if ($inlineFooterJSint) {
741 $pageRenderer->addJsFooterInlineCode('TS_inlineFooterJSint', $inlineFooterJSint, $tsfe->config['config']['compressJs']);
742 }
743 $pageRenderer->addJsFooterFile(self::inline2TempFile($inlineFooterJs, 'js'), 'text/javascript', $tsfe->config['config']['compressJs']);
744 }
745 } else {
746 // Include only inlineJS
747 if ($inlineJS) {
748 $pageRenderer->addJsInlineCode('TS_inlineJS', $inlineJS, $tsfe->config['config']['compressJs']);
749 }
750 if ($inlineFooterJs) {
751 $pageRenderer->addJsFooterInlineCode('TS_inlineFooter', $inlineFooterJs, $tsfe->config['config']['compressJs']);
752 }
753 }
754 if (isset($tsfe->pSetup['inlineLanguageLabelFiles.']) && is_array($tsfe->pSetup['inlineLanguageLabelFiles.'])) {
755 foreach ($tsfe->pSetup['inlineLanguageLabelFiles.'] as $key => $languageFile) {
756 if (is_array($languageFile)) {
757 continue;
758 }
759 $languageFileConfig = &$tsfe->pSetup['inlineLanguageLabelFiles.'][$key . '.'];
760 if (isset($languageFileConfig['if.']) && !$tsfe->cObj->checkIf($languageFileConfig['if.'])) {
761 continue;
762 }
763 $pageRenderer->addInlineLanguageLabelFile(
764 $languageFile,
765 $languageFileConfig['selectionPrefix'] ?: '',
766 $languageFileConfig['stripFromSelectionName'] ?: ''
767 );
768 }
769 }
770 if (isset($tsfe->pSetup['inlineSettings.']) && is_array($tsfe->pSetup['inlineSettings.'])) {
771 $pageRenderer->addInlineSettingArray('TS', $tsfe->pSetup['inlineSettings.']);
772 }
773 // Compression and concatenate settings
774 if ($tsfe->config['config']['compressCss'] ?? false) {
775 $pageRenderer->enableCompressCss();
776 }
777 if ($tsfe->config['config']['compressJs'] ?? false) {
778 $pageRenderer->enableCompressJavascript();
779 }
780 if ($tsfe->config['config']['concatenateCss'] ?? false) {
781 $pageRenderer->enableConcatenateCss();
782 }
783 if ($tsfe->config['config']['concatenateJs'] ?? false) {
784 $pageRenderer->enableConcatenateJavascript();
785 }
786 // Backward compatibility for old configuration
787 // @deprecated - remove this option in TYPO3 v10.0.
788 if ($tsfe->config['config']['concatenateJsAndCss'] ?? false) {
789 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);
790 $pageRenderer->enableConcatenateCss();
791 $pageRenderer->enableConcatenateJavascript();
792 }
793 // Add header data block
794 if ($tsfe->additionalHeaderData) {
795 $pageRenderer->addHeaderData(implode(LF, $tsfe->additionalHeaderData));
796 }
797 // Add footer data block
798 if ($tsfe->additionalFooterData) {
799 $pageRenderer->addFooterData(implode(LF, $tsfe->additionalFooterData));
800 }
801 // Header complete, now add content
802 // Bodytag:
803 if ($tsfe->config['config']['disableBodyTag'] ?? false) {
804 $bodyTag = '';
805 } else {
806 $defBT = (isset($tsfe->pSetup['bodyTagCObject']) && $tsfe->pSetup['bodyTagCObject'])
807 ? $tsfe->cObj->cObjGetSingle($tsfe->pSetup['bodyTagCObject'], $tsfe->pSetup['bodyTagCObject.'], 'bodyTagCObject')
808 : '<body>';
809 $bodyTag = (isset($tsfe->pSetup['bodyTag']) && $tsfe->pSetup['bodyTag'])
810 ? $tsfe->pSetup['bodyTag']
811 : $defBT;
812 if (trim($tsfe->pSetup['bodyTagAdd'] ?? '')) {
813 $bodyTag = preg_replace('/>$/', '', trim($bodyTag)) . ' ' . trim($tsfe->pSetup['bodyTagAdd']) . '>';
814 }
815 }
816 $pageRenderer->addBodyContent(LF . $bodyTag);
817 // Div-sections
818 if ($tsfe->divSection) {
819 $pageRenderer->addBodyContent(LF . $tsfe->divSection);
820 }
821 // Page content
822 $pageRenderer->addBodyContent(LF . $pageContent);
823 if (!empty($tsfe->config['INTincScript']) && is_array($tsfe->config['INTincScript'])) {
824 // Store the serialized pageRenderer in configuration
825 $tsfe->config['INTincScript_ext']['pageRenderer'] = serialize($pageRenderer);
826 // Render complete page, keep placeholders for JavaScript and CSS
827 $tsfe->content = $pageRenderer->renderPageWithUncachedObjects($tsfe->config['INTincScript_ext']['divKey']);
828 } else {
829 // Render complete page
830 $tsfe->content = $pageRenderer->render();
831 }
832 }
833
834 /*************************
835 *
836 * Helper functions
837 * Remember: Calls internally must still be done on the non-instantiated class: PageGenerator::inline2TempFile()
838 *
839 *************************/
840 /**
841 * Searches for placeholder created from *_INT cObjects, removes them from
842 * $searchString and merges them to $intObjects
843 *
844 * @param string $searchString The String which should be cleaned from int-object markers
845 * @param string $intObjects The String the found int-placeholders are moved to (for further processing)
846 */
847 protected static function stripIntObjectPlaceholder(&$searchString, &$intObjects)
848 {
849 $tempArray = [];
850 preg_match_all('/\\<\\!--INT_SCRIPT.[a-z0-9]*--\\>/', $searchString, $tempArray);
851 $searchString = preg_replace('/\\<\\!--INT_SCRIPT.[a-z0-9]*--\\>/', '', $searchString);
852 $intObjects = implode('', $tempArray[0]);
853 }
854
855 /**
856 * Writes string to a temporary file named after the md5-hash of the string
857 *
858 * @param string $str CSS styles / JavaScript to write to file.
859 * @param string $ext Extension: "css" or "js
860 * @return string <script> or <link> tag for the file.
861 * @deprecated since TYPO3 v9.4, will be removed in TYPO3 v10.0. This functionality is now within TYPO3's Frontend Request Handler.
862 */
863 public static function inline2TempFile($str, $ext)
864 {
865 trigger_error('PageGenerator::inline2TempFile() will be removed in TYPO3 v10.0. This logic is now built in TYPO3s Frontend RequestHandler.', E_USER_DEPRECATED);
866 // Create filename / tags:
867 $script = '';
868 switch ($ext) {
869 case 'js':
870 $script = 'typo3temp/assets/js/' . GeneralUtility::shortMD5($str) . '.js';
871 break;
872 case 'css':
873 $script = 'typo3temp/assets/css/' . GeneralUtility::shortMD5($str) . '.css';
874 break;
875 }
876 // Write file
877 if ($script && !@is_file(Environment::getPublicPath() . '/' . $script)) {
878 GeneralUtility::writeFileToTypo3tempDir(Environment::getPublicPath() . '/' . $script, $str);
879 }
880 return $script;
881 }
882
883 /**
884 * Checks if the value defined in "config.linkVars" contains an allowed value. Otherwise, return FALSE which means the value will not be added to any links.
885 *
886 * @param string $haystack The string in which to find $needle
887 * @param string $needle The string to find in $haystack
888 * @return bool Returns TRUE if $needle matches or is found in $haystack
889 *
890 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10, is now called within TSFE itself, if needed outside the regular calculations, reimplement the method on your own.
891 */
892 public static function isAllowedLinkVarValue($haystack, $needle)
893 {
894 trigger_error('The method will be removed in TYPO3 v10.0, if needed outside of linkVar calculation, re-implement the method in your own extension', E_USER_DEPRECATED);
895 $OK = false;
896 // Integer
897 if ($needle === 'int' || $needle === 'integer') {
898 if (MathUtility::canBeInterpretedAsInteger($haystack)) {
899 $OK = true;
900 }
901 } elseif (preg_match('/^\\/.+\\/[imsxeADSUXu]*$/', $needle)) {
902 // Regular expression, only "//" is allowed as delimiter
903 if (@preg_match($needle, $haystack)) {
904 $OK = true;
905 }
906 } elseif (strstr($needle, '-')) {
907 // Range
908 if (MathUtility::canBeInterpretedAsInteger($haystack)) {
909 $range = explode('-', $needle);
910 if ($range[0] <= $haystack && $range[1] >= $haystack) {
911 $OK = true;
912 }
913 }
914 } elseif (strstr($needle, '|')) {
915 // List
916 // Trim the input
917 $haystack = str_replace(' ', '', $haystack);
918 if (strstr('|' . $needle . '|', '|' . $haystack . '|')) {
919 $OK = true;
920 }
921 } elseif ((string)$needle === (string)$haystack) {
922 // String comparison
923 $OK = true;
924 }
925 return $OK;
926 }
927
928 /**
929 * Generate title for page.
930 * Takes the settings [config][noPageTitle], [config][pageTitleFirst], [config][titleTagFunction]
931 * [config][pageTitleSeparator] and [config][noPageTitle] into account.
932 * Furthermore $GLOBALS[TSFE]->altPageTitle is observed.
933 *
934 * @deprecated since TYPO3 v9, will be removed in TYPO3 v10.0, as TSFE->generatePageTitle() should be used instead.
935 */
936 public static function generatePageTitle()
937 {
938 trigger_error('This method will be removed in TYPO3 v10.0. Use $TSFE->generatePageTitle() instead.', E_USER_DEPRECATED);
939 $GLOBALS['TSFE']->generatePageTitle();
940 }
941
942 /**
943 * Generate meta tags from meta tag TypoScript
944 *
945 * @param array $metaTagTypoScript TypoScript configuration for meta tags (e.g. $GLOBALS['TSFE']->pSetup['meta.'])
946 * @param ContentObjectRenderer $cObj
947 */
948 protected static function generateMetaTagHtml(array $metaTagTypoScript, ContentObjectRenderer $cObj)
949 {
950 $pageRenderer = static::getPageRenderer();
951
952 /** @var TypoScriptService $typoScriptService */
953 $typoScriptService = GeneralUtility::makeInstance(TypoScriptService::class);
954 $conf = $typoScriptService->convertTypoScriptArrayToPlainArray($metaTagTypoScript);
955 foreach ($conf as $key => $properties) {
956 $replace = false;
957 if (is_array($properties)) {
958 $nodeValue = $properties['_typoScriptNodeValue'] ?? '';
959 $value = trim($cObj->stdWrap($nodeValue, $metaTagTypoScript[$key . '.']));
960 if ($value === '' && !empty($properties['value'])) {
961 $value = $properties['value'];
962 $replace = false;
963 }
964 } else {
965 $value = $properties;
966 }
967
968 $attribute = 'name';
969 if ((is_array($properties) && !empty($properties['httpEquivalent'])) || strtolower($key) === 'refresh') {
970 $attribute = 'http-equiv';
971 }
972 if (is_array($properties) && !empty($properties['attribute'])) {
973 $attribute = $properties['attribute'];
974 }
975 if (is_array($properties) && !empty($properties['replace'])) {
976 $replace = true;
977 }
978
979 if (!is_array($value)) {
980 $value = (array)$value;
981 }
982 foreach ($value as $subValue) {
983 if (trim($subValue) !== '') {
984 $pageRenderer->setMetaTag($attribute, $key, $subValue, [], $replace);
985 }
986 }
987 }
988 }
989
990 /**
991 * @return PageRenderer
992 */
993 protected static function getPageRenderer()
994 {
995 return GeneralUtility::makeInstance(PageRenderer::class);
996 }
997
998 /**
999 * Adds inline CSS code, by respecting the inlineStyle2TempFile option
1000 *
1001 * @param string $cssStyles the inline CSS styling
1002 * @param bool $excludeFromConcatenation option to see if it should be concatenated
1003 * @param string $inlineBlockName the block name to add it
1004 */
1005 protected static function addCssToPageRenderer($cssStyles, $excludeFromConcatenation = false, $inlineBlockName = 'TSFEinlineStyle')
1006 {
1007 if (empty($GLOBALS['TSFE']->config['config']['inlineStyle2TempFile'])) {
1008 self::getPageRenderer()->addCssInlineBlock($inlineBlockName, $cssStyles, !empty($GLOBALS['TSFE']->config['config']['compressCss']));
1009 } else {
1010 self::getPageRenderer()->addCssFile(
1011 self::inline2TempFile($cssStyles, 'css'),
1012 'stylesheet',
1013 'all',
1014 '',
1015 (bool)$GLOBALS['TSFE']->config['config']['compressCss'],
1016 false,
1017 '',
1018 $excludeFromConcatenation
1019 );
1020 }
1021 }
1022
1023 /**
1024 * Returns the currently configured "site language" if a site is configured (= resolved) in the current request.
1025 *
1026 * @internal
1027 */
1028 protected static function getCurrentSiteLanguage(): ?SiteLanguage
1029 {
1030 if (isset($GLOBALS['TYPO3_REQUEST'])
1031 && $GLOBALS['TYPO3_REQUEST'] instanceof ServerRequestInterface
1032 && $GLOBALS['TYPO3_REQUEST']->getAttribute('language') instanceof SiteLanguage) {
1033 return $GLOBALS['TYPO3_REQUEST']->getAttribute('language');
1034 }
1035 return null;
1036 }
1037 }