Completed
Pull Request — master (#1307)
by Peter
01:39
created

ImagineController::filterAction()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 14
rs 9.7998
c 0
b 0
f 0
cc 1
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\Helper\PathHelper;
19
use Liip\ImagineBundle\Imagine\Cache\SignerInterface;
20
use Liip\ImagineBundle\Imagine\Data\DataManager;
21
use Liip\ImagineBundle\Service\FilterService;
22
use Symfony\Component\HttpFoundation\RedirectResponse;
23
use Symfony\Component\HttpFoundation\Request;
24
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
25
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
26
27
class ImagineController
28
{
29
    /**
30
     * @var FilterService
31
     */
32
    private $filterService;
33
34
    /**
35
     * @var DataManager
36
     */
37
    private $dataManager;
38
39
    /**
40
     * @var SignerInterface
41
     */
42
    private $signer;
43
44
    /**
45
     * @var ControllerConfig
46
     */
47
    private $controllerConfig;
48
49
    /**
50
     * @param FilterService         $filterService
51
     * @param DataManager           $dataManager
52
     * @param SignerInterface       $signer
53
     * @param ControllerConfig|null $controllerConfig
54
     */
55
    public function __construct(
56
        FilterService $filterService,
57
        DataManager $dataManager,
58
        SignerInterface $signer,
59
        ?ControllerConfig $controllerConfig = null
60
    ) {
61
        $this->filterService = $filterService;
62
        $this->dataManager = $dataManager;
63
        $this->signer = $signer;
64
65
        if (null === $controllerConfig) {
66
            @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...
67
                'Instantiating "%s" without a forth argument of type "%s" is deprecated since 2.2.0 and will be required in 3.0.', self::class, ControllerConfig::class
68
            ), E_USER_DEPRECATED);
69
        }
70
71
        $this->controllerConfig = $controllerConfig ?? new ControllerConfig(301);
72
    }
73
74
    /**
75
     * This action applies a given filter to a given image, saves the image and redirects the browser to the stored
76
     * image.
77
     *
78
     * The resulting image is cached so subsequent requests will redirect to the cached image instead applying the
79
     * filter and storing the image again.
80
     *
81
     * @param Request $request
82
     * @param string  $path
83
     * @param string  $filter
84
     *
85
     * @throws RuntimeException
86
     * @throws NotFoundHttpException
87
     *
88
     * @return RedirectResponse
89
     */
90
    public function filterAction(Request $request, $path, $filter)
91
    {
92
        $path = PathHelper::urlPathToFilePath($path);
93
        $resolver = $request->get('resolver');
94
95
        return $this->createRedirectResponse(function () use ($path, $filter, $resolver, $request) {
96
            return $this->filterService->getUrlOfFilteredImage(
97
                $path,
98
                $filter,
99
                $resolver,
100
                $this->isSupportWebp($request)
101
            );
102
        }, $path, $filter);
103
    }
104
105
    /**
106
     * This action applies a given filter -merged with additional runtime filters- to a given image, saves the image and
107
     * redirects the browser to the stored image.
108
     *
109
     * The resulting image is cached so subsequent requests will redirect to the cached image instead applying the
110
     * filter and storing the image again.
111
     *
112
     * @param Request $request
113
     * @param string  $hash
114
     * @param string  $path
115
     * @param string  $filter
116
     *
117
     * @throws RuntimeException
118
     * @throws BadRequestHttpException
119
     * @throws NotFoundHttpException
120
     *
121
     * @return RedirectResponse
122
     */
123
    public function filterRuntimeAction(Request $request, $hash, $path, $filter)
124
    {
125
        $resolver = $request->get('resolver');
126
        $path = PathHelper::urlPathToFilePath($path);
127
        $runtimeConfig = $request->query->get('filters', []);
0 ignored issues
show
Documentation introduced by
array() is of type array, but the function expects a string|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
128
129
        if (!\is_array($runtimeConfig)) {
130
            throw new NotFoundHttpException(sprintf('Filters must be an array. Value was "%s"', $runtimeConfig));
131
        }
132
133
        if (true !== $this->signer->check($hash, $path, $runtimeConfig)) {
134
            throw new BadRequestHttpException(sprintf(
135
                'Signed url does not pass the sign check for path "%s" and filter "%s" and runtime config %s',
136
                $path,
137
                $filter,
138
                json_encode($runtimeConfig)
139
            ));
140
        }
141
142
        return $this->createRedirectResponse(function () use ($path, $filter, $runtimeConfig, $resolver, $request) {
143
            return $this->filterService->getUrlOfFilteredImageWithRuntimeFilters(
144
                $path,
145
                $filter,
146
                $runtimeConfig,
147
                $resolver,
148
                $this->isSupportWebp($request)
149
            );
150
        }, $path, $filter, $hash);
151
    }
152
153
    /**
154
     * @param \Closure    $url
155
     * @param string      $path
156
     * @param string      $filter
157
     * @param string|null $hash
158
     *
159
     * @return RedirectResponse
160
     */
161
    private function createRedirectResponse(\Closure $url, string $path, string $filter, ?string $hash = null): RedirectResponse
162
    {
163
        try {
164
            return new RedirectResponse($url(), $this->controllerConfig->getRedirectResponseCode());
165
        } catch (NotLoadableException $exception) {
166
            if (null !== $this->dataManager->getDefaultImageUrl($filter)) {
167
                return new RedirectResponse($this->dataManager->getDefaultImageUrl($filter));
168
            }
169
170
            throw new NotFoundHttpException(sprintf('Source image for path "%s" could not be found', $path), $exception);
171
        } catch (NonExistingFilterException $exception) {
172
            throw new NotFoundHttpException(sprintf('Requested non-existing filter "%s"', $filter), $exception);
173
        } catch (RuntimeException $exception) {
174
            throw new \RuntimeException(vsprintf('Unable to create image for path "%s" and filter "%s". Message was "%s"', [
175
                $hash ? sprintf('%s/%s', $hash, $path) : $path,
176
                $filter,
177
                $exception->getMessage(),
178
            ]), 0, $exception);
179
        }
180
    }
181
182
    /**
183
     * @param Request $request
184
     *
185
     * @return bool
186
     */
187
    private function isSupportWebp(Request $request): bool
188
    {
189
        return false !== stripos($request->headers->get('accept', ''), 'image/webp');
190
    }
191
}
192