TYPO3 CMS  TYPO3_8-7
RequestHandler.php
Go to the documentation of this file.
1 <?php
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 
28 
39 {
44  protected $bootstrap;
45 
50  protected $timeTracker;
51 
56  protected $controller;
57 
62  protected $request;
63 
69  public function __construct(Bootstrap $bootstrap)
70  {
71  $this->bootstrap = $bootstrap;
72  }
73 
80  public function handleRequest(\Psr\Http\Message\ServerRequestInterface $request)
81  {
82  $response = null;
83  $this->request = $request;
84  $this->initializeTimeTracker();
85 
86  // Hook to preprocess the current request:
87  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/index_ts.php']['preprocessRequest'])) {
88  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/index_ts.php']['preprocessRequest'] as $hookFunction) {
89  $hookParameters = [];
90  GeneralUtility::callUserFunction($hookFunction, $hookParameters, $hookParameters);
91  }
92  unset($hookFunction);
93  unset($hookParameters);
94  }
95 
96  $this->initializeController();
97 
98  if ($GLOBALS['TYPO3_CONF_VARS']['FE']['pageUnavailable_force']
100  GeneralUtility::getIndpEnv('REMOTE_ADDR'),
101  $GLOBALS['TYPO3_CONF_VARS']['SYS']['devIPmask']
102  )
103  ) {
104  $this->controller->pageUnavailableAndExit('This page is temporarily unavailable.');
105  }
106 
107  $this->controller->connectToDB();
108  $this->controller->sendRedirect();
109 
110  // Output compression
111  // Remove any output produced until now
112  $this->bootstrap->endOutputBufferingAndCleanPreviousOutput();
114 
115  $this->bootstrap->loadBaseTca();
116 
117  // Initializing the Frontend User
118  $this->timeTracker->push('Front End user initialized', '');
119  $this->controller->initFEuser();
120  $this->timeTracker->pull();
121 
122  // Initializing a possible logged-in Backend User
124  $GLOBALS['BE_USER'] = $this->controller->initializeBackendUser();
125 
126  // Process the ID, type and other parameters.
127  // After this point we have an array, $page in TSFE, which is the page-record
128  // of the current page, $id.
129  $this->timeTracker->push('Process ID', '');
130  // Initialize admin panel since simulation settings are required here:
131  if ($this->controller->isBackendUserLoggedIn()) {
132  $GLOBALS['BE_USER']->initializeAdminPanel();
133  $this->bootstrap
134  ->initializeBackendRouter()
135  ->loadExtTables();
136  }
137  $this->controller->checkAlternativeIdMethods();
138  $this->controller->clear_preview();
139  $this->controller->determineId();
140 
141  // Now, if there is a backend user logged in and he has NO access to this page,
142  // then re-evaluate the id shown! _GP('ADMCMD_noBeUser') is placed here because
143  // \TYPO3\CMS\Version\Hook\PreviewHook might need to know if a backend user is logged in.
144  if (
145  $this->controller->isBackendUserLoggedIn()
146  && (!$GLOBALS['BE_USER']->extPageReadAccess($this->controller->page) || GeneralUtility::_GP('ADMCMD_noBeUser'))
147  ) {
148  // Remove user
149  unset($GLOBALS['BE_USER']);
150  $this->controller->beUserLogin = false;
151  // Re-evaluate the page-id.
152  $this->controller->checkAlternativeIdMethods();
153  $this->controller->clear_preview();
154  $this->controller->determineId();
155  }
156 
157  $this->controller->makeCacheHash();
158  $this->timeTracker->pull();
159 
160  // Admin Panel & Frontend editing
161  if ($this->controller->isBackendUserLoggedIn()) {
162  $GLOBALS['BE_USER']->initializeFrontendEdit();
163  if ($GLOBALS['BE_USER']->adminPanel instanceof AdminPanelView) {
164  $this->bootstrap->initializeLanguageObject();
165  }
166  if ($GLOBALS['BE_USER']->frontendEdit instanceof FrontendEditingController) {
167  $GLOBALS['BE_USER']->frontendEdit->initConfigOptions();
168  }
169  }
170 
171  // Starts the template
172  $this->timeTracker->push('Start Template', '');
173  $this->controller->initTemplate();
174  $this->timeTracker->pull();
175  // Get from cache
176  $this->timeTracker->push('Get Page from cache', '');
177  // Locks may be acquired here
178  $this->controller->getFromCache();
179  $this->timeTracker->pull();
180  // Get config if not already gotten
181  // After this, we should have a valid config-array ready
182  $this->controller->getConfigArray();
183  // Setting language and locale
184  $this->timeTracker->push('Setting language and locale', '');
185  $this->controller->settingLanguage();
186  $this->controller->settingLocale();
187  $this->timeTracker->pull();
188 
189  // Convert POST data to utf-8 for internal processing if metaCharset is different
190  $this->controller->convPOSTCharset();
191 
192  $this->controller->initializeRedirectUrlHandlers();
193 
194  $this->controller->handleDataSubmission();
195 
196  // Check for shortcut page and redirect
197  $this->controller->checkPageForShortcutRedirect();
198  $this->controller->checkPageForMountpointRedirect();
199 
200  // Generate page
201  $this->controller->setUrlIdToken();
202  if ($this->controller->isGeneratePage()) {
203  $this->timeTracker->push('Page generation');
204  $this->controller->generatePage_preProcessing();
205  $temp_theScript = $this->controller->generatePage_whichScript();
206  if ($temp_theScript) {
207  include $temp_theScript;
208  } else {
209  $this->controller->preparePageContentGeneration();
210  // Content generation
211  PageGenerator::renderContent();
212  $this->controller->setAbsRefPrefix();
213  }
214  $this->controller->generatePage_postProcessing();
215  $this->timeTracker->pull();
216  }
217  $this->controller->releaseLocks();
218 
219  // Render non-cached page parts by replacing placeholders which are taken from cache or added during page generation
220  if ($this->controller->isINTincScript()) {
221  if (!$this->controller->isGeneratePage()) {
222  // When page was generated, this was already called. Avoid calling this twice.
223  $this->controller->preparePageContentGeneration();
224  }
225  $this->timeTracker->push('Non-cached objects');
226  $this->controller->INTincScript();
227  $this->timeTracker->pull();
228  }
229 
230  // Output content
231  $sendTSFEContent = false;
232  if ($this->controller->isOutputting()) {
233  $this->timeTracker->push('Print Content', '');
234  $this->controller->processOutput();
235  $sendTSFEContent = true;
236  $this->timeTracker->pull();
237  }
238  // Store session data for fe_users
239  $this->controller->storeSessionData();
240  // Statistics
241  $GLOBALS['TYPO3_MISC']['microtime_end'] = microtime(true);
242  if ($this->controller->isOutputting()) {
243  if (isset($this->controller->config['config']['debug'])) {
244  $debugParseTime = (bool)$this->controller->config['config']['debug'];
245  } else {
246  $debugParseTime = !empty($GLOBALS['TYPO3_CONF_VARS']['FE']['debug']);
247  }
248  if ($debugParseTime) {
249  $this->controller->content .= LF . '<!-- Parsetime: ' . $this->timeTracker->getParseTime() . 'ms -->';
250  }
251  }
252  $this->controller->redirectToExternalUrl();
253  // Preview info
254  $this->controller->previewInfo();
255  // Hook for end-of-frontend
256  $this->controller->hook_eofe();
257  // Finish timetracking
258  $this->timeTracker->pull();
259 
260  // Admin panel
261  if ($this->controller->isBackendUserLoggedIn() && $GLOBALS['BE_USER'] instanceof FrontendBackendUserAuthentication) {
262  if ($GLOBALS['BE_USER']->isAdminPanelVisible()) {
263  $this->controller->content = str_ireplace('</body>', $GLOBALS['BE_USER']->displayAdminPanel() . '</body>', $this->controller->content);
264  }
265  }
266 
267  if ($sendTSFEContent) {
269  $response = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Http\Response::class);
270  // Send content-length header.
271  // Notice that all HTML content outside the length of the content-length header will be cut off!
272  // Therefore content of unknown length from included PHP-scripts and if admin users are logged
273  // in (admin panel might show...) or if debug mode is turned on, we disable it!
274  if (
275  (!isset($this->controller->config['config']['enableContentLengthHeader']) || $this->controller->config['config']['enableContentLengthHeader'])
276  && !$this->controller->beUserLogin && !$GLOBALS['TYPO3_CONF_VARS']['FE']['debug']
277  && !$this->controller->config['config']['debug'] && !$this->controller->doWorkspacePreview()
278  ) {
279  header('Content-Length: ' . strlen($this->controller->content));
280  }
281  $response->getBody()->write($this->controller->content);
282  }
283  // Debugging Output
284  if (isset($GLOBALS['error']) && is_object($GLOBALS['error']) && @is_callable([$GLOBALS['error'], 'debugOutput'])) {
285  $GLOBALS['error']->debugOutput();
286  }
287  GeneralUtility::devLog('END of FRONTEND session', 'cms', 0, ['_FLUSH' => true]);
288 
289  return $response;
290  }
291 
298  public function canHandleRequest(\Psr\Http\Message\ServerRequestInterface $request)
299  {
300  return $request->getQueryParams()['eID'] || $request->getParsedBody()['eID'] ? false : true;
301  }
302 
309  public function getPriority()
310  {
311  return 50;
312  }
313 
318  protected function initializeOutputCompression()
319  {
320  if ($GLOBALS['TYPO3_CONF_VARS']['FE']['compressionLevel'] && extension_loaded('zlib')) {
321  if (MathUtility::canBeInterpretedAsInteger($GLOBALS['TYPO3_CONF_VARS']['FE']['compressionLevel'])) {
322  @ini_set('zlib.output_compression_level', $GLOBALS['TYPO3_CONF_VARS']['FE']['compressionLevel']);
323  }
324  ob_start([GeneralUtility::makeInstance(CompressionUtility::class), 'compressionOutputHandler']);
325  }
326  }
327 
331  protected function initializeTimeTracker()
332  {
333  $configuredCookieName = trim($GLOBALS['TYPO3_CONF_VARS']['BE']['cookieName']) ?: 'be_typo_user';
334 
336  $this->timeTracker = GeneralUtility::makeInstance(TimeTracker::class, ($this->request->getCookieParams()[$configuredCookieName] ? true : false));
337  $this->timeTracker->start();
338  }
339 
343  protected function initializeController()
344  {
345  $this->controller = GeneralUtility::makeInstance(
346  TypoScriptFrontendController::class,
347  null,
348  GeneralUtility::_GP('id'),
349  GeneralUtility::_GP('type'),
350  GeneralUtility::_GP('no_cache'),
351  GeneralUtility::_GP('cHash'),
352  null,
353  GeneralUtility::_GP('MP'),
354  GeneralUtility::_GP('RDCT')
355  );
356  // setting the global variable for the controller
357  // We have to define this as reference here, because there is code around
358  // which exchanges the TSFE object in the global variable. The reference ensures
359  // that the $controller member always works on the same object as the global variable.
360  // This is a dirty workaround and bypasses the protected access modifier of the controller member.
361  $GLOBALS['TSFE'] = &$this->controller;
362  }
363 }
static devLog($msg, $extKey, $severity=0, $dataVar=false)
handleRequest(\Psr\Http\Message\ServerRequestInterface $request)
static callUserFunction($funcName, &$params, &$ref, $_='', $errorMode=0)
static makeInstance($className,... $constructorArguments)
canHandleRequest(\Psr\Http\Message\ServerRequestInterface $request)
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']