BackendModuleRequestHandler.php 6.55 KB
Newer Older
1
<?php
2
namespace TYPO3\CMS\Backend\Http;
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

/*
 * This file is part of the TYPO3 CMS project.
 *
 * It is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License, either version 2
 * of the License, or any later version.
 *
 * For the full copyright and license information, please read the
 * LICENSE.txt file that was distributed with this source code.
 *
 * The TYPO3 project - inspiring people to share!
 */

use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
use TYPO3\CMS\Core\Core\Bootstrap;
19
use TYPO3\CMS\Core\FormProtection\BackendFormProtection;
20
21
use TYPO3\CMS\Core\FormProtection\FormProtectionFactory;
use TYPO3\CMS\Core\Exception;
22
use TYPO3\CMS\Core\Http\RequestHandlerInterface;
23
24
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Object\ObjectManager;
25
use Psr\Http\Message\ServerRequestInterface;
26
27
28
29

/**
 * Handles the request for backend modules and wizards
 */
30
class BackendModuleRequestHandler implements RequestHandlerInterface {
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

	/**
	 * @var Bootstrap
	 */
	protected $bootstrap;

	/**
	 * @var array
	 */
	protected $moduleRegistry = array();

	/**
	 * @var BackendUserAuthentication
	 */
	protected $backendUserAuthentication;

	/**
48
49
50
51
52
53
54
55
56
	 * Instance of the current Http Request
	 * @var ServerRequestInterface
	 */
	protected $request;

	/**
	 * Constructor handing over the bootstrap and the original request
	 *
	 * @param Bootstrap $bootstrap
57
58
59
60
61
62
63
64
	 */
	public function __construct(Bootstrap $bootstrap) {
		$this->bootstrap = $bootstrap;
	}

	/**
	 * Handles the request, evaluating the configuration and executes the module accordingly
	 *
65
66
	 * @param ServerRequestInterface $request
	 * @return NULL|\Psr\Http\Message\ResponseInterface
67
68
	 * @throws Exception
	 */
69
70
	public function handleRequest(ServerRequestInterface $request) {
		$this->request = $request;
71
72
73
74
75
76
77
78
		$this->boot();

		$this->moduleRegistry = $GLOBALS['TBE_MODULES'];

		if (!$this->isValidModuleRequest()) {
			throw new Exception('The CSRF protection token for the requested module is missing or invalid', 1417988921);
		}

79
		// Set to empty as it is not needed / always coming from typo3/index.php
80
81
82
83
		$GLOBALS['BACK_PATH'] = '';

		$this->backendUserAuthentication = $GLOBALS['BE_USER'];

84
		$moduleName = (string)$this->request->getQueryParams()['M'];
85
86
87
88
89
90
91
92
93
94
95
96
97
98
		if ($this->isDispatchedModule($moduleName)) {
			$isDispatched = $this->dispatchModule($moduleName);
		} else {
			$isDispatched = $this->callTraditionalModule($moduleName);
		}
		if ($isDispatched === FALSE) {
			throw new Exception('No module "' . $moduleName . '" could be found.', 1294585070);
		}
	}

	/**
	 * Execute TYPO3 bootstrap
	 */
	protected function boot() {
99
100
101
102
103
104
105
		// Evaluate the constant for skipping the BE user check for the bootstrap, will be done without the constant at a later point
		if (defined('TYPO3_PROCEED_IF_NO_USER') && TYPO3_PROCEED_IF_NO_USER) {
			$proceedIfNoUserIsLoggedIn = TRUE;
		} else {
			$proceedIfNoUserIsLoggedIn = FALSE;
		}

106
107
108
109
110
111
		$this->bootstrap->checkLockedBackendAndRedirectOrDie()
			->checkBackendIpOrDie()
			->checkSslBackendAndRedirectIfNeeded()
			->loadExtensionTables(TRUE)
			->initializeSpriteManager()
			->initializeBackendUser()
112
			->initializeBackendAuthentication($proceedIfNoUserIsLoggedIn)
113
114
115
116
117
118
119
120
			->initializeLanguageObject()
			->initializeBackendTemplate()
			->endOutputBufferingAndCleanPreviousOutput()
			->initializeOutputCompression()
			->sendHttpHeaders();
	}

