TYPO3 CMS  TYPO3_8-7
AjaxRequestHandler.php
Go to the documentation of this file.
1 <?php
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 
26 
39 {
44  protected $bootstrap;
45 
50  protected $publicAjaxIds = [
51  '/ajax/login',
52  '/ajax/logout',
53  '/ajax/login/refresh',
54  '/ajax/login/timedout',
55  '/ajax/rsa/publickey',
56  '/ajax/core/requirejs'
57  ];
58 
64  public function __construct(Bootstrap $bootstrap)
65  {
66  $this->bootstrap = $bootstrap;
67  }
68 
75  public function handleRequest(ServerRequestInterface $request)
76  {
77  // First get the ajaxID
78  $ajaxID = isset($request->getParsedBody()['ajaxID']) ? $request->getParsedBody()['ajaxID'] : $request->getQueryParams()['ajaxID'];
79  $request = $request->withAttribute('routePath', $ajaxID);
80  $proceedIfNoUserIsLoggedIn = $this->isLoggedInBackendUserRequired($ajaxID);
81  $this->boot($proceedIfNoUserIsLoggedIn);
82 
83  try {
84  // Backend Routing - check if a valid route is there, and dispatch
85  return $this->dispatch($request);
86  } catch (ResourceNotFoundException $e) {
87  // no Route found, fallback to the traditional AJAX request
88  }
89  return $this->dispatchTraditionalAjaxRequest($request);
90  }
91 
99  public function canHandleRequest(ServerRequestInterface $request)
100  {
101  return $request->getAttribute('isAjaxRequest', false);
102  }
103 
109  public function getPriority()
110  {
111  return 80;
112  }
113 
121  protected function isLoggedInBackendUserRequired($ajaxId)
122  {
123  return in_array($ajaxId, $this->publicAjaxIds, true);
124  }
125 
131  protected function boot($proceedIfNoUserIsLoggedIn)
132  {
133  $this->bootstrap
134  ->checkLockedBackendAndRedirectOrDie($proceedIfNoUserIsLoggedIn)
135  ->checkBackendIpOrDie()
136  ->checkSslBackendAndRedirectIfNeeded()
137  ->initializeBackendRouter()
138  ->loadBaseTca()
139  ->loadExtTables()
140  ->initializeBackendUser()
141  ->initializeBackendAuthentication($proceedIfNoUserIsLoggedIn)
142  ->initializeLanguageObject()
143  ->initializeBackendTemplate()
144  ->endOutputBufferingAndCleanPreviousOutput()
145  ->initializeOutputCompression()
146  ->sendHttpHeaders();
147  }
148 
157  protected function dispatch(ServerRequestInterface $request)
158  {
160  $response = GeneralUtility::makeInstance(Response::class, 'php://temp', 200, [
161  'Content-Type' => 'application/json; charset=utf-8',
162  'X-JSON' => 'true'
163  ]);
164 
166  $dispatcher = GeneralUtility::makeInstance(RouteDispatcher::class);
167  return $dispatcher->dispatch($request, $response);
168  }
169 
177  protected function dispatchTraditionalAjaxRequest($request)
178  {
179  GeneralUtility::deprecationLog('Using the traditional way for AJAX requests via $TYPO3_CONF_VARS[BE][AJAX] is discouraged. Use the Backend Routes logic instead.');
180  $ajaxID = $request->getAttribute('routePath');
181  // Finding the script path from the registry
182  $ajaxRegistryEntry = isset($GLOBALS['TYPO3_CONF_VARS']['BE']['AJAX'][$ajaxID]) ? $GLOBALS['TYPO3_CONF_VARS']['BE']['AJAX'][$ajaxID] : null;
183  $ajaxScript = null;
184  $csrfTokenCheck = false;
185  if ($ajaxRegistryEntry !== null && is_array($ajaxRegistryEntry) && isset($ajaxRegistryEntry['callbackMethod'])) {
186  $ajaxScript = $ajaxRegistryEntry['callbackMethod'];
187  $csrfTokenCheck = $ajaxRegistryEntry['csrfTokenCheck'];
188  }
189 
190  // Instantiating the AJAX object
192  $ajaxObj = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Http\AjaxRequestHandler::class, $ajaxID);
193  $ajaxParams = ['request' => $request];
194 
195  // Evaluating the arguments and calling the AJAX method/function
196  if (empty($ajaxID)) {
197  $ajaxObj->setError('No valid ajaxID parameter given.');
198  } elseif (empty($ajaxScript)) {
199  $ajaxObj->setError('No backend function registered for ajaxID "' . $ajaxID . '".');
200  } elseif ($csrfTokenCheck && !$this->isValidRequest($request)) {
201  $ajaxObj->setError('Invalid CSRF token detected for ajaxID "' . $ajaxID . '", reload the backend of TYPO3');
202  } else {
203  $success = GeneralUtility::callUserFunction($ajaxScript, $ajaxParams, $ajaxObj, '', 1);
204  if ($success === false) {
205  $ajaxObj->setError('Registered backend function for ajaxID "' . $ajaxID . '" was not found.');
206  }
207  }
208 
209  // Outputting the content (and setting the X-JSON-Header)
210  return $ajaxObj->render();
211  }
212 
218  protected function getFormProtection()
219  {
221  }
222 
232  protected function isValidRequest(ServerRequestInterface $request)
233  {
234  $token = (string)(isset($request->getParsedBody()['ajaxToken']) ? $request->getParsedBody()['ajaxToken'] : $request->getQueryParams()['ajaxToken']);
235  return $this->getFormProtection()->validateToken($token, 'ajaxCall', $request->getAttribute('routePath'));
236  }
237 }
canHandleRequest(ServerRequestInterface $request)
static callUserFunction($funcName, &$params, &$ref, $_='', $errorMode=0)
isValidRequest(ServerRequestInterface $request)
static makeInstance($className,... $constructorArguments)
handleRequest(ServerRequestInterface $request)
static get($classNameOrType='default',... $constructorArguments)
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']