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