Completed
Push — master ( a99c75...28b121 )
by Philip
05:53
created

ControllerProvider::staticFile()   B

Complexity

Conditions 3
Paths 2

Size

Total Lines 24
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 3

Importance

Changes 3
Bugs 0 Features 0
Metric Value
dl 0
loc 24
ccs 16
cts 16
cp 1
rs 8.9713
c 3
b 0
f 0
cc 3
eloc 16
nc 2
nop 2
crap 3
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\Adapter\Local;
15
use League\Flysystem\Filesystem;
16
use Silex\Api\ControllerProviderInterface;
17
use Silex\Application;
18
use Symfony\Component\HttpFoundation\Request;
19
use Symfony\Component\HttpFoundation\Response;
20
use Symfony\Component\HttpFoundation\StreamedResponse;
21
22
/**
23
 * This is the ControllerProvider offering all CRUD pages.
24
 *
25
 * It offers this routes:
26
 *
27
 * "/resource/static" serving static resources
28
 *
29
 * "/{entity}/create" creation page of the entity
30
 *
31
 * "/{entity}" list page of the entity
32
 *
33
 * "/{entity}/{id}" details page of a single entity instance
34
 *
35
 * "/{entity}/{id}/edit" edit page of a single entity instance
36
 *
37
 * "/{entity}/{id}/delete" POST only deletion route for an entity instance
38
 *
39
 * "/{entity}/{id}/{field}/file" renders a file field of an entity instance
40
 *
41
 * "/{entity}/{id}/{field}/delete" POST only deletion of a file field of an entity instance
42
 */
43
class ControllerProvider implements ControllerProviderInterface
44
{
45
46
    /**
47
     * Generates the not found page.
48
     *
49
     * @param Application $app
50
     * the Silex application
51
     * @param string $error
52
     * the cause of the not found error
53
     *
54
     * @return Response
55
     * the rendered not found page with the status code 404
56
     */
57 9
    protected function getNotFoundPage(Application $app, $error)
58
    {
59 9
        return new Response($app['twig']->render('@crud/notFound.twig', [
60 9
            'error' => $error,
61 9
            'crudEntity' => '',
62 9
            'layout' => $app['crud.layout']
63 9
        ]), 404);
64
    }
65
66
    /**
67
     * Postprocesses the entity after modification by handling the uploaded
68
     * files and setting the flash.
69
     *
70
     * @param Application $app
71
     * the current application
72
     * @param AbstractData $crudData
73
     * the data instance of the entity
74
     * @param Entity $instance
75
     * the entity
76
     * @param string $entity
77
     * the name of the entity
78
     * @param string $mode
79
     * whether to 'edit' or to 'create' the entity
80
     *
81
     * @return null|\Symfony\Component\HttpFoundation\RedirectResponse
82
     * the HTTP response of this modification
83
     */
84 4
    protected function modifyFilesAndSetFlashBag(Application $app, AbstractData $crudData, Entity $instance, $entity, $mode)
85
    {
86 4
        $id          = $instance->get('id');
87 4
        $request     = $app['request_stack']->getCurrentRequest();
88 4
        $fileHandler = new FileHandler($app['crud.filesystem'], $crudData->getDefinition());
89 4
        $result      = $mode == 'edit' ? $fileHandler->updateFiles($crudData, $request, $instance, $entity) : $fileHandler->createFiles($crudData, $request, $instance, $entity);
90 4
        if (!$result) {
91 2
            return null;
92
        }
93 4
        $app['session']->getFlashBag()->add('success', $app['translator']->trans('crudlex.'.$mode.'.success', [
94 4
            '%label%' => $crudData->getDefinition()->getLabel(),
95 4
            '%id%' => $id
96
        ]));
97 4
        return $app->redirect($app['url_generator']->generate('crudShow', ['entity' => $entity, 'id' => $id]));
98
    }
99
100
    /**
101
     * Sets the flashes of a failed entity modification.
102
     *
103
     * @param Application $app
104
     * the current application
105
     * @param boolean $optimisticLocking
106
     * whether the optimistic locking failed
107
     * @param string $mode
108
     * the modification mode, either 'create' or 'edit'
109
     */
110 2
    protected function setValidationFailedFlashes(Application $app, $optimisticLocking, $mode)
111
    {
112 2
        $app['session']->getFlashBag()->add('danger', $app['translator']->trans('crudlex.'.$mode.'.error'));
113 2
        if ($optimisticLocking) {
114 1
            $app['session']->getFlashBag()->add('danger', $app['translator']->trans('crudlex.edit.locked'));
115
        }
116 2
    }
117
118
    /**
119
     * Validates and saves the new or updated entity and returns the appropriate HTTP
120
     * response.
121
     *
122
     * @param Application $app
123
     * the current application
124
     * @param AbstractData $crudData
125
     * the data instance of the entity
126
     * @param Entity $instance
127
     * the entity
128
     * @param string $entity
129
     * the name of the entity
130
     * @param boolean $edit
131
     * whether to edit (true) or to create (false) the entity
132
     *
133
     * @return Response
134
     * the HTTP response of this modification
135
     */
136 5
    protected function modifyEntity(Application $app, AbstractData $crudData, Entity $instance, $entity, $edit)
137
    {
138 5
        $fieldErrors = [];
139 5
        $mode        = $edit ? 'edit' : 'create';
140 5
        $request     = $app['request_stack']->getCurrentRequest();
141 5
        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($app, $optimisticLocking, $mode);
150
            } else {
151 4
                $modified = $edit ? $crudData->update($instance) : $crudData->create($instance);
152 4
                $response = $modified ? $this->modifyFilesAndSetFlashBag($app, $crudData, $instance, $entity, $mode) : false;
153 4
                if ($response) {
154 4
                    return $response;
155
                }
156 2
                $app['session']->getFlashBag()->add('danger', $app['translator']->trans('crudlex.'.$mode.'.failed'));
157
            }
158
        }
