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 | /** |
||
4 | * |
||
5 | * This file is part of the Apix Project. |
||
6 | * |
||
7 | * (c) Franck Cassedanne <franck at ouarz.net> |
||
8 | * |
||
9 | * @license http://opensource.org/licenses/BSD-3-Clause New BSD License |
||
10 | * |
||
11 | */ |
||
12 | |||
13 | namespace Apix; |
||
14 | |||
15 | use Apix\Listener, |
||
16 | Apix\Config, |
||
17 | Apix\Router, |
||
18 | Apix\Entity\EntityInterface; |
||
19 | |||
20 | /** |
||
21 | * Represents a resource entity. |
||
22 | */ |
||
23 | class Entity extends Listener |
||
24 | { |
||
25 | /** |
||
26 | * Holds this entity (parsed) documentaions. |
||
27 | * @var array|null |
||
28 | */ |
||
29 | protected $docs = null; |
||
30 | |||
31 | /** |
||
32 | * @var Route |
||
33 | */ |
||
34 | protected $route; |
||
35 | |||
36 | /** |
||
37 | * Holds the entity redirect location. |
||
38 | * @var string|null |
||
39 | */ |
||
40 | protected $redirect; |
||
41 | |||
42 | /** |
||
43 | * Holds all the entity available actions. |
||
44 | * @var array|null |
||
45 | */ |
||
46 | protected $actions = null; |
||
47 | |||
48 | /** |
||
49 | * Holds all default actions. |
||
50 | * @var array |
||
51 | */ |
||
52 | protected $defaultActions = array( |
||
53 | 'OPTIONS' => 'help', |
||
54 | 'HEAD' => 'test' |
||
55 | ); |
||
56 | |||
57 | /** |
||
58 | * Holds the array of results of an entity. |
||
59 | * @var array|null |
||
60 | */ |
||
61 | protected $results = null; |
||
62 | |||
63 | /** |
||
64 | * @var Config |
||
65 | */ |
||
66 | protected $config; |
||
67 | |||
68 | /** |
||
69 | * Constructor. |
||
70 | * |
||
71 | * @param Config|null $config A config object |
||
72 | */ |
||
73 | public function __construct(Config $config = null) |
||
74 | { |
||
75 | $this->config = $config ?: \Apix\Config::getInstance(); |
||
76 | } |
||
77 | |||
78 | /** |
||
79 | * Appends the given array definition and apply generic mappings. |
||
80 | * |
||
81 | * @param array $def An entity array definition. |
||
82 | * @return void |
||
83 | * @see EntityInterface::_append |
||
84 | */ |
||
85 | final public function _append(array $def) |
||
86 | { |
||
87 | if (isset($def['redirect'])) { |
||
88 | $this->redirect = $def['redirect']; |
||
89 | } |
||
90 | } |
||
91 | |||
92 | /** |
||
93 | * Call the resource entity and return its results as an array. |
||
94 | * |
||
95 | * @return array |
||
96 | * @see EntityInterface::underlineCall |
||
97 | */ |
||
98 | public function call($direct=false) |
||
99 | { |
||
100 | // early listeners @ pre-entity |
||
101 | if (!$direct) { |
||
102 | $this->hook('entity', 'early'); |
||
103 | } |
||
104 | |||
105 | if (null === $this->results) { |
||
106 | $this->results = $this->underlineCall($this->route); |
||
0 ignored issues
–
show
|
|||
107 | } |
||
108 | |||
109 | // late listeners @ post-entity |
||
110 | if (!$direct) { |
||
111 | $this->hook('entity', 'late'); |
||
112 | } |
||
113 | |||
114 | return self::convertToArray($this->results); |
||
115 | } |
||
116 | |||
117 | /** |
||
118 | * Converts the provided variable to an array. |
||
119 | * |
||
120 | * @param mixed $mix |
||
121 | * @return array |
||
122 | */ |
||
123 | public static function convertToArray($mix) |
||
124 | { |
||
125 | switch(true): |
||
126 | case is_object($mix): |
||
127 | // TODO: convert nested objects recursively... |
||
128 | return get_object_vars($mix); |
||
129 | |||
130 | case is_string($mix): |
||
131 | return array($mix); |
||
132 | |||
133 | default: // so it must be an array! |
||
0 ignored issues
–
show
The default body in a switch statement must start on the line following the statement.
According to the PSR-2, the body of a default statement must start on the line immediately following the statement. switch ($expr) {
default:
doSomething(); //right
break;
}
switch ($expr) {
default:
doSomething(); //wrong
break;
}
To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. ![]() |
|||
134 | |||
135 | return $mix; |
||
136 | endswitch; |
||
137 | } |
||
138 | |||
139 | /** |
||
140 | * Checks wether the current entity holds the specified method. |
||
141 | * |
||
142 | * @param string $method |
||
143 | * @param array $actions=null Use to override local actions. |
||
0 ignored issues
–
show
There is no parameter named
$actions=null . Was it maybe removed?
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. Consider the following example. The parameter /**
* @param array $germany
* @param array $island
* @param array $italy
*/
function finale($germany, $island) {
return "2:1";
}
The most likely cause is that the parameter was removed, but the annotation was not. ![]() |
|||
144 | * @return boolean |
||
145 | */ |
||
146 | public function hasMethod($method) |
||
147 | { |
||
148 | return array_key_exists($method, $this->getActions()); |
||
149 | } |
||
150 | |||
151 | /** |
||
152 | * Returns all the available actions. |
||
153 | * |
||
154 | * @return array |
||
155 | */ |
||
156 | public function getAllActions() |
||
157 | { |
||
158 | $current = null === $this->getActions() ? array() : $this->getActions(); |
||
159 | $default = $this->defaultActions; |
||
160 | if (false == array_key_exists('GET', $current) ) { |
||
0 ignored issues
–
show
|
|||
161 | unset($default['HEAD']); |
||
162 | } |
||
163 | |||
164 | return $current+$default; |
||
165 | } |
||
166 | |||
167 | /** |
||
168 | * Gets the specified default action. |
||
169 | * |
||
170 | * @return string|null |
||
171 | */ |
||
172 | public function getDefaultAction($method) |
||
173 | { |
||
174 | if (isset($this->defaultActions[$method])) { |
||
175 | return $this->defaultActions[$method]; |
||
176 | } |
||
177 | } |
||
178 | |||
179 | /** |
||
180 | * Returns this entity as an associative array. |
||
181 | * |
||
182 | * @return array |
||
183 | */ |
||
184 | public function toArray() |
||
185 | { |
||
186 | return get_object_vars($this); |
||
187 | } |
||
188 | |||
189 | /** |
||
190 | * Returns the full class/group or specified method documentation. |
||
191 | * |
||
192 | * @param string $method |
||
193 | * @return array |
||
194 | */ |
||
195 | public function getDocs($method=null) |
||
196 | { |
||
197 | if (null == $this->docs) { |
||
198 | $name = 'apix_docs'; |
||
199 | if (!$this->config->get('cache_annotation')) { |
||
200 | $this->docs = $this->parseDocs(); |
||
0 ignored issues
–
show
It seems like you code against a specific sub-type and not the parent class
Apix\Entity as the method parseDocs() does only exist in the following sub-classes of Apix\Entity : Apix\Entity\EntityClass , Apix\Entity\EntityClosure . Maybe you want to instanceof check for one of these explicitly?
Let’s take a look at an example: abstract class User
{
/** @return string */
abstract public function getPassword();
}
class MyUser extends User
{
public function getPassword()
{
// return something
}
public function getDisplayName()
{
// return some name.
}
}
class AuthSystem
{
public function authenticate(User $user)
{
$this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
// do something.
}
}
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break. Available Fixes
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types
inside the if block in such a case.
![]() |
|||
201 | } elseif (false === $this->docs = apc_fetch($name)) { |
||
202 | apc_store($name, $this->docs = $this->parseDocs()); |
||
0 ignored issues
–
show
It seems like you code against a specific sub-type and not the parent class
Apix\Entity as the method parseDocs() does only exist in the following sub-classes of Apix\Entity : Apix\Entity\EntityClass , Apix\Entity\EntityClosure . Maybe you want to instanceof check for one of these explicitly?
Let’s take a look at an example: abstract class User
{
/** @return string */
abstract public function getPassword();
}
class MyUser extends User
{
public function getPassword()
{
// return something
}
public function getDisplayName()
{
// return some name.
}
}
class AuthSystem
{
public function authenticate(User $user)
{
$this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
// do something.
}
}
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break. Available Fixes
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types
inside the if block in such a case.
![]() |
|||
203 | } |
||
204 | } |
||
205 | |||
206 | if (null !== $method) { |
||
207 | return isset($this->docs['methods'][$method]) |
||
208 | ? $this->docs['methods'][$method] : null; |
||
209 | } |
||
210 | |||
211 | return $this->docs; |
||
212 | } |
||
213 | |||
214 | /** |
||
215 | * Returns the validated and required parameters. |
||
216 | * |
||
217 | * @param \ReflectionFunctionAbstract $refMethod A reflected method/function to introspect. |
||
218 | * @param string $httpMethod A public method name e.g. GET, POST. |
||
219 | * @param array $routeParams An array of route parameters to check upon. |
||
220 | * @return array The array of validated and required parameters |
||
221 | * @throws \BadMethodCallException 400 |
||
222 | */ |
||
223 | public function getValidatedParams( |
||
224 | \ReflectionFunctionAbstract $refMethod, $httpMethod, array $routeParams |
||
225 | ) { |
||
226 | $params = array(); |
||
227 | foreach ($refMethod->getParameters() as $param) { |
||
228 | $name = $param->getName(); |
||
229 | if ( |
||
230 | !$param->isOptional() |
||
231 | && !array_key_exists($name, $routeParams) |
||
232 | ) { |
||
233 | |||
234 | // auto inject local objects |
||
235 | if ($class = $param->getClass()) { |
||
236 | $obj = strtolower(str_replace(__NAMESPACE__ |
||
237 | . '\\', '', $class->getName())); |
||
238 | $params[$name] = $obj == 'server' |
||
239 | ? $this->route->server |
||
240 | : $this->route->server->$obj; |
||
241 | } else { |
||
242 | throw new \BadMethodCallException( |
||
243 | "Required {$httpMethod} parameter \"{$name}\" missing in action.", |
||
244 | 400 |
||
245 | ); |
||
246 | } |
||
247 | |||
248 | } elseif (isset($routeParams[$name])) { |
||
249 | $params[$name] = $routeParams[$name]; |
||
250 | } |
||
251 | } |
||
252 | |||
253 | // TODO: maybe we need to check the order of params to match the method? |
||
254 | |||
255 | // TODO: eventually add some kind of type casting using namespacing |
||
256 | // e.g. method(integer $myInteger) => Apix\Casting\Integer, etc... |
||
257 | return $params; |
||
258 | } |
||
259 | |||
260 | /** |
||
261 | * Sets the entity results. |
||
262 | * |
||
263 | * @param array $results |
||
264 | * @return void |
||
265 | */ |
||
266 | public function setResults(array $results=null) |
||
267 | { |
||
268 | $this->results = $results; |
||
269 | } |
||
270 | |||
271 | /** |
||
272 | * Sets the entity results. |
||
273 | * |
||
274 | * @return array |
||
275 | */ |
||
276 | public function getResults() |
||
277 | { |
||
278 | return $this->results; |
||
279 | } |
||
280 | |||
281 | /** |
||
282 | * Sets the route object. |
||
283 | * |
||
284 | * @param Router $route |
||
285 | * @return void |
||
286 | */ |
||
287 | public function setRoute(Router $route) |
||
288 | { |
||
289 | $this->route = $route; |
||
0 ignored issues
–
show
It seems like
$route of type object<Apix\Router> is incompatible with the declared type object<Apix\Route> of property $route .
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property. Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.. ![]() |
|||
290 | } |
||
291 | |||
292 | /** |
||
293 | * Returns the route object. |
||
294 | * |
||
295 | * @return Router |
||
296 | */ |
||
297 | public function getRoute() |
||
298 | { |
||
299 | return $this->route; |
||
300 | } |
||
301 | |||
302 | /** |
||
303 | * Returns the redirect location. |
||
304 | * |
||
305 | * @return string |
||
306 | */ |
||
307 | public function hasRedirect() |
||
308 | { |
||
309 | return isset($this->redirect); |
||
310 | } |
||
311 | |||
312 | /** |
||
313 | * Returns the redirect location. |
||
314 | * |
||
315 | * @return string |
||
316 | */ |
||
317 | public function getRedirect() |
||
318 | { |
||
319 | return $this->redirect; |
||
320 | } |
||
321 | |||
322 | /** |
||
323 | * Returns an array of method keys and action values. |
||
324 | * |
||
325 | * @param array $array |
||
0 ignored issues
–
show
There is no parameter named
$array . Was it maybe removed?
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. Consider the following example. The parameter /**
* @param array $germany
* @param array $island
* @param array $italy
*/
function finale($germany, $island) {
return "2:1";
}
The most likely cause is that the parameter was removed, but the annotation was not. ![]() |
|||
326 | * @return array |
||
327 | */ |
||
328 | public function getActions() |
||
329 | { |
||
330 | if (null === $this->actions) { |
||
331 | $this->setActions(); |
||
0 ignored issues
–
show
It seems like you code against a specific sub-type and not the parent class
Apix\Entity as the method setActions() does only exist in the following sub-classes of Apix\Entity : Apix\Entity\EntityClass , Apix\Entity\EntityClosure . Maybe you want to instanceof check for one of these explicitly?
Let’s take a look at an example: abstract class User
{
/** @return string */
abstract public function getPassword();
}
class MyUser extends User
{
public function getPassword()
{
// return something
}
public function getDisplayName()
{
// return some name.
}
}
class AuthSystem
{
public function authenticate(User $user)
{
$this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
// do something.
}
}
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break. Available Fixes
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types
inside the if block in such a case.
![]() |
|||
332 | } |
||
333 | |||
334 | return $this->actions; |
||
335 | } |
||
336 | |||
337 | /** |
||
338 | * Returns the value of an anotation. |
||
339 | * |
||
340 | * @param string $name |
||
341 | * @return mix|null |
||
342 | */ |
||
343 | public function getAnnotationValue($name) |
||
344 | { |
||
345 | $method = $this->route->getMethod(); |
||
346 | $doc = $this->getDocs($method); |
||
347 | |||
348 | return isset($doc[$name]) ? $doc[$name] : null; |
||
349 | } |
||
350 | |||
351 | } |
||
352 |
Let’s take a look at an example:
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.
Available Fixes
Change the type-hint for the parameter:
Add an additional type-check:
Add the method to the parent class: