Issues (6)

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/Container.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
namespace Lebran;
3
4
use Closure;
5
use ArrayAccess;
6
use ReflectionClass;
7
use ReflectionMethod;
8
use ReflectionFunction;
9
use ReflectionParameter;
10
use Lebran\Container\NotFoundException;
11
use Lebran\Container\InjectableInterface;
12
use Interop\Container\ContainerInterface;
13
use Lebran\Container\ServiceProviderInterface;
14
15
/**
16
 * Lebran\Container it's a component that implements Dependency Injection/Service Location patterns.
17
 * Supports string, object and anonymous function definition. Allows using the array and magical syntax.
18
 *
19
 *                              Example
20
 *  <code>
21
 *      // Create service container
22
 *      $di = new \Lebran\Container();
23
 *
24
 *      // Container supports 3 types of definition
25
 *
26
 *      // Type 1: Object
27
 *      $di->set('myservice', new \MyNamespace\MyService());
28
 *
29
 *      // Type 2: String
30
 *      $di->set('myservice2', '\MyNamespace\MyService2');
31
 *
32
 *      // Type 3: Closure
33
 *      $di->set('myservice3', function(){
34
 *          return new \MyNamespace\MyService3();
35
 *      });
36
 *
37
 *      // Getting service
38
 *      $di->get('myservice');
39
 *  </code>
40
 *
41
 * @package    Container
42
 * @version    1.0
43
 * @author     Roman Kritskiy <[email protected]>
44
 * @license    MIT
45
 * @copyright  2015 - 2016 Roman Kritskiy
46
 */
