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