‪TYPO3CMS  11.5
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 
27 use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper;
28 use TYPO3Fluid\Fluid\Core\ViewHelper\Exception;
29 
66 class ‪FileViewHelper extends AbstractTagBasedViewHelper
67 {
71  protected ‪$tagName = 'a';
72 
73  public function ‪initializeArguments(): void
74  {
75  parent::initializeArguments();
76  $this->registerArgument('file', FileInterface::class, 'Specifies the file to create a link to', true);
77  $this->registerArgument('download', 'bool', 'Specifies if file should be downloaded instead of displayed');
78  $this->registerArgument('filename', 'string', 'Specifies an alternative filename. If filename contains a file extension, this must be the same as from \'file\'.');
79  $this->registerUniversalTagAttributes();
80  $this->registerTagAttribute('name', 'string', 'Specifies the name of an anchor');
81  $this->registerTagAttribute('rel', 'string', 'Specifies the relationship between the current document and the linked document');
82  $this->registerTagAttribute('rev', 'string', 'Specifies the relationship between the linked document and the current document');
83  $this->registerTagAttribute('target', 'string', 'Specifies where to open the linked document');
84  }
85 
86  public function ‪render(): string
87  {
88  $file = $this->arguments['file'];
89 
90  if (!($file instanceof ‪FileInterface)) {
91  throw new Exception('Argument \'file\' must be an instance of ' . FileInterface::class, 1621511632);
92  }
93 
94  // Get the public URL. This url is either be defined by a GeneratePublicUrlForResourceEvent,
95  // an OnlineMedia helper, the corresponding driver or using the file dump functionality.
96  $publicUrl = $file->getPublicUrl();
97 
98  // Early return in case public url is null as this indicates the file is
99  // not accessible, e.g. because the corresponding storage is offline.
100  if ($publicUrl === null) {
101  return '';
102  }
103 
104  if (str_contains($publicUrl, 'dumpFile')) {
105  // In case we deal with is a file dump URL, recreate the URL
106  // by taking the defined view helper arguments into account.
107  $publicUrl = $this->‪createFileDumpUrl($file);
108  } elseif ($this->arguments['download'] ?? false) {
109  // In case the URL directly links to the file (no eID) and
110  // the file should be downloaded instead of displayed, this
111  // must be set by the "download" tag attribute, which may
112  // contain an alternative filename.
113  $this->tag->addAttribute(
114  'download',
115  $this->‪getAlternativeFilename($file)
116  );
117  }
118 
119  $this->tag->addAttribute('href', $publicUrl);
120  $this->tag->setContent($this->renderChildren() ?? htmlspecialchars($file->getName()));
121  $this->tag->forceClosingTag(true);
122 
123  return $this->tag->render();
124  }
125 
129  protected function ‪createFileDumpUrl(‪FileInterface $file): string
130  {
131  $parameters = ['eID' => 'dumpFile'];
132 
133  if ($file instanceof ‪File) {
134  $parameters['t'] = 'f';
135  $parameters['f'] = $file->getUid();
136  } elseif ($file instanceof ‪FileReference) {
137  $parameters['t'] = 'r';
138  $parameters['r'] = $file->getUid();
139  } elseif ($file instanceof ProcessedFile) {
140  $parameters['t'] = 'p';
141  $parameters['p'] = $file->getUid();
142  }
143 
144  if ($download = $this->arguments['download'] ?? false) {
145  $parameters['dl'] = (int)$download;
146  }
147 
148  if (($filename = $this->‪getAlternativeFilename($file)) !== '') {
149  $parameters['fn'] = $filename;
150  }
151 
152  $parameters['token'] = GeneralUtility::hmac(implode('|', $parameters), 'resourceStorageDumpFile');
153 
154  return GeneralUtility::locationHeaderUrl(‪PathUtility::getAbsoluteWebPath(‪Environment::getPublicPath() . '/index.php'))
155  . '?' . http_build_query($parameters, '', '&', PHP_QUERY_RFC3986);
156  }
157 
158  protected function ‪getAlternativeFilename(‪FileInterface $file): string
159  {
160  $alternativeFilename = $this->arguments['filename'] ?? '';
161 
162  // Return early if filename is empty or not valid
163  if ($alternativeFilename === '' || !preg_match('/^[0-9a-z._\-]+$/i', $alternativeFilename)) {
164  return '';
165  }
166 
167  $extension = pathinfo($alternativeFilename, PATHINFO_EXTENSION);
168  if ($extension === '') {
169  // Add original extension in case alternative filename did not contain any
170  $alternativeFilename = rtrim($alternativeFilename, '.') . '.' . $file->‪getExtension();
171  }
172 
173  // Check if given or resolved extension matches the original one
174  return $file->‪getExtension() === pathinfo($alternativeFilename, PATHINFO_EXTENSION)
175  ? $alternativeFilename
176  : '';
177  }
178 }
‪TYPO3\CMS\Core\Resource\FileInterface\getExtension
‪string getExtension()
‪TYPO3\CMS\Core\Utility\PathUtility
Definition: PathUtility.php:25
‪TYPO3\CMS\Core\Core\Environment\getPublicPath
‪static string getPublicPath()
Definition: Environment.php:206
‪TYPO3\CMS\Core\Resource\FileInterface
Definition: FileInterface.php:22
‪TYPO3\CMS\Core\Resource\FileReference
Definition: FileReference.php:33
‪TYPO3\CMS\Core\Resource\File
Definition: File.php:24
‪TYPO3\CMS\Core\Resource\ProcessedFile
Definition: ProcessedFile.php:45
‪TYPO3\CMS\Core\Core\Environment
Definition: Environment.php:43
‪TYPO3\CMS\Core\Utility\PathUtility\getAbsoluteWebPath
‪static string getAbsoluteWebPath($targetPath, bool $prefixWithSitePath=true)
Definition: PathUtility.php:51
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:50