Completed
Pull Request — 2.0 (#1101)
by Rob
02:06
created

ImagineController::filterAction()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 9
rs 9.6666
c 0
b 0
f 0
cc 1
eloc 6
nc 1
nop 3
1
<?php
2
3
/*
4
 * This file is part of the `liip/LiipImagineBundle` project.
5
 *
6
 * (c) https://github.com/liip/LiipImagineBundle/graphs/contributors
7
 *
8
 * For the full copyright and license information, please view the LICENSE.md
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Liip\ImagineBundle\Controller;
13
14
use Imagine\Exception\RuntimeException;
15
use Liip\ImagineBundle\Config\Controller\ControllerConfig;
16
use Liip\ImagineBundle\Exception\Binary\Loader\NotLoadableException;
17
use Liip\ImagineBundle\Exception\Imagine\Filter\NonExistingFilterException;
18
use Liip\ImagineBundle\Imagine\Cache\SignerInterface;
19
use Liip\ImagineBundle\Imagine\Data\DataManager;
20
use Liip\ImagineBundle\Service\FilterService;
21
use Symfony\Component\HttpFoundation\RedirectResponse;
22
use Symfony\Component\HttpFoundation\Request;
23
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
24
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
25
26
class ImagineController
27
{
28
    /**
29
     * @var FilterService
30
     */
31
    private $filterService;
32
33
    /**
34
     * @var DataManager
35
     */
36
    private $dataManager;
37
38
    /**
39
     * @var SignerInterface
40
     */
41
    private $signer;
42
43
    /**
44
     * @var ControllerConfig
45
     */
46
    private $controllerConfig;
47
48
    /**
49
     * @param FilterService         $filterService
50
     * @param DataManager           $dataManager
51
     * @param SignerInterface       $signer
52
     * @param ControllerConfig|null $controllerConfig
53
     */
54
    public function __construct(FilterService $filterService, DataManager $dataManager, SignerInterface $signer, ?ControllerConfig $controllerConfig = null)
55
    {
56
        $this->filterService = $filterService;
57
        $this->dataManager = $dataManager;
58
        $this->signer = $signer;
59
60
        if (null === $controllerConfig) {
61
            @trigger_error(sprintf(
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
62
                'Instantiating "%s" without a forth argument of type "%s" is deprecated since 2.1.0 and will be required in 3.0.', self::class, ControllerConfig::class
63
            ), E_USER_DEPRECATED);
64
        }
65
66
        $this->controllerConfig = $controllerConfig ?? new ControllerConfig(301);
67
    }
68
69
    /**
70
     * This action applies a given filter to a given image, saves the image and redirects the browser to the stored
71
     * image.
72
     *
73
     * The resulting image is cached so subsequent requests will redirect to the cached image instead applying the
74
     * filter and storing the image again.
75
     *
76
     * @param Request $request
77
     * @param string  $path
78
     * @param string  $filter
79
     *
80
     * @throws RuntimeException
81
     * @throws NotFoundHttpException
82
     *
83
     * @return RedirectResponse
84
     */
85
    public function filterAction(Request $request, $path, $filter)
86
    {
87
        $resolver = $request->get('resolver');
88
        $path = urldecode($path);
89
90
        return $this->createRedirectResponse(function () use ($path, $filter, $resolver) {
91
            return $this->filterService->getUrlOfFilteredImage($path, $filter, $resolver);
92
        }, $path, $filter);
93
    }
94
95
    /**
96
     * This action applies a given filter -merged with additional runtime filters- to a given image, saves the image and
97
     * redirects the browser to the stored image.
98
     *
99
     * The resulting image is cached so subsequent requests will redirect to the cached image instead applying the
100
     * filter and storing the image again.
101
     *
102
     * @param Request $request
103
     * @param string  $hash
104
     * @param string  $path
105
     * @param string  $filter
106
     *
107
     * @throws RuntimeException
108
     * @throws BadRequestHttpException
109
     * @throws NotFoundHttpException
110
     *
111
     * @return RedirectResponse
112
     */
113
    public function filterRuntimeAction(Request $request, $hash, $path, $filter)
114
    {
115
        $resolver = $request->get('resolver');
116
        $path = urldecode($path);
117
        $runtimeConfig = $request->query->get('filters', []);
118
119
        if (!is_array($runtimeConfig)) {
120
            throw new NotFoundHttpException(sprintf('Filters must be an array. Value was "%s"', $runtimeConfig));
121
        }
122
123
        if (true !== $this->signer->check($hash, $path, $runtimeConfig)) {
124
            throw new BadRequestHttpException(sprintf(
125
                'Signed url does not pass the sign check for path "%s" and filter "%s" and runtime config %s',
126
                $path,
127
                $filter,
128
                json_encode($runtimeConfig)
129
            ));
130
        }
131
132
        return $this->createRedirectResponse(function () use ($path, $filter, $runtimeConfig, $resolver) {
133
            return $this->filterService->getUrlOfFilteredImageWithRuntimeFilters($path, $filter, $runtimeConfig, $resolver);
134
        }, $path, $filter, $hash);
135
    }
136
137
    /**
138
     * @param \Closure    $url
139
     * @param string      $path
140
     * @param string      $filter
141
     * @param null|string $hash
142
     *
143
     * @return RedirectResponse
144
     */
145
    private function createRedirectResponse(\Closure $url, string $path, string $filter, ?string $hash = null): RedirectResponse
146
    {
147
        try {
148
            return new RedirectResponse($url(), $this->controllerConfig->getRedirectResponseCode());
149
        } catch (NotLoadableException $exception) {
150
            if (null !== $this->dataManager->getDefaultImageUrl($filter)) {
151
                return new RedirectResponse($this->dataManager->getDefaultImageUrl($filter));
152
            }
153
154
            throw new NotFoundHttpException(sprintf('Source image for path "%s" could not be found', $path));
155
        } catch (NonExistingFilterException $exception) {
156
            throw new NotFoundHttpException(sprintf('Requested non-existing filter "%s"', $filter));
157
        } catch (RuntimeException $exception) {
158
            throw new \RuntimeException(vsprintf('Unable to create image for path "%s" and filter "%s". Message was "%s"', [
159
                $hash ? sprintf('%s/%s', $hash, $path) : $path,
160
                $filter,
161
                $exception->getMessage(),
162
            ]), 0, $exception);
163
        }
164
    }
165
}
166