919258ef30cabcfda466cf1bda253c695c631d87
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / ExtDirect / ExtDirectRouter.php
1 <?php
2 namespace TYPO3\CMS\Core\ExtDirect;
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 Psr\Http\Message\ResponseInterface;
18 use Psr\Http\Message\ServerRequestInterface;
19 use TYPO3\CMS\Core\Utility\GeneralUtility;
20
21 /**
22 * Ext Direct Router
23 */
24 class ExtDirectRouter
25 {
26 /**
27 * Dispatches the incoming calls to methods about the ExtDirect API.
28 *
29 * @param ServerRequestInterface $request
30 * @param ResponseInterface $response
31 * @return ResponseInterface
32 */
33 public function routeAction(ServerRequestInterface $request, ResponseInterface $response)
34 {
35 $GLOBALS['error'] = GeneralUtility::makeInstance(\TYPO3\CMS\Core\ExtDirect\ExtDirectDebug::class);
36 $isForm = false;
37 $isUpload = false;
38 $rawPostData = file_get_contents('php://input');
39 $postParameters = $request->getParsedBody();
40 $namespace = isset($request->getParsedBody()['namespace']) ? $request->getParsedBody()['namespace'] : $request->getQueryParams()['namespace'];
41 $extResponse = array();
42 $extRequest = null;
43 $isValidRequest = true;
44 if (!empty($postParameters['extAction'])) {
45 $isForm = true;
46 $isUpload = $postParameters['extUpload'] === 'true';
47 $extRequest = new \stdClass();
48 $extRequest->action = $postParameters['extAction'];
49 $extRequest->method = $postParameters['extMethod'];
50 $extRequest->tid = $postParameters['extTID'];
51 unset($_POST['securityToken']);
52 $extRequest->data = array($_POST + $_FILES);
53 $extRequest->data[] = $postParameters['securityToken'];
54 } elseif (!empty($rawPostData)) {
55 $extRequest = json_decode($rawPostData);
56 } else {
57 $extResponse[] = array(
58 'type' => 'exception',
59 'message' => 'Something went wrong with an ExtDirect call!',
60 'code' => 'router'
61 );
62 $isValidRequest = false;
63 }
64 if (!is_array($extRequest)) {
65 $extRequest = array($extRequest);
66 }
67 if ($isValidRequest) {
68 $validToken = false;
69 $firstCall = true;
70 foreach ($extRequest as $index => $singleRequest) {
71 $extResponse[$index] = array(
72 'tid' => $singleRequest->tid,
73 'action' => $singleRequest->action,
74 'method' => $singleRequest->method
75 );
76 $token = array_pop($singleRequest->data);
77 if ($firstCall) {
78 $firstCall = false;
79 $formprotection = \TYPO3\CMS\Core\FormProtection\FormProtectionFactory::get();
80 $validToken = $formprotection->validateToken($token, 'extDirect');
81 }
82 try {
83 if (!$validToken) {
84 throw new \TYPO3\CMS\Core\FormProtection\Exception('ExtDirect: Invalid Security Token!');
85 }
86 $extResponse[$index]['type'] = 'rpc';
87 $extResponse[$index]['result'] = $this->processRpc($singleRequest, $namespace);
88 $extResponse[$index]['debug'] = $GLOBALS['error']->toString();
89 } catch (\Exception $exception) {
90 $extResponse[$index]['type'] = 'exception';
91 $extResponse[$index]['message'] = $exception->getMessage();
92 $extResponse[$index]['code'] = 'router';
93 }
94 }
95 }
96 if ($isForm && $isUpload) {
97 $extResponse = json_encode($extResponse);
98 $extResponse = preg_replace('/&quot;/', '\\&quot;', $extResponse);
99 $extResponse = array(
100 '<html><body><textarea>' . $extResponse . '</textarea></body></html>'
101 );
102 } else {
103 $extResponse = json_encode($extResponse);
104 }
105 $response->getBody()->write($extResponse);
106 return $response;
107 }
108
109 /**
110 * Processes an incoming extDirect call by executing the defined method. The configuration
111 * array "$GLOBALS['TYPO3_CONF_VARS']['BE']['ExtDirect']" is taken to find the class/method
112 * information.
113 *
114 * @param \stdClass $singleRequest request object from extJS
115 * @param string $namespace namespace like TYPO3.Backend
116 * @return mixed return value of the called method
117 * @throws \UnexpectedValueException if the remote method couldn't be found
118 */
119 protected function processRpc($singleRequest, $namespace)
120 {
121 $endpointName = $namespace . '.' . $singleRequest->action;
122 if (!isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ExtDirect'][$endpointName])) {
123 throw new \UnexpectedValueException('ExtDirect: Call to undefined endpoint: ' . $endpointName, 1294586450);
124 }
125 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ExtDirect'][$endpointName])) {
126 if (!isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ExtDirect'][$endpointName]['callbackClass'])) {
127 throw new \UnexpectedValueException('ExtDirect: Call to undefined endpoint: ' . $endpointName, 1294586451);
128 }
129 $callbackClass = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ExtDirect'][$endpointName]['callbackClass'];
130 $configuration = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ExtDirect'][$endpointName];
131 if (!is_null($configuration['moduleName']) && !is_null($configuration['accessLevel'])) {
132 $GLOBALS['BE_USER']->modAccess(array(
133 'name' => $configuration['moduleName'],
134 'access' => $configuration['accessLevel']
135 ), true);
136 }
137 }
138 $endpointObject = GeneralUtility::getUserObj($callbackClass);
139 return call_user_func_array(array($endpointObject, $singleRequest->method), is_array($singleRequest->data) ? $singleRequest->data : array());
140 }
141 }