	/**
121
	 * This request handler can handle any backend request coming from index.php
122
	 *
123
	 * @param ServerRequestInterface $request
124
125
	 * @return bool
	 */
126
	public function canHandleRequest(ServerRequestInterface $request) {
127
		return $request->getAttribute('isModuleRequest', FALSE);
128
129
130
131
132
133
134
135
	}

	/**
	 * Checks if all parameters are met.
	 *
	 * @return bool
	 */
	protected function isValidModuleRequest() {
136
137
138
		return
			$this->getFormProtection() instanceof BackendFormProtection
		&& $this->getFormProtection()->validateToken((string)$this->request->getQueryParams()['moduleToken'], 'moduleCall', (string)$this->request->getQueryParams()['M']);
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
	}

	/**
	 * A dispatched module, currently only Extbase modules are dispatched,
	 * traditional modules have a module path set.
	 *
	 * @param string $moduleName
	 * @return bool
	 */
	protected function isDispatchedModule($moduleName) {
		return empty($this->moduleRegistry['_PATHS'][$moduleName]);
	}

	/**
	 * Executes the module dispatcher which calls the module appropriately.
	 * Currently only used by Extbase
	 *
	 * @param string $moduleName
	 * @return bool
	 */
	protected function dispatchModule($moduleName) {
		if (is_array($this->moduleRegistry['_dispatcher'])) {
			foreach ($this->moduleRegistry['_dispatcher'] as $dispatcherClassName) {
				$dispatcher = GeneralUtility::makeInstance(ObjectManager::class)->get($dispatcherClassName);
				if ($dispatcher->callModule($moduleName) === TRUE) {
					return TRUE;
					break;
				}
			}
		}
		return FALSE;
	}

	/**
173
	 * Calls traditional modules which are identified by having an index.php in their directory
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
	 * and were previously located within the global scope.
	 *
	 * @param string $moduleName
	 * @return bool
	 */
	protected function callTraditionalModule($moduleName) {
		$moduleBasePath = $this->moduleRegistry['_PATHS'][$moduleName];
		$GLOBALS['MCONF'] = $moduleConfiguration = $this->getModuleConfiguration($moduleName);
		if (!empty($moduleConfiguration['access'])) {
			$this->backendUserAuthentication->modAccess($moduleConfiguration, TRUE);
		}
		if (file_exists($moduleBasePath . 'index.php')) {
			global $SOBE;
			require $moduleBasePath . 'index.php';
			return TRUE;
		}
		return FALSE;
	}

	/**
	 * Returns the module configuration which is either provided in a conf.php file
	 * or during module registration
	 *
	 * @param string $moduleName
	 * @return array
	 */
	protected function getModuleConfiguration($moduleName) {
		$moduleBasePath = $this->moduleRegistry['_PATHS'][$moduleName];
		if (file_exists($moduleBasePath . 'conf.php')) {
			// Some modules still rely on this global configuration array in a conf.php file
			require $moduleBasePath . 'conf.php';
			$moduleConfiguration = $MCONF;
		} else {
			$moduleConfiguration = $this->moduleRegistry['_configuration'][$moduleName];
		}
		return $moduleConfiguration;
	}


	/**
	 * Returns the priority - how eager the handler is to actually handle the request.
	 *
	 * @return int The priority of the request handler.
	 */
	public function getPriority() {
		return 90;
	}

	/**
	 * Wrapper method for static form protection utility
	 *
	 * @return \TYPO3\CMS\Core\FormProtection\AbstractFormProtection
	 */
	protected function getFormProtection() {
		return FormProtectionFactory::get();
	}

}