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