Issues (9)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/ReflectionFileNamespace.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * Parser Reflection API
4
 *
5
 * @copyright Copyright 2015, Lisachenko Alexander <[email protected]>
6
 *
7
 * This source file is subject to the license that is bundled
8
 * with this source code in the file LICENSE.
9
 */
10
11
namespace Go\ParserReflection;
12
13
use Go\ParserReflection\Instrument\PathResolver;
14
use Go\ParserReflection\ValueResolver\NodeExpressionResolver;
15
use PhpParser\Node;
16
use PhpParser\Node\Expr\FuncCall;
17
use PhpParser\Node\Name;
18
use PhpParser\Node\Stmt\ClassLike;
19
use PhpParser\Node\Stmt\Const_;
20
use PhpParser\Node\Stmt\Expression;
21
use PhpParser\Node\Stmt\Function_;
22
use PhpParser\Node\Stmt\Namespace_;
23
use PhpParser\Node\Stmt\Use_;
24
25
/**
26
 * AST-based reflection for the concrete namespace in the file
27
 */
28
class ReflectionFileNamespace
29
{
30
    /**
31
     * List of classes in the namespace
32
     *
33
     * @var array|ReflectionClass[]
34
     */
35
    protected $fileClasses;
36
37
    /**
38
     * List of functions in the namespace
39
     *
40
     * @var array|ReflectionFunction[]
41
     */
42
    protected $fileFunctions;
43
44
    /**
45
     * List of constants in the namespace
46
     *
47
     * @var array
48
     */
49
    protected $fileConstants;
50
51
    /**
52
     * List of constants in the namespace including defined via "define(...)"
53
     *
54
     * @var array
55
     */
56
    protected $fileConstantsWithDefined;
57
58
    /**
59
     * List of imported namespaces (aliases)
60
     *
61
     * @var array
62
     */
63
    protected $fileNamespaceAliases;
64
65
    /**
66
     * Namespace node
67
     *
68
     * @var Namespace_
69
     */
70
    private $namespaceNode;
71
72
    /**
73
     * Name of the file
74
     *
75
     * @var string
76
     */
77
    private $fileName;
78
79
    /**
80
     * File namespace constructor
81
     *
82
     * @param string          $fileName      Name of the file
83
     * @param string          $namespaceName Name of the namespace
84
     * @param Namespace_|null $namespaceNode Optional AST-node for this namespace block
85
     */
86 3041
    public function __construct($fileName, $namespaceName, Namespace_ $namespaceNode = null)
87
    {
88 3041
        if (!is_string($fileName)) {
89 2
            throw new \InvalidArgumentException(
90 2
                sprintf(
91 2
                    '$fileName must be a string, but a %s was passed',
92 2
                    gettype($fileName)
93
                )
94
            );
95
        }
96 3041
        $fileName = PathResolver::realpath($fileName);
97 3041
        if (!$namespaceNode) {
98 24
            $namespaceNode = ReflectionEngine::parseFileNamespace($fileName, $namespaceName);
99
        }
100 3041
        $this->namespaceNode = $namespaceNode;
101 3041
        $this->fileName      = $fileName;
0 ignored issues
show
Documentation Bug introduced by Lisachenko Alexander
It seems like $fileName can also be of type array or boolean. However, the property $fileName is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
102 3041
    }
103
104
    /**
105
     * Returns the concrete class from the file namespace or false if there is no class
106
     *
107
     * @param string $className
108
     *
109
     * @return bool|ReflectionClass
110
     */
111 3003
    public function getClass($className)
112
    {
113 3003
        if ($this->hasClass($className)) {
114 3003
            return $this->fileClasses[$className];
115
        }
116
117 10
        return false;
118
    }
119
120
    /**
121
     * Gets list of classes in the namespace
122
     *
123
     * @return ReflectionClass[]|array
124
     */
125 3007
    public function getClasses()
126
    {
127 3007
        if (!isset($this->fileClasses)) {
128 3007
            $this->fileClasses = $this->findClasses();
129
        }
130
131 3007
        return $this->fileClasses;
132
    }
133
134
    /**
135
     * Returns a value for the constant
136
     *
137
     * @param string $constantName name of the constant to fetch
138
     *
139
     * @return bool|mixed
140
     */
141 15
    public function getConstant($constantName)
142
    {
143 15
        if ($this->hasConstant($constantName)) {
144 15
            return $this->fileConstants[$constantName];
145
        }
146
147 2
        return false;
148
    }
149
150
    /**
151
     * Returns a list of defined constants in the namespace
152
     *
153
     * @param bool $withDefined Include constants defined via "define(...)" in results.
154
     *
155
     * @return array
156
     */
157 28
    public function getConstants($withDefined = false)
158
    {
159 28
        if ($withDefined) {
160 2
            if (!isset($this->fileConstantsWithDefined)) {
161 2
                $this->fileConstantsWithDefined = $this->findConstants(true);
162
            }
163
164 2
            return $this->fileConstantsWithDefined;
165
        }
166
167 27
        if (!isset($this->fileConstants)) {
168 27
            $this->fileConstants = $this->findConstants();
169
        }
170
171 27
        return $this->fileConstants;
172
    }
173
174
    /**
175
     * Gets doc comments from a class.
176
     *
177
     * @return string|false The doc comment if it exists, otherwise "false"
178
     */
179 1
    public function getDocComment()
180
    {
181 1
        $docComment = false;
182 1
        $comments   = $this->namespaceNode->getAttribute('comments');
183
184 1
        if ($comments) {
185 1
            $docComment = (string)$comments[0];
186
        }
187
188 1
        return $docComment;
189
    }
190
191
    /**
192
     * Gets starting line number
193
     *
194
     * @return integer
195
     */
196 1
    public function getEndLine()
197
    {
198 1
        return $this->namespaceNode->getAttribute('endLine');
199
    }
200
201
    /**
202
     * Returns the name of file
203
     *
204
     * @return string
205
     */
206 4
    public function getFileName()
207
    {
208 4
        return $this->fileName;
209
    }
210
211
    /**
212
     * Returns the concrete function from the file namespace or false if there is no function
213
     *
214
     * @param string $functionName
215
     *
216
     * @return bool|ReflectionFunction
217
     */
218 9
    public function getFunction($functionName)
219
    {
220 9
        if ($this->hasFunction($functionName)) {
221 9
            return $this->fileFunctions[$functionName];
222
        }
223
224 1
        return false;
225
    }
226
227
    /**
228
     * Gets list of functions in the namespace
229
     *
230
     * @return ReflectionFunction[]|array
231
     */
232 17
    public function getFunctions()
233
    {
234 17
        if (!isset($this->fileFunctions)) {
235 17
            $this->fileFunctions = $this->findFunctions();
236
        }
237
238 17
        return $this->fileFunctions;
239
    }
240
241
    /**
242
     * Gets namespace name
243
     *
244
     * @return string
245
     */
246 3029
    public function getName()
247
    {
248 3029
        $nameNode = $this->namespaceNode->name;
249
250 3029
        return $nameNode ? $nameNode->toString() : '';
251
    }
252
253
    /**
254
     * Returns a list of namespace aliases
255
     *
256
     * @return array
257
     */
258 1
    public function getNamespaceAliases()
259
    {
260 1
        if (!isset($this->fileNamespaceAliases)) {
261 1
            $this->fileNamespaceAliases = $this->findNamespaceAliases();
262
        }
263
264 1
        return $this->fileNamespaceAliases;
265
    }
266
267
    /**
268
     * Returns an AST-node for namespace
269
     *
270
     * @return Namespace_
271
     */
272
    public function getNode()
273
    {
274
        return $this->namespaceNode;
275
    }
276
277
    /**
278
     * Helper method to access last token position for namespace
279
     *
280
     * This method is useful because namespace can be declared with braces or without them
281
     */
282
    public function getLastTokenPosition()
283
    {
284
        $endNamespaceTokenPosition = $this->namespaceNode->getAttribute('endTokenPos');
285
286
        /** @var Node $lastNamespaceNode */
287
        $lastNamespaceNode         = end($this->namespaceNode->stmts);
288
        $endStatementTokenPosition = $lastNamespaceNode->getAttribute('endTokenPos');
289
290
        return max($endNamespaceTokenPosition, $endStatementTokenPosition);
291
    }
292
293
    /**
294
     * Gets starting line number
295
     *
296
     * @return integer
297
     */
298 1
    public function getStartLine()
299
    {
300 1
        return $this->namespaceNode->getAttribute('startLine');
301
    }
302
303
    /**
304
     * Checks if the given class is present in this filenamespace
305
     *
306
     * @param string $className
307
     *
308
     * @return bool
309
     */
310 3004
    public function hasClass($className)
311
    {
312 3004
        $classes = $this->getClasses();
313
314 3004
        return isset($classes[$className]);
315
    }
316
317
    /**
318
     * Checks if the given constant is present in this filenamespace
319
     *
320
     * @param string $constantName
321
     *
322
     * @return bool
323
     */
324 27
    public function hasConstant($constantName)
325
    {
326 27
        $constants = $this->getConstants();
327
328 27
        return isset($constants[$constantName]);
329
    }
330
331
    /**
332
     * Checks if the given function is present in this filenamespace
333
     *
334
     * @param string $functionName
335
     *
336
     * @return bool
337
     */
338 10
    public function hasFunction($functionName)
339
    {
340 10
        $functions = $this->getFunctions();
341
342 10
        return isset($functions[$functionName]);
343
    }
344
345
    /**
346
     * Searches for classes in the given AST
347
     *
348
     * @return array|ReflectionClass[]
349
     */
350 3007
    private function findClasses()
351
    {
352 3007
        $classes       = array();
353 3007
        $namespaceName = $this->getName();
354
        // classes can be only top-level nodes in the namespace, so we can scan them directly
355 3007
        foreach ($this->namespaceNode->stmts as $namespaceLevelNode) {
356 3007
            if ($namespaceLevelNode instanceof ClassLike) {
357 3007
                $classShortName = $namespaceLevelNode->name->toString();
358 3007
                $className = $namespaceName ? $namespaceName .'\\' . $classShortName : $classShortName;
359
360 3007
                $namespaceLevelNode->setAttribute('fileName', $this->fileName);
361 3007
                $classes[$className] = new ReflectionClass($className, $namespaceLevelNode);
362
            }
363
        }
364
365 3007
        return $classes;
366
    }
367
368
    /**
369
     * Searches for functions in the given AST
370
     *
371
     * @return array
372
     */
373 17
    private function findFunctions()
374
    {
375 17
        $functions     = array();
376 17
        $namespaceName = $this->getName();
377
378
        // functions can be only top-level nodes in the namespace, so we can scan them directly
379 17
        foreach ($this->namespaceNode->stmts as $namespaceLevelNode) {
380 17
            if ($namespaceLevelNode instanceof Function_) {
381 17
                $funcShortName = $namespaceLevelNode->name->toString();
382 17
                $functionName  = $namespaceName ? $namespaceName .'\\' . $funcShortName : $funcShortName;
383
384 17
                $namespaceLevelNode->setAttribute('fileName', $this->fileName);
385 17
                $functions[$funcShortName] = new ReflectionFunction($functionName, $namespaceLevelNode);
386
            }
387
        }
388
389 17
        return $functions;
390
    }
391
392
    /**
393
     * Searches for constants in the given AST
394
     *
395
     * @param bool $withDefined Include constants defined via "define(...)" in results.
396
     *
397
     * @return array
398
     */
399 28
    private function findConstants($withDefined = false)
400
    {
401 28
        $constants        = array();
402 28
        $expressionSolver = new NodeExpressionResolver($this);
403
404
        // constants can be only top-level nodes in the namespace, so we can scan them directly
405 28
        foreach ($this->namespaceNode->stmts as $namespaceLevelNode) {
406 28
            if ($namespaceLevelNode instanceof Const_) {
407 26
                $nodeConstants = $namespaceLevelNode->consts;
408 26
                if (!empty($nodeConstants)) {
409 26
                    foreach ($nodeConstants as $nodeConstant) {
410 26
                        $expressionSolver->process($nodeConstant->value);
411 26
                        $constants[$nodeConstant->name->toString()] = $expressionSolver->getValue();
412
                    }
413
                }
414
            }
415
        }
416
417 28
        if ($withDefined) {
418 2
            foreach ($this->namespaceNode->stmts as $namespaceLevelNode) {
419 2
                if ($namespaceLevelNode instanceof Expression
420 2
                    && $namespaceLevelNode->expr instanceof FuncCall
421 2
                    && $namespaceLevelNode->expr->name instanceof Name
422 2
                    && (string)$namespaceLevelNode->expr->name === 'define'
423
                ) {
424 2
                    $functionCallNode = $namespaceLevelNode->expr;
425 2
                    $expressionSolver->process($functionCallNode->args[0]->value);
426 2
                    $constantName = $expressionSolver->getValue();
427
428
                    // Ignore constants, for which name can't be determined.
429 2
                    if (strlen($constantName)) {
430 2
                        $expressionSolver->process($functionCallNode->args[1]->value);
431 2
                        $constantValue = $expressionSolver->getValue();
432
433 2
                        $constants[$constantName] = $constantValue;
434
                    }
435
                }
436
            }
437
        }
438
439 28
        return $constants;
440
    }
441
442
    /**
443
     * Searchse for namespace aliases for the current block
444
     *
445
     * @return array
446
     */
447 1
    private function findNamespaceAliases()
448
    {
449 1
        $namespaceAliases = [];
450
451
        // aliases can be only top-level nodes in the namespace, so we can scan them directly
452 1
        foreach ($this->namespaceNode->stmts as $namespaceLevelNode) {
453 1
            if ($namespaceLevelNode instanceof Use_) {
454 1
                $useAliases = $namespaceLevelNode->uses;
455 1
                if (!empty($useAliases)) {
456 1
                    foreach ($useAliases as $useNode) {
457 1
                        $namespaceAliases[$useNode->name->toString()] = (string) $useNode->getAlias();
458
                    }
459
                }
460
            }
461
        }
462
463 1
        return $namespaceAliases;
464
    }
465
}
466