Issues (47)

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/Addendum.php (2 issues)

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
/**
4
 * This software package is licensed under AGPL, Commercial license.
5
 *
6
 * @package maslosoft/addendum
7
 * @licence AGPL, Commercial
8
 * @copyright Copyright (c) Piotr MaseÅ‚kowski <[email protected]> (Meta container, further improvements, bugfixes)
9
 * @copyright Copyright (c) Maslosoft (Meta container, further improvements, bugfixes)
10
 * @copyright Copyright (c) Jan Suchal (Original version, builder, parser)
11
 * @link https://maslosoft.com/addendum/ - maslosoft addendum
12
 * @link https://code.google.com/p/addendum/ - original addendum project
13
 */
14
15
namespace Maslosoft\Addendum;
16
17
use Maslosoft\Addendum\Annotations\TargetAnnotation;
18
use Maslosoft\Addendum\Builder\Builder;
19
use Maslosoft\Addendum\Builder\DocComment;
20
use Maslosoft\Addendum\Cache\MetaCache;
21
use Maslosoft\Addendum\Collections\AddendumPlugins;
22
use Maslosoft\Addendum\Collections\Meta;
23
use Maslosoft\Addendum\Interfaces\AnnotatedInterface;
24
use Maslosoft\Addendum\Interfaces\AnnotationInterface;
25
use Maslosoft\Addendum\Matcher\AnnotationsMatcher;
26
use Maslosoft\Addendum\Matcher\ClassLiteralMatcher;
27
use Maslosoft\Addendum\Matcher\StaticConstantMatcher;
28
use Maslosoft\Addendum\Plugins\Matcher\ClassErrorSilencer;
29
use Maslosoft\Addendum\Plugins\Matcher\DefencerDecorator;
30
use Maslosoft\Addendum\Plugins\Matcher\MagicConstantDecorator;
31
use Maslosoft\Addendum\Plugins\Matcher\SelfKeywordDecorator;
32
use Maslosoft\Addendum\Plugins\Matcher\UseResolverDecorator;
33
use Maslosoft\Addendum\Reflection\ReflectionAnnotatedClass;
34
use Maslosoft\Addendum\Reflection\ReflectionAnnotatedMethod;
35
use Maslosoft\Addendum\Reflection\ReflectionAnnotatedProperty;
36
use Maslosoft\Addendum\Signals\NamespacesSignal;
37
use Maslosoft\Addendum\Utilities\Blacklister;
38
use Maslosoft\Addendum\Utilities\NameNormalizer;
39
use Maslosoft\EmbeDi\EmbeDi;
40
use Maslosoft\Signals\Signal;
41
use Psr\Log\LoggerAwareInterface;
42
use Psr\Log\LoggerInterface;
43
use Psr\Log\NullLogger;
44
use ReflectionClass;
45
use ReflectionException;
46
use Reflector;
47
48
class Addendum implements LoggerAwareInterface
49
{
50
51
	const DefaultInstanceId = 'addendum';
52
53
	/**
54
	 * Runtime path
55
	 * @var string
56
	 */
57
	public $runtimePath = 'runtime';
58
59
	/**
60
	 * Whether to check modification time of file to invalidate cache.
61
	 * Set this to true for development, and false for production.
62
	 * @var bool
63
	 */
64
	public $checkMTime = false;
65
66
	/**
67
	 * Namespaces to check for annotations.
68
	 * By default global and addendum namespace is included.
69
	 * @var string[]
70
	 */
71
	public $namespaces = [
72
		'\\',
73
		TargetAnnotation::Ns
74
	];
75
76
	/**
77
	 * @var bool[]
78
	 * @internal Do not use, this for performance only
79
	 */
80
	public $nameKeys = [];
81
82
	/**
83
	 * Translatable annotations
84
	 * TODO This should be moved to `maslosoft/addendum-i18n-extractor`
85
	 * @var string[]
86
	 */
87
	public $i18nAnnotations = [
88
		'Label',
89
		'Description'
90
	];
91
92
	/**
93
	 * Plugins collection
94
	 * @var AddendumPlugins|mixed[]
95
	 */
96
	public $plugins = [
97
		'matcher' => [
98
			ClassLiteralMatcher::class => [
99
				SelfKeywordDecorator::class,
100
				UseResolverDecorator::class,
101
				[
102
					'class' => ClassErrorSilencer::class,
103
					'classes' => [
104
						'PHPMD'
105
					]
106
				]
107
			],
108
			StaticConstantMatcher::class => [
109
				UseResolverDecorator::class,
110
				MagicConstantDecorator::class
111
			],
112
			AnnotationsMatcher::class => [
113
				DefencerDecorator::class
114
			]
115
		]
116
	];
117
118
	/**
119
	 * Current instance id
120
	 * @var string
121
	 */
122
	protected $instanceId = self::DefaultInstanceId;
123
124
	/**
125
	 * DI
126
	 * @var EmbeDi
127
	 */
128
	protected $di = null;
129
130
	/**
131
	 * Logger
132
	 * @var LoggerInterface
133
	 */
134
	private $loggerInstance;
135
136
	/**
137
	 * Cache for resolved annotations class names.
138
	 * Key is short annotation name.
139
	 * @var string[]
140
	 */
141
	private static $classNames = [];
142
143
	/**
144
	 * This holds information about all declared classes implementing AnnotatedInterface.
145
	 * @see AnnotatedInterface
146
	 * @var string[]
147
	 */
148
	private static $annotations = [];
149
150
	/**
151
	 * Version holder
152
	 * @var string
153
	 */
154
	private static $versionNumber = null;
155
156
	/**
157
	 * Addendum instances
158
	 * @var Addendum[]
159
	 */
160
	private static $addendums = [];
161
162
	/**
163
	 *
164
	 * @param string $instanceId
165
	 */
166 68
	public function __construct($instanceId = self::DefaultInstanceId)
167
	{
168 68
		$this->instanceId = $instanceId;
169 68
		$this->plugins = new AddendumPlugins($this->plugins);
0 ignored issues
show
It seems like $this->plugins can also be of type object<Maslosoft\Addendu...ctions\AddendumPlugins>; however, Maslosoft\Gazebo\ConfigContainer::__construct() does only seem to accept array<integer,*>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
170
171 68
		$this->di = new EmbeDi($instanceId);
172 68
		$this->di->configure($this);
173 68
	}
174
175
	/**
176
	 * Get flyweight addendum instance of `Addendum`.
177
	 * Only one instance will be created for each `$instanceId`
178
	 *
179
	 * @param string $instanceId
180
	 * @return Addendum
181
	 */
182 61
	public static function fly($instanceId = self::DefaultInstanceId)
183
	{
184 61
		if (empty(self::$addendums[$instanceId]))
185
		{
186
			self::$addendums[$instanceId] = (new Addendum($instanceId))->init();
187
		}
188 61
		return self::$addendums[$instanceId];
189
	}
190
191 58
	public function getInstanceId()
192
	{
193 58
		return $this->instanceId;
194
	}
195
196
	/**
197
	 * Get current addendum version.
198
	 *
199
	 * @return string
200
	 */
201
	public function getVersion()
202
	{
203
		if (null === self::$versionNumber)
204
		{
205
			self::$versionNumber = require __DIR__ . '/version.php';
206
		}
207
		return self::$versionNumber;
208
	}
209
210
	/**
211
	 * Initialize addendum and store configuration.
212
	 * This should be called upon first instance creation.
213
	 *
214
	 * @return Addendum
215
	 */
216
	public function init()
217
	{
218
		if (!$this->di->isStored($this))
219
		{
220
			(new Signal())->emit(new NamespacesSignal($this));
221
		}
222
		$this->di->store($this);
223
		return $this;
224
	}
225
226
	/**
227
	 * Check if class could have annotations.
228
	 * **NOTE:**
229
	 * > This does not check check if class have annotations. It only checks if it implements `AnnotatedInterface`
230
	 * @param string|object $class
231
	 * @return bool
232
	 */
233 37
	public function hasAnnotations($class)
234
	{
235 37
		return (new ReflectionClass($class))->implementsInterface(AnnotatedInterface::class);
236
	}
237
238
	/**
239
	 * Use $class name or object to annotate class
240
	 * @param string|object $class
241
	 * @return ReflectionAnnotatedMethod|ReflectionAnnotatedProperty|ReflectionAnnotatedClass
242
	 */
243 37
	public function annotate($class)
244
	{
245 37
		$className = is_object($class) ? get_class($class) : $class;
246 37
		if (!$this->hasAnnotations($class))
247
		{
248
			throw new ReflectionException(sprintf('To annotate class "%s", it must implement interface %s', $className, AnnotatedInterface::class));
249
		}
250 37
		$reflection = new ReflectionAnnotatedClass($class, $this);
251 32
		return $reflection;
252
	}
253
254
	/**
255
	 * Set logger
256
	 *
257
	 * @param LoggerInterface $logger
258
	 * @return Addendum
259
	 */
260
	public function setLogger(LoggerInterface $logger)
261
	{
262
		$this->loggerInstance = $logger;
263
		return $this;
264
	}
265
266
	/**
267
	 * Get logger
268
	 *
269
	 * @return LoggerInterface logger
270
	 */
271 52
	public function getLogger()
272
	{
273 52
		if (null === $this->loggerInstance)
274
		{
275 35
			$this->loggerInstance = new NullLogger;
276
		}
277 52
		return $this->loggerInstance;
278
	}
279
280
	/**
281
	 * Add annotations namespace.
282
	 * Every added namespace will be included in annotation name resolving for current instance.
283
	 *
284
	 * @param string $ns
285
	 * @return Addendum
286
	 */
287 4
	public function addNamespace($ns)
288
	{
289 4
		NameNormalizer::normalize($ns, false);
290 4
		if (!in_array($ns, $this->namespaces))
291
		{
292
			$before = count($this->namespaces);
293
			$this->namespaces[] = $ns;
294
			$this->namespaces = array_unique($this->namespaces);
295
			$after = count($this->namespaces);
296
			if ($after !== $before)
297
			{
298
				$this->nameKeys = array_flip($this->namespaces);
299
				Cache\NsCache::$addedNs = true;
300
			}
301
302
			$this->di->store($this, [], true);
303
304
			// Reconfigure flyweight instances if present
305
			if (!empty(self::$addendums[$this->instanceId]))
306
			{
307
				self::$addendums[$this->instanceId]->di->configure(self::$addendums[$this->instanceId]);
308
			}
309
		}
310 4
		Meta::$addNs = true;
311 4
		return $this;
312
	}
313
314
	/**
315
	 * Add many annotation namespaces.
316
	 * This is same as `addNamespace`, in that difference that many namespaces at once can be added.
317
	 *
318
	 * It accepts array of namespaces as param:
319
	 * ```php
320
	 * $nss = [
321
	 * 		'Maslosoft\Addendum\Annotations',
322
	 * 		'Maslosoft\Mangan\Annotations'
323
	 * ];
324
	 * ```
325
	 *
326
	 * @param string[] $nss
327
	 * @return Addendum
328
	 */
329 37
	public function addNamespaces($nss)
330
	{
331 37
		foreach ($nss as $ns)
332
		{
333 4
			$this->addNamespace($ns);
334
		}
335 37
		return $this;
336
	}
337
338
	/**
339
	 * Clear entire annotations cache.
340
	 */
341 3
	public static function cacheClear()
342
	{
343 3
		self::$annotations = [];
344 3
		self::$classNames = [];
345 3
		Blacklister::reset();
346 3
		Builder::clearCache();
347 3
		(new MetaCache())->clear();
348 3
	}
349
350
	/**
351
	 * @param Reflector $reflection
352
	 * @return mixed[]
353
	 */
354 51
	public static function getDocComment(Reflector $reflection)
355
	{
356
		// NOTE: Due to a nature of traits, raw doc parsing is always needed
357
		// When using reflection's method `getDocComment` it will return
358
		// doc comment like if it was pasted in code. Thus use statement
359
		// from traits would be omitted. See https://github.com/Maslosoft/Addendum/issues/24
360 51
		$docComment = new DocComment();
361 51
		if ($reflection instanceof ReflectionClass)
362
		{
363 44
			$commentString = $docComment->get($reflection)['class'];
364
		}
365
		else
366
		{
367 26
			$commentString = $docComment->get($reflection);
368
		}
369 51
		return $commentString;
370
	}
371
372
	/**
373
	 * This method has no effect
374
	 * @deprecated Since 4.0.4 this has no effect
375
	 * @param bool $enabled
376
	 */
377
	public static function setRawMode($enabled = true)
0 ignored issues
show
The parameter $enabled is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
378
	{
379
		// Deprecated
380
	}
381
382
	/**
383
	 * Resolve annotation class name to prefixed annotation class name
384
	 *
385
	 * @param string|bool $class
386
	 * @return string
387
	 */
388 58
	public static function resolveClassName($class)
389
	{
390 58
		if (false === $class)
391
		{
392 58
			return null;
393
		}
394 55
		if (isset(self::$classNames[$class]))
395
		{
396 42
			return self::$classNames[$class];
397
		}
398 55
		$matching = [];
399 55
		foreach (self::getDeclaredAnnotations() as $declared)
400
		{
401 55
			if ($declared == $class)
402
			{
403
				$matching[] = $declared;
404
			}
405
			else
406
			{
407 55
				$pos = strrpos($declared, "_$class");
408 55
				if ($pos !== false && ($pos + strlen($class) == strlen($declared) - 1))
409
				{
410 55
					$matching[] = $declared;
411
				}
412
			}
413
		}
414 55
		$result = null;
415 55
		switch (count($matching))
416
		{
417 55
			case 0: $result = $class;
418 55
				break;
419
			case 1: $result = $matching[0];
420
				break;
421
			default: trigger_error("Cannot resolve class name for '$class'. Possible matches: " . join(', ', $matching), E_USER_ERROR);
422
		}
423 55
		self::$classNames[$class] = $result;
424 55
		return $result;
425
	}
426
427 55
	private static function getDeclaredAnnotations()
428
	{
429 55
		if (empty(self::$annotations))
430
		{
431 55
			self::$annotations = [];
432 55
			foreach (get_declared_classes() as $class)
433
			{
434 55
				if ((new ReflectionClass($class))->implementsInterface(AnnotationInterface::class) || $class == AnnotationInterface::class)
435
				{
436 55
					self::$annotations[] = $class;
437
				}
438
			}
439
		}
440 55
		return self::$annotations;
441
	}
442
443
}
444