Completed
Push — master ( fddfa5...c7beea )
by Philip
03:26
created

ControllerProvider::setupRoutes()   B

Complexity

Conditions 2
Paths 1

Size

Total Lines 41
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 41
rs 8.8571
cc 2
eloc 35
nc 1
nop 1
1
<?php
2
3
/*
4
 * This file is part of the CRUDlex package.
5
 *
6
 * (c) Philip Lehmann-Böhm <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace CRUDlex;
13
14
use Silex\Api\ControllerProviderInterface;
15
use Silex\Application;
16
use Symfony\Component\HttpFoundation\Request;
17
use Symfony\Component\HttpFoundation\Response;
18
use Symfony\Component\HttpFoundation\StreamedResponse;
19
20
/**
21
 * This is the ControllerProvider offering all CRUD pages.
22
 *
23
 * It offers this routes:
24
 *
25
 * "/resource/static" serving static resources
26
 *
27
 * "/{entity}/create" creation page of the entity
28
 *
29
 * "/{entity}" list page of the entity
30
 *
31
 * "/{entity}/{id}" details page of a single entity instance
32
 *
33
 * "/{entity}/{id}/edit" edit page of a single entity instance
34
 *
35
 * "/{entity}/{id}/delete" POST only deletion route for an entity instance
36
 *
37
 * "/{entity}/{id}/{field}/file" renders a file field of an entity instance
38
 *
39
 * "/{entity}/{id}/{field}/delete" POST only deletion of a file field of an entity instance
40
 */