159
160 3
        return $app['twig']->render($app['crud']->getTemplate($app, 'template', 'form', $entity), [
161 3
            'crudEntity' => $entity,
162 3
            'crudData' => $crudData,
163 3
            'entity' => $instance,
164 3
            'mode' => $mode,
165 3
            'fieldErrors' => $fieldErrors,
166 3
            'layout' => $app['crud']->getTemplate($app, 'layout', $mode, $entity)
167
        ]);
168
    }
169
170
    /**
171
     * Gets the parameters for the redirection after deleting an entity.
172
     *
173
     * @param Request $request
174
     * the current request
175
     * @param string $entity
176
     * the entity name
177
     * @param string $redirectPage
178
     * reference, where the page to redirect to will be stored
179
     *
180
     * @return array<string,string>
181
     * the parameters of the redirection, entity and id
182
     */
183 1
    protected function getAfterDeleteRedirectParameters(Request $request, $entity, &$redirectPage)
184
    {
185 1
        $redirectPage       = 'crudList';
186 1
        $redirectParameters = ['entity' => $entity];
187 1
        $redirectEntity     = $request->get('redirectEntity');
188 1
        $redirectId         = $request->get('redirectId');
189 1
        if ($redirectEntity && $redirectId) {
190 1
            $redirectPage       = 'crudShow';
191
            $redirectParameters = [
192 1
                'entity' => $redirectEntity,
193 1
                'id' => $redirectId
194
            ];
195
        }
196 1
        return $redirectParameters;
197
    }
198
199
    /**
200
     * Builds up the parameters of the list page filters.
201
     *
202
     * @param Request $request
203
     * the current application
204
     * @param EntityDefinition $definition
205
     * the current entity definition
206
     * @param array &$filter
207
     * will hold a map of fields to request parameters for the filters
208
     * @param boolean $filterActive
209
     * reference, will be true if at least one filter is active
210
     * @param array $filterToUse
211
     * reference, will hold a map of fields to integers (0 or 1) which boolean filters are active
212
     * @param array $filterOperators
213
     * reference, will hold a map of fields to operators for AbstractData::listEntries()
214
     */
215 4
    protected function buildUpListFilter(Request $request, EntityDefinition $definition, &$filter, &$filterActive, &$filterToUse, &$filterOperators)
216
    {
217 4
        foreach ($definition->getFilter() as $filterField) {
218 4
            $type                 = $definition->getType($filterField);
219 4
            $filter[$filterField] = $request->get('crudFilter'.$filterField);
220 4
            if ($filter[$filterField]) {
221 1
                $filterActive                  = true;
222 1
                $filterToUse[$filterField]     = $filter[$filterField];
223 1
                $filterOperators[$filterField] = '=';
224 1
                if ($type === 'boolean') {
225 1
                    $filterToUse[$filterField] = $filter[$filterField] == 'true' ? 1 : 0;
226 1
                } else if ($type === 'reference') {
227 1
                    $filter[$filterField] = ['id' => $filter[$filterField]];
228 1
                } else if ($type === 'many') {
229
                    $filter[$filterField] = array_map(function($value) {
230 1
                        return ['id' => $value];
231 1
                    }, $filter[$filterField]);
232 1
                    $filterToUse[$filterField] = $filter[$filterField];
233 1
                } else if (in_array($type, ['text', 'multiline', 'fixed'])){
234 1
                    $filterToUse[$filterField]     = '%'.$filter[$filterField].'%';
235 1
                    $filterOperators[$filterField] = 'LIKE';
236
                }
237
            }
238
        }
239 4
    }
240
241
    /**
242
     * Setups the templates.
243
     *
244
     * @param Application $app
245
     * the Application instance of the Silex application
246
     */
247 10
    protected function setupTemplates(Application $app)