47
class Container implements ContainerInterface, ArrayAccess
48
{
49
    const MAX_DEPENDENCY_LEVEL = 30;
50
51
    /**
52
     * @var self Store for last container instance
53
     */
54
    protected static $instance;
55
56
    /**
57
     * @var array Store for services.
58
     */
59
    protected $services = [];
60
61
    /**
62
     * @var array Store for shared services.
63
     */
64
    protected $shared = [];
65
66
    /**
67
     * @var int
68
     */
69
    protected $level = 0;
70
71
    /**
72
     * Returns last container instance.
73
     *
74
     * @return Container Last container instance.
75
     */
76
    public static function instance()
77
    {
78
        return static::$instance;
79
    }
80
81
    /**
82
     * Initialisation
83
     */
84
    public function __construct()
85
    {
86
        static::$instance = $this;
87
    }
88
89
    /**
90
     * Merge two containers into one.
91
     *
92
     * @param ServiceProviderInterface $provider Service provider.
93
     *
94
     * @return self
95
     */
96
    public function register(ServiceProviderInterface $provider)
97
    {
98
        $provider->register($this);
99
        return $this;
100
    }
101
102
    /**
103
     * Registers a service in the container.
104
     *
105
     * @param string $id         Service id.
106
     * @param mixed  $definition Service definition.
107
     * @param bool   $shared     Shared or not.
108
     *
109
     * @return $this
110
     * @throws ContainerException Error while retrieving the entry.
111
     */
112
    public function set($id, $definition, $shared = false)
113
    {
114
        if (is_string($definition)) {
115
            $definition = $this->normalize($definition);
116
        }
117
        $this->services[$this->normalize($id)] = compact('definition', 'shared');
118
        return $this;
119
    }
120
121
    /**
122
     * Normalize service name.
123
     *
124
     * @param string $id Service id.
125
     *
126
     * @return string Normalized name.
127
     */
128
    protected function normalize($id)
129
    {
130
        return trim(trim($id), '\\');
131
    }
132
133
    /**
134
     * Registers a shared service in the container.
135
     *
136
     * @param string $id         Service id.
137
     * @param mixed  $definition Service definition.
138
     *
139
     * @return $this
140
     */
141
    public function shared($id, $definition)
142
    {
143
        return $this->set($id, $definition, true);
144
    }
145
146
    /**
147
     * Check whether the service is shared or not.
148
     *
149
     * @param string $id Service id.
150
     *
151
     * @return bool True if shared, false - not.
152
     */
153
    public function isShared($id)
154
    {
155
        return $this->has($id) ? $this->services[$id]['shared'] : false;
156
    }
157
158
    /**
159
     * Sets if the service is shared or not.
160
     *
161
     * @param string $id     Service id.
162
     * @param bool   $shared Shared or not.
163
     *
164
     * @return self
165
     * @throws NotFoundException No entry was found for this identifier.
166
     */
167
    public function setShared($id, $shared = true)
168
    {
169
        if ($this->has($id)) {
170
            $this->services[$id]['shared'] = $shared;
171
        } else {
172
            throw new NotFoundException('');
173
        }
174
        return $this;
175
    }
176
177
    /**
178
     * Finds an entry of the container by its identifier and returns it.
179
     *
180
     * @param string $id         Identifier of the entry to look for.
181
     * @param array  $parameters Parameter for service construct.
182
     *
183
     * @throws NotFoundException  No entry was found for this identifier.
184
     * @throws ContainerException Error while retrieving the entry.
185
     *
186
     * @return mixed Entry.
187
     */
188
    public function get($id, array $parameters = [])
189
    {
190
        if($this->level++ > static::MAX_DEPENDENCY_LEVEL){
191
            throw new ContainerException('Circular dependency.');
192
        }
193
194
        if (array_key_exists($id, $this->shared)) {
195
            return $this->shared[$id];
196
        }
197
198
        $instance = $this->resolveService(
199
            $this->has($id) ? $this->services[$id]['definition'] : $id,
200
            $parameters
201
        );
202
203
        if ($this->has($id) && $this->services[$id]['shared']) {
204
            $this->shared[$id] = $instance;
205
        }
206
207
        if ($instance instanceof InjectableInterface) {
208
            $instance->setDi($this);
209
        }
210
        $this->level = 0;
211
        return $instance;
212
    }
213
214
    /**
215
     * Resolves the service.
216
     *
217
     * @param mixed $definition The definition of service.
218
     * @param array $parameters Parameters for service construct.
219
     *
220
     * @return mixed Entry.
221
     * @throws ContainerException Error while retrieving the entry.
222
     * @throws NotFoundException No entry was found for this identifier.
223
     */
224
    protected function resolveService($definition, array $parameters = [])
225
    {
226
        switch (gettype($definition)) {
227
            case 'string':
0 ignored issues
show
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
228
                if ($this->has($definition)) {
229
                    return $this->get($definition, $parameters);
230
                } else if (class_exists($definition)) {
231
                    $reflection = new ReflectionClass($definition);
232
                    if (($construct = $reflection->getConstructor())) {
233
                        $parameters = $this->resolveOptions(
234
                            $construct->getParameters(),
235
                            $parameters
236
                        );
237
                    }
238
                    return $reflection->newInstanceArgs($parameters);
239
                } else {
240
                    throw new NotFoundException('');
241
                }
242
            case 'object':
0 ignored issues
show
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
243
                if ($definition instanceof Closure) {
244
                    return call_user_func_array($definition->bindTo($this), $parameters);
245
                } else {
246
                    return clone $definition;
247
                }
248
            default:
249
                throw new ContainerException('Type of definition is not correct.');
250
        }
251
    }
252
253
    /**
254
     * Resolve callback dependencies and executes him.
255
     *
256
     * @param callable $callback
257
     * @param array    $parameters
258
     *
259
     * @return mixed
260
     * @throws ContainerException Error while retrieving the entry.
261
     * @throws NotFoundException No entry was found for this identifier.
262
     */
263
    public function call(callable $callback, array $parameters = [])
264
    {
265
        if (is_array($callback)) {
266
            $reflection = new ReflectionMethod($callback[0], $callback[1]);
267
        } else {
268
            $reflection = new ReflectionFunction($callback);
269
        }
270
271
        return call_user_func_array(
272
            $callback,
273
            $this->resolveOptions(
274
                $reflection->getParameters(),
275
                $parameters
276
            )
277
        );
278
    }
279
280
    /**
281
     * Resolve parameters of service.
282
     *
283
     * @param array $dependencies
284
     * @param array $parameters
285
     *
286
     * @return array Resolved parameters.
287
     * @throws ContainerException Error while retrieving the entry.
288
     * @throws NotFoundException No entry was found for this identifier.
289
     */
290
    protected function resolveOptions(array $dependencies, array $parameters)
291
    {
292
        $resolved = [];
293
        foreach ($parameters as $key => $value) {
294
            if (is_numeric($key)) {
295
                unset($parameters[$key]);
296
                $parameters[$dependencies[$key]->name] = $value;
297
            }
298
        }
299
300
        foreach ($dependencies as $parameter) {
301
            /** @var ReflectionParameter $parameter */
302
            if (array_key_exists($parameter->name, $parameters)) {
303
                $resolved[] = $parameters[$parameter->name];
304
            } else if (($type = $parameter->getClass())) {
305
                $type       = $type->name;
306
                $resolved[] = $this->get(
307
                    $type,
308
                    array_key_exists($type, $parameters) ? $parameters[$type] : []
309
                );
310
            } else if ($parameter->isDefaultValueAvailable()) {
311
                $resolved[] = $parameter->getDefaultValue();
312
            } else {
313
                throw new ContainerException('Parameter "'.$parameter->name.'" not passed.');
314
            }
315
        }
316
317
        return $resolved;
318
    }
319
320
    /**
321
     * Removes a service in the services container.
322
     *
323
     * @param string $id Service id.
324
     *
325
     * @return void
326
     */
327
    public function remove($id)
328
    {
329
        unset($this->services[$id]);
330
    }
331
332
    /**
333
     * Returns true if the container can return an entry for the given identifier.
334
     * Returns false otherwise.
335
     *
336
     * @param string $id Identifier of the entry to look for.
337
     *
338
     * @return bool
339
     */
340
    public function has($id)
341
    {
342
        return array_key_exists($id, $this->services);
343
    }
344
345
    /**
346
     * Allows to register a shared service using the array syntax.
347
     *
348
     * @param string $id         Service id.
349
     * @param mixed  $definition Service definition.
350
     *
351
     * @return self
352
     */
353
    public function offsetSet($id, $definition)
354
    {
355
        return $this->set($id, $definition);
356
    }
357
358
    /**
359
     * Finds an entry of the container by its identifier and returns it.
360
     *
361
     * @param string $id Identifier of the entry to look for.
362
     *
363
     * @throws NotFoundException  No entry was found for this identifier.
364
     * @throws ContainerException Error while retrieving the entry.
365
     *
366
     * @return mixed Entry.
367
     */
368
    public function offsetGet($id)
369
    {
370
        return $this->get($id);
371
    }
372
373
    /**
374
     * Removes a service from the services container using the array syntax.
375
     *
376
     * @param string $id Service id.
377
     *
378
     * @return void
379
     */
380
    public function offsetUnset($id)
381
    {
382
        $this->remove($id);
383
    }
384
385
    /**
386
     * Returns true if the container can return an entry for the given identifier.
387
     * Returns false otherwise.
388
     *
389
     * @param string $id Identifier of the entry to look for.
390
     *
391
     * @return bool
392
     */
393
    public function offsetExists($id)
394
    {
395
        return $this->has($id);
396
    }
397
398
    /**
399
     * Allows to register a shared service using the array syntax.
400
     *
401
     * @param string $id         Service id.
402
     * @param mixed  $definition Service definition.
403
     *
404
     * @return self
405
     */
406
    public function __set($id, $definition)
407
    {
408
        $this->shared($id, $definition);
409
    }
410
411
    /**
412
     * Finds an entry of the container by its identifier and returns it.
413
     *
414
     * @param string $id Identifier of the entry to look for.
415
     *
416
     * @throws NotFoundException  No entry was found for this identifier.
417
     * @throws ContainerException Error while retrieving the entry.
418
     *
419
     * @return mixed Entry.
420
     */
421
    public function __get($id)
422
    {
423
        return $this->get($id);
424
    }
425
426
    /**
427
     * Removes a service from the services container using the array syntax.
428
     *
429
     * @param string $id Service id.
430
     *
431
     * @return void
432
     */
433
    public function __unset($id)
434
    {
435
        $this->remove($id);
436
    }
437
438
    /**
439
     * Returns true if the container can return an entry for the given identifier.
440
     * Returns false otherwise.
441
     *
442
     * @param string $id Identifier of the entry to look for.
443
     *
444
     * @return bool
445
     */
446
    public function __isset($id)
447
    {
448
        return $this->has($id);
449
    }
450
}