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 Anax\Route; |
||
4 | |||
5 | use Anax\Commons\ContainerInjectableInterface; |
||
6 | use Anax\Route\Exception\ConfigurationException; |
||
7 | use Anax\Route\Exception\NotFoundException; |
||
8 | use Psr\Container\ContainerInterface; |
||
9 | |||
10 | /** |
||
11 | * Call a routes handler and return the results. |
||
12 | */ |
||
13 | class RouteHandler |
||
14 | { |
||
15 | /** |
||
16 | * @var ContainerInterface $di the dependency/service container. |
||
17 | */ |
||
18 | protected $di; |
||
19 | |||
20 | |||
21 | |||
22 | /** |
||
23 | * Handle the action for a route and return the results. |
||
24 | * |
||
25 | * @param string $method the request method. |
||
26 | * @param string $path that was matched. |
||
27 | * @param string|array $action base for the callable. |
||
28 | * @param array $arguments optional arguments. |
||
29 | * @param ContainerInjectableInterface $di container with services. |
||
30 | * |
||
31 | * @return mixed as the result from the route handler. |
||
32 | */ |
||
33 | 149 | public function handle( |
|
34 | ?string $method, |
||
35 | ?string $path, |
||
36 | $action, |
||
37 | array $arguments = [], |
||
38 | ContainerInterface $di = null |
||
39 | ) { |
||
40 | 149 | $this->di = $di; |
|
41 | |||
42 | 149 | if (is_null($action)) { |
|
43 | 1 | return; |
|
44 | } |
||
45 | |||
46 | 148 | if (is_callable($action)) { |
|
47 | 118 | if (is_array($action) |
|
48 | 118 | && is_string($action[0]) |
|
49 | 118 | && class_exists($action[0]) |
|
50 | ) { |
||
51 | 2 | $action[] = $arguments; |
|
52 | 2 | return $this->handleAsControllerAction($action); |
|
53 | } |
||
54 | 116 | return $this->handleAsCallable($action, $arguments); |
|
55 | } |
||
56 | |||
57 | 30 | if (is_string($action) && class_exists($action)) { |
|
58 | 26 | $callable = $this->isControllerAction($method, $path, $action); |
|
59 | 25 | if ($callable) { |
|
60 | 21 | return $this->handleAsControllerAction($callable); |
|
61 | } |
||
62 | |||
63 | 4 | $isinvocable = $this->isInvocableClass($action); |
|
64 | 4 | if ($isinvocable) { |
|
65 | 3 | return $this->handleAsInvocableClass($action); |
|
66 | } |
||
67 | } |
||
68 | |||
69 | 5 | if ($di |
|
70 | 5 | && is_array($action) |
|
71 | 5 | && isset($action[0]) |
|
72 | 5 | && isset($action[1]) |
|
73 | 5 | && is_string($action[0]) |
|
74 | ) { |
||
75 | // Try to load service from app/di injected container |
||
76 | 3 | return $this->handleUsingDi($action, $arguments, $di); |
|
77 | } |
||
78 | |||
79 | 2 | throw new ConfigurationException("Handler for route does not seem to be a callable action."); |
|
80 | } |
||
81 | |||
82 | |||
83 | |||
84 | /** |
||
85 | * Get an informative string representing the handler type. |
||
86 | * |
||
87 | * @param string|array $action base for the callable. |
||
88 | * @param ContainerInjectableInterface $di container with services. |
||
89 | * |
||
90 | * @return string as the type of handler. |
||
91 | */ |
||
92 | 2 | public function getHandlerType( |
|
93 | $action, |
||
94 | ContainerInterface $di = null |
||
95 | ) { |
||
96 | 2 | if (is_null($action)) { |
|
97 | 1 | return "null"; |
|
98 | } |
||
99 | |||
100 | 2 | if (is_callable($action)) { |
|
101 | 1 | return "callable"; |
|
102 | } |
||
103 | |||
104 | 2 | if (is_string($action) && class_exists($action)) { |
|
105 | 1 | $callable = $this->isControllerAction(null, null, $action); |
|
106 | 1 | if ($callable) { |
|
107 | 1 | return "controller"; |
|
108 | } |
||
109 | } |
||
110 | |||
111 | 2 | if ($di |
|
112 | 2 | && is_array($action) |
|
113 | 2 | && isset($action[0]) |
|
114 | 2 | && isset($action[1]) |
|
115 | 2 | && is_string($action[0]) |
|
116 | 2 | && $di->has($action[0]) |
|
117 | 2 | && is_callable([$di->get($action[0]), $action[1]]) |
|
118 | ) { |
||
119 | 1 | return "di"; |
|
120 | } |
||
121 | |||
122 | 1 | return "not found"; |
|
123 | } |
||
124 | |||
125 | |||
126 | |||
127 | /** |
||
128 | * Check if action is a class with the magic method __invoke. |
||
129 | * |
||
130 | * @param string $action the proposed handler. |
||
131 | * |
||
132 | * @return boolean true if class has implemented __invoke, else false. |
||
133 | */ |
||
134 | 4 | protected function isInvocableClass(string $action) : bool |
|
135 | { |
||
136 | 4 | $rc = new \ReflectionClass($action); |
|
137 | 4 | return $rc->hasMethod("__invoke"); |
|
138 | } |
||
139 | |||
140 | |||
141 | |||
142 | /** |
||
143 | * Call the __invoke action with optional arguments and call |
||
144 | * initialisation methods if available. |
||
145 | * |
||
146 | * @param string $class as class that implements __invokable. |
||
147 | * |
||
148 | * @return mixed result from the handler. |
||
149 | */ |
||
150 | 3 | protected function handleAsInvocableClass(string $class) |
|
151 | { |
||
152 | 3 | $obj = new $class(); |
|
153 | // $class = $callable[0]; |
||
154 | 3 | $action = "__invoke"; |
|
155 | // $args = $callable[2]; |
||
156 | |||
157 | 3 | $refl = new \ReflectionClass($class); |
|
158 | 3 | $diInterface = "Anax\Commons\ContainerInjectableInterface"; |
|
159 | 3 | $appInterface = "Anax\Commons\AppInjectableInterface"; |
|
160 | |||
161 | 3 | if ($this->di && $refl->implementsInterface($diInterface)) { |
|
162 | 1 | $obj->setDI($this->di); |
|
163 | 2 | } elseif ($this->di && $refl->implementsInterface($appInterface)) { |
|
164 | if (!$this->di->has("app")) { |
||
165 | throw new ConfigurationException( |
||
166 | "Controller '$class' implements AppInjectableInterface but \$app is not available in \$di." |
||
167 | ); |
||
168 | } |
||
169 | $obj->setApp($this->di->get("app")); |
||
170 | } |
||
171 | |||
172 | try { |
||
173 | 3 | $refl = new \ReflectionMethod($class, "initialize"); |
|
174 | 2 | if ($refl->isPublic()) { |
|
175 | 2 | $res = $obj->initialize(); |
|
176 | 2 | if (!is_null($res)) { |
|
177 | 2 | return $res; |
|
178 | } |
||
179 | } |
||
180 | 1 | } catch (\ReflectionException $e) { |
|
181 | ; |
||
182 | } |
||
183 | |||
184 | 2 | $refl = new \ReflectionMethod($obj, $action); |
|
185 | 2 | $paramIsVariadic = false; |
|
0 ignored issues
–
show
|
|||
186 | 2 | foreach ($refl->getParameters() as $param) { |
|
187 | if ($param->isVariadic()) { |
||
188 | $paramIsVariadic = true; |
||
0 ignored issues
–
show
$paramIsVariadic is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the
Loading history...
|
|||
189 | break; |
||
190 | } |
||
191 | } |
||
192 | |||
193 | // if (!$paramIsVariadic |
||
194 | // && $refl->getNumberOfParameters() < count($args) |
||
195 | // ) { |
||
196 | // throw new NotFoundException( |
||
197 | // "Controller '$class' with action method '$action' valid but to many parameters. Got " |
||
198 | // . count($args) |
||
199 | // . ", expected " |
||
200 | // . $refl->getNumberOfParameters() . "." |
||
201 | // ); |
||
202 | // } |
||
203 | |||
204 | try { |
||
205 | //$res = $obj(...$args); |
||
206 | 2 | $res = $obj(); |
|
207 | } catch (\ArgumentCountError $e) { |
||
208 | throw new NotFoundException($e->getMessage()); |
||
209 | } catch (\TypeError $e) { |
||
210 | throw new NotFoundException($e->getMessage()); |
||
211 | } |
||
212 | |||
213 | 2 | return $res; |
|
214 | } |
||
215 | |||
216 | |||
217 | |||
218 | /** |
||
219 | * Check if items can be used to call a controller action, verify |
||
220 | * that the controller exists, the action has a class-method to call. |
||
221 | * |
||
222 | * @param string $method the request method. |
||
223 | * @param string $path the matched path, base for the controller action |
||
224 | * and the arguments. |
||
225 | * @param string $class the controller class |
||
226 | * |
||
227 | * @return array with callable details. |
||
228 | */ |
||
229 | 27 | protected function isControllerAction( |
|
230 | ?string $method, |
||
231 | ?string $path, |
||
232 | string $class |
||
233 | ) { |
||
234 | 27 | $method = ucfirst(strtolower($method)); |
|
235 | 27 | $args = explode("/", $path); |
|
236 | 27 | $action = array_shift($args); |
|
237 | 27 | $action = empty($action) ? "index" : $action; |
|
238 | 27 | $action = str_replace("-", "", $action); |
|
239 | 27 | $action1 = "{$action}Action{$method}"; |
|
240 | 27 | $action2 = "{$action}Action"; |
|
241 | 27 | $action3 = "catchAll{$method}"; |
|
242 | 27 | $action4 = "catchAll"; |
|
243 | |||
244 | 27 | foreach ([$action1, $action2] as $target) { |
|
245 | try { |
||
246 | 27 | $refl = new \ReflectionMethod($class, $target); |
|
247 | 19 | if (!$refl->isPublic()) { |
|
248 | 1 | throw new NotFoundException("Controller method '$class::$target' is not a public method."); |
|
249 | } |
||
250 | |||
251 | 18 | return [$class, $target, $args]; |
|
252 | 17 | } catch (\ReflectionException $e) { |
|
253 | ; |
||
254 | } |
||
255 | } |
||
256 | |||
257 | 8 | foreach ([$action3, $action4] as $target) { |
|
258 | try { |
||
259 | 8 | $refl = new \ReflectionMethod($class, $target); |
|
260 | 4 | if (!$refl->isPublic()) { |
|
261 | throw new NotFoundException("Controller method '$class::$target' is not a public method."); |
||
262 | } |
||
263 | |||
264 | 4 | array_unshift($args, $action); |
|
265 | 4 | return [$class, $target, $args]; |
|
266 | 5 | } catch (\ReflectionException $e) { |
|
267 | ; |
||
268 | } |
||
269 | } |
||
270 | |||
271 | 4 | return false; |
|
272 | } |
||
273 | |||
274 | |||
275 | |||
276 | /** |
||
277 | * Call the controller action with optional arguments and call |
||
278 | * initialisation methods if available. |
||
279 | * |
||
280 | * @param string $callable with details on what controller action to call. |
||
281 | * |
||
282 | * @return mixed result from the handler. |
||
283 | */ |
||
284 | 23 | protected function handleAsControllerAction(array $callable) |
|
285 | { |
||
286 | 23 | $class = $callable[0]; |
|
287 | 23 | $action = $callable[1]; |
|
288 | 23 | $args = $callable[2]; |
|
289 | 23 | $obj = new $class(); |
|
290 | |||
291 | 23 | $refl = new \ReflectionClass($class); |
|
292 | 23 | $diInterface = "Anax\Commons\ContainerInjectableInterface"; |
|
293 | 23 | $appInterface = "Anax\Commons\AppInjectableInterface"; |
|
294 | |||
295 | 23 | if ($this->di && $refl->implementsInterface($diInterface)) { |
|
296 | 1 | $obj->setDI($this->di); |
|
297 | 22 | } elseif ($this->di && $refl->implementsInterface($appInterface)) { |
|
298 | 2 | if (!$this->di->has("app")) { |
|
299 | 1 | throw new ConfigurationException( |
|
300 | 1 | "Controller '$class' implements AppInjectableInterface but \$app is not available in \$di." |
|
301 | ); |
||
302 | } |
||
303 | 1 | $obj->setApp($this->di->get("app")); |
|
304 | } |
||
305 | |||
306 | try { |
||
307 | 22 | $refl = new \ReflectionMethod($class, "initialize"); |
|
308 | 15 | if ($refl->isPublic()) { |
|
309 | 15 | $res = $obj->initialize(); |
|
310 | 15 | if (!is_null($res)) { |
|
311 | 15 | return $res; |
|
312 | } |
||
313 | } |
||
314 | 7 | } catch (\ReflectionException $e) { |
|
315 | ; |
||
316 | } |
||
317 | |||
318 | 21 | $refl = new \ReflectionMethod($obj, $action); |
|
319 | 21 | $paramIsVariadic = false; |
|
320 | 21 | foreach ($refl->getParameters() as $param) { |
|
321 | 9 | if ($param->isVariadic()) { |
|
322 | 4 | $paramIsVariadic = true; |
|
323 | 9 | break; |
|
324 | } |
||
325 | } |
||
326 | |||
327 | 21 | if (!$paramIsVariadic |
|
328 | 21 | && $refl->getNumberOfParameters() < count($args) |
|
329 | ) { |
||
330 | 1 | throw new NotFoundException( |
|
331 | 1 | "Controller '$class' with action method '$action' valid but to many parameters. Got " |
|
332 | 1 | . count($args) |
|
333 | 1 | . ", expected " |
|
334 | 1 | . $refl->getNumberOfParameters() . "." |
|
335 | ); |
||
336 | } |
||
337 | |||
338 | try { |
||
339 | 20 | $res = $obj->$action(...$args); |
|
340 | 2 | } catch (\ArgumentCountError $e) { |
|
341 | 1 | throw new NotFoundException($e->getMessage()); |
|
342 | 1 | } catch (\TypeError $e) { |
|
343 | 1 | throw new NotFoundException($e->getMessage()); |
|
344 | } |
||
345 | |||
346 | 18 | return $res; |
|
347 | } |
||
348 | |||
349 | |||
350 | |||
351 | /** |
||
352 | * Handle as callable support callables where the method is not static. |
||
353 | * |
||
354 | * @param string|array $action base for the callable |
||
355 | * @param array $arguments optional arguments |
||
356 | * @param ContainerInjectableInterface $di container with services |
||
357 | * |
||
358 | * @return mixed as the result from the route handler. |
||
359 | */ |
||
360 | 116 | protected function handleAsCallable( |
|
361 | $action, |
||
362 | array $arguments |
||
363 | ) { |
||
364 | 116 | if (is_array($action) |
|
365 | 116 | && isset($action[0]) |
|
366 | 116 | && isset($action[1]) |
|
367 | 116 | && is_string($action[0]) |
|
368 | 116 | && is_string($action[1]) |
|
369 | 116 | && class_exists($action[0]) |
|
370 | ) { |
||
371 | // ["SomeClass", "someMethod"] but not static |
||
372 | $refl = new \ReflectionMethod($action[0], $action[1]); |
||
373 | if ($refl->isPublic() && !$refl->isStatic()) { |
||
374 | $obj = new $action[0](); |
||
375 | return $obj->{$action[1]}(...$arguments); |
||
376 | } |
||
377 | } |
||
378 | |||
379 | // Add $di to param list, if defined by the callback |
||
380 | 116 | $refl = is_array($action) |
|
381 | 1 | ? new \ReflectionMethod($action[0], $action[1]) |
|
382 | 116 | : new \ReflectionFunction($action); |
|
383 | 116 | $params = $refl->getParameters(); |
|
384 | 116 | if (isset($params[0]) && $params[0]->getName() === "di") { |
|
385 | 1 | array_unshift($arguments, $this->di); |
|
386 | } |
||
387 | |||
388 | 116 | return call_user_func($action, ...$arguments); |
|
389 | } |
||
390 | |||
391 | |||
392 | |||
393 | /** |
||
394 | * Load callable as a service from the $di container. |
||
395 | * |
||
396 | * @param string|array $action base for the callable |
||
397 | * @param array $arguments optional arguments |
||
398 | * @param ContainerInjectableInterface $di container with services |
||
399 | * |
||
400 | * @return mixed as the result from the route handler. |
||
401 | */ |
||
402 | 3 | protected function handleUsingDi( |
|
403 | $action, |
||
404 | array $arguments, |
||
405 | ContainerInterface $di |
||
406 | ) { |
||
407 | 3 | if (!$di->has($action[0])) { |
|
408 | 1 | throw new ConfigurationException("Routehandler '{$action[0]}' not loaded in di."); |
|
409 | } |
||
410 | |||
411 | 2 | $service = $di->get($action[0]); |
|
412 | 2 | if (!is_callable([$service, $action[1]])) { |
|
413 | 1 | throw new ConfigurationException( |
|
414 | 1 | "Routehandler '{$action[0]}' does not have a callable method '{$action[1]}'." |
|
415 | ); |
||
416 | } |
||
417 | |||
418 | 1 | return call_user_func( |
|
419 | 1 | [$service, $action[1]], |
|
420 | 1 | ...$arguments |
|
421 | ); |
||
422 | } |
||
423 | } |
||
424 |
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.
Both the
$myVar
assignment in line 1 and the$higher
assignment in line 2 are dead. The first because$myVar
is never used and the second because$higher
is always overwritten for every possible time line.