‪TYPO3CMS  10.4
ShowImageController.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of the TYPO3 CMS project.
5  *
6  * It is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License, either version 2
8  * of the License, or any later version.
9  *
10  * For the full copyright and license information, please read the
11  * LICENSE.txt file that was distributed with this source code.
12  *
13  * The TYPO3 project - inspiring people to share!
14  */
15 
17 
18 use Psr\Http\Message\ResponseInterface;
19 use Psr\Http\Message\ServerRequestInterface;
28 
45 {
46  protected const ‪ALLOWED_PARAMETER_NAMES = ['width', 'height', 'crop', 'bodyTag', 'title'];
47 
51  protected ‪$request;
52 
56  protected ‪$file;
57 
61  protected ‪$width;
62 
66  protected ‪$height;
67 
71  protected ‪$crop;
72 
76  protected ‪$frame;
77 
81  protected ‪$bodyTag = '<body>';
82 
86  protected ‪$title = 'Image';
87 
91  protected ‪$content = <<<EOF
92 <!DOCTYPE html>
93 <html>
94 <head>
95  <title>###TITLE###</title>
96  <meta name="robots" content="noindex,follow" />
97 </head>
98 ###BODY###
99  ###IMAGE###
100 </body>
101 </html>
102 EOF;
103 
107  protected ‪$imageTag = '<img src="###publicUrl###" alt="###alt###" title="###title###" width="###width###" height="###height###" />';
108 
115  public function ‪initialize()
116  {
117  $fileUid = $this->request->getQueryParams()['file'] ?? null;
118  $parametersArray = $this->request->getQueryParams()['parameters'] ?? null;
119 
120  // If no file-param or parameters are given, we must exit
121  if (!$fileUid || !isset($parametersArray) || !is_array($parametersArray)) {
122  throw new \InvalidArgumentException('No valid fileUid given', 1476048455);
123  }
124 
125  // rebuild the parameter array and check if the HMAC is correct
126  $parametersEncoded = implode('', $parametersArray);
127 
128  /* For backwards compatibility the HMAC is transported within the md5 param */
129  $hmacParameter = $this->request->getQueryParams()['md5'] ?? null;
130  $hmac = GeneralUtility::hmac(implode('|', [$fileUid, $parametersEncoded]));
131  if (!is_string($hmacParameter) || !hash_equals($hmac, $hmacParameter)) {
132  throw new \InvalidArgumentException('hash does not match', 1476048456);
133  }
134 
135  // decode the parameters Array - `bodyTag` contains HTML if set and would lead
136  // to a false-positive XSS-detection, that's why parameters are base64-encoded
137  $parameters = json_decode(base64_decode($parametersEncoded), true) ?? [];
138  foreach ($parameters as $parameterName => $parameterValue) {
139  if (in_array($parameterName, static::ALLOWED_PARAMETER_NAMES, true)) {
140  $this->{$parameterName} = $parameterValue;
141  }
142  }
143 
145  $this->file = GeneralUtility::makeInstance(ResourceFactory::class)->getFileObject((int)$fileUid);
146  } else {
147  $this->file = GeneralUtility::makeInstance(ResourceFactory::class)->retrieveFileOrFolderObject($fileUid);
148  }
149  if (!($this->file instanceof ‪FileInterface && $this->‪isFileValid($this->file))) {
150  throw new ‪Exception('File processing for local storage is denied', 1594043425);
151  }
152 
153  $this->frame = $this->request->getQueryParams()['frame'] ?? null;
154  }
155 
160  public function ‪main()
161  {
162  $processedImage = $this->‪processImage();
163  $imageTagMarkers = [
164  '###publicUrl###' => htmlspecialchars($processedImage->getPublicUrl() ?? ''),
165  '###alt###' => htmlspecialchars($this->file->getProperty('alternative') ?: $this->title),
166  '###title###' => htmlspecialchars($this->file->getProperty('title') ?: $this->title),
167  '###width###' => $processedImage->getProperty('width'),
168  '###height###' => $processedImage->getProperty('height')
169  ];
170  $this->imageTag = str_replace(array_keys($imageTagMarkers), array_values($imageTagMarkers), $this->imageTag);
171  $markerArray = [
172  '###TITLE###' => $this->file->getProperty('title') ?: ‪$this->title,
173  '###IMAGE###' => ‪$this->imageTag,
174  '###BODY###' => ‪$this->bodyTag
175  ];
176 
177  $this->content = str_replace(array_keys($markerArray), array_values($markerArray), $this->content);
178  }
179 
185  protected function ‪processImage()
186  {
187  $max = strpos($this->width . $this->height, 'm') !== false ? 'm' : '';
188  $this->height = ‪MathUtility::forceIntegerInRange($this->height, 0);
189  $this->width = ‪MathUtility::forceIntegerInRange($this->width, 0) . $max;
190 
191  $processingConfiguration = [
192  'width' => ‪$this->width,
193  'height' => ‪$this->height,
194  'frame' => ‪$this->frame,
195  'crop' => ‪$this->crop,
196  ];
197  return $this->file->process(‪ProcessedFile::CONTEXT_IMAGECROPSCALEMASK, $processingConfiguration);
198  }
199 
206  public function ‪processRequest(ServerRequestInterface ‪$request): ResponseInterface
207  {
208  $this->request = ‪$request;
209 
210  try {
211  $this->‪initialize();
212  $this->‪main();
213  $response = new ‪Response();
214  $response->getBody()->write($this->content);
215  return $response;
216  } catch (\InvalidArgumentException $e) {
217  // add a 410 "gone" if invalid parameters given
218  return (new ‪Response())->withStatus(410);
219  } catch (‪Exception $e) {
220  return (new Response())->withStatus(404);
221  }
222  }
223 
224  protected function ‪isFileValid(FileInterface ‪$file): bool
225  {
226  return ‪$file->getStorage()->getDriverType() !== 'Local'
227  || GeneralUtility::makeInstance(FileNameValidator::class)
228  ->isValid(basename(‪$file->getIdentifier()));
229  }
230 }
‪TYPO3\CMS\Frontend\Controller\ShowImageController\$file
‪TYPO3 CMS Core Resource File $file
Definition: ShowImageController.php:54
‪TYPO3\CMS\Core\Utility\MathUtility\canBeInterpretedAsInteger
‪static bool canBeInterpretedAsInteger($var)
Definition: MathUtility.php:74
‪TYPO3\CMS\Frontend\Controller\ShowImageController\$bodyTag
‪string $bodyTag
Definition: ShowImageController.php:74
‪TYPO3\CMS\Core\Resource\FileInterface
Definition: FileInterface.php:22
‪TYPO3\CMS\Frontend\Controller\ShowImageController\$width
‪int $width
Definition: ShowImageController.php:58
‪TYPO3\CMS\Core\Exception
Definition: Exception.php:22
‪TYPO3\CMS\Core\Resource\Security\FileNameValidator
Definition: FileNameValidator.php:25
‪TYPO3\CMS\Frontend\Controller\ShowImageController\ALLOWED_PARAMETER_NAMES
‪const ALLOWED_PARAMETER_NAMES
Definition: ShowImageController.php:46
‪TYPO3\CMS\Core\Resource\ProcessedFile\CONTEXT_IMAGECROPSCALEMASK
‪const CONTEXT_IMAGECROPSCALEMASK
Definition: ProcessedFile.php:58
‪TYPO3\CMS\Core\Utility\MathUtility\forceIntegerInRange
‪static int forceIntegerInRange($theInt, $min, $max=2000000000, $defaultValue=0)
Definition: MathUtility.php:32
‪TYPO3\CMS\Core\Exception
‪TYPO3\CMS\Frontend\Controller\ShowImageController\processImage
‪TYPO3 CMS Core Resource ProcessedFile processImage()
Definition: ShowImageController.php:175
‪TYPO3\CMS\Frontend\Controller\ShowImageController\$frame
‪int $frame
Definition: ShowImageController.php:70
‪TYPO3\CMS\Frontend\Controller\ShowImageController\isFileValid
‪isFileValid(FileInterface $file)
Definition: ShowImageController.php:214
‪TYPO3\CMS\Frontend\Controller\ShowImageController\processRequest
‪ResponseInterface processRequest(ServerRequestInterface $request)
Definition: ShowImageController.php:196
‪TYPO3\CMS\Frontend\Controller\ShowImageController\initialize
‪initialize()
Definition: ShowImageController.php:105
‪TYPO3\CMS\Frontend\Controller\ShowImageController\$crop
‪string $crop
Definition: ShowImageController.php:66
‪TYPO3\CMS\Core\Http\Response
Definition: Response.php:30
‪TYPO3\CMS\Frontend\Controller\ShowImageController\$title
‪string $title
Definition: ShowImageController.php:78
‪TYPO3\CMS\Frontend\Controller\ShowImageController\$request
‪Psr Http Message ServerRequestInterface $request
Definition: ShowImageController.php:50
‪TYPO3\CMS\Frontend\Exception
Definition: Exception.php:24
‪TYPO3\CMS\Frontend\Controller\ShowImageController\$content
‪string $content
Definition: ShowImageController.php:82
‪TYPO3\CMS\Core\Resource\ResourceFactory
Definition: ResourceFactory.php:41
‪TYPO3\CMS\Frontend\Controller\ShowImageController\main
‪main()
Definition: ShowImageController.php:150
‪TYPO3\CMS\Frontend\Controller\ShowImageController\$height
‪int $height
Definition: ShowImageController.php:62
‪TYPO3\CMS\Frontend\Controller\ShowImageController\$imageTag
‪string $imageTag
Definition: ShowImageController.php:97
‪TYPO3\CMS\Core\Resource\ProcessedFile
Definition: ProcessedFile.php:44
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:22
‪TYPO3\CMS\Frontend\Controller
Definition: ErrorController.php:18
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:46
‪TYPO3\CMS\Frontend\Controller\ShowImageController
Definition: ShowImageController.php:45