[TASK] Move BE User initialization into PSR-15 middleware
[Packages/TYPO3.CMS.git] / typo3 / sysext / frontend / Classes / Http / RequestHandler.php
1 <?php
2 declare(strict_types = 1);
3 namespace TYPO3\CMS\Frontend\Http;
4
5 /*
6 * This file is part of the TYPO3 CMS project.
7 *
8 * It is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, either version 2
10 * of the License, or any later version.
11 *
12 * For the full copyright and license information, please read the
13 * LICENSE.txt file that was distributed with this source code.
14 *
15 * The TYPO3 project - inspiring people to share!
16 */
17
18 use Psr\Http\Message\ResponseInterface;
19 use Psr\Http\Message\ServerRequestInterface;
20 use Psr\Http\Server\RequestHandlerInterface as PsrRequestHandlerInterface;
21 use TYPO3\CMS\Backend\FrontendBackendUserAuthentication;
22 use TYPO3\CMS\Core\Core\Bootstrap;
23 use TYPO3\CMS\Core\FrontendEditing\FrontendEditingController;
24 use TYPO3\CMS\Core\Http\NullResponse;
25 use TYPO3\CMS\Core\Http\RequestHandlerInterface;
26 use TYPO3\CMS\Core\Http\Response;
27 use TYPO3\CMS\Core\TimeTracker\TimeTracker;
28 use TYPO3\CMS\Core\Utility\GeneralUtility;
29 use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
30 use TYPO3\CMS\Frontend\Page\PageGenerator;
31
32 /**
33 * This is the main entry point of the TypoScript driven standard front-end
34 *
35 * Basically put, this is the script which all requests for TYPO3 delivered pages goes to in the
36 * frontend (the website). The script instantiates a $TSFE object, includes libraries and does a little logic here
37 * and there in order to instantiate the right classes to create the webpage.
38 * Previously, this was called index_ts.php and also included the logic for the lightweight "eID" concept,
39 * which is now handled in a separate middleware (EidHandler).
40 */
41 class RequestHandler implements RequestHandlerInterface, PsrRequestHandlerInterface
42 {
43 /**
44 * Instance of the current TYPO3 bootstrap
45 * @var Bootstrap
46 */
47 protected $bootstrap;
48
49 /**
50 * Instance of the timetracker
51 * @var TimeTracker
52 */
53 protected $timeTracker;
54
55 /**
56 * Constructor handing over the bootstrap and the original request
57 *
58 * @param Bootstrap $bootstrap
59 */
60 public function __construct(Bootstrap $bootstrap)
61 {
62 $this->bootstrap = $bootstrap;
63 }
64
65 /**
66 * Handles a frontend request
67 *
68 * @param ServerRequestInterface $request
69 * @return ResponseInterface
70 */
71 public function handleRequest(ServerRequestInterface $request): ResponseInterface
72 {
73 return $this->handle($request);
74 }
75
76 /**
77 * Handles a frontend request, after finishing running middlewares
78 *
79 * @param ServerRequestInterface $request
80 * @return ResponseInterface|null
81 */
82 public function handle(ServerRequestInterface $request): ResponseInterface
83 {
84 // Fetch the initialized time tracker object
85 $this->timeTracker = GeneralUtility::makeInstance(TimeTracker::class);
86 /** @var TypoScriptFrontendController $controller */
87 $controller = $GLOBALS['TSFE'];
88
89 // Process the ID, type and other parameters.
90 // After this point we have an array, $page in TSFE, which is the page-record
91 // of the current page, $id.
92 $this->timeTracker->push('Process ID', '');
93 $controller->checkAlternativeIdMethods();
94 $controller->clear_preview();
95 $controller->determineId();
96
97 // Now, if there is a backend user logged in and he has NO access to this page,
98 // then re-evaluate the id shown! _GP('ADMCMD_noBeUser') is placed here because
99 // \TYPO3\CMS\Version\Hook\PreviewHook might need to know if a backend user is logged in.
100 if (
101 $controller->isBackendUserLoggedIn()
102 && (!$GLOBALS['BE_USER']->extPageReadAccess($controller->page) || GeneralUtility::_GP('ADMCMD_noBeUser'))
103 ) {
104 // Remove user
105 unset($GLOBALS['BE_USER']);
106 $controller->beUserLogin = false;
107 // Re-evaluate the page-id.
108 $controller->checkAlternativeIdMethods();
109 $controller->clear_preview();
110 $controller->determineId();
111 }
112
113 $controller->makeCacheHash();
114 $this->timeTracker->pull();
115
116 // Admin Panel & Frontend editing
117 if ($controller->isBackendUserLoggedIn()) {
118 $GLOBALS['BE_USER']->initializeFrontendEdit();
119 if ($GLOBALS['BE_USER']->frontendEdit instanceof FrontendEditingController) {
120 $GLOBALS['BE_USER']->frontendEdit->initConfigOptions();
121 }
122 }
123
124 // Starts the template
125 $this->timeTracker->push('Start Template', '');
126 $controller->initTemplate();
127 $this->timeTracker->pull();
128 // Get from cache
129 $this->timeTracker->push('Get Page from cache', '');
130 $controller->getFromCache();
131 $this->timeTracker->pull();
132 // Get config if not already gotten
133 // After this, we should have a valid config-array ready
134 $controller->getConfigArray();
135 // Setting language and locale
136 $this->timeTracker->push('Setting language and locale', '');
137 $controller->settingLanguage();
138 $controller->settingLocale();
139 $this->timeTracker->pull();
140
141 // Convert POST data to utf-8 for internal processing if metaCharset is different
142 $controller->convPOSTCharset();
143
144 $controller->initializeRedirectUrlHandlers();
145
146 $controller->handleDataSubmission();
147
148 // Check for shortcut page and redirect
149 $controller->checkPageForShortcutRedirect();
150 $controller->checkPageForMountpointRedirect();
151
152 // Generate page
153 $controller->setUrlIdToken();
154 $this->timeTracker->push('Page generation', '');
155 if ($controller->isGeneratePage()) {
156 $controller->generatePage_preProcessing();
157 $controller->preparePageContentGeneration();
158 // Content generation
159 if (!$controller->isINTincScript()) {
160 PageGenerator::renderContent();
161 $controller->setAbsRefPrefix();
162 }
163 $controller->generatePage_postProcessing();
164 } elseif ($controller->isINTincScript()) {
165 $controller->preparePageContentGeneration();
166 }
167 $controller->releaseLocks();
168 $this->timeTracker->pull();
169
170 // Render non-cached parts
171 if ($controller->isINTincScript()) {
172 $this->timeTracker->push('Non-cached objects', '');
173 $controller->INTincScript();
174 $this->timeTracker->pull();
175 }
176
177 // Create a Response object when sending content
178 $response = new Response();
179
180 // Output content
181 $isOutputting = $controller->isOutputting();
182 if ($isOutputting) {
183 $this->timeTracker->push('Print Content', '');
184 $controller->processOutput();
185 $this->timeTracker->pull();
186 }
187 // Store session data for fe_users
188 $controller->storeSessionData();
189
190 $redirectResponse = $controller->redirectToExternalUrl();
191 if ($redirectResponse instanceof ResponseInterface) {
192 return $redirectResponse;
193 }
194
195 // Statistics
196 $GLOBALS['TYPO3_MISC']['microtime_end'] = microtime(true);
197 if ($isOutputting && ($controller->config['config']['debug'] ?? !empty($GLOBALS['TYPO3_CONF_VARS']['FE']['debug']))) {
198 $response = $response->withHeader('X-TYPO3-Parsetime', $this->timeTracker->getParseTime() . 'ms');
199 }
200
201 // Preview info
202 $controller->previewInfo();
203 // Hook for end-of-frontend
204 $controller->hook_eofe();
205 // Finish timetracking
206 $this->timeTracker->pull();
207
208 // Admin panel
209 if ($controller->isBackendUserLoggedIn() && $GLOBALS['BE_USER'] instanceof FrontendBackendUserAuthentication && $GLOBALS['BE_USER']->isAdminPanelVisible()) {
210 $controller->content = str_ireplace('</body>', $GLOBALS['BE_USER']->displayAdminPanel() . '</body>', $controller->content);
211 }
212
213 if ($isOutputting) {
214 $response->getBody()->write($controller->content);
215 }
216
217 return $isOutputting ? $response : new NullResponse();
218 }
219
220 /**
221 * This request handler can handle any frontend request.
222 *
223 * @param ServerRequestInterface $request
224 * @return bool If the request is not an eID request, TRUE otherwise FALSE
225 */
226 public function canHandleRequest(ServerRequestInterface $request): bool
227 {
228 return true;
229 }
230
231 /**
232 * Returns the priority - how eager the handler is to actually handle the
233 * request.
234 *
235 * @return int The priority of the request handler.
236 */
237 public function getPriority(): int
238 {
239 return 50;
240 }
241 }