248
    {
249 10
        if ($app->offsetExists('twig.loader.filesystem')) {
250 10
            $app['twig.loader.filesystem']->addPath(__DIR__.'/../views/', 'crud');
251
        }
252
253 10
        if (!$app->offsetExists('crud.layout')) {
254 10
            $app['crud.layout'] = '@crud/layout.twig';
255
        }
256 10
    }
257
258
    /**
259
     * Setups the routes.
260
     *
261
     * @param Application $app
262
     * the Application instance of the Silex application
263
     *
264
     * @return mixed
265
     * the created controller factory
266
     */
267 10
    protected function setupRoutes(Application $app)
268
    {
269
270 10
        $self                 = $this;
271
        $localeAndCheckEntity = function(Request $request, Application $app) use ($self) {
272 9
            $locale = $app['translator']->getLocale();
273 9
            $app['crud']->setLocale($locale);
274 9
            if (!$app['crud']->getData($request->get('entity'))) {
275 7
                return $self->getNotFoundPage($app, $app['translator']->trans('crudlex.entityNotFound'));
276
            }
277 10
        };
278
279 10
        $class   = get_class($this);
280 10
        $factory = $app['controllers_factory'];
281 10
        $factory->get('/resource/static', $class.'::staticFile')->bind('crudStatic');
282 10
        $factory->match('/{entity}/create', $class.'::create')->bind('crudCreate')->before($localeAndCheckEntity, 10);
283 10
        $factory->get('/{entity}', $class.'::showList')->bind('crudList')->before($localeAndCheckEntity, 10);
284 10
        $factory->get('/{entity}/{id}', $class.'::show')->bind('crudShow')->before($localeAndCheckEntity, 10);
285 10
        $factory->match('/{entity}/{id}/edit', $class.'::edit')->bind('crudEdit')->before($localeAndCheckEntity, 10);
286 10
        $factory->post('/{entity}/{id}/delete', $class.'::delete')->bind('crudDelete')->before($localeAndCheckEntity, 10);
287 10
        $factory->get('/{entity}/{id}/{field}/file', $class.'::renderFile')->bind('crudRenderFile')->before($localeAndCheckEntity, 10);
288 10
        $factory->post('/{entity}/{id}/{field}/delete', $class.'::deleteFile')->bind('crudDeleteFile')->before($localeAndCheckEntity, 10);
289 10
        $factory->get('/setting/locale/{locale}', $class.'::setLocale')->bind('crudSetLocale');
290
291 10
        return $factory;
292
    }
293
294
    /**
295
     * Setups i18n.
296
     *
297
     * @param Application $app
298
     * the Application instance of the Silex application
299
     */
300
    protected function setupI18n(Application $app)
301
    {
302 10
        $app->before(function(Request $request, Application $app) {
303 10
            $manageI18n = $app->offsetExists('crud.manageI18n') ? $app['crud.manageI18n'] : true;
304 10
            if ($manageI18n) {
305 10
                $locale = $app['session']->get('locale', 'en');
306 10
                $app['translator']->setLocale($locale);
307
            }
308 10
        }, 1);
309 10
    }
310
311
    /**
312
     * Implements ControllerProviderInterface::connect() connecting this
313
     * controller.
314
     *
315
     * @param Application $app
316
     * the Application instance of the Silex application
317
     *
318
     * @return \SilexController\Collection
319
     * this method is expected to return the used ControllerCollection instance
320
     */
321 10
    public function connect(Application $app)
