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