Issues (447)

Security Analysis    not enabled

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.

Routing/Loader/ConventionalLoader.php (8 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
namespace Knp\RadBundle\Routing\Loader;
4
5
use Symfony\Component\Routing\RouteCollection;
6
use Symfony\Component\Routing\Route;
7
use Symfony\Component\Routing\Loader\YamlFileLoader;
8
use Symfony\Component\Config\Resource\FileResource;
9
use Symfony\Component\Config\FileLocatorInterface;
10
11
class ConventionalLoader extends YamlFileLoader
12
{
13
    private static $supportedControllerKeys = array(
14
        'prefix', 'defaults', 'requirements', 'options', 'collections', 'resources'
15
    );
16
    private static $supportedActionKeys = array(
17
        'pattern', 'defaults', 'requirements', 'options', 'methods'
18
    );
19
    private $yaml;
20
21
    public function __construct(FileLocatorInterface $locator, YamlParser $yaml = null)
22
    {
23
        parent::__construct($locator);
24
25
        $this->yaml = $yaml ?: new YamlParser;
26
    }
27
28
    public function supports($resource, $type = null)
29
    {
30
        return 'rad_convention' === $type;
31
    }
32
33
    public function load($file, $type = null)
34
    {
35
        $path   = $this->locator->locate($file);
36
        $config = $this->yaml->parse($path);
37
38
        $collection = new RouteCollection();
39
        $collection->addResource(new FileResource($file));
40
41
        if (null === $config) {
42
            return $collection;
43
        }
44
45
        if (!is_array($config)) {
46
            throw new \InvalidArgumentException(sprintf(
47
                'The file "%s" must contain a YAML array.', $path
48
            ));
49
        }
50
51
        foreach ($config as $shortname => $mapping) {
52
            $parts = explode(':', $shortname);
53
54
            if (3 == count($parts)) {
55
                list($bundle, $class, $action) = $parts;
56
57
                $routeName = $this->getRouteName($bundle, $class, $action);
58
                $route     = $this->getCustomCollectionRoute($bundle, $class, $action);
59
60
                $this->overrideRouteParams($shortname, $route, $mapping);
61
                $collection->add($routeName, $route);
62
63
                continue;
64
            }
65
66
            if (1 == count($parts)) {
67
                $this->parseClassical($collection, $shortname, $mapping, $path, $file);
68
69
                continue;
70
            }
71
72
            if (is_array($mapping)) {
73
                foreach ($mapping as $key => $val) {
74
                    if (in_array($key, self::$supportedControllerKeys)) {
75
                        continue;
76
                    }
77
78
                    if ('pattern' === $key) {
79
                        throw new \InvalidArgumentException(
80
                            'The `pattern` is only supported for actions, if you want to prefix '.
81
                            'all the routes of the controller, use `prefix` instead.'
82
                        );
83
                    }
84
85
                    throw new \InvalidArgumentException(sprintf(
86
                        '`%s` parameter is not supported by `%s` controller route. Use one of [%s].',
87
                        $key, $shortname, implode(', ', self::$supportedControllerKeys)
88
                    ));
89
                }
90
            }
91
92
            list($bundle, $class) = $parts;
93
94
            $prefix                 = $this->getPatternPrefix($class, $mapping);
95
            $collectionDefaults     = $this->getDefaultsFromMapping($mapping, 'collections');
96
            $collectionRequirements = $this->getRequirementsFromMapping($mapping, 'collections');
97
            $collectionOptions      = $this->getOptionsFromMapping($mapping, 'collections');
98
            $resourceDefaults       = $this->getDefaultsFromMapping($mapping, 'resources');
99
            $resourceRequirements   = $this->getRequirementsFromMapping($mapping, 'resources');
100
            $resourceOptions        = $this->getOptionsFromMapping($mapping, 'resources');
101
102
            $collectionRoutes = $this->getCollectionRoutesFromMapping($shortname, $mapping, $bundle, $class);
103
            $resourceRoutes   = $this->getResourceRoutesFromMapping($shortname, $mapping, $bundle, $class);
104
105
            $controllerCollection = new RouteCollection();
106
            foreach ($collectionRoutes as $name => $route) {
107
                $route->setDefaults(array_merge($collectionDefaults, $route->getDefaults()));
108
                $route->setRequirements(array_merge(
109
                    $collectionRequirements, $route->getRequirements()
110
                ));
111
                $route->setOptions(array_merge(
112
                    $collectionOptions, $route->getOptions()
113
                ));
114
                $controllerCollection->add($name, $route);
115
            }
116
            foreach ($resourceRoutes as $name => $route) {
117
                $route->setDefaults(array_merge($resourceDefaults, $route->getDefaults()));
118
                $route->setRequirements(array_merge(
119
                    $resourceRequirements, $route->getRequirements()
120
                ));
121
                $route->setOptions(array_merge(
122
                    $resourceOptions, $route->getOptions()
123
                ));
124
                $controllerCollection->add($name, $route);
125
            }
126
            $controllerCollection->addPrefix($prefix);
127
            $collection->addCollection($controllerCollection);
128
        }
129
130
        return $collection;
131
    }
132
133
    protected function parseClassical(RouteCollection $collection, $shortname,
0 ignored issues
show
The first parameter of a multi-line function declaration must be on the line after the opening bracket
Loading history...
Multi-line function declarations must define one parameter per line
Loading history...
134
                                      array $mapping, $path, $file)
0 ignored issues
show
Multi-line function declarations must define one parameter per line
Loading history...
The closing parenthesis of a multi-line function declaration must be on a new line
Loading history...
Multi-line function declaration not indented correctly; expected 8 spaces but found 38
Loading history...
135
    {
0 ignored issues
show
The closing parenthesis and the opening brace of a multi-line function declaration must be on the same line
Loading history...
136
        // Symfony 2.2+
137
        if (method_exists($this, 'validate')) {
138
            if (isset($mapping['pattern'])) {
139
                if (isset($mapping['path'])) {
140
                    throw new \InvalidArgumentException(sprintf(
141
                        'The file "%s" cannot define both a "path" and a "pattern" attribute. Use only "path".',
142
                        $path
143
                    ));
144
                }
145
146
                $mapping['path'] = $mapping['pattern'];
147
                unset($mapping['pattern']);
148
            }
149
150
            $this->validate($mapping, $shortname, $path);
151
        // Symfony 2.0, 2.1
152
        } else {
153
            foreach ($mapping as $key => $value) {
154
                if (!in_array($key, $expected = array(
155
                    'type', 'resource', 'prefix', 'pattern', 'options',
156
                    'defaults', 'requirements'
157
                ))) {
158
                    throw new \InvalidArgumentException(sprintf(
159
                        'Yaml routing loader does not support given key: "%s". Expected one of the (%s).',
160
                        $key, implode(', ', $expected)
161
                    ));
162
                }
163
            }
164
        }
165
166
        if (isset($mapping['resource'])) {
167
            // Symfony 2.2+
168
            if (method_exists($this, 'parseImport')) {
169
                $this->parseImport($collection, $mapping, $path, $file);
170
            // Symfony 2.1
171
            } else {
172
                $getOr = function ($key, $def) use ($mapping) {
173
                    return isset($mapping[$key]) ? $mapping[$key] : $def;
174
                };
175
176
                $type         = $getOr('type', null);
177
                $prefix       = $getOr('prefix', null);
178
                $defaults     = $getOr('defaults', array());
179
                $requirements = $getOr('requirements', array());
180
                $options      = $getOr('options', array());
181
182
                $this->setCurrentDir(dirname($path));
183
                $resourceCollection = $this->import($mapping['resource'], $type, false, $file);
184
                $resourceCollection->addPrefix($prefix, $defaults, $requirements);
185
                $resourceCollection->addOptions($options);
186
                $collection->addCollection($resourceCollection);
187
            }
188
        } else {
189
            $this->parseRoute($collection, $shortname, $mapping, $path);
190
        }
191
    }
192
193
    private function getDefaultsFromMapping($mapping, $routeType = 'collections')
194
    {
195
        $defaults = array();
196
197
        if (!is_array($mapping)) {
198
            return $defaults;
199
        }
200
201
        if (isset($mapping['defaults'])) {
202
            $defaults = $mapping['defaults'];
203
        }
204
205
        if (isset($mapping[$routeType]) && is_array($mapping[$routeType])) {
206
            if (isset($mapping[$routeType]['defaults'])) {
207
                $defaults = array_merge($defaults, $mapping[$routeType]['defaults']);
208
            }
209
        }
210
211
        return $defaults;
212
    }
213
214
    private function getRequirementsFromMapping($mapping, $routeType = 'collections')
215
    {
216
        $requirements = array();
217
218
        if (!is_array($mapping)) {
219
            return $requirements;
220
        }
221
222
        if (isset($mapping['requirements'])) {
223
            $requirements = $mapping['requirements'];
224
        }
225
226
        if (isset($mapping[$routeType]) && is_array($mapping[$routeType])) {
227
            if (isset($mapping[$routeType]['requirements'])) {
228
                $requirements = array_merge($requirements, $mapping[$routeType]['requirements']);
229
            }
230
        }
231
232
        return $requirements;
233
    }
234
235
    private function getOptionsFromMapping($mapping, $routeType = 'collections')
236
    {
237
        $options = array();
238
239
        if (!is_array($mapping)) {
240
            return $options;
241
        }
242
243
        if (isset($mapping['options'])) {
244
            $options = $mapping['options'];
245
        }
246
247
        if (isset($mapping[$routeType]) && is_array($mapping[$routeType])) {
248
            if (isset($mapping[$routeType]['options'])) {
249
                $options = array_merge($options, $mapping[$routeType]['options']);
250
            }
251
        }
252
253
        return $options;
254
    }
255
256
    private function getCollectionRoutesFromMapping($shortname, $mapping, $bundle, $class)
257
    {
258
        $defaults = $this->getDefaultCollectionRoutes($bundle, $class);
259
        if (!is_array($mapping) || !isset($mapping['collections'])) {
260
            return $defaults;
261
        }
262
263
        $collections = $mapping['collections'];
264
        unset($collections['defaults']);
265
        unset($collections['requirements']);
266
        unset($collections['options']);
267
268
        if (0 == count($collections)) {
269
            return $defaults;
270
        }
271
272
        if (false === $collections) {
273
            return array();
274
        }
275
276
        $routes = array();
277
        foreach ($collections as $action => $params) {
278
            if (is_integer($action)) {
279
                $action = $params;
280
                $params = null;
281
            }
282
283
            $routeName = $this->getRouteName($bundle, $class, $action);
284
            if (isset($defaults[$routeName])) {
285
                $route = $defaults[$routeName];
286
            } else {
287
                $route = $this->getCustomCollectionRoute($bundle, $class, $action);
288
            }
289
290
            $this->overrideRouteParams($shortname, $route, $params);
291
292
            $routes[$routeName] = $route;
293
        }
294
295
        return $routes;
296
    }
297
298
    private function getResourceRoutesFromMapping($shortname, $mapping, $bundle, $class)
299
    {
300
        $defaults = $this->getDefaultResourceRoutes($bundle, $class);
301
        if (!is_array($mapping) || !isset($mapping['resources'])) {
302
            return $defaults;
303
        }
304
305
        $resources = $mapping['resources'];
306
        unset($resources['defaults']);
307
        unset($resources['requirements']);
308
        unset($resources['options']);
309
310
        if (0 == count($resources)) {
311
            return $defaults;
312
        }
313
314
        if (false === $resources) {
315
            return array();
316
        }
317
318
        $routes = array();
319
        foreach ($resources as $action => $params) {
320
            if (is_integer($action)) {
321
                $action = $params;
322
                $params = null;
323
            }
324
325
            $routeName = $this->getRouteName($bundle, $class, $action);
326
            if (isset($defaults[$routeName])) {
327
                $route = $defaults[$routeName];
328
            } else {
329
                $route = $this->getCustomResourceRoute($bundle, $class, $action);
330
            }
331
332
            $this->overrideRouteParams($shortname, $route, $params);
333
334
            $routes[$routeName] = $route;
335
        }
336
337
        return $routes;
338
    }
339
340
    private function overrideRouteParams($shortname, Route $route, $params)
341
    {
342
        if (is_array($params)) {
343
            foreach ($params as $key => $val) {
344
                if (in_array($key, self::$supportedActionKeys)) {
345
                    continue;
346
                }
347
348
                throw new \InvalidArgumentException(sprintf(
349
                    '`%s` parameter is not supported by `%s` action route. Use one of [%s].',
350
                    $key, $shortname, implode(', ', self::$supportedActionKeys)
351
                ));
352
            }
353
        }
354
355
        if (is_string($params)) {
356
            $route->setPattern($params);
0 ignored issues
show
Deprecated Code introduced by
The method Symfony\Component\Routing\Route::setPattern() has been deprecated with message: since version 2.2, to be removed in 3.0. Use setPath instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
357
        }
358
        if (is_array($params)) {
359
            if (isset($params['pattern'])) {
360
                $route->setPattern($params['pattern']);
0 ignored issues
show
Deprecated Code introduced by
The method Symfony\Component\Routing\Route::setPattern() has been deprecated with message: since version 2.2, to be removed in 3.0. Use setPath instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
361
            }
362
            if (isset($params['defaults'])) {
363
                $route->setDefaults(array_merge(
364
                    $route->getDefaults(), $params['defaults']
365
                ));
366
            }
367
            if (isset($params['requirements'])) {
368
                $route->setRequirements($params['requirements']);
369
            }
370
            if (isset($params['options'])) {
371
                $route->setOptions($params['options']);
372
            }
373
            if (isset($params['methods'])) {
374
                $route->setMethods($params['methods']);
375
            }
376
        }
377
    }
378
379
    private function getDefaultCollectionRoutes($bundle, $class)
380
    {
381
        return array(
382
            $this->getRouteName($bundle, $class, 'index') => new Route(
383
                '/',
384
                array('_controller' => sprintf('%s:%s:index', $bundle, $class)),
385
                array('_method' => 'GET')
386
            ),
387
            $this->getRouteName($bundle, $class, 'new') => new Route(
388
                '/new',
389
                array('_controller' => sprintf('%s:%s:new', $bundle, $class)),
390
                array('_method' => 'GET')
391
            ),
392
            $this->getRouteName($bundle, $class, 'create') => new Route(
393
                '/',
394
                array('_controller' => sprintf('%s:%s:new', $bundle, $class)),
395
                array('_method' => 'POST')
396
            ),
397
        );
398
    }
399
400
    private function getCustomCollectionRoute($bundle, $class, $action)
401
    {
402
        return new Route(
403
            '/'.$action,
404
            array('_controller' => sprintf('%s:%s:%s', $bundle, $class, $action)),
405
            array('_method' => 'GET')
406
        );
407
    }
408
409
    private function getDefaultResourceRoutes($bundle, $class)
410
    {
411
        return array(
412
            $this->getRouteName($bundle, $class, 'show') => new Route(
413
                '/{id}',
414
                array('_controller' => sprintf('%s:%s:show', $bundle, $class)),
415
                array('_method' => 'GET')
416
            ),
417
            $this->getRouteName($bundle, $class, 'edit') => new Route(
418
                '/{id}/edit',
419
                array('_controller' => sprintf('%s:%s:edit', $bundle, $class)),
420
                array('_method' => 'GET')
421
            ),
422
            $this->getRouteName($bundle, $class, 'update') => new Route(
423
                '/{id}',
424
                array('_controller' => sprintf('%s:%s:edit', $bundle, $class)),
425
                array('_method' => 'PUT')
426
            ),
427
            $this->getRouteName($bundle, $class, 'delete') => new Route(
428
                '/{id}',
429
                array('_controller' => sprintf('%s:%s:delete', $bundle, $class)),
430
                array('_method' => 'DELETE')
431
            ),
432
        );
433
    }
434
435
    private function getCustomResourceRoute($bundle, $class, $action)
436
    {
437
        return new Route(
438
            '/{id}/'.$action,
439
            array('_controller' => sprintf('%s:%s:%s', $bundle, $class, $action)),
440
            array('_method' => 'PUT')
441
        );
442
    }
443
444
    private function getPatternPrefix($class, $mapping)
445
    {
446
        if (is_string($mapping)) {
447
            return $mapping;
448
        } elseif (is_array($mapping) && isset($mapping['prefix'])) {
449
            return $mapping['prefix'];
450
        }
451
452
        return '/'.strtolower(str_replace('\\', '/', $class));
453
    }
454
455
    private function getRouteName($bundle, $class, $action)
456
    {
457
        $group = implode('_', array_map('lcfirst', explode('\\', $class)));
458
459
        return sprintf('%s_%s_%s', lcfirst($bundle), $group, lcfirst($action));
460
    }
461
}
462