‪TYPO3CMS  ‪main
FileViewHelper.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
28 use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper;
29 use TYPO3Fluid\Fluid\Core\ViewHelper\Exception;
30 
67 final class ‪FileViewHelper extends AbstractTagBasedViewHelper
68 {
72  protected ‪$tagName = 'a';
73 
74  public function ‪initializeArguments(): void
75  {
76  parent::initializeArguments();
77  $this->registerArgument('file', FileInterface::class, 'Specifies the file to create a link to', true);
78  $this->registerArgument('download', 'bool', 'Specifies if file should be downloaded instead of displayed');
79  $this->registerArgument('filename', 'string', 'Specifies an alternative filename. If filename contains a file extension, this must be the same as from \'file\'.');
80  $this->registerUniversalTagAttributes();
81  $this->registerTagAttribute('name', 'string', 'Specifies the name of an anchor');
82  $this->registerTagAttribute('rel', 'string', 'Specifies the relationship between the current document and the linked document');
83  $this->registerTagAttribute('rev', 'string', 'Specifies the relationship between the linked document and the current document');
84  $this->registerTagAttribute('target', 'string', 'Specifies where to open the linked document');
85  }
86 
87  public function ‪render(): string
88  {
89  $file = $this->arguments['file'];
90 
91  if (!($file instanceof ‪FileInterface)) {
92  throw new Exception('Argument \'file\' must be an instance of ' . FileInterface::class, 1621511632);
93  }
94 
95  // Get the public URL. This url is either be defined by a GeneratePublicUrlForResourceEvent,
96  // an OnlineMedia helper, the corresponding driver or using the file dump functionality.
97  ‪$publicUrl = $file->getPublicUrl();
98 
99  // Early return in case public url is null as this indicates the file is
100  // not accessible, e.g. because the corresponding storage is offline.
101  if (‪$publicUrl === null) {
102  return '';
103  }
104 
105  if (str_contains(‪$publicUrl, 'dumpFile')) {
106  // In case we deal with is a file dump URL, recreate the URL
107  // by taking the defined view helper arguments into account.
108  ‪$publicUrl = $this->‪createFileDumpUrl($file);
109  } elseif ($this->arguments['download'] ?? false) {
110  // In case the URL directly links to the file (no eID) and
111  // the file should be downloaded instead of displayed, this
112  // must be set by the "download" tag attribute, which may
113  // contain an alternative filename.
114  $this->tag->addAttribute(
115  'download',
116  $this->‪getAlternativeFilename($file)
117  );
118  }
119 
120  $this->tag->addAttribute('href', ‪$publicUrl);
121  $this->tag->setContent($this->renderChildren() ?? htmlspecialchars($file->getName()));
122  $this->tag->forceClosingTag(true);
123 
124  return $this->tag->render();
125  }
126 
130  protected function ‪createFileDumpUrl(‪FileInterface $file): string
131  {
132  $parameters = ['eID' => 'dumpFile'];
133 
134  if ($file instanceof ‪File) {
135  $parameters['t'] = 'f';
136  $parameters['f'] = $file->getUid();
137  } elseif ($file instanceof ‪FileReference) {
138  $parameters['t'] = 'r';
139  $parameters['r'] = $file->getUid();
140  } elseif ($file instanceof ProcessedFile) {
141  $parameters['t'] = 'p';
142  $parameters['p'] = $file->getUid();
143  }
144 
145  if ($download = $this->arguments['download'] ?? false) {
146  $parameters['dl'] = (int)$download;
147  }
148 
149  if (($filename = $this->‪getAlternativeFilename($file)) !== '') {
150  $parameters['fn'] = $filename;
151  }
152 
153  $hashService = GeneralUtility::makeInstance(HashService::class);
154  $parameters['token'] = $hashService->hmac(implode('|', $parameters), 'resourceStorageDumpFile');
155 
156  return GeneralUtility::locationHeaderUrl(‪PathUtility::getAbsoluteWebPath(‪Environment::getPublicPath() . '/index.php'))
157  . '?' . http_build_query($parameters, '', '&', PHP_QUERY_RFC3986);
158  }
159 
160  protected function ‪getAlternativeFilename(‪FileInterface $file): string
161  {
162  $alternativeFilename = $this->arguments['filename'] ?? '';
163 
164  // Return early if filename is empty or not valid
165  if ($alternativeFilename === '' || !preg_match('/^[0-9a-z._\-]+$/i', $alternativeFilename)) {
166  return '';
167  }
168 
169  $extension = pathinfo($alternativeFilename, PATHINFO_EXTENSION);
170  if ($extension === '') {
171  // Add original extension in case alternative filename did not contain any
172  $alternativeFilename = rtrim($alternativeFilename, '.') . '.' . $file->getExtension();
173  }
174 
175  // Check if given or resolved extension matches the original one
176  return $file->getExtension() === pathinfo($alternativeFilename, PATHINFO_EXTENSION)
177  ? $alternativeFilename
178  : '';
179  }
180 }
‪TYPO3\CMS\Core\Utility\PathUtility
Definition: PathUtility.php:27
‪TYPO3\CMS\Core\Resource\FileInterface
Definition: FileInterface.php:26
‪TYPO3\CMS\Core\Core\Environment\getPublicPath
‪static getPublicPath()
Definition: Environment.php:187
‪TYPO3\CMS\Core\Resource\FileReference
Definition: FileReference.php:37
‪TYPO3\CMS\Core\Utility\PathUtility\getAbsoluteWebPath
‪static string getAbsoluteWebPath(string $targetPath, bool $prefixWithSitePath=true)
Definition: PathUtility.php:52
‪TYPO3\CMS\Webhooks\Message\$publicUrl
‪identifier readonly string readonly string $publicUrl
Definition: FileUpdatedMessage.php:36
‪TYPO3\CMS\Core\Resource\File
Definition: File.php:26
‪TYPO3\CMS\Core\Resource\ProcessedFile
Definition: ProcessedFile.php:47
‪TYPO3\CMS\Core\Core\Environment
Definition: Environment.php:41
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Core\Crypto\HashService
Definition: HashService.php:27