41
class ControllerProvider implements ControllerProviderInterface {
42
43
    /**
44
     * Generates the not found page.
45
     *
46
     * @param Application $app
47
     * the Silex application
48
     * @param string $error
49
     * the cause of the not found error
50
     *
51
     * @return Response
52
     * the rendered not found page with the status code 404
53
     */
54
    protected function getNotFoundPage(Application $app, $error) {
55
        return new Response($app['twig']->render('@crud/notFound.twig', [
56
            'error' => $error,
57
            'crudEntity' => '',
58
            'layout' => $app['crud.layout']
59
        ]), 404);
60
    }
61
62
    /**
63
     * Postprocesses the entity after modification by handling the uploaded
64
     * files and setting the flash.
65
     *
66
     * @param Application $app
67
     * the current application
68
     * @param AbstractData $crudData
69
     * the data instance of the entity
70
     * @param Entity $instance
71
     * the entity
72
     * @param string $entity
73
     * the name of the entity
74
     * @param string $mode
75
     * whether to 'edit' or to 'create' the entity
76
     *
77
     * @return null|\Symfony\Component\HttpFoundation\RedirectResponse
78
     * the HTTP response of this modification
79
     */
80
    protected function modifyFilesAndSetFlashBag(Application $app, AbstractData $crudData, Entity $instance, $entity, $mode) {
81
        $id      = $instance->get('id');
82
        $request = $app['request_stack']->getCurrentRequest();
83
        $result  = $mode == 'edit' ? $crudData->updateFiles($request, $instance, $entity) : $crudData->createFiles($request, $instance, $entity);
84
        if (!$result) {
85
            return null;
86
        }
87
        $app['session']->getFlashBag()->add('success', $app['translator']->trans('crudlex.'.$mode.'.success', [
88
            '%label%' => $crudData->getDefinition()->getLabel(),
89
            '%id%' => $id
90
        ]));
91
        return $app->redirect($app['url_generator']->generate('crudShow', ['entity' => $entity, 'id' => $id]));
92
    }
93
94
    /**
95
     * Sets the flashes of a failed entity modification.
96
     *
97
     * @param Application $app
98
     * the current application
99
     * @param boolean $optimisticLocking
100
     * whether the optimistic locking failed
101
     * @param string $mode
102
     * the modification mode, either 'create' or 'edit'
103
     */
104
    protected function setValidationFailedFlashes(Application $app, $optimisticLocking, $mode) {
105
        $app['session']->getFlashBag()->add('danger', $app['translator']->trans('crudlex.'.$mode.'.error'));
106
        if ($optimisticLocking) {
107
            $app['session']->getFlashBag()->add('danger', $app['translator']->trans('crudlex.edit.locked'));
108
        }
109
    }
110
111
    /**
112
     * Validates and saves the new or updated entity and returns the appropriate HTTP
113
     * response.
114
     *
115
     * @param Application $app
116
     * the current application
117
     * @param AbstractData $crudData
118
     * the data instance of the entity
119
     * @param Entity $instance
120
     * the entity
121
     * @param string $entity
122
     * the name of the entity
123
     * @param boolean $edit
124
     * whether to edit (true) or to create (false) the entity
125
     *
126
     * @return Response
127
     * the HTTP response of this modification
128
     */
129
    protected function modifyEntity(Application $app, AbstractData $crudData, Entity $instance, $entity, $edit) {
130
        $fieldErrors = [];
131
        $mode        = $edit ? 'edit' : 'create';
132
        $request     = $app['request_stack']->getCurrentRequest();
133
        if ($request->getMethod() == 'POST') {
134
            $instance->populateViaRequest($request);
135
            $validator  = new EntityValidator($instance);
136
            $validation = $validator->validate($crudData, intval($request->get('version')));
137
138
            $fieldErrors = $validation['errors'];
139
            if (!$validation['valid']) {
140
                $optimisticLocking = isset($fieldErrors['version']);
141
                $this->setValidationFailedFlashes($app, $optimisticLocking, $mode);
142
            } else {
143
                $modified = $edit ? $crudData->update($instance) : $crudData->create($instance);
144
                $response = $modified ? $this->modifyFilesAndSetFlashBag($app, $crudData, $instance, $entity, $mode) : false;
145
                if ($response) {
146
                    return $response;
147
                }
148
                $app['session']->getFlashBag()->add('danger', $app['translator']->trans('crudlex.'.$mode.'.failed'));
149
            }
150
        }
151
152
        return $app['twig']->render($app['crud']->getTemplate($app, 'template', 'form', $entity), [
153
            'crudEntity' => $entity,
154
            'crudData' => $crudData,
155
            'entity' => $instance,
156
            'mode' => $mode,
157
            'fieldErrors' => $fieldErrors,
158
            'layout' => $app['crud']->getTemplate($app, 'layout', $mode, $entity)
159
        ]);
160
    }
161
162
    /**
163
     * Gets the parameters for the redirection after deleting an entity.
164
     *
165
     * @param Request $request
166
     * the current request
167
     * @param string $entity
168
     * the entity name
169
     * @param string $redirectPage
170
     * reference, where the page to redirect to will be stored
171
     *
172
     * @return array<string,string>
173
     * the parameters of the redirection, entity and id
174
     */
175
    protected function getAfterDeleteRedirectParameters(Request $request, $entity, &$redirectPage) {
176
        $redirectPage       = 'crudList';
177
        $redirectParameters = ['entity' => $entity];
178
        $redirectEntity     = $request->get('redirectEntity');
179
        $redirectId         = $request->get('redirectId');
180
        if ($redirectEntity && $redirectId) {
181
            $redirectPage       = 'crudShow';
182
            $redirectParameters = [
183
                'entity' => $redirectEntity,
184
                'id' => $redirectId
185
            ];
186
        }
187
        return $redirectParameters;
188
    }
189
190
    /**
191
     * Builds up the parameters of the list page filters.
192
     *
193
     * @param Request $request
194
     * the current application
195
     * @param EntityDefinition $definition
196
     * the current entity definition
197
     * @param array &$filter
198
     * will hold a map of fields to request parameters for the filters
199
     * @param boolean $filterActive
200
     * reference, will be true if at least one filter is active
201
     * @param array $filterToUse
202
     * reference, will hold a map of fields to integers (0 or 1) which boolean filters are active
203
     * @param array $filterOperators
204
     * reference, will hold a map of fields to operators for AbstractData::listEntries()
205
     */
206
    protected function buildUpListFilter(Request $request, EntityDefinition $definition, &$filter, &$filterActive, &$filterToUse, &$filterOperators) {
207
        foreach ($definition->getFilter() as $filterField) {
208
            $type                 = $definition->getType($filterField);
209
            $filter[$filterField] = $request->get('crudFilter'.$filterField);
210
            if ($filter[$filterField]) {
211
                $filterActive = true;
212
                if ($type === 'boolean') {
213
                    $filterToUse[$filterField]     = $filter[$filterField] == 'true' ? 1 : 0;
214
                    $filterOperators[$filterField] = '=';
215
                } else if ($type === 'many') {
216
                    $filter[$filterField] = array_map(function($value) {
217
                        return ['id' => $value];
218
                    }, $filter[$filterField]);
219
                    $filterToUse[$filterField] = $filter[$filterField];
220
                } else {
221
                    $filterToUse[$filterField]     = '%'.$filter[$filterField].'%';
222
                    $filterOperators[$filterField] = 'LIKE';
223
                }
224
            }
225
        }
226
    }
227
228
    /**
229
     * Setups the templates.
230
     *
231
     * @param Application $app
232
     * the Application instance of the Silex application
233
     */
234
    protected function setupTemplates(Application $app) {
235
        if ($app->offsetExists('twig.loader.filesystem')) {
236
            $app['twig.loader.filesystem']->addPath(__DIR__.'/../views/', 'crud');
237
        }
238
239
        if (!$app->offsetExists('crud.layout')) {
240
            $app['crud.layout'] = '@crud/layout.twig';
241
        }
242
    }
243
244
    /**
245
     * Setups the routes.
246
     *
247
     * @param Application $app
248
     * the Application instance of the Silex application
249
     *
250
     * @return mixed
251
     * the created controller factory
252
     */
253
    protected function setupRoutes(Application $app) {
254
255
        $self = $this;
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 8 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
256
        $entityCheck = function(Request $request, Application $app) use ($self) {
257
            $entity = $request->get('entity');
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned with surrounding assignments; expected 3 spaces but found 1 space

This check looks for multiple assignments in successive lines of code. It will report an issue if the operators are not in a straight line.

To visualize

$a = "a";
$ab = "ab";
$abc = "abc";

will produce issues in the first and second line, while this second example

$a   = "a";
$ab  = "ab";
$abc = "abc";

will produce no issues.

Loading history...
258
            $crudData = $app['crud']->getData($entity);
259
            if (!$crudData) {
260
                return $self->getNotFoundPage($app, $app['translator']->trans('crudlex.entityNotFound'));
261
            }
262
        };
263
264
        $class   = get_class($this);
265
        $factory = $app['controllers_factory'];
266
        $factory->get('/resource/static', $class.'::staticFile')
267
                ->bind('static');
268
        $factory->match('/{entity}/create', $class.'::create')
269
                ->bind('crudCreate')
270
                ->before($entityCheck);
271
        $factory->match('/{entity}', $class.'::showList')
272
                ->bind('crudList')
273
                ->before($entityCheck);
274
        $factory->match('/{entity}/{id}', $class.'::show')
275
                ->bind('crudShow')
276
                ->before($entityCheck);
277
        $factory->match('/{entity}/{id}/edit', $class.'::edit')
278
                ->bind('crudEdit')
279
                ->before($entityCheck);
280
        $factory->post('/{entity}/{id}/delete', $class.'::delete')
281
                ->bind('crudDelete')
282
                ->before($entityCheck);
283
        $factory->match('/{entity}/{id}/{field}/file', $class.'::renderFile')
284
                ->bind('crudRenderFile')
285
                ->before($entityCheck);
286
        $factory->post('/{entity}/{id}/{field}/delete', $class.'::deleteFile')
287
                ->bind('crudDeleteFile')
288
                ->before($entityCheck);
289
        $factory->get('/setting/locale/{locale}', $class.'::setLocale')
290
                ->bind('crudSetLocale');
291
292
        return $factory;
293
    }
294
295
    /**
296
     * Setups i18n.
297
     *
298
     * @param Application $app
299
     * the Application instance of the Silex application
300
     */
301
    protected function setupI18n(Application $app) {
302
        $app->before(function(Request $request, Application $app) {
303
            if ($app['crud']->isManagingI18n()) {
304
                $locale = $app['session']->get('locale', 'en');
305
                $app['translator']->setLocale($locale);
306
            }
307
            $locale = $app['translator']->getLocale();
308
            $app['crud']->setLocale($locale);
309
        });
310
    }
311
312
    /**
313
     * Implements ControllerProviderInterface::connect() connecting this
314
     * controller.
315
     *
316
     * @param Application $app
317
     * the Application instance of the Silex application
318
     *
319
     * @return \SilexController\Collection
320
     * this method is expected to return the used ControllerCollection instance
321
     */
322
    public function connect(Application $app) {
323
        $this->setupTemplates($app);
324
        $factory = $this->setupRoutes($app);
325
        $this->setupI18n($app);
326
        return $factory;
327
    }
328
329
    /**
330
     * The controller for the "create" action.
331
     *
332
     * @param Application $app
333
     * the Silex application
334
     * @param string $entity
335
     * the current entity
336
     *
337
     * @return Response
338
     * the HTTP response of this action
339
     */
340
    public function create(Application $app, $entity) {
341
        $crudData = $app['crud']->getData($entity);
342
        $instance = $crudData->createEmpty();
343
        return $this->modifyEntity($app, $crudData, $instance, $entity, false);
344
    }
345
346
    /**
347
     * The controller for the "show list" action.
348
     *
349
     * @param Request $request
350
     * the current request
351
     * @param Application $app
352
     * the Silex application
353
     * @param string $entity
354
     * the current entity
355
     *
356
     * @return Response
357
     * the HTTP response of this action or 404 on invalid input
358
     */
359
    public function showList(Request $request, Application $app, $entity) {
360
        $crudData   = $app['crud']->getData($entity);
361
        $definition = $crudData->getDefinition();
362
363
        $filter          = [];
364
        $filterActive    = false;
365
        $filterToUse     = [];
366
        $filterOperators = [];
367
        $this->buildUpListFilter($request, $definition, $filter, $filterActive, $filterToUse, $filterOperators);
368
369
        $pageSize = $definition->getPageSize();
370
        $total    = $crudData->countBy($definition->getTable(), $filterToUse, $filterOperators, true);
371
        $page     = abs(intval($request->get('crudPage', 0)));
372
        $maxPage  = intval($total / $pageSize);
373
        if ($total % $pageSize == 0) {
374
            $maxPage--;
375
        }
376
        if ($page > $maxPage) {
377
            $page = $maxPage;
378
        }
379
        $skip = $page * $pageSize;
380
381
        $sortField            = $request->get('crudSortField', $definition->getInitialSortField());
382
        $sortAscendingRequest = $request->get('crudSortAscending');
383
        $sortAscending        = $sortAscendingRequest !== null ? $sortAscendingRequest === 'true' : $definition->isInitialSortAscending();
384
385
        $entities = $crudData->listEntries($filterToUse, $filterOperators, $skip, $pageSize, $sortField, $sortAscending);
386
        $crudData->fetchReferences($entities);
387
388
        return $app['twig']->render($app['crud']->getTemplate($app, 'template', 'list', $entity), [
389
            'crudEntity' => $entity,
390
            'crudData' => $crudData,
391
            'definition' => $definition,
392
            'entities' => $entities,
393
            'pageSize' => $pageSize,
394
            'maxPage' => $maxPage,
395
            'page' => $page,
396
            'total' => $total,
397
            'filter' => $filter,
398
            'filterActive' => $filterActive,
399
            'sortField' => $sortField,
400
            'sortAscending' => $sortAscending,
401
            'layout' => $app['crud']->getTemplate($app, 'layout', 'list', $entity)
402
        ]);
403
    }
404
405
    /**
406
     * The controller for the "show" action.
407
     *
408
     * @param Application $app
409
     * the Silex application
410
     * @param string $entity
411
     * the current entity
412
     * @param string $id
413
     * the instance id to show
414
     *
415
     * @return Response
416
     * the HTTP response of this action or 404 on invalid input
417
     */
418
    public function show(Application $app, $entity, $id) {
419
        $crudData = $app['crud']->getData($entity);
420
        $instance = $crudData->get($id);
421
        if (!$instance) {
422
            return $this->getNotFoundPage($app, $app['translator']->trans('crudlex.instanceNotFound'));
423
        }
424
        $instance = [$instance];
425
        $crudData->fetchReferences($instance);
426
        $instance   = $instance[0];
427
        $definition = $crudData->getDefinition();
428
429
        $childrenLabelFields = $definition->getChildrenLabelFields();
430
        $children            = [];
431
        if (count($childrenLabelFields) > 0) {
432
            foreach ($definition->getChildren() as $child) {
433
                $childField      = $child[1];
434
                $childEntity     = $child[2];
435
                $childLabelField = array_key_exists($childEntity, $childrenLabelFields) ? $childrenLabelFields[$childEntity] : 'id';
436
                $childCrud       = $app['crud']->getData($childEntity);
437
                $children[]      = [
438
                    $childCrud->getDefinition()->getLabel(),
439
                    $childEntity,
440
                    $childLabelField,
441
                    $childCrud->listEntries([$childField => $instance->get('id')])
442
                ];
443
            }
444
        }
445
446
        return $app['twig']->render($app['crud']->getTemplate($app, 'template', 'show', $entity), [
447
            'crudEntity' => $entity,
448
            'entity' => $instance,
449
            'children' => $children,
450
            'layout' => $app['crud']->getTemplate($app, 'layout', 'show', $entity)
451
        ]);
452
    }
453
454
    /**
455
     * The controller for the "edit" action.
456
     *
457
     * @param Application $app
458
     * the Silex application
459
     * @param string $entity
460
     * the current entity
461
     * @param string $id
462
     * the instance id to edit
463
     *
464
     * @return Response
465
     * the HTTP response of this action or 404 on invalid input
466
     */
467
    public function edit(Application $app, $entity, $id) {
468
        $crudData = $app['crud']->getData($entity);
469
        $instance = $crudData->get($id);
470
        if (!$instance) {
471
            return $this->getNotFoundPage($app, $app['translator']->trans('crudlex.instanceNotFound'));
472
        }
473
474
        return $this->modifyEntity($app, $crudData, $instance, $entity, true);
475
    }
476
477
    /**
478
     * The controller for the "delete" action.
479
     *
480
     * @param Application $app
481
     * the Silex application
482
     * @param string $entity
483
     * the current entity
484
     * @param string $id
485
     * the instance id to delete
486
     *
487
     * @return Response
488
     * redirects to the entity list page or 404 on invalid input
489
     */
490
    public function delete(Application $app, $entity, $id) {
491
        $crudData = $app['crud']->getData($entity);
492
        $instance = $crudData->get($id);
493
        if (!$instance) {
494
            return $this->getNotFoundPage($app, $app['translator']->trans('crudlex.instanceNotFound'));
495
        }
496
497
        $filesDeleted = $crudData->deleteFiles($instance, $entity);
498
        $deleted      = $filesDeleted ? $crudData->delete($instance) : AbstractData::DELETION_FAILED_EVENT;
499
500
        if ($deleted === AbstractData::DELETION_FAILED_EVENT) {
501
            $app['session']->getFlashBag()->add('danger', $app['translator']->trans('crudlex.delete.failed'));
502
            return $app->redirect($app['url_generator']->generate('crudShow', ['entity' => $entity, 'id' => $id]));
503
        } elseif ($deleted === AbstractData::DELETION_FAILED_STILL_REFERENCED) {
504
            $app['session']->getFlashBag()->add('danger', $app['translator']->trans('crudlex.delete.error', [
505
                '%label%' => $crudData->getDefinition()->getLabel()
506
            ]));
507
            return $app->redirect($app['url_generator']->generate('crudShow', ['entity' => $entity, 'id' => $id]));
508
        }
509
510
        $redirectPage       = 'crudList';
511
        $redirectParameters = $this->getAfterDeleteRedirectParameters($app['request_stack']->getCurrentRequest(), $entity, $redirectPage);
512
513
        $app['session']->getFlashBag()->add('success', $app['translator']->trans('crudlex.delete.success', [
514
            '%label%' => $crudData->getDefinition()->getLabel()
515
        ]));
516
        return $app->redirect($app['url_generator']->generate($redirectPage, $redirectParameters));
517
    }
518
519
    /**
520
     * The controller for the "render file" action.
521
     *
522
     * @param Application $app
523
     * the Silex application
524
     * @param string $entity
525
     * the current entity
526
     * @param string $id
527
     * the instance id
528
     * @param string $field
529
     * the field of the file to render of the instance
530
     *
531
     * @return Response
532
     * the rendered file
533
     */
534
        public function renderFile(Application $app, $entity, $id, $field) {
535
        $crudData   = $app['crud']->getData($entity);
536
        $instance   = $crudData->get($id);
537
        $definition = $crudData->getDefinition();
538
        if (!$instance || $definition->getType($field) != 'file' || !$instance->get($field)) {
539
            return $this->getNotFoundPage($app, $app['translator']->trans('crudlex.instanceNotFound'));
540
        }
541
        return $crudData->renderFile($instance, $entity, $field);
542
    }
543
544
    /**
545
     * The controller for the "delete file" action.
546
     *
547
     * @param Application $app
548
     * the Silex application
549
     * @param string $entity
550
     * the current entity
551
     * @param string $id
552
     * the instance id
553
     * @param string $field
554
     * the field of the file to delete of the instance
555
     *
556
     * @return Response
557
     * redirects to the instance details page or 404 on invalid input
558
     */
559
    public function deleteFile(Application $app, $entity, $id, $field) {
560
        $crudData = $app['crud']->getData($entity);
561
        $instance = $crudData->get($id);
562
        if (!$instance) {
563
            return $this->getNotFoundPage($app, $app['translator']->trans('crudlex.instanceNotFound'));
564
        }
565
        if (!$crudData->getDefinition()->isRequired($field) && $crudData->deleteFile($instance, $entity, $field)) {
566
            $instance->set($field, '');
567
            $crudData->update($instance);
568
            $app['session']->getFlashBag()->add('success', $app['translator']->trans('crudlex.file.deleted'));
569
        } else {
570
            $app['session']->getFlashBag()->add('danger', $app['translator']->trans('crudlex.file.notDeleted'));
571
        }
572
        return $app->redirect($app['url_generator']->generate('crudShow', ['entity' => $entity, 'id' => $id]));
573
    }
574
575
    /**
576
     * The controller for serving static files.
577
     *
578
     * @param Request $request
579
     * the current request
580
     * @param Application $app
581
     * the Silex application
582
     *
583
     * @return Response
584
     * redirects to the instance details page or 404 on invalid input
585
     */
586
    public function staticFile(Request $request, Application $app) {
587
        $fileParam = str_replace('..', '', $request->get('file'));
588
        $file      = __DIR__.'/../static/'.$fileParam;
589
        if (!$fileParam || !file_exists($file)) {
590
            return $this->getNotFoundPage($app, $app['translator']->trans('crudlex.resourceNotFound'));
591
        }
592
593
        $mimeTypes = new MimeTypes();
594
        $mimeType  = $mimeTypes->getMimeType($file);
595
        $size      = filesize($file);
596
597
        $streamedFileResponse = new StreamedFileResponse();
598
        $response             = new StreamedResponse($streamedFileResponse->getStreamedFileFunction($file), 200, [
599
            'Content-Type' => $mimeType,
600
            'Content-Disposition' => 'attachment; filename="'.basename($file).'"',
601
            'Content-length' => $size
602
        ]);
603
        $response->send();
604
605
        return $response;
606
    }
607
608
    /**
609
     * The controller for setting the locale.
610
     *
611
     * @param Request $request
612
     * the current request
613
     * @param Application $app
614
     * the Silex application
615
     * @param string $locale
616
     * the new locale
617
     *
618
     * @return Response
619
     * redirects to the instance details page or 404 on invalid input
620
     */
621
    public function setLocale(Request $request, Application $app, $locale) {
622
623
        if (!in_array($locale, $app['crud']->getLocales())) {
624
            return $this->getNotFoundPage($app, 'Locale '.$locale.' not found.');
625
        }
626
627
        if ($app['crud']->isManagingI18n()) {
628
            $app['session']->set('locale', $locale);
629
        }
630
        $redirect = $request->get('redirect');
631
        return $app->redirect($redirect);
0 ignored issues
show
Security Cross-Site Scripting introduced by
$redirect can contain request data and is used in output context(s) leading to a potential security vulnerability.

8 paths for user data to reach this point

  1. Path: $this->parameters['HTTP_AUTHORIZATION'] seems to return tainted data, and $authorizationHeader is assigned in ServerBag.php on line 62
  1. $this->parameters['HTTP_AUTHORIZATION'] seems to return tainted data, and $authorizationHeader is assigned
    in vendor/ServerBag.php on line 62
  2. ParameterBag::$parameters is assigned
    in vendor/ServerBag.php on line 77
  3. Tainted property ParameterBag::$parameters is read
    in vendor/ParameterBag.php on line 88
  4. ParameterBag::get() returns tainted data, and $result is assigned
    in vendor/Request.php on line 719
  5. Request::get() returns tainted data, and $redirect is assigned
    in src/CRUDlex/ControllerProvider.php on line 630
  2. Path: Read from $_POST, and $_POST is passed to Request::createRequestFromFactory() in Request.php on line 281
  1. Read from $_POST, and $_POST is passed to Request::createRequestFromFactory()
    in vendor/Request.php on line 281
  2. $request is passed to Request::__construct()
    in vendor/Request.php on line 1929
  3. $request is passed to Request::initialize()
    in vendor/Request.php on line 222
  4. $request is passed to ParameterBag::__construct()
    in vendor/Request.php on line 240
  5. ParameterBag::$parameters is assigned
    in vendor/ParameterBag.php on line 35
  6. Tainted property ParameterBag::$parameters is read
    in vendor/ParameterBag.php on line 88
  7. ParameterBag::get() returns tainted data, and $result is assigned
    in vendor/Request.php on line 719
  8. Request::get() returns tainted data, and $redirect is assigned
    in src/CRUDlex/ControllerProvider.php on line 630
  3. Path: Read from $_SERVER, and $server is assigned in Request.php on line 271
  1. Read from $_SERVER, and $server is assigned
    in vendor/Request.php on line 271
  2. $server is passed to Request::createRequestFromFactory()
    in vendor/Request.php on line 281
  3. $server is passed to Request::__construct()
    in vendor/Request.php on line 1929
  4. $server is passed to Request::initialize()
    in vendor/Request.php on line 222
  5. $server is passed to ParameterBag::__construct()
    in vendor/Request.php on line 245
  6. ParameterBag::$parameters is assigned
    in vendor/ParameterBag.php on line 35
  7. Tainted property ParameterBag::$parameters is read
    in vendor/ParameterBag.php on line 88
  8. ParameterBag::get() returns tainted data, and $result is assigned
    in vendor/Request.php on line 719
  9. Request::get() returns tainted data, and $redirect is assigned
    in src/CRUDlex/ControllerProvider.php on line 630
  4. Path: Fetching key HTTP_CONTENT_LENGTH from $_SERVER, and $server is assigned in Request.php on line 274
  1. Fetching key HTTP_CONTENT_LENGTH from $_SERVER, and $server is assigned
    in vendor/Request.php on line 274
  2. $server is passed to Request::createRequestFromFactory()
    in vendor/Request.php on line 281
  3. $server is passed to Request::__construct()
    in vendor/Request.php on line 1929
  4. $server is passed to Request::initialize()
    in vendor/Request.php on line 222
  5. $server is passed to ParameterBag::__construct()
    in vendor/Request.php on line 245
  6. ParameterBag::$parameters is assigned
    in vendor/ParameterBag.php on line 35
  7. Tainted property ParameterBag::$parameters is read
    in vendor/ParameterBag.php on line 88
  8. ParameterBag::get() returns tainted data, and $result is assigned
    in vendor/Request.php on line 719
  9. Request::get() returns tainted data, and $redirect is assigned
    in src/CRUDlex/ControllerProvider.php on line 630
  5. Path: Fetching key HTTP_CONTENT_TYPE from $_SERVER, and $server is assigned in Request.php on line 277
  1. Fetching key HTTP_CONTENT_TYPE from $_SERVER, and $server is assigned
    in vendor/Request.php on line 277
  2. $server is passed to Request::createRequestFromFactory()
    in vendor/Request.php on line 281
  3. $server is passed to Request::__construct()
    in vendor/Request.php on line 1929
  4. $server is passed to Request::initialize()
    in vendor/Request.php on line 222
  5. $server is passed to ParameterBag::__construct()
    in vendor/Request.php on line 245
  6. ParameterBag::$parameters is assigned
    in vendor/ParameterBag.php on line 35
  7. Tainted property ParameterBag::$parameters is read
    in vendor/ParameterBag.php on line 88
  8. ParameterBag::get() returns tainted data, and $result is assigned
    in vendor/Request.php on line 719
  9. Request::get() returns tainted data, and $redirect is assigned
    in src/CRUDlex/ControllerProvider.php on line 630
  6. Path: $server['HTTP_HOST'] seems to return tainted data, and $server is assigned in Request.php on line 347
  1. $server['HTTP_HOST'] seems to return tainted data, and $server is assigned
    in vendor/Request.php on line 347
  2. $server is assigned
    in vendor/Request.php on line 395
  3. $server is assigned
    in vendor/Request.php on line 396
  4. $server is passed to Request::createRequestFromFactory()
    in vendor/Request.php on line 398
  5. $server is passed to Request::__construct()
    in vendor/Request.php on line 1929
  6. $server is passed to Request::initialize()
    in vendor/Request.php on line 222
  7. $server is passed to ParameterBag::__construct()
    in vendor/Request.php on line 245
  8. ParameterBag::$parameters is assigned
    in vendor/ParameterBag.php on line 35
  9. Tainted property ParameterBag::$parameters is read
    in vendor/ParameterBag.php on line 88
  10. ParameterBag::get() returns tainted data, and $result is assigned
    in vendor/Request.php on line 719
  11. Request::get() returns tainted data, and $redirect is assigned
    in src/CRUDlex/ControllerProvider.php on line 630
  7. Path: $this->parameters['PHP_AUTH_USER'] seems to return tainted data, and $headers is assigned in ServerBag.php on line 43
  1. $this->parameters['PHP_AUTH_USER'] seems to return tainted data, and $headers is assigned
    in vendor/ServerBag.php on line 43
  2. $headers is assigned
    in vendor/ServerBag.php on line 44
  3. ServerBag::getHeaders() returns tainted data, and $this->server->getHeaders() is passed to HeaderBag::__construct()
    in vendor/Request.php on line 246
  4. $values is assigned
    in vendor/HeaderBag.php on line 31
  5. $values is passed to HeaderBag::set()
    in vendor/HeaderBag.php on line 32
  6. (array) $values is passed through array_values(), and $values is assigned
    in vendor/HeaderBag.php on line 142
  7. HeaderBag::$headers is assigned
    in vendor/HeaderBag.php on line 145
  8. Tainted property HeaderBag::$headers is read
    in vendor/HeaderBag.php on line 125
  9. HeaderBag::get() returns tainted data, and $requestUri is assigned
    in vendor/Request.php on line 1699
  10. $requestUri is passed to ParameterBag::set()
    in vendor/Request.php on line 1730
  11. ParameterBag::$parameters is assigned
    in vendor/ParameterBag.php on line 99
  12. Tainted property ParameterBag::$parameters is read
    in vendor/ParameterBag.php on line 88
  13. ParameterBag::get() returns tainted data, and $result is assigned
    in vendor/Request.php on line 719
  14. Request::get() returns tainted data, and $redirect is assigned
    in src/CRUDlex/ControllerProvider.php on line 630
  8. Path: $this->parameters['PHP_AUTH_PW'] seems to return tainted data, and $headers is assigned in ServerBag.php on line 44
  1. $this->parameters['PHP_AUTH_PW'] seems to return tainted data, and $headers is assigned
    in vendor/ServerBag.php on line 44
  2. ServerBag::getHeaders() returns tainted data, and $this->server->getHeaders() is passed to HeaderBag::__construct()
    in vendor/Request.php on line 246
  3. $values is assigned
    in vendor/HeaderBag.php on line 31
  4. $values is passed to HeaderBag::set()
    in vendor/HeaderBag.php on line 32
  5. (array) $values is passed through array_values(), and $values is assigned
    in vendor/HeaderBag.php on line 142
  6. HeaderBag::$headers is assigned
    in vendor/HeaderBag.php on line 145
  7. Tainted property HeaderBag::$headers is read
    in vendor/HeaderBag.php on line 125
  8. HeaderBag::get() returns tainted data, and $requestUri is assigned
    in vendor/Request.php on line 1699
  9. $requestUri is passed to ParameterBag::set()
    in vendor/Request.php on line 1730
  10. ParameterBag::$parameters is assigned
    in vendor/ParameterBag.php on line 99
  11. Tainted property ParameterBag::$parameters is read
    in vendor/ParameterBag.php on line 88
  12. ParameterBag::get() returns tainted data, and $result is assigned
    in vendor/Request.php on line 719
  13. Request::get() returns tainted data, and $redirect is assigned
    in src/CRUDlex/ControllerProvider.php on line 630

Used in output context

  1. Application::redirect() uses RedirectResponse::__construct() ($url)
    in vendor/src/Silex/Application.php on line 376
  2. RedirectResponse::__construct() uses RedirectResponse::setTargetUrl() ($url)
    in vendor/RedirectResponse.php on line 39
  3. RedirectResponse::setTargetUrl() uses Response::setContent() ($content)
    in vendor/RedirectResponse.php on line 82
  4. Response::setContent() uses property Response::$content for writing
    in vendor/Response.php on line 406
  5. Property Response::$content is used in echo
    in vendor/Response.php on line 365

Preventing Cross-Site-Scripting Attacks

Cross-Site-Scripting allows an attacker to inject malicious code into your website - in particular Javascript code, and have that code executed with the privileges of a visiting user. This can be used to obtain data, or perform actions on behalf of that visiting user.

In order to prevent this, make sure to escape all user-provided data:

// for HTML
$sanitized = htmlentities($tainted, ENT_QUOTES);

// for URLs
$sanitized = urlencode($tainted);

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
632
    }
633
}
634