322
    {
323 10
        $this->setupTemplates($app);
324 10
        $factory = $this->setupRoutes($app);
325 10
        $this->setupI18n($app);
326 10
        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 4
    public function create(Application $app, $entity)
341
    {
342 4
        $crudData = $app['crud']->getData($entity);
343 4
        $instance = $crudData->createEmpty();
344 4
        $request  = $app['request_stack']->getCurrentRequest();
345 4
        $instance->populateViaRequest($request);
346 4
        return $this->modifyEntity($app, $crudData, $instance, $entity, false);
347
    }
348
349
    /**
350
     * The controller for the "show list" action.
351
     *
352
     * @param Request $request
353
     * the current request
354
     * @param Application $app
355
     * the Silex application
356
     * @param string $entity
357
     * the current entity
358
     *
359
     * @return Response
360
     * the HTTP response of this action or 404 on invalid input
361
     */
362 4
    public function showList(Request $request, Application $app, $entity)
363
    {
364 4
        $crudData   = $app['crud']->getData($entity);
365 4
        $definition = $crudData->getDefinition();
366
367 4
        $filter          = [];
368 4
        $filterActive    = false;
369 4
        $filterToUse     = [];
370 4
        $filterOperators = [];
371 4
        $this->buildUpListFilter($request, $definition, $filter, $filterActive, $filterToUse, $filterOperators);
372
373 4
        $pageSize = $definition->getPageSize();
374 4
        $total    = $crudData->countBy($definition->getTable(), $filterToUse, $filterOperators, true);
375 4
        $page     = abs(intval($request->get('crudPage', 0)));
376 4
        $maxPage  = intval($total / $pageSize);
377 4
        if ($total % $pageSize == 0) {
378 4
            $maxPage--;
379
        }
380 4
        if ($page > $maxPage) {
381 4
            $page = $maxPage;
382
        }
383 4
        $skip = $page * $pageSize;
384
385 4
        $sortField            = $request->get('crudSortField', $definition->getInitialSortField());
386 4
        $sortAscendingRequest = $request->get('crudSortAscending');
387 4
        $sortAscending        = $sortAscendingRequest !== null ? $sortAscendingRequest === 'true' : $definition->isInitialSortAscending();
388
389 4
        $entities = $crudData->listEntries($filterToUse, $filterOperators, $skip, $pageSize, $sortField, $sortAscending);
390
391 4
        return $app['twig']->render($app['crud']->getTemplate($app, 'template', 'list', $entity), [
392 4
            'crudEntity' => $entity,
393 4
            'crudData' => $crudData,
394 4
            'definition' => $definition,
395 4
            'entities' => $entities,
396 4
            'pageSize' => $pageSize,
397 4
            'maxPage' => $maxPage,
398 4
            'page' => $page,
399 4
            'total' => $total,
400 4
            'filter' => $filter,
401 4
            'filterActive' => $filterActive,
402 4
            'sortField' => $sortField,
403 4
            'sortAscending' => $sortAscending,
404 4
            'layout' => $app['crud']->getTemplate($app, 'layout', 'list', $entity)
405
        ]);
406
    }
407
408
    /**
409
     * The controller for the "show" action.
410
     *
411
     * @param Application $app
412
     * the Silex application
413
     * @param string $entity
414
     * the current entity
415
     * @param string $id
416
     * the instance id to show
417
     *
418
     * @return Response
419
     * the HTTP response of this action or 404 on invalid input
420
     */
421 6
    public function show(Application $app, $entity, $id)
422
    {
423 6
        $crudData = $app['crud']->getData($entity);
424 6
        $instance = $crudData->get($id);
425 6
        if (!$instance) {
426 1
            return $this->getNotFoundPage($app, $app['translator']->trans('crudlex.instanceNotFound'));
427
        }
428 6
        $definition = $crudData->getDefinition();
429
430 6
        $childrenLabelFields = $definition->getChildrenLabelFields();
431 6
        $children            = [];
432 6
        if (count($childrenLabelFields) > 0) {
433 3
            foreach ($definition->getChildren() as $child) {
434 3
                $childField      = $child[1];
435 3
                $childEntity     = $child[2];
436 3
                $childLabelField = array_key_exists($childEntity, $childrenLabelFields) ? $childrenLabelFields[$childEntity] : 'id';
437 3
                $childCrud       = $app['crud']->getData($childEntity);
438 3
                $children[]      = [
439 3
                    $childCrud->getDefinition()->getLabel(),
440 3
                    $childEntity,
441 3
                    $childLabelField,
442 3
                    $childCrud->listEntries([$childField => $instance->get('id')]),
443 3
                    $childField
444
                ];
445
            }
446
        }
447
448 6
        return $app['twig']->render($app['crud']->getTemplate($app, 'template', 'show', $entity), [
449 6
            'crudEntity' => $entity,
450 6
            'entity' => $instance,
451 6
            'children' => $children,
452 6
            'layout' => $app['crud']->getTemplate($app, 'layout', 'show', $entity)
453
        ]);
454
    }
455
456
    /**
457
     * The controller for the "edit" action.
458
     *
459
     * @param Application $app
460
     * the Silex application
461
     * @param string $entity
462
     * the current entity
463
     * @param string $id
464
     * the instance id to edit
465
     *
466
     * @return Response
467
     * the HTTP response of this action or 404 on invalid input
468
     */
469 1
    public function edit(Application $app, $entity, $id)
470
    {
471 1
        $crudData = $app['crud']->getData($entity);
472 1
        $instance = $crudData->get($id);
473 1
        if (!$instance) {
474 1
            return $this->getNotFoundPage($app, $app['translator']->trans('crudlex.instanceNotFound'));
475
        }
476
477 1
        return $this->modifyEntity($app, $crudData, $instance, $entity, true);
478
    }
479
480
    /**
481
     * The controller for the "delete" action.
482
     *
483
     * @param Application $app
484
     * the Silex application
485
     * @param string $entity
486
     * the current entity
487
     * @param string $id
488
     * the instance id to delete
489
     *
490
     * @return Response
491
     * redirects to the entity list page or 404 on invalid input
492
     */
493 1
    public function delete(Application $app, $entity, $id)
494
    {
495 1
        $crudData = $app['crud']->getData($entity);
496 1
        $instance = $crudData->get($id);
497 1
        if (!$instance) {
498 1
            return $this->getNotFoundPage($app, $app['translator']->trans('crudlex.instanceNotFound'));
499
        }
500
501 1
        $fileHandler  = new FileHandler($app['crud.filesystem'], $crudData->getDefinition());
502 1
        $filesDeleted = $fileHandler->deleteFiles($crudData, $instance, $entity);
503 1
        $deleted      = $filesDeleted ? $crudData->delete($instance) : AbstractData::DELETION_FAILED_EVENT;
504
505 1
        if ($deleted === AbstractData::DELETION_FAILED_EVENT) {
506 1
            $app['session']->getFlashBag()->add('danger', $app['translator']->trans('crudlex.delete.failed'));
507 1
            return $app->redirect($app['url_generator']->generate('crudShow', ['entity' => $entity, 'id' => $id]));
508 1
        } elseif ($deleted === AbstractData::DELETION_FAILED_STILL_REFERENCED) {
509 1
            $app['session']->getFlashBag()->add('danger', $app['translator']->trans('crudlex.delete.error', [
510 1
                '%label%' => $crudData->getDefinition()->getLabel()
511
            ]));
512 1
            return $app->redirect($app['url_generator']->generate('crudShow', ['entity' => $entity, 'id' => $id]));
513
        }
514
515 1
        $redirectPage       = 'crudList';
516 1
        $redirectParameters = $this->getAfterDeleteRedirectParameters($app['request_stack']->getCurrentRequest(), $entity, $redirectPage);
517
518 1
        $app['session']->getFlashBag()->add('success', $app['translator']->trans('crudlex.delete.success', [
519 1
            '%label%' => $crudData->getDefinition()->getLabel()
520
        ]));
521 1
        return $app->redirect($app['url_generator']->generate($redirectPage, $redirectParameters));
522
    }
523
524
    /**
525
     * The controller for the "render file" action.
526
     *
527
     * @param Application $app
528
     * the Silex application
529
     * @param string $entity
530
     * the current entity
531
     * @param string $id
532
     * the instance id
533
     * @param string $field
534
     * the field of the file to render of the instance
535
     *
536
     * @return Response
537
     * the rendered file
538
     */
539 1
    public function renderFile(Application $app, $entity, $id, $field)
540
    {
541 1
        $crudData   = $app['crud']->getData($entity);
542 1
        $instance   = $crudData->get($id);
543 1
        $definition = $crudData->getDefinition();
544 1
        if (!$instance || $definition->getType($field) != 'file' || !$instance->get($field)) {
545 1
            return $this->getNotFoundPage($app, $app['translator']->trans('crudlex.instanceNotFound'));
546
        }
547 1
        $fileHandler = new FileHandler($app['crud.filesystem'], $definition);
548 1
        return $fileHandler->renderFile($instance, $entity, $field);
549
    }
550
551
    /**
552
     * The controller for the "delete file" action.
553
     *
554
     * @param Application $app
555
     * the Silex application
556
     * @param string $entity
557
     * the current entity
558
     * @param string $id
559
     * the instance id
560
     * @param string $field
561
     * the field of the file to delete of the instance
562
     *
563
     * @return Response
564
     * redirects to the instance details page or 404 on invalid input
565
     */
566 1
    public function deleteFile(Application $app, $entity, $id, $field)
567
    {
568 1
        $crudData = $app['crud']->getData($entity);
569 1
        $instance = $crudData->get($id);
570 1
        if (!$instance) {
571 1
            return $this->getNotFoundPage($app, $app['translator']->trans('crudlex.instanceNotFound'));
572
        }
573 1
        $fileHandler = new FileHandler($app['crud.filesystem'], $crudData->getDefinition());
574 1
        if (!$crudData->getDefinition()->getField($field, 'required', false) && $fileHandler->deleteFile($crudData, $instance, $entity, $field)) {
575 1
            $instance->set($field, '');
576 1
            $crudData->update($instance);
577 1
            $app['session']->getFlashBag()->add('success', $app['translator']->trans('crudlex.file.deleted'));
578
        } else {
579 1
            $app['session']->getFlashBag()->add('danger', $app['translator']->trans('crudlex.file.notDeleted'));
580
        }
581 1
        return $app->redirect($app['url_generator']->generate('crudShow', ['entity' => $entity, 'id' => $id]));
582
    }
583
584
    /**
585
     * The controller for serving static files.
586
     *
587
     * @param Request $request
588
     * the current request
589
     * @param Application $app
590
     * the Silex application
591
     *
592
     * @return Response
593
     * redirects to the instance details page or 404 on invalid input
594
     */
595 1
    public function staticFile(Request $request, Application $app)
596
    {
597 1
        $fileParam = str_replace('..', '', $request->get('file'));
598 1
        $file      = __DIR__.'/../static/'.$fileParam;
599 1
        if (!$fileParam || !file_exists($file)) {
600 1
            return $this->getNotFoundPage($app, $app['translator']->trans('crudlex.resourceNotFound'));
601
        }
602
603 1
        $filesystem = new Filesystem(new Local(dirname($file)));
0 ignored issues
show
Security File Manipulation introduced by
dirname($file) can contain request data and is used in file manipulation 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 798
  5. Request::get() returns tainted data, and $request->get('file') is passed through str_replace(), and $fileParam is assigned
    in src/CRUDlex/ControllerProvider.php on line 597
  6. $file is assigned
    in src/CRUDlex/ControllerProvider.php on line 598
  7. $file is passed through dirname()
    in src/CRUDlex/ControllerProvider.php on line 603
  2. Path: Read from $_POST, and $_POST is passed to Request::createRequestFromFactory() in Request.php on line 317
  1. Read from $_POST, and $_POST is passed to Request::createRequestFromFactory()
    in vendor/Request.php on line 317
  2. $request is passed to Request::__construct()
    in vendor/Request.php on line 2018
  3. $request is passed to Request::initialize()
    in vendor/Request.php on line 258
  4. $request is passed to ParameterBag::__construct()
    in vendor/Request.php on line 276
  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 798
  8. Request::get() returns tainted data, and $request->get('file') is passed through str_replace(), and $fileParam is assigned
    in src/CRUDlex/ControllerProvider.php on line 597
  9. $file is assigned
    in src/CRUDlex/ControllerProvider.php on line 598
  10. $file is passed through dirname()
    in src/CRUDlex/ControllerProvider.php on line 603
  3. Path: Read from $_SERVER, and $server is assigned in Request.php on line 307
  1. Read from $_SERVER, and $server is assigned
    in vendor/Request.php on line 307
  2. $server is passed to Request::createRequestFromFactory()
    in vendor/Request.php on line 317
  3. $server is passed to Request::__construct()
    in vendor/Request.php on line 2018
  4. $server is passed to Request::initialize()
    in vendor/Request.php on line 258
  5. $server is passed to ParameterBag::__construct()
    in vendor/Request.php on line 281
  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 798
  9. Request::get() returns tainted data, and $request->get('file') is passed through str_replace(), and $fileParam is assigned
    in src/CRUDlex/ControllerProvider.php on line 597
  10. $file is assigned
    in src/CRUDlex/ControllerProvider.php on line 598
  11. $file is passed through dirname()
    in src/CRUDlex/ControllerProvider.php on line 603
  4. Path: Fetching key HTTP_CONTENT_LENGTH from $_SERVER, and $server is assigned in Request.php on line 310
  1. Fetching key HTTP_CONTENT_LENGTH from $_SERVER, and $server is assigned
    in vendor/Request.php on line 310
  2. $server is passed to Request::createRequestFromFactory()
    in vendor/Request.php on line 317
  3. $server is passed to Request::__construct()
    in vendor/Request.php on line 2018
  4. $server is passed to Request::initialize()
    in vendor/Request.php on line 258
  5. $server is passed to ParameterBag::__construct()
    in vendor/Request.php on line 281
  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 798
  9. Request::get() returns tainted data, and $request->get('file') is passed through str_replace(), and $fileParam is assigned
    in src/CRUDlex/ControllerProvider.php on line 597
  10. $file is assigned
    in src/CRUDlex/ControllerProvider.php on line 598
  11. $file is passed through dirname()
    in src/CRUDlex/ControllerProvider.php on line 603
  5. Path: Fetching key HTTP_CONTENT_TYPE from $_SERVER, and $server is assigned in Request.php on line 313
  1. Fetching key HTTP_CONTENT_TYPE from $_SERVER, and $server is assigned
    in vendor/Request.php on line 313
  2. $server is passed to Request::createRequestFromFactory()
    in vendor/Request.php on line 317
  3. $server is passed to Request::__construct()
    in vendor/Request.php on line 2018
  4. $server is passed to Request::initialize()
    in vendor/Request.php on line 258
  5. $server is passed to ParameterBag::__construct()
    in vendor/Request.php on line 281
  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 798
  9. Request::get() returns tainted data, and $request->get('file') is passed through str_replace(), and $fileParam is assigned
    in src/CRUDlex/ControllerProvider.php on line 597
  10. $file is assigned
    in src/CRUDlex/ControllerProvider.php on line 598
  11. $file is passed through dirname()
    in src/CRUDlex/ControllerProvider.php on line 603
  6. Path: $server['HTTP_HOST'] seems to return tainted data, and $server is assigned in Request.php on line 383
  1. $server['HTTP_HOST'] seems to return tainted data, and $server is assigned
    in vendor/Request.php on line 383
  2. $server is assigned
    in vendor/Request.php on line 431
  3. $server is assigned
    in vendor/Request.php on line 432
  4. $server is passed to Request::createRequestFromFactory()
    in vendor/Request.php on line 434
  5. $server is passed to Request::__construct()
    in vendor/Request.php on line 2018
  6. $server is passed to Request::initialize()
    in vendor/Request.php on line 258
  7. $server is passed to ParameterBag::__construct()
    in vendor/Request.php on line 281
  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 798
  11. Request::get() returns tainted data, and $request->get('file') is passed through str_replace(), and $fileParam is assigned
    in src/CRUDlex/ControllerProvider.php on line 597
  12. $file is assigned
    in src/CRUDlex/ControllerProvider.php on line 598
  13. $file is passed through dirname()
    in src/CRUDlex/ControllerProvider.php on line 603
  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 282
  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 143
  7. HeaderBag::$headers is assigned
    in vendor/HeaderBag.php on line 146
  8. Tainted property HeaderBag::$headers is read
    in vendor/HeaderBag.php on line 67
  9. HeaderBag::all() returns tainted data, and $headers is assigned
    in vendor/HeaderBag.php on line 115
  10. HeaderBag::get() returns tainted data, and $requestUri is assigned
    in vendor/Request.php on line 1788
  11. $requestUri is passed to ParameterBag::set()
    in vendor/Request.php on line 1819
  12. ParameterBag::$parameters is assigned
    in vendor/ParameterBag.php on line 99
  13. Tainted property ParameterBag::$parameters is read
    in vendor/ParameterBag.php on line 88
  14. ParameterBag::get() returns tainted data, and $result is assigned
    in vendor/Request.php on line 798
  15. Request::get() returns tainted data, and $request->get('file') is passed through str_replace(), and $fileParam is assigned
    in src/CRUDlex/ControllerProvider.php on line 597
  16. $file is assigned
    in src/CRUDlex/ControllerProvider.php on line 598
  17. $file is passed through dirname()
    in src/CRUDlex/ControllerProvider.php on line 603
  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 282
  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 143
  6. HeaderBag::$headers is assigned
    in vendor/HeaderBag.php on line 146
  7. Tainted property HeaderBag::$headers is read
    in vendor/HeaderBag.php on line 67
  8. HeaderBag::all() returns tainted data, and $headers is assigned
    in vendor/HeaderBag.php on line 115
  9. HeaderBag::get() returns tainted data, and $requestUri is assigned
    in vendor/Request.php on line 1788
  10. $requestUri is passed to ParameterBag::set()
    in vendor/Request.php on line 1819
  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 798
  14. Request::get() returns tainted data, and $request->get('file') is passed through str_replace(), and $fileParam is assigned
    in src/CRUDlex/ControllerProvider.php on line 597
  15. $file is assigned
    in src/CRUDlex/ControllerProvider.php on line 598
  16. $file is passed through dirname()
    in src/CRUDlex/ControllerProvider.php on line 603

Used in path-write context

  1. Local::__construct() uses Local::ensureDirectory() ($root)
    in vendor/src/Adapter/Local.php on line 78
  2. Local::ensureDirectory() uses mkdir() ($pathname)
    in vendor/src/Adapter/Local.php on line 102

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...
604 1
        $mimeType   = $filesystem->getMimetype(basename($file));
605 1
        $size       = filesize($file);
606
607 1
        $streamedFileResponse = new StreamedFileResponse();
608 1
        $response             = new StreamedResponse($streamedFileResponse->getStreamedFileFunction($file), 200, [
609 1
            'Content-Type' => $mimeType,
610 1
            'Content-Disposition' => 'attachment; filename="'.basename($file).'"',
611 1
            'Content-length' => $size
612
        ]);
613
614 1
        $response->setETag(filemtime($file))->setPublic()->isNotModified($request);
615 1
        $response->send();
616
617 1
        return $response;
618
    }
619
620
    /**
621
     * The controller for setting the locale.
622
     *
623
     * @param Request $request
624
     * the current request
625
     * @param Application $app
626
     * the Silex application
627
     * @param string $locale
628
     * the new locale
629
     *
630
     * @return Response
631
     * redirects to the instance details page or 404 on invalid input
632
     */
633 1
    public function setLocale(Request $request, Application $app, $locale)
634
    {
635
636 1
        if (!in_array($locale, $app['crud']->getLocales())) {
637 1
            return $this->getNotFoundPage($app, 'Locale '.$locale.' not found.');
638
        }
639
640 1
        $manageI18n = $app->offsetExists('crud.manageI18n') ? $app['crud.manageI18n'] : true;
641 1
        if ($manageI18n) {
642 1
            $app['session']->set('locale', $locale);
643
        }
644 1
        $redirect = $request->get('redirect');
645 1
        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 798
  5. Request::get() returns tainted data, and $redirect is assigned
    in src/CRUDlex/ControllerProvider.php on line 644
  2. Path: Read from $_POST, and $_POST is passed to Request::createRequestFromFactory() in Request.php on line 317
  1. Read from $_POST, and $_POST is passed to Request::createRequestFromFactory()
    in vendor/Request.php on line 317
  2. $request is passed to Request::__construct()
    in vendor/Request.php on line 2018
  3. $request is passed to Request::initialize()
    in vendor/Request.php on line 258
  4. $request is passed to ParameterBag::__construct()
    in vendor/Request.php on line 276
  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 798
  8. Request::get() returns tainted data, and $redirect is assigned
    in src/CRUDlex/ControllerProvider.php on line 644
  3. Path: Read from $_SERVER, and $server is assigned in Request.php on line 307
  1. Read from $_SERVER, and $server is assigned
    in vendor/Request.php on line 307
  2. $server is passed to Request::createRequestFromFactory()
    in vendor/Request.php on line 317
  3. $server is passed to Request::__construct()
    in vendor/Request.php on line 2018
  4. $server is passed to Request::initialize()
    in vendor/Request.php on line 258
  5. $server is passed to ParameterBag::__construct()
    in vendor/Request.php on line 281
  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 798
  9. Request::get() returns tainted data, and $redirect is assigned
    in src/CRUDlex/ControllerProvider.php on line 644
  4. Path: Fetching key HTTP_CONTENT_LENGTH from $_SERVER, and $server is assigned in Request.php on line 310
  1. Fetching key HTTP_CONTENT_LENGTH from $_SERVER, and $server is assigned
    in vendor/Request.php on line 310
  2. $server is passed to Request::createRequestFromFactory()
    in vendor/Request.php on line 317
  3. $server is passed to Request::__construct()
    in vendor/Request.php on line 2018
  4. $server is passed to Request::initialize()
    in vendor/Request.php on line 258
  5. $server is passed to ParameterBag::__construct()
    in vendor/Request.php on line 281
  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 798
  9. Request::get() returns tainted data, and $redirect is assigned
    in src/CRUDlex/ControllerProvider.php on line 644
  5. Path: Fetching key HTTP_CONTENT_TYPE from $_SERVER, and $server is assigned in Request.php on line 313
  1. Fetching key HTTP_CONTENT_TYPE from $_SERVER, and $server is assigned
    in vendor/Request.php on line 313
  2. $server is passed to Request::createRequestFromFactory()
    in vendor/Request.php on line 317
  3. $server is passed to Request::__construct()
    in vendor/Request.php on line 2018
  4. $server is passed to Request::initialize()
    in vendor/Request.php on line 258
  5. $server is passed to ParameterBag::__construct()
    in vendor/Request.php on line 281
  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 798
  9. Request::get() returns tainted data, and $redirect is assigned
    in src/CRUDlex/ControllerProvider.php on line 644
  6. Path: $server['HTTP_HOST'] seems to return tainted data, and $server is assigned in Request.php on line 383
  1. $server['HTTP_HOST'] seems to return tainted data, and $server is assigned
    in vendor/Request.php on line 383
  2. $server is assigned
    in vendor/Request.php on line 431
  3. $server is assigned
    in vendor/Request.php on line 432
  4. $server is passed to Request::createRequestFromFactory()
    in vendor/Request.php on line 434
  5. $server is passed to Request::__construct()
    in vendor/Request.php on line 2018
  6. $server is passed to Request::initialize()
    in vendor/Request.php on line 258
  7. $server is passed to ParameterBag::__construct()
    in vendor/Request.php on line 281
  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 798
  11. Request::get() returns tainted data, and $redirect is assigned
    in src/CRUDlex/ControllerProvider.php on line 644
  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 282
  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 143
  7. HeaderBag::$headers is assigned
    in vendor/HeaderBag.php on line 146
  8. Tainted property HeaderBag::$headers is read
    in vendor/HeaderBag.php on line 67
  9. HeaderBag::all() returns tainted data, and $headers is assigned
    in vendor/HeaderBag.php on line 115
  10. HeaderBag::get() returns tainted data, and $requestUri is assigned
    in vendor/Request.php on line 1788
  11. $requestUri is passed to ParameterBag::set()
    in vendor/Request.php on line 1819
  12. ParameterBag::$parameters is assigned
    in vendor/ParameterBag.php on line 99
  13. Tainted property ParameterBag::$parameters is read
    in vendor/ParameterBag.php on line 88
  14. ParameterBag::get() returns tainted data, and $result is assigned
    in vendor/Request.php on line 798
  15. Request::get() returns tainted data, and $redirect is assigned
    in src/CRUDlex/ControllerProvider.php on line 644
  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 282
  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 143
  6. HeaderBag::$headers is assigned
    in vendor/HeaderBag.php on line 146
  7. Tainted property HeaderBag::$headers is read
    in vendor/HeaderBag.php on line 67
  8. HeaderBag::all() returns tainted data, and $headers is assigned
    in vendor/HeaderBag.php on line 115
  9. HeaderBag::get() returns tainted data, and $requestUri is assigned
    in vendor/Request.php on line 1788
  10. $requestUri is passed to ParameterBag::set()
    in vendor/Request.php on line 1819
  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 798
  14. Request::get() returns tainted data, and $redirect is assigned
    in src/CRUDlex/ControllerProvider.php on line 644

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 86
  4. Response::setContent() uses property Response::$content for writing
    in vendor/Response.php on line 412
  5. Property Response::$content is used in echo
    in vendor/Response.php on line 371

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...
646
    }
647
}
648