Completed
Push — master ( e65005...8fb123 )
by Philip
03:31
created

Controller::buildUpListFilter()   B

Complexity

Conditions 8
Paths 8

Size

Total Lines 28

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 22
CRAP Score 8

Importance

Changes 0
Metric Value
dl 0
loc 28
ccs 22
cts 22
cp 1
rs 8.4444
c 0
b 0
f 0
cc 8
nc 8
nop 6
crap 8
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 League\Flysystem\FilesystemInterface;
15
use League\Flysystem\Util\MimeType;
16
use Symfony\Component\HttpFoundation\RedirectResponse;
17
use Symfony\Component\HttpFoundation\Request;
18
use Symfony\Component\HttpFoundation\Response;
19
use Symfony\Component\HttpFoundation\Session\SessionInterface;
20
use Symfony\Component\HttpFoundation\StreamedResponse;
21
use Symfony\Component\Translation\TranslatorInterface;
22
use Twig_Environment;
23
24
25
/**
26
 * Default implementation of the ControllerInterface.
27
 */
28
class Controller implements ControllerInterface {
29
30
    /**
31
     * Often used i18n key.
32
     */
33
    const TR_RESOURCE_NOT_FOUND = 'crudlex.resourceNotFound';
34
35
    /**
36
     * Often used i18n key.
37
     */
38
    const TR_INSTANCE_NOT_FOUND = 'crudlex.instanceNotFound';
39
40
    /**
41
     * Holds the filesystme.
42
     * @var FilesystemInterface
43
     */
44
    protected $filesystem;
45
46
    /**
47
     * Holds the session.
48
     * @var SessionInterface
49
     */
50
    protected $session;
51
52
    /**
53
     * Holds the translator.
54
     * @var TranslatorInterface
55
     */
56
    protected $translator;
57
58
    /**
59
     * Holds the service.
60
     * @var Service
61
     */
62
    protected $service;
63
64
    /**
65
     * Holds the Twig instance.
66
     * @var Twig_Environment
67
     */
68
    protected $twig;
69
70
    /**
71
     * Postprocesses the entity after modification by handling the uploaded
72
     * files and setting the flash.
73
     *
74
     * @param Request $request
75
     * the current request
76
     * @param AbstractData $crudData
77
     * the data instance of the entity
78
     * @param Entity $instance
79
     * the entity
80
     * @param string $entity
81
     * the name of the entity
82
     * @param string $mode
83
     * whether to 'edit' or to 'create' the entity
84
     *
85
     * @return null|\Symfony\Component\HttpFoundation\RedirectResponse
86
     * the HTTP response of this modification
87
     */
88 4
    protected function modifyFilesAndSetFlashBag(Request $request, AbstractData $crudData, Entity $instance, $entity, $mode)
89
    {
90 4
        $id          = $instance->get('id');
91 4
        $fileHandler = new FileHandler($this->filesystem, $crudData->getDefinition());
92 4
        $result      = $mode == 'edit' ? $fileHandler->updateFiles($crudData, $request, $instance, $entity) : $fileHandler->createFiles($crudData, $request, $instance, $entity);
93 4
        if (!$result) {
94 2
            return null;
95
        }
96 4
        $this->session->getFlashBag()->add('success', $this->translator->trans('crudlex.'.$mode.'.success', [
97 4
            '%label%' => $crudData->getDefinition()->getLabel(),
98 4
            '%id%' => $id
99
        ]));
100 4
        return new RedirectResponse($this->service->generateURL('crudShow', ['entity' => $entity, 'id' => $id]));
101
    }
102
103
    /**
104
     * Sets the flashes of a failed entity modification.
105
     *
106
     * @param boolean $optimisticLocking
107
     * whether the optimistic locking failed
108
     * @param string $mode
109
     * the modification mode, either 'create' or 'edit'
110
     */
111 2
    protected function setValidationFailedFlashes($optimisticLocking, $mode)
112
    {
113 2
        $this->session->getFlashBag()->add('danger', $this->translator->trans('crudlex.'.$mode.'.error'));
114 2
        if ($optimisticLocking) {
115 1
            $this->session->getFlashBag()->add('danger', $this->translator->trans('crudlex.edit.locked'));
116
        }
117 2
    }
118
119
    /**
120
     * Validates and saves the new or updated entity and returns the appropriate HTTP
121
     * response.
122
     *
123
     * @param Request $request
124
     * the current request
125
     * @param AbstractData $crudData
126
     * the data instance of the entity
127
     * @param Entity $instance
128
     * the entity
129
     * @param string $entity
130
     * the name of the entity
131
     * @param boolean $edit
132
     * whether to edit (true) or to create (false) the entity
133
     *
134
     * @return Response
135
     * the HTTP response of this modification
136
     */
137 4
    protected function modifyEntity(Request $request, AbstractData $crudData, Entity $instance, $entity, $edit)
138
    {
139 4
        $fieldErrors = [];
140 4
        $mode        = $edit ? 'edit' : 'create';
141 4
        if ($request->getMethod() == 'POST') {
142 4
            $instance->populateViaRequest($request);
143 4
            $validator  = new EntityValidator($instance);
144 4
            $validation = $validator->validate($crudData, intval($request->get('version')));
145
146 4
            $fieldErrors = $validation['errors'];
147 4
            if (!$validation['valid']) {
148 2
                $optimisticLocking = isset($fieldErrors['version']);
149 2
                $this->setValidationFailedFlashes($optimisticLocking, $mode);
150
            } else {
151 4
                $modified = $edit ? $crudData->update($instance) : $crudData->create($instance);
152 4
                $response = $modified ? $this->modifyFilesAndSetFlashBag($request, $crudData, $instance, $entity, $mode) : false;
153 4
                if ($response) {
154 4
                    return $response;
155
                }
156 2
                $this->session->getFlashBag()->add('danger', $this->translator->trans('crudlex.'.$mode.'.failed'));
157
            }
158
        }
159
160 2
        return new Response($this->twig->render($this->service->getTemplate('template', 'form', $entity), [
161 2
            'crud' => $this->service,
162 2
            'crudEntity' => $entity,
163 2
            'crudData' => $crudData,
164 2
            'entity' => $instance,
165 2
            'mode' => $mode,
166 2
            'fieldErrors' => $fieldErrors,
167 2
            'layout' => $this->service->getTemplate('layout', $mode, $entity)
168
        ]));
169
    }
170
171
    /**
172
     * Gets the parameters for the redirection after deleting an entity.
173
     *
174
     * @param Request $request
175
     * the current request
176
     * @param string $entity
177
     * the entity name
178
     * @param string $redirectPage
179
     * reference, where the page to redirect to will be stored
180
     *
181
     * @return array<string,string>
182
     * the parameters of the redirection, entity and id
183
     */
184 1
    protected function getAfterDeleteRedirectParameters(Request $request, $entity, &$redirectPage)
185
    {
186 1
        $redirectPage       = 'crudList';
187 1
        $redirectParameters = ['entity' => $entity];
188 1
        $redirectEntity     = $request->get('redirectEntity');
189 1
        $redirectId         = $request->get('redirectId');
190 1
        if ($redirectEntity && $redirectId) {
191 1
            $redirectPage       = 'crudShow';
192
            $redirectParameters = [
193 1
                'entity' => $redirectEntity,
194 1
                'id' => $redirectId
195
            ];
196
        }
197 1
        return $redirectParameters;
198
    }
199
200
    /**
201
     * Builds up the parameters of the list page filters.
202
     *
203
     * @param Request $request
204
     * the current request
205
     * @param EntityDefinition $definition
206
     * the current entity definition
207
     * @param array &$filter
208
     * will hold a map of fields to request parameters for the filters
209
     * @param boolean $filterActive
210
     * reference, will be true if at least one filter is active
211
     * @param array $filterToUse
212
     * reference, will hold a map of fields to integers (0 or 1) which boolean filters are active
213
     * @param array $filterOperators
214
     * reference, will hold a map of fields to operators for AbstractData::listEntries()
215
     *
216
     * @return array
217
     * the raw filter query parameters
218
     */
219 2
    protected function buildUpListFilter(Request $request, EntityDefinition $definition, &$filter, &$filterActive, &$filterToUse, &$filterOperators)
220
    {
221 2
        $rawFilter = [];
222 2
        foreach ($definition->getFilter() as $filterField) {
223 2
            $type                    = $definition->getType($filterField);
224 2
            $filter[$filterField]    = $request->get('crudFilter'.$filterField);
225 2
            $rawFilter[$filterField] = $filter[$filterField];
226 2
            if ($filter[$filterField]) {
227 1
                $filterActive                  = true;
228 1
                $filterToUse[$filterField]     = $filter[$filterField];
229 1
                $filterOperators[$filterField] = '=';
230 1
                if ($type === 'boolean') {
231 1
                    $filterToUse[$filterField] = $filter[$filterField] == 'true' ? 1 : 0;
232 1
                } else if ($type === 'reference') {
233 1
                    $filter[$filterField] = ['id' => $filter[$filterField]];
234 1
                } else if ($type === 'many') {
235
                    $filter[$filterField] = array_map(function($value) {
236 1
                        return ['id' => $value];
237 1
                    }, $filter[$filterField]);
238 1
                    $filterToUse[$filterField] = $filter[$filterField];
239 1
                } else if (in_array($type, ['text', 'multiline', 'fixed'])) {
240 1
                    $filterToUse[$filterField]     = '%'.$filter[$filterField].'%';
241 1
                    $filterOperators[$filterField] = 'LIKE';
242
                }
243
            }
244
        }
245 2
        return $rawFilter;
246
    }
247
248
    /**
249
     * Generates the not found page.
250
     *
251
     * @param string $error
252
     * the cause of the not found error
253
     *
254
     * @return Response
255
     * the rendered not found page with the status code 404
256
     */
257 10
    protected function getNotFoundPage($error)
258
    {
259 10
        return new Response($this->twig->render('@crud/notFound.twig', [
260 10
            'crud' => $this->service,
261 10
            'error' => $error,
262 10
            'crudEntity' => '',
263 10
            'layout' => $this->service->getTemplate('layout', '', '')
264 10
        ]), 404);
265
    }
266
267
    /**
268
     * Controller constructor.
269
     *
270
     * @param Service $service
271
     * the CRUDlex service
272
     * @param FilesystemInterface $filesystem
273
     * the used filesystem
274
     * @param \Twig\Environment $twig
275
     * the Twig environment
276
     * @param SessionInterface $session
277
     * the session service
278
     * @param TranslatorInterface $translator
279
     * the translation service
280
     */
281 10
    public function __construct(Service $service, FilesystemInterface $filesystem, \Twig\Environment $twig, SessionInterface $session, TranslatorInterface $translator)
282
    {
283 10
        $this->service    = $service;
284 10
        $this->filesystem = $filesystem;
285 10
        $this->twig       = $twig;
0 ignored issues
show
Documentation Bug introduced by
It seems like $twig of type object<Twig\Environment> is incompatible with the declared type object<Twig_Environment> of property $twig.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
286 10
        $this->session    = $session;
287 10
        $this->translator = $translator;
288 10
    }
289
290
    /**
291
     * {@inheritdoc}
292
     */
293 2
    public function setLocaleAndCheckEntity(Request $request)
294
    {
295 2
        $locale = $this->translator->getLocale();
296 2
        $this->service->setLocale($locale);
297 2
        if (!$this->service->getData($request->get('entity'))) {
298 2
            return $this->getNotFoundPage($this->translator->trans('crudlex.entityNotFound'));
299
        }
300 1
        return null;
301
    }
302
303
    /**
304
     * {@inheritdoc}
305
     */
306 3
    public function create(Request $request, $entity)
307
    {
308 3
        $crudData = $this->service->getData($entity);
309 3
        if (!$crudData) {
310 1
            return $this->getNotFoundPage($this->translator->trans(static::TR_RESOURCE_NOT_FOUND));
311
        }
312 3
        $instance = $crudData->createEmpty();
313 3
        $instance->populateViaRequest($request);
314 3
        return $this->modifyEntity($request, $crudData, $instance, $entity, false);
315
    }
316
317
    /**
318
     * {@inheritdoc}
319
     */
320 2
    public function showList(Request $request, $entity)
321
    {
322 2
        $crudData = $this->service->getData($entity);
323 2
        if (!$crudData) {
324 1
            return $this->getNotFoundPage($this->translator->trans(static::TR_RESOURCE_NOT_FOUND));
325
        }
326 2
        $definition = $crudData->getDefinition();
327
328 2
        $filter          = [];
329 2
        $filterActive    = false;
330 2
        $filterToUse     = [];
331 2
        $filterOperators = [];
332 2
        $rawFilter       = $this->buildUpListFilter($request, $definition, $filter, $filterActive, $filterToUse, $filterOperators);
333
334 2
        $pageSize = $definition->getPageSize();
335 2
        $total    = $crudData->countBy($definition->getTable(), $filterToUse, $filterOperators, true);
336 2
        $page     = abs(intval($request->get('crudPage', 0)));
337 2
        $maxPage  = intval($total / $pageSize);
338 2
        if ($total % $pageSize == 0) {
339 2
            $maxPage--;
340
        }
341 2
        if ($page > $maxPage) {
342 1
            $page = $maxPage;
343
        }
344 2
        $skip = $page * $pageSize;
345
346 2
        $sortField            = $request->get('crudSortField', $definition->getInitialSortField());
347 2
        $sortAscendingRequest = $request->get('crudSortAscending');
348 2
        $sortAscending        = $sortAscendingRequest !== null ? $sortAscendingRequest === 'true' : $definition->isInitialSortAscending();
349
350 2
        $entities = $crudData->listEntries($filterToUse, $filterOperators, $skip, $pageSize, $sortField, $sortAscending);
351
352 2
        return new Response($this->twig->render($this->service->getTemplate('template', 'list', $entity), [
353 2
            'crud' => $this->service,
354 2
            'crudEntity' => $entity,
355 2
            'crudData' => $crudData,
356 2
            'definition' => $definition,
357 2
            'entities' => $entities,
358 2
            'pageSize' => $pageSize,
359 2
            'maxPage' => $maxPage,
360 2
            'page' => $page,
361 2
            'total' => $total,
362 2
            'filter' => $filter,
363 2
            'rawFilter' => $rawFilter,
364 2
            'filterActive' => $filterActive,
365 2
            'sortField' => $sortField,
366 2
            'sortAscending' => $sortAscending,
367 2
            'layout' => $this->service->getTemplate('layout', 'list', $entity)
368
        ]));
369
    }
370
371
    /**
372
     * {@inheritdoc}
373
     */
374 1
    public function show($entity, $id)
375
    {
376 1
        $crudData = $this->service->getData($entity);
377 1
        if (!$crudData) {
378 1
            return $this->getNotFoundPage($this->translator->trans(static::TR_RESOURCE_NOT_FOUND));
379
        }
380 1
        $instance = $crudData->get($id);
381 1
        if (!$instance) {
382 1
            return $this->getNotFoundPage($this->translator->trans(static::TR_INSTANCE_NOT_FOUND));
383
        }
384 1
        $definition = $crudData->getDefinition();
385
386 1
        $childrenLabelFields = $definition->getChildrenLabelFields();
387 1
        $children            = [];
388 1
        if (count($childrenLabelFields) > 0) {
389 1
            foreach ($definition->getChildren() as $child) {
390 1
                $childField      = $child[1];
391 1
                $childEntity     = $child[2];
392 1
                $childLabelField = array_key_exists($childEntity, $childrenLabelFields) ? $childrenLabelFields[$childEntity] : 'id';
393 1
                $childCrud       = $this->service->getData($childEntity);
394 1
                $children[]      = [
395 1
                    $childCrud->getDefinition()->getLabel(),
396 1
                    $childEntity,
397 1
                    $childLabelField,
398 1
                    $childCrud->listEntries([$childField => $instance->get('id')]),
399 1
                    $childField
400
                ];
401
            }
402
        }
403
404 1
        return new Response($this->twig->render($this->service->getTemplate('template', 'show', $entity), [
405 1
            'crud' => $this->service,
406 1
            'crudEntity' => $entity,
407 1
            'entity' => $instance,
408 1
            'children' => $children,
409 1
            'layout' => $this->service->getTemplate('layout', 'show', $entity)
410
        ]));
411
    }
412
413
    /**
414
     * {@inheritdoc}
415
     */
416 1
    public function edit(Request $request, $entity, $id)
417
    {
418 1
        $crudData = $this->service->getData($entity);
419 1
        if (!$crudData) {
420 1
            return $this->getNotFoundPage($this->translator->trans(static::TR_RESOURCE_NOT_FOUND));
421
        }
422 1
        $instance = $crudData->get($id);
423 1
        if (!$instance) {
424 1
            return $this->getNotFoundPage($this->translator->trans(static::TR_INSTANCE_NOT_FOUND));
425
        }
426
427 1
        return $this->modifyEntity($request, $crudData, $instance, $entity, true);
428
    }
429
430
    /**
431
     * {@inheritdoc}
432
     */
433 1
    public function delete(Request $request, $entity, $id)
434
    {
435 1
        $crudData = $this->service->getData($entity);
436 1
        if (!$crudData) {
437 1
            return $this->getNotFoundPage($this->translator->trans(static::TR_RESOURCE_NOT_FOUND));
438
        }
439 1
        $instance = $crudData->get($id);
440 1
        if (!$instance) {
441 1
            return $this->getNotFoundPage($this->translator->trans(static::TR_INSTANCE_NOT_FOUND));
442
        }
443
444 1
        $fileHandler  = new FileHandler($this->filesystem, $crudData->getDefinition());
445 1
        $filesDeleted = $fileHandler->deleteFiles($crudData, $instance, $entity);
446 1
        $deleted      = $filesDeleted ? $crudData->delete($instance) : AbstractData::DELETION_FAILED_EVENT;
447
448 1
        if ($deleted === AbstractData::DELETION_FAILED_EVENT) {
449 1
            $this->session->getFlashBag()->add('danger', $this->translator->trans('crudlex.delete.failed'));
450 1
            return new RedirectResponse($this->service->generateURL('crudShow', ['entity' => $entity, 'id' => $id]));
451 1
        } elseif ($deleted === AbstractData::DELETION_FAILED_STILL_REFERENCED) {
452 1
            $this->session->getFlashBag()->add('danger', $this->translator->trans('crudlex.delete.error', [
453 1
                '%label%' => $crudData->getDefinition()->getLabel()
454
            ]));
455 1
            return new RedirectResponse($this->service->generateURL('crudShow', ['entity' => $entity, 'id' => $id]));
456
        }
457
458 1
        $redirectPage       = 'crudList';
459 1
        $redirectParameters = $this->getAfterDeleteRedirectParameters($request, $entity, $redirectPage);
460
461 1
        $this->session->getFlashBag()->add('success', $this->translator->trans('crudlex.delete.success', [
462 1
            '%label%' => $crudData->getDefinition()->getLabel()
463
        ]));
464 1
        return new RedirectResponse($this->service->generateURL($redirectPage, $redirectParameters));
465
    }
466
467
    /**
468
     * {@inheritdoc}
469
     */
470 1
    public function renderFile($entity, $id, $field)
471
    {
472 1
        $crudData = $this->service->getData($entity);
473 1
        if (!$crudData) {
474 1
            return $this->getNotFoundPage($this->translator->trans(static::TR_RESOURCE_NOT_FOUND));
475
        }
476 1
        $instance   = $crudData->get($id);
477 1
        $definition = $crudData->getDefinition();
478 1
        if (!$instance || $definition->getType($field) != 'file' || !$instance->get($field)) {
479 1
            return $this->getNotFoundPage($this->translator->trans(static::TR_INSTANCE_NOT_FOUND));
480
        }
481 1
        $fileHandler = new FileHandler($this->filesystem, $definition);
482 1
        return $fileHandler->renderFile($instance, $entity, $field);
483
    }
484
485
    /**
486
     * {@inheritdoc}
487
     */
488 1
    public function deleteFile($entity, $id, $field)
489
    {
490 1
        $crudData = $this->service->getData($entity);
491 1
        if (!$crudData) {
492 1
            return $this->getNotFoundPage($this->translator->trans(static::TR_RESOURCE_NOT_FOUND));
493
        }
494 1
        $instance = $crudData->get($id);
495 1
        if (!$instance) {
496 1
            return $this->getNotFoundPage($this->translator->trans(static::TR_INSTANCE_NOT_FOUND));
497
        }
498 1
        $fileHandler = new FileHandler($this->filesystem, $crudData->getDefinition());
499 1
        if (!$crudData->getDefinition()->getField($field, 'required', false) && $fileHandler->deleteFile($crudData, $instance, $entity, $field)) {
500 1
            $instance->set($field, '');
501 1
            $crudData->update($instance);
502 1
            $this->session->getFlashBag()->add('success', $this->translator->trans('crudlex.file.deleted'));
503
        } else {
504 1
            $this->session->getFlashBag()->add('danger', $this->translator->trans('crudlex.file.notDeleted'));
505
        }
506 1
        return new RedirectResponse($this->service->generateURL('crudShow', ['entity' => $entity, 'id' => $id]));
507
    }
508
509
    /**
510
     * {@inheritdoc}
511
     */
512 1
    public function staticFile(Request $request)
513
    {
514 1
        $fileParam = str_replace('..', '', $request->get('file'));
515 1
        $file      = __DIR__.'/../static/'.$fileParam;
516 1
        if (!$fileParam || !file_exists($file)) {
517 1
            return $this->getNotFoundPage($this->translator->trans(static::TR_RESOURCE_NOT_FOUND));
518
        }
519
520 1
        $mimeType = MimeType::detectByFilename($file);
521 1
        $size     = filesize($file);
522
523 1
        $streamedFileResponse = new StreamedFileResponse();
524 1
        $response             = new StreamedResponse($streamedFileResponse->getStreamedFileFunction($file), 200, [
525 1
            'Content-Type' => $mimeType,
526 1
            'Content-Disposition' => 'attachment; filename="'.basename($file).'"',
527 1
            'Content-length' => $size
528
        ]);
529
530 1
        $response->setETag(filemtime($file))->setPublic()->isNotModified($request);
531 1
        $response->send();
532
533 1
        return $response;
534
    }
535
536
    /**
537
     * {@inheritdoc}
538
     */
539 1
    public function setLocale(Request $request, $locale)
540
    {
541
542 1
        if (!in_array($locale, $this->service->getLocales())) {
543 1
            return $this->getNotFoundPage('Locale '.$locale.' not found.');
544
        }
545
546 1
        $manageI18n = $this->service->isManageI18n();
547 1
        if ($manageI18n) {
548 1
            $this->session->set('locale', $locale);
549
        }
550 1
        $redirect = $request->get('redirect');
551 1
        return new RedirectResponse($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.

2 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 59
  1. $this->parameters['HTTP_AUTHORIZATION'] seems to return tainted data, and $authorizationHeader is assigned
    in vendor/ServerBag.php on line 59
  2. ParameterBag::$parameters is assigned
    in vendor/ServerBag.php on line 74
  3. Tainted property ParameterBag::$parameters is read
    in vendor/ParameterBag.php on line 77
  4. ParameterBag::get() returns tainted data, and $result is assigned
    in vendor/Request.php on line 707
  5. Request::get() returns tainted data, and $redirect is assigned
    in src/CRUDlex/Controller.php on line 550
  2. Path: Read from $_POST, and $_POST is passed to Request::createRequestFromFactory() in Request.php on line 293
  1. Read from $_POST, and $_POST is passed to Request::createRequestFromFactory()
    in vendor/Request.php on line 293
  2. $request is passed to Request::__construct()
    in vendor/Request.php on line 1988
  3. $request is passed to Request::initialize()
    in vendor/Request.php on line 247
  4. $request is passed to ParameterBag::__construct()
    in vendor/Request.php on line 265
  5. ParameterBag::$parameters is assigned
    in vendor/ParameterBag.php on line 28
  6. Tainted property ParameterBag::$parameters is read
    in vendor/ParameterBag.php on line 77
  7. ParameterBag::get() returns tainted data, and $result is assigned
    in vendor/Request.php on line 707
  8. Request::get() returns tainted data, and $redirect is assigned
    in src/CRUDlex/Controller.php on line 550

Used in output context

  1. RedirectResponse::__construct() uses RedirectResponse::setTargetUrl() ($url)
    in vendor/RedirectResponse.php on line 39
  2. RedirectResponse::setTargetUrl() uses Response::setContent() ($content)
    in vendor/RedirectResponse.php on line 92
  3. Response::setContent() uses property Response::$content for writing
    in vendor/Response.php on line 397
  4. Property Response::$content is used in echo
    in vendor/Response.php on line 356

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...
552
    }
553
}
554