[TASK] Introduce unified RequestHandling for all requests
[Packages/TYPO3.CMS.git] / typo3 / sysext / frontend / Classes / RequestHandler.php
1 <?php
2 namespace TYPO3\CMS\Frontend;
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\Core\Bootstrap;
18 use TYPO3\CMS\Core\Core\RequestHandlerInterface;
19 use TYPO3\CMS\Core\Utility\GeneralUtility;
20
21 /**
22 * This is the main entry point of the TypoScript driven standard front-end
23 *
24 * Basically put, this is the script which all requests for TYPO3 delivered pages goes to in the
25 * frontend (the website). The script instantiates a $TSFE object, includes libraries and does a little logic here
26 * and there in order to instantiate the right classes to create the webpage.
27 * Previously, this was called index_ts.php and also included the logic for the lightweight "eID" concept,
28 * which is now handled in a separate request handler (EidRequestHandler).
29 */
30 class RequestHandler implements RequestHandlerInterface {
31
32 /**
33 * Instance of the current TYPO3 bootstrap
34 * @var Bootstrap
35 */
36 protected $bootstrap;
37
38 /**
39 * Constructor handing over the bootstrap
40 *
41 * @param Bootstrap $bootstrap
42 */
43 public function __construct(Bootstrap $bootstrap) {
44 $this->bootstrap = $bootstrap;
45 }
46
47 /**
48 * Handles a frontend request
49 *
50 * @return void
51 */
52 public function handleRequest() {
53 // Hook to preprocess the current request:
54 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/index_ts.php']['preprocessRequest'])) {
55 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/index_ts.php']['preprocessRequest'] as $hookFunction) {
56 $hookParameters = array();
57 GeneralUtility::callUserFunction($hookFunction, $hookParameters, $hookParameters);
58 }
59 unset($hookFunction);
60 unset($hookParameters);
61 }
62
63 // Timetracking started
64 $configuredCookieName = trim($GLOBALS['TYPO3_CONF_VARS']['BE']['cookieName']);
65 if (empty($configuredCookieName)) {
66 $configuredCookieName = 'be_typo_user';
67 }
68 if ($_COOKIE[$configuredCookieName]) {
69 $GLOBALS['TT'] = new \TYPO3\CMS\Core\TimeTracker\TimeTracker();
70 } else {
71 $GLOBALS['TT'] = new \TYPO3\CMS\Core\TimeTracker\NullTimeTracker();
72 }
73
74 $GLOBALS['TT']->start();
75
76 /** @var $GLOBALS['TSFE'] \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController */
77 $GLOBALS['TSFE'] = GeneralUtility::makeInstance(
78 \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController::class,
79 $GLOBALS['TYPO3_CONF_VARS'],
80 GeneralUtility::_GP('id'),
81 GeneralUtility::_GP('type'),
82 GeneralUtility::_GP('no_cache'),
83 GeneralUtility::_GP('cHash'),
84 GeneralUtility::_GP('jumpurl'),
85 GeneralUtility::_GP('MP'),
86 GeneralUtility::_GP('RDCT')
87 );
88
89 if ($GLOBALS['TYPO3_CONF_VARS']['FE']['pageUnavailable_force']
90 && !GeneralUtility::cmpIP(
91 GeneralUtility::getIndpEnv('REMOTE_ADDR'),
92 $GLOBALS['TYPO3_CONF_VARS']['SYS']['devIPmask'])
93 ) {
94 $GLOBALS['TSFE']->pageUnavailableAndExit('This page is temporarily unavailable.');
95 }
96
97 $GLOBALS['TSFE']->connectToDB();
98 $GLOBALS['TSFE']->sendRedirect();
99
100 // Output compression
101 // Remove any output produced until now
102 ob_clean();
103 if ($GLOBALS['TYPO3_CONF_VARS']['FE']['compressionLevel'] && extension_loaded('zlib')) {
104 if (\TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($GLOBALS['TYPO3_CONF_VARS']['FE']['compressionLevel'])) {
105 // Prevent errors if ini_set() is unavailable (safe mode)
106 @ini_set('zlib.output_compression_level', $GLOBALS['TYPO3_CONF_VARS']['FE']['compressionLevel']);
107 }
108 ob_start(array(GeneralUtility::makeInstance(\TYPO3\CMS\Frontend\Utility\CompressionUtility::class), 'compressionOutputHandler'));
109 }
110
111 // FE_USER
112 $GLOBALS['TT']->push('Front End user initialized', '');
113 /** @var $GLOBALS['TSFE'] \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController */
114 $GLOBALS['TSFE']->initFEuser();
115 $GLOBALS['TT']->pull();
116
117 // BE_USER
118 /** @var $GLOBALS['BE_USER'] \TYPO3\CMS\Backend\FrontendBackendUserAuthentication */
119 $GLOBALS['BE_USER'] = $GLOBALS['TSFE']->initializeBackendUser();
120
121 // Process the ID, type and other parameters.
122 // After this point we have an array, $page in TSFE, which is the page-record
123 // of the current page, $id.
124 $GLOBALS['TT']->push('Process ID', '');
125 // Initialize admin panel since simulation settings are required here:
126 if ($GLOBALS['TSFE']->isBackendUserLoggedIn()) {
127 $GLOBALS['BE_USER']->initializeAdminPanel();
128 $this->bootstrap->loadExtensionTables(TRUE);
129 } else {
130 $this->bootstrap->loadCachedTca();
131 }
132 $GLOBALS['TSFE']->checkAlternativeIdMethods();
133 $GLOBALS['TSFE']->clear_preview();
134 $GLOBALS['TSFE']->determineId();
135
136 // Now, if there is a backend user logged in and he has NO access to this page,
137 // then re-evaluate the id shown! _GP('ADMCMD_noBeUser') is placed here because
138 // \TYPO3\CMS\Version\Hook\PreviewHook might need to know if a backend user is logged in.
139 if (
140 $GLOBALS['TSFE']->isBackendUserLoggedIn()
141 && (!$GLOBALS['BE_USER']->extPageReadAccess($GLOBALS['TSFE']->page) || GeneralUtility::_GP('ADMCMD_noBeUser'))
142 ) {
143 // Remove user
144 unset($GLOBALS['BE_USER']);
145 $GLOBALS['TSFE']->beUserLogin = FALSE;
146 // Re-evaluate the page-id.
147 $GLOBALS['TSFE']->checkAlternativeIdMethods();
148 $GLOBALS['TSFE']->clear_preview();
149 $GLOBALS['TSFE']->determineId();
150 }
151
152 $GLOBALS['TSFE']->makeCacheHash();
153 $GLOBALS['TT']->pull();
154
155 // Admin Panel & Frontend editing
156 if ($GLOBALS['TSFE']->isBackendUserLoggedIn()) {
157 $GLOBALS['BE_USER']->initializeFrontendEdit();
158 if ($GLOBALS['BE_USER']->adminPanel instanceof \TYPO3\CMS\Frontend\View\AdminPanelView) {
159 $this->bootstrap
160 ->initializeLanguageObject()
161 ->initializeSpriteManager();
162 }
163 if ($GLOBALS['BE_USER']->frontendEdit instanceof \TYPO3\CMS\Core\FrontendEditing\FrontendEditingController) {
164 $GLOBALS['BE_USER']->frontendEdit->initConfigOptions();
165 }
166 }
167
168 // Starts the template
169 $GLOBALS['TT']->push('Start Template', '');
170 $GLOBALS['TSFE']->initTemplate();
171 $GLOBALS['TT']->pull();
172 // Get from cache
173 $GLOBALS['TT']->push('Get Page from cache', '');
174 $GLOBALS['TSFE']->getFromCache();
175 $GLOBALS['TT']->pull();
176 // Get config if not already gotten
177 // After this, we should have a valid config-array ready
178 $GLOBALS['TSFE']->getConfigArray();
179 // Setting language and locale
180 $GLOBALS['TT']->push('Setting language and locale', '');
181 $GLOBALS['TSFE']->settingLanguage();
182 $GLOBALS['TSFE']->settingLocale();
183 $GLOBALS['TT']->pull();
184
185 // Convert POST data to internal "renderCharset" if different from the metaCharset
186 $GLOBALS['TSFE']->convPOSTCharset();
187
188 // Check JumpUrl
189 $GLOBALS['TSFE']->setExternalJumpUrl();
190 $GLOBALS['TSFE']->checkJumpUrlReferer();
191
192 $GLOBALS['TSFE']->handleDataSubmission();
193
194 // Check for shortcut page and redirect
195 $GLOBALS['TSFE']->checkPageForShortcutRedirect();
196 $GLOBALS['TSFE']->checkPageForMountpointRedirect();
197
198 // Generate page
199 $GLOBALS['TSFE']->setUrlIdToken();
200 $GLOBALS['TT']->push('Page generation', '');
201 if ($GLOBALS['TSFE']->isGeneratePage()) {
202 $GLOBALS['TSFE']->generatePage_preProcessing();
203 $temp_theScript = $GLOBALS['TSFE']->generatePage_whichScript();
204 if ($temp_theScript) {
205 include $temp_theScript;
206 } else {
207 \TYPO3\CMS\Frontend\Page\PageGenerator::pagegenInit();
208 // Global content object
209 $GLOBALS['TSFE']->newCObj();
210 // LIBRARY INCLUSION, TypoScript
211 $temp_incFiles = \TYPO3\CMS\Frontend\Page\PageGenerator::getIncFiles();
212 foreach ($temp_incFiles as $temp_file) {
213 include_once './' . $temp_file;
214 }
215 // Content generation
216 if (!$GLOBALS['TSFE']->isINTincScript()) {
217 \TYPO3\CMS\Frontend\Page\PageGenerator::renderContent();
218 $GLOBALS['TSFE']->setAbsRefPrefix();
219 }
220 }
221 $GLOBALS['TSFE']->generatePage_postProcessing();
222 } elseif ($GLOBALS['TSFE']->isINTincScript()) {
223 \TYPO3\CMS\Frontend\Page\PageGenerator::pagegenInit();
224 // Global content object
225 $GLOBALS['TSFE']->newCObj();
226 // LIBRARY INCLUSION, TypoScript
227 $temp_incFiles = \TYPO3\CMS\Frontend\Page\PageGenerator::getIncFiles();
228 foreach ($temp_incFiles as $temp_file) {
229 include_once './' . $temp_file;
230 }
231 }
232 $GLOBALS['TT']->pull();
233
234 // $GLOBALS['TSFE']->config['INTincScript']
235 if ($GLOBALS['TSFE']->isINTincScript()) {
236 $GLOBALS['TT']->push('Non-cached objects', '');
237 $GLOBALS['TSFE']->INTincScript();
238 $GLOBALS['TT']->pull();
239 }
240 // Output content
241 $sendTSFEContent = FALSE;
242 if ($GLOBALS['TSFE']->isOutputting()) {
243 $GLOBALS['TT']->push('Print Content', '');
244 $GLOBALS['TSFE']->processOutput();
245 $sendTSFEContent = TRUE;
246 $GLOBALS['TT']->pull();
247 }
248 // Store session data for fe_users
249 $GLOBALS['TSFE']->storeSessionData();
250 // Statistics
251 $GLOBALS['TYPO3_MISC']['microtime_end'] = microtime(TRUE);
252 $GLOBALS['TSFE']->setParseTime();
253 if (isset($GLOBALS['TSFE']->config['config']['debug'])) {
254 $debugParseTime = (bool)$GLOBALS['TSFE']->config['config']['debug'];
255 } else {
256 $debugParseTime = !empty($GLOBALS['TSFE']->TYPO3_CONF_VARS['FE']['debug']);
257 }
258 if ($GLOBALS['TSFE']->isOutputting() && $debugParseTime) {
259 $GLOBALS['TSFE']->content .= LF . '<!-- Parsetime: ' . $GLOBALS['TSFE']->scriptParseTime . 'ms -->';
260 }
261 // Check JumpUrl
262 $GLOBALS['TSFE']->jumpurl();
263 // Preview info
264 $GLOBALS['TSFE']->previewInfo();
265 // Hook for end-of-frontend
266 $GLOBALS['TSFE']->hook_eofe();
267 // Finish timetracking
268 $GLOBALS['TT']->pull();
269 // Check memory usage
270 \TYPO3\CMS\Core\Utility\MonitorUtility::peakMemoryUsage();
271 // beLoginLinkIPList
272 echo $GLOBALS['TSFE']->beLoginLinkIPList();
273
274 // Admin panel
275 if (
276 $GLOBALS['TSFE']->isBackendUserLoggedIn()
277 && $GLOBALS['BE_USER'] instanceof \TYPO3\CMS\Backend\FrontendBackendUserAuthentication
278 && $GLOBALS['BE_USER']->isAdminPanelVisible()
279 ) {
280 $GLOBALS['TSFE']->content = str_ireplace('</head>', $GLOBALS['BE_USER']->adminPanel->getAdminPanelHeaderData() . '</head>', $GLOBALS['TSFE']->content);
281 $GLOBALS['TSFE']->content = str_ireplace('</body>', $GLOBALS['BE_USER']->displayAdminPanel() . '</body>', $GLOBALS['TSFE']->content);
282 }
283
284 if ($sendTSFEContent) {
285 echo $GLOBALS['TSFE']->content;
286 }
287 // Debugging Output
288 if (isset($GLOBALS['error']) && is_object($GLOBALS['error']) && @is_callable(array($GLOBALS['error'], 'debugOutput'))) {
289 $GLOBALS['error']->debugOutput();
290 }
291 if (TYPO3_DLOG) {
292 GeneralUtility::devLog('END of FRONTEND session', 'cms', 0, array('_FLUSH' => TRUE));
293 }
294 }
295
296 /**
297 * This request handler can handle any frontend request.
298 *
299 * @return bool If the request is not an eID request, TRUE otherwise FALSE
300 */
301 public function canHandleRequest() {
302 return GeneralUtility::_GP('eID') ? FALSE : TRUE;
303 }
304
305 /**
306 * Returns the priority - how eager the handler is to actually handle the
307 * request.
308 *
309 * @return int The priority of the request handler.
310 */
311 public function getPriority() {
312 return 50;
313 }
314 }