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