This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace Faulancer\Controller; |
||
4 | |||
5 | use Faulancer\Event\Observer; |
||
6 | use Faulancer\Event\Type\OnDispatch; |
||
7 | use Faulancer\Exception\IncompatibleResponseException; |
||
8 | use Faulancer\Http\Http; |
||
9 | use Faulancer\Http\JsonResponse; |
||
10 | use Faulancer\Http\Request; |
||
11 | use Faulancer\Http\Response; |
||
12 | use Faulancer\Exception\MethodNotFoundException; |
||
13 | use Faulancer\Service\AuthenticatorService; |
||
14 | use Faulancer\Service\Config; |
||
15 | use Faulancer\ServiceLocator\ServiceLocator; |
||
16 | use Faulancer\Session\SessionManager; |
||
17 | |||
18 | /** |
||
19 | * Class Dispatcher | Dispatcher.php |
||
20 | * |
||
21 | * @package Faulancer\AbstractController |
||
22 | * @author Florian Knapp <[email protected]> |
||
23 | */ |
||
24 | class Dispatcher |
||
25 | { |
||
26 | |||
27 | /** |
||
28 | * The current request object |
||
29 | * |
||
30 | * @var Request |
||
31 | */ |
||
32 | protected $request; |
||
33 | |||
34 | /** |
||
35 | * The configuration object |
||
36 | * |
||
37 | * @var Config |
||
38 | */ |
||
39 | protected $config; |
||
40 | |||
41 | /** |
||
42 | * user, api |
||
43 | * |
||
44 | * @var string |
||
45 | */ |
||
46 | protected $requestType = 'default'; |
||
47 | |||
48 | /** |
||
49 | * Dispatcher constructor. |
||
50 | * |
||
51 | * @param Request $request |
||
52 | * @param Config $config |
||
53 | */ |
||
54 | public function __construct(Request $request, Config $config) |
||
55 | { |
||
56 | $this->request = $request; |
||
57 | $this->config = $config; |
||
58 | } |
||
59 | |||
60 | /** |
||
61 | * Bootstrap for every route call |
||
62 | * |
||
63 | * @return Response|JsonResponse|mixed |
||
64 | * @throws MethodNotFoundException |
||
65 | * @throws IncompatibleResponseException |
||
66 | */ |
||
67 | public function dispatch() |
||
68 | { |
||
69 | // Check for core assets path |
||
70 | if ($assets = $this->_resolveAssetsPath()) { |
||
71 | return $assets; |
||
72 | } |
||
73 | |||
74 | Observer::instance()->trigger(new OnDispatch($this)); |
||
75 | |||
76 | $this->_setLanguageFromUri(); |
||
77 | |||
78 | if (strpos($this->request->getPath(), '/api') === 0) { |
||
79 | $this->requestType = 'api'; |
||
80 | } |
||
81 | |||
82 | list($class, $action, $permission, $payload) = $this->_getRoute($this->request->getPath()); |
||
83 | |||
84 | /** @var Controller $class */ |
||
85 | $class = new $class($this->request); |
||
86 | |||
87 | if (!empty($permission)) { |
||
88 | |||
89 | /** @var AuthenticatorService $authenticator */ |
||
90 | $authenticator = ServiceLocator::instance()->get(AuthenticatorService::class); |
||
91 | $isPermitted = $authenticator->isPermitted($permission); |
||
92 | |||
93 | if ($isPermitted === null) { |
||
94 | |||
95 | return ServiceLocator::instance()->get(Http::class)->redirect($this->config->get('auth:authUrl')); |
||
96 | |||
97 | } else if ($isPermitted === false) { |
||
98 | |||
99 | $errorController = $this->config->get('customErrorController'); |
||
100 | return (new $errorController($this->request))->notPermittedAction(); |
||
101 | |||
102 | } |
||
103 | |||
104 | } |
||
105 | |||
106 | if (!method_exists($class, $action)) { |
||
107 | |||
108 | throw new MethodNotFoundException( |
||
109 | 'Class "' . get_class($class) . '" doesn\'t have the method ' . $action |
||
110 | ); |
||
111 | |||
112 | } |
||
113 | |||
114 | $payload = array_map('strip_tags', $payload); |
||
115 | $payload = array_map('htmlspecialchars', $payload); |
||
116 | |||
117 | $response = call_user_func_array([$class, $action], $payload); |
||
118 | |||
119 | if (!$response instanceof Response) { |
||
120 | throw new IncompatibleResponseException('No valid response returned.'); |
||
121 | } |
||
122 | |||
123 | return $response; |
||
124 | |||
125 | } |
||
126 | |||
127 | /** |
||
128 | * @return bool |
||
129 | */ |
||
130 | private function _setLanguageFromUri() |
||
131 | { |
||
132 | if ($this->request->getParam('lang') !== null) { |
||
133 | |||
134 | $serviceLocator = ServiceLocator::instance(); |
||
135 | |||
136 | /** @var SessionManager $sessionManager */ |
||
137 | $sessionManager = $serviceLocator->get(SessionManager::class); |
||
138 | $sessionManager->set('language', $this->request->getParam('lang')); |
||
139 | |||
140 | return true; |
||
141 | |||
142 | } |
||
143 | |||
144 | return false; |
||
145 | } |
||
146 | |||
147 | /** |
||
148 | * @return bool|string |
||
149 | */ |
||
150 | private function _resolveAssetsPath() |
||
151 | { |
||
152 | $matches = []; |
||
153 | |||
154 | if (preg_match('/(?<style>css)|(?<script>js)/', $this->request->getPath(), $matches)) { |
||
155 | |||
156 | $file = $this->request->getPath(); |
||
157 | |||
158 | if (strpos($file, 'core') !== false) { |
||
159 | |||
160 | $path = str_replace('/core', '', $file); |
||
161 | |||
162 | if ($matches['style'] === 'css') { |
||
163 | return $this->sendCssFileHeader($path); |
||
164 | } else if ($matches['script'] === 'js') { |
||
165 | return $this->sendJsFileHeader($path); |
||
166 | } |
||
167 | |||
168 | } |
||
169 | |||
170 | } |
||
171 | |||
172 | return false; |
||
173 | } |
||
174 | |||
175 | /** |
||
176 | * @param $file |
||
177 | * @return string |
||
178 | * @codeCoverageIgnore |
||
179 | */ |
||
180 | public function sendCssFileHeader($file) |
||
181 | { |
||
182 | header('Content-Type: text/css'); |
||
183 | echo file_get_contents(__DIR__ . '/../../public/assets' . $file); |
||
184 | exit(0); |
||
185 | } |
||
186 | |||
187 | /** |
||
188 | * @param $file |
||
189 | * @return string |
||
190 | * @codeCoverageIgnore |
||
191 | */ |
||
192 | public function sendJsFileHeader($file) |
||
193 | { |
||
194 | header('Content-Type: text/javascript'); |
||
195 | echo file_get_contents(__DIR__ . '/../../public/assets' . $file); |
||
196 | exit(0); |
||
197 | } |
||
198 | |||
199 | /** |
||
200 | * Get data for specific route path |
||
201 | * |
||
202 | * @param string $path |
||
203 | * |
||
204 | * @return array |
||
205 | * @throws MethodNotFoundException |
||
206 | */ |
||
207 | private function _getRoute($path) |
||
208 | { |
||
209 | if (strpos($this->request->getPath(), '/api') === 0) { |
||
210 | $routes = $this->config->get('routes:rest'); |
||
211 | } else { |
||
212 | $routes = $this->config->get('routes'); |
||
213 | } |
||
214 | |||
215 | foreach ($routes as $name => $data) { |
||
216 | |||
217 | if ($target = $this->_getDirectMatch($path, $data)) { |
||
218 | return $target; |
||
219 | } else if ($target = $this->_getVariableMatch($path, $data)) { |
||
220 | return $target; |
||
221 | } |
||
222 | |||
223 | } |
||
224 | |||
225 | throw new MethodNotFoundException('No matching route for path "' . $path . '" found'); |
||
226 | } |
||
227 | |||
228 | /** |
||
229 | * Determines if we have a direct/static route match |
||
230 | * |
||
231 | * @param string $uri The request uri |
||
232 | * @param array $data The result from ClassParser |
||
233 | * |
||
234 | * @return array |
||
235 | * @throws MethodNotFoundException |
||
236 | */ |
||
237 | private function _getDirectMatch($uri, array $data) :array |
||
238 | { |
||
239 | if (!empty($data['path']) && $uri === $data['path']) { |
||
240 | |||
241 | if ($this->requestType === 'default' && in_array($this->request->getMethod(), $data['method'] ?? ['GET'])) { |
||
242 | |||
243 | return [ |
||
244 | $data['controller'], |
||
245 | $data['action'] . 'Action', |
||
246 | $data['permission'] ?? null, |
||
247 | [] |
||
248 | ]; |
||
249 | |||
250 | View Code Duplication | } else if ($this->requestType === 'api') { |
|
0 ignored issues
–
show
|
|||
251 | |||
252 | return [ |
||
253 | $data['controller'], |
||
254 | $this->_getRestfulAction(), |
||
255 | $data['permission'] ?? null, |
||
256 | [] |
||
257 | ]; |
||
258 | |||
259 | } |
||
260 | |||
261 | throw new MethodNotFoundException('Non valid request method available.'); |
||
262 | |||
263 | } |
||
264 | |||
265 | return []; |
||
266 | } |
||
267 | |||
268 | /** |
||
269 | * Determines if we have a variable route match |
||
270 | * |
||
271 | * @param string $uri |
||
272 | * @param array $data |
||
273 | * |
||
274 | * @return array |
||
275 | */ |
||
276 | private function _getVariableMatch($uri, array $data) :array |
||
277 | { |
||
278 | if (empty($data['path']) || $data['path'] === '/') { |
||
279 | return []; |
||
280 | } |
||
281 | |||
282 | $var = []; |
||
283 | $regex = str_replace(['/', '___'], ['\/', '+'], $data['path']); |
||
284 | |||
285 | if (preg_match('|^' . $regex . '$|', $uri, $var)) { |
||
286 | |||
287 | array_splice($var, 0, 1); |
||
288 | |||
289 | if ($this->requestType === 'default' && in_array($this->request->getMethod(), $data['method'])) { |
||
290 | |||
291 | return [ |
||
292 | $data['controller'], |
||
293 | $data['action'] . 'Action', |
||
294 | $data['permission'] ?? null, |
||
295 | $var |
||
296 | ]; |
||
297 | |||
298 | View Code Duplication | } else if ($this->requestType === 'api') { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
299 | |||
300 | return [ |
||
301 | $data['controller'], |
||
302 | $this->_getRestfulAction(), |
||
303 | $data['permission'] ?? null, |
||
304 | $var |
||
305 | ]; |
||
306 | |||
307 | } |
||
308 | |||
309 | } |
||
310 | |||
311 | return []; |
||
312 | } |
||
313 | |||
314 | |||
315 | /** |
||
316 | * @return string |
||
317 | * @codeCoverageIgnore |
||
318 | */ |
||
319 | private function _getRestfulAction() |
||
320 | { |
||
321 | $method = strtoupper($this->request->getMethod()); |
||
322 | |||
323 | switch ($method) { |
||
324 | |||
325 | case 'GET': |
||
326 | return 'get'; |
||
327 | |||
328 | case 'POST': |
||
329 | return 'create'; |
||
330 | |||
331 | case 'PUT': |
||
332 | return 'update'; |
||
333 | |||
334 | case 'DELETE': |
||
335 | return 'delete'; |
||
336 | |||
337 | case 'PATCH': |
||
338 | return 'update'; |
||
339 | |||
340 | default: |
||
341 | return 'get'; |
||
342 | |||
343 | } |
||
344 | } |
||
345 | |||
346 | } |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.