[!!!][FEATURE] Introduce Backend Routing
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Http / BackendModuleRequestHandler.php
1 <?php
2 namespace TYPO3\CMS\Backend\Http;
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\Authentication\BackendUserAuthentication;
18 use TYPO3\CMS\Core\Core\Bootstrap;
19 use TYPO3\CMS\Core\FormProtection\BackendFormProtection;
20 use TYPO3\CMS\Core\FormProtection\FormProtectionFactory;
21 use TYPO3\CMS\Core\Exception;
22 use TYPO3\CMS\Core\Http\RequestHandlerInterface;
23 use TYPO3\CMS\Core\Utility\GeneralUtility;
24 use TYPO3\CMS\Extbase\Object\ObjectManager;
25 use Psr\Http\Message\ServerRequestInterface;
26
27 /**
28 * Handles the request for backend modules and wizards
29 */
30 class BackendModuleRequestHandler implements RequestHandlerInterface {
31
32 /**
33 * @var Bootstrap
34 */
35 protected $bootstrap;
36
37 /**
38 * @var array
39 */
40 protected $moduleRegistry = array();
41
42 /**
43 * @var BackendUserAuthentication
44 */
45 protected $backendUserAuthentication;
46
47 /**
48 * Instance of the current Http Request
49 * @var ServerRequestInterface
50 */
51 protected $request;
52
53 /**
54 * Constructor handing over the bootstrap and the original request
55 *
56 * @param Bootstrap $bootstrap
57 */
58 public function __construct(Bootstrap $bootstrap) {
59 $this->bootstrap = $bootstrap;
60 }
61
62 /**
63 * Handles the request, evaluating the configuration and executes the module accordingly
64 *
65 * @param ServerRequestInterface $request
66 * @return NULL|\Psr\Http\Message\ResponseInterface
67 * @throws Exception
68 */
69 public function handleRequest(ServerRequestInterface $request) {
70 $this->request = $request;
71 $this->boot();
72
73 $this->moduleRegistry = $GLOBALS['TBE_MODULES'];
74
75 if (!$this->isValidModuleRequest()) {
76 throw new Exception('The CSRF protection token for the requested module is missing or invalid', 1417988921);
77 }
78
79 // Set to empty as it is not needed / always coming from typo3/index.php
80 $GLOBALS['BACK_PATH'] = '';
81
82 $this->backendUserAuthentication = $GLOBALS['BE_USER'];
83
84 $moduleName = (string)$this->request->getQueryParams()['M'];
85 if ($this->isDispatchedModule($moduleName)) {
86 $isDispatched = $this->dispatchModule($moduleName);
87 } else {
88 $isDispatched = $this->callTraditionalModule($moduleName);
89 }
90 if ($isDispatched === FALSE) {
91 throw new Exception('No module "' . $moduleName . '" could be found.', 1294585070);
92 }
93 }
94
95 /**
96 * Execute TYPO3 bootstrap
97 */
98 protected function boot() {
99 // Evaluate the constant for skipping the BE user check for the bootstrap, will be done without the constant at a later point
100 if (defined('TYPO3_PROCEED_IF_NO_USER') && TYPO3_PROCEED_IF_NO_USER) {
101 $proceedIfNoUserIsLoggedIn = TRUE;
102 } else {
103 $proceedIfNoUserIsLoggedIn = FALSE;
104 }
105
106 $this->bootstrap->checkLockedBackendAndRedirectOrDie()
107 ->checkBackendIpOrDie()
108 ->checkSslBackendAndRedirectIfNeeded()
109 ->initializeBackendRouter()
110 ->loadExtensionTables(TRUE)
111 ->initializeSpriteManager()
112 ->initializeBackendUser()
113 ->initializeBackendAuthentication($proceedIfNoUserIsLoggedIn)
114 ->initializeLanguageObject()
115 ->initializeBackendTemplate()
116 ->endOutputBufferingAndCleanPreviousOutput()
117 ->initializeOutputCompression()
118 ->sendHttpHeaders();
119 }
120
121 /**
122 * This request handler can handle any backend request coming from index.php
123 *
124 * @param ServerRequestInterface $request
125 * @return bool
126 */
127 public function canHandleRequest(ServerRequestInterface $request) {
128 return $request->getAttribute('isModuleRequest', FALSE);
129 }
130
131 /**
132 * Checks if all parameters are met.
133 *
134 * @return bool
135 */
136 protected function isValidModuleRequest() {
137 return
138 $this->getFormProtection() instanceof BackendFormProtection
139 && $this->getFormProtection()->validateToken((string)$this->request->getQueryParams()['moduleToken'], 'moduleCall', (string)$this->request->getQueryParams()['M']);
140 }
141
142 /**
143 * A dispatched module, currently only Extbase modules are dispatched,
144 * traditional modules have a module path set.
145 *
146 * @param string $moduleName
147 * @return bool
148 */
149 protected function isDispatchedModule($moduleName) {
150 return empty($this->moduleRegistry['_PATHS'][$moduleName]);
151 }
152
153 /**
154 * Executes the module dispatcher which calls the module appropriately.
155 * Currently only used by Extbase
156 *
157 * @param string $moduleName
158 * @return bool
159 */
160 protected function dispatchModule($moduleName) {
161 if (is_array($this->moduleRegistry['_dispatcher'])) {
162 foreach ($this->moduleRegistry['_dispatcher'] as $dispatcherClassName) {
163 $dispatcher = GeneralUtility::makeInstance(ObjectManager::class)->get($dispatcherClassName);
164 if ($dispatcher->callModule($moduleName) === TRUE) {
165 return TRUE;
166 break;
167 }
168 }
169 }
170 return FALSE;
171 }
172
173 /**
174 * Calls traditional modules which are identified by having an index.php in their directory
175 * and were previously located within the global scope.
176 *
177 * @param string $moduleName
178 * @return bool
179 */
180 protected function callTraditionalModule($moduleName) {
181 $moduleBasePath = $this->moduleRegistry['_PATHS'][$moduleName];
182 $GLOBALS['MCONF'] = $moduleConfiguration = $this->getModuleConfiguration($moduleName);
183 if (!empty($moduleConfiguration['access'])) {
184 $this->backendUserAuthentication->modAccess($moduleConfiguration, TRUE);
185 }
186 if (file_exists($moduleBasePath . 'index.php')) {
187 global $SOBE;
188 require $moduleBasePath . 'index.php';
189 return TRUE;
190 }
191 return FALSE;
192 }
193
194 /**
195 * Returns the module configuration which is either provided in a conf.php file
196 * or during module registration
197 *
198 * @param string $moduleName
199 * @return array
200 */
201 protected function getModuleConfiguration($moduleName) {
202 $moduleBasePath = $this->moduleRegistry['_PATHS'][$moduleName];
203 if (file_exists($moduleBasePath . 'conf.php')) {
204 // Some modules still rely on this global configuration array in a conf.php file
205 require $moduleBasePath . 'conf.php';
206 $moduleConfiguration = $MCONF;
207 } else {
208 $moduleConfiguration = $this->moduleRegistry['_configuration'][$moduleName];
209 }
210 return $moduleConfiguration;
211 }
212
213
214 /**
215 * Returns the priority - how eager the handler is to actually handle the request.
216 *
217 * @return int The priority of the request handler.
218 */
219 public function getPriority() {
220 return 90;
221 }
222
223 /**
224 * Wrapper method for static form protection utility
225 *
226 * @return \TYPO3\CMS\Core\FormProtection\AbstractFormProtection
227 */
228 protected function getFormProtection() {
229 return FormProtectionFactory::get();
230 }
231
232 }