[!!!][FEATURE] Introduce Backend Routing
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / RequestHandler.php
1 <?php
2 namespace TYPO3\CMS\Backend;
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\Backend\Routing\Exception\RouteNotFoundException;
18 use TYPO3\CMS\Core\Core\Bootstrap;
19 use TYPO3\CMS\Core\Core\RequestHandlerInterface;
20 use TYPO3\CMS\Core\FormProtection\FormProtectionFactory;
21 use TYPO3\CMS\Core\Utility\GeneralUtility;
22
23 /**
24 * General RequestHandler for the TYPO3 Backend. This is used for all backend requests except for CLI, AJAX or
25 * calls to mod.php (currently handled by BackendModuleRequestHandler).
26 *
27 * At first, this request handler serves as a replacement to typo3/init.php. It is called but does not exit
28 * so any typical script that is not dispatched, is just running through the handleRequest() method and then
29 * calls its own code.
30 *
31 * However, if a get/post parameter "route" is set, the unified Backend Routing is called and searches for a
32 * matching route inside the Router. The corresponding controller / action is called then which returns content.
33 *
34 * The following get/post parameters are evaluated here:
35 * - route
36 * - token
37 */
38 class RequestHandler implements RequestHandlerInterface {
39
40 /**
41 * Instance of the current TYPO3 bootstrap
42 * @var Bootstrap
43 */
44 protected $bootstrap;
45
46 /**
47 * Constructor handing over the bootstrap
48 *
49 * @param Bootstrap $bootstrap
50 */
51 public function __construct(Bootstrap $bootstrap) {
52 $this->bootstrap = $bootstrap;
53 }
54
55 /**
56 * Handles any backend request
57 *
58 * @throws \Exception
59 * @throws \TYPO3\CMS\Core\Exception
60 */
61 public function handleRequest() {
62 // Only enable routing for typo3/index.php
63 $routingEnabled = GeneralUtility::getIndpEnv('SCRIPT_FILENAME') === PATH_typo3 . 'index.php';
64 $pathToRoute = (string)GeneralUtility::getIndpEnv('PATH_INFO');
65
66 // Allow the login page to be displayed if routing is not used and on index.php
67 if ($routingEnabled && empty($pathToRoute)) {
68 define('TYPO3_PROCEED_IF_NO_USER', 1);
69 $pathToRoute = '/login';
70 }
71
72 $this->boot();
73
74 // Check if the router has the available route and dispatch.
75 if ($routingEnabled) {
76 $this->dispatchRoute($pathToRoute);
77 $this->bootstrap->shutdown();
78 }
79
80 // No route found, so the system proceeds in called entrypoint as fallback.
81 }
82
83 /**
84 * This request handler can handle any backend request (but not CLI).
85 *
86 * @return bool If the request is not a CLI script, TRUE otherwise FALSE
87 */
88 public function canHandleRequest() {
89 return (TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_BE && !(TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_CLI));
90 }
91
92 /**
93 * Returns the priority - how eager the handler is to actually handle the request.
94 *
95 * @return int The priority of the request handler.
96 */
97 public function getPriority() {
98 return 50;
99 }
100
101 /**
102 * Does the main work for setting up the backend environment for any Backend request
103 *
104 * @return void
105 */
106 protected function boot() {
107 $this->bootstrap
108 ->checkLockedBackendAndRedirectOrDie()
109 ->checkBackendIpOrDie()
110 ->checkSslBackendAndRedirectIfNeeded()
111 ->checkValidBrowserOrDie()
112 ->initializeBackendRouter()
113 ->loadExtensionTables(TRUE)
114 ->initializeSpriteManager()
115 ->initializeBackendUser()
116 ->initializeBackendAuthentication()
117 ->initializeLanguageObject()
118 ->initializeBackendTemplate()
119 ->endOutputBufferingAndCleanPreviousOutput()
120 ->initializeOutputCompression()
121 ->sendHttpHeaders();
122 }
123
124 /**
125 * If the request can be handled by the routing framework, dispatch to the correct
126 * controller and action, and then echo the content.
127 *
128 * @param string $pathToRoute
129 *
130 * @throws RouteNotFoundException
131 * @throws \TYPO3\CMS\Core\Exception
132 */
133 protected function dispatchRoute($pathToRoute) {
134 $route = $this->bootstrap->getEarlyInstance(Routing\Router::class)->match($pathToRoute);
135 $routeToken = (string)GeneralUtility::_GP('token');
136 $routeName = $route->getOption('_identifier');
137 $isPublicRoute = $route->getOption('public') || (defined('TYPO3_PROCEED_IF_NO_USER') && TYPO3_PROCEED_IF_NO_USER > 0);
138 if ($isPublicRoute || $this->isValidRequest($routeToken, $routeName)) {
139 list($className, $methodName) = $route->getOption('controller');
140 // parameters can be used at a later point to define the available request parameters
141 $parameters = array();
142 echo GeneralUtility::callUserFunction($className . '->' . $methodName, $parameters, $this);
143 } else {
144 throw new RouteNotFoundException('Invalid request for route "' . $pathToRoute . '"', 1425389455);
145 }
146 }
147
148 /**
149 * Wrapper method for static form protection utility
150 *
151 * @return \TYPO3\CMS\Core\FormProtection\AbstractFormProtection
152 */
153 protected function getFormProtection() {
154 return FormProtectionFactory::get();
155 }
156
157 /**
158 * Checks if the request token is valid. This is checked to see if the route is really
159 * created by the same instance. Should be called for all routes in the backend except
160 * for the ones that don't require a login.
161 *
162 * @param string $token
163 * @param string $name
164 * @return bool
165 * @see \TYPO3\CMS\Backend\Routing\Generator\UrlGenerator::generate() where the token is generated.
166 */
167 protected function isValidRequest($token, $name) {
168 return $this->getFormProtection()->validateToken($token, 'route', $name);
169 }
170 }