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