TYPO3 CMS  TYPO3_7-6
ThumbnailView.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Backend\View;
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
23 
34 {
40  public $outdir = 'typo3temp/';
41 
45  public $output = '';
46 
50  public $sizeDefault = '64x64';
51 
57  public $imageList;
58 
64  public $image;
65 
71  public $size;
72 
78  public $mTime = 0;
79 
88  public function init()
89  {
90  GeneralUtility::deprecationLog('The class ThumbnailView is deprecated since TYPO3 CMS 7 and will be removed with TYPO3 CMS 8, use the corresponding Resource objects and Processing functionality');
91  // Setting GPvars:
92  // Only needed for MD5 sum calculation of backwards-compatibility uploads/ files thumbnails.
93  $size = GeneralUtility::_GP('size');
94  $filePathOrCombinedFileIdentifier = rawurldecode(GeneralUtility::_GP('file'));
95  $md5sum = GeneralUtility::_GP('md5sum');
96  // Image extension list is set:
97  // valid extensions. OBS: No spaces in the list, all lowercase...
98  $this->imageList = $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'];
99  // Check if we got a combined file identifier of the form storageUid:fileIdentifer.
100  // We need to distinguish it from absolute Windows paths by cbecking for an integer as first part.
101  $parts = GeneralUtility::trimExplode(':', $filePathOrCombinedFileIdentifier);
102  // Best case: we get a sys_file UID
103  if (!empty($filePathOrCombinedFileIdentifier) && MathUtility::canBeInterpretedAsInteger($filePathOrCombinedFileIdentifier)) {
105  $fileObject = ResourceFactory::getInstance()->getFileObject($filePathOrCombinedFileIdentifier);
106  } elseif (count($parts) <= 1 || !MathUtility::canBeInterpretedAsInteger($parts[0])) {
107  // @todo Historically, the input parameter could also be an absolute path. This should be supported again to stay compatible.
108  // We assume the FilePath to be a relative file path (as in backwards compatibility mode)
109  $relativeFilePath = $filePathOrCombinedFileIdentifier;
110  // The incoming relative path is relative to the typo3/ directory, but we need it relative to PATH_site. This is corrected here:
111  if (substr($relativeFilePath, 0, 3) == '../') {
112  $relativeFilePath = substr($relativeFilePath, 3);
113  } else {
114  $relativeFilePath = 'typo3/' . $relativeFilePath;
115  }
116  $relativeFilePath = ltrim($relativeFilePath, '/');
117  $mTime = 0;
118  // Checking for backpath and double slashes + the thumbnail can be made from files which are in the PATH_site OR the lockRootPath only!
119  if (GeneralUtility::isAllowedAbsPath(PATH_site . $relativeFilePath)) {
120  $mTime = filemtime(PATH_site . $relativeFilePath);
121  }
122  if (strstr($relativeFilePath, '../') !== false) {
123  // Maybe this could be relaxed to not throw an error as long as the path is still within PATH_site
124  $this->errorGif('File path', 'must not contain', '"../"');
125  }
126  if ($relativeFilePath && file_exists(PATH_site . $relativeFilePath)) {
127  // Check file extension:
128  $reg = [];
129  if (preg_match('/(.*)\\.([^\\.]*$)/', $relativeFilePath, $reg)) {
130  $ext = strtolower($reg[2]);
131  $ext = $ext == 'jpeg' ? 'jpg' : $ext;
132  if (!GeneralUtility::inList($this->imageList, $ext)) {
133  $this->errorGif('Not imagefile!', $ext, basename($relativeFilePath));
134  }
135  } else {
136  $this->errorGif('Not imagefile!', 'No ext!', basename($relativeFilePath));
137  }
138  } else {
139  $this->errorGif('Input file not found.', 'not found in thumbs.php', basename($relativeFilePath));
140  }
141  // Do an MD5 check to prevent viewing of images without permission
142  $OK = false;
143  if ($mTime) {
144  // Always use the absolute path for this check!
145  $check = basename($relativeFilePath) . ':' . $mTime . ':' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'];
146  if (GeneralUtility::shortMD5($check) === (string)$md5sum) {
147  $OK = true;
148  }
149  }
150  $combinedIdentifier = '0:' . $relativeFilePath;
151  } else {
152  $combinedIdentifier = $filePathOrCombinedFileIdentifier;
153  $OK = false;
154  }
155  if (empty($fileObject)) {
156  $fileObject = ResourceFactory::getInstance()->getFileObjectFromCombinedIdentifier($combinedIdentifier);
157  }
158  if (empty($OK)) {
159  $OK = $fileObject !== null && $fileObject->checkActionPermission('read') && $fileObject->calculateChecksum() == $md5sum;
160  }
161  if ($OK) {
162  $this->image = $fileObject;
163  $this->size = $size;
164  } else {
165  // Hide the path to the document root;
166  throw new \RuntimeException('TYPO3 Fatal Error: The requested image does not exist and/or MD5 checksum did not match. If the target file exists and its file name contains special characters, the setting of $TYPO3_CONF_VARS[SYS][systemLocale] might be wrong.', 1270853950);
167  }
168  }
169 
176  public function main()
177  {
178  // Clean output buffer to ensure no extraneous output exists
179  ob_clean();
180  // If file exists, we make a thumbnail of the file.
181  if (is_object($this->image)) {
182  // Check file extension:
183  if ($this->image->getExtension() == 'ttf') {
184  // Make font preview... (will not return)
185  $this->fontGif($this->image);
186  } elseif ($this->image->getType() != File::FILETYPE_IMAGE && !GeneralUtility::inList($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'], $this->image->getExtension())) {
187  $this->errorGif('Not imagefile!', 'No ext!', $this->image->getName());
188  }
189  // ... so we passed the extension test meaning that we are going to make a thumbnail here:
190  // default
191  if (!$this->size) {
192  $this->size = $this->sizeDefault;
193  }
194  // I added extra check, so that the size input option could not be fooled to pass other values.
195  // That means the value is exploded, evaluated to an integer and the imploded to [value]x[value].
196  // Furthermore you can specify: size=340 and it'll be translated to 340x340.
197  // explodes the input size (and if no "x" is found this will add size again so it is the same for both dimensions)
198  $sizeParts = explode('x', $this->size . 'x' . $this->size);
199  // Cleaning it up, only two parameters now.
200  $sizeParts = [MathUtility::forceIntegerInRange($sizeParts[0], 1, 1000), MathUtility::forceIntegerInRange($sizeParts[1], 1, 1000)];
201  // Imploding the cleaned size-value back to the internal variable
202  $this->size = implode('x', $sizeParts);
203  // Getting max value
204  $sizeMax = max($sizeParts);
205  // Init
206  $outpath = PATH_site . $this->outdir;
207  // Should be - ? 'png' : 'gif' - , but doesn't work (ImageMagick prob.?)
208  // René: png work for me
209  $thmMode = MathUtility::forceIntegerInRange($GLOBALS['TYPO3_CONF_VARS']['GFX']['thumbnails_png'], 0);
210  $outext = $this->image->getExtension() != 'jpg' || $thmMode & Permission::PAGE_EDIT ? ($thmMode & 1 ? 'png' : 'gif') : 'jpg';
211  $outfile = 'tmb_' . substr(md5(($this->image->getName() . $this->mtime . $this->size)), 0, 10) . '.' . $outext;
212  $this->output = $outpath . $outfile;
213  if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['im']) {
214  // If thumbnail does not exist, we generate it
215  if (!file_exists($this->output)) {
216  $parameters = '-sample ' . $this->size . ' ' . CommandUtility::escapeShellArgument($this->image->getForLocalProcessing(false)) . '[0] ' . CommandUtility::escapeShellArgument($this->output);
217  $cmd = GeneralUtility::imageMagickCommand('convert', $parameters);
219  if (!file_exists($this->output)) {
220  $this->errorGif('No thumb', 'generated!', $this->image->getName());
221  } else {
222  GeneralUtility::fixPermissions($this->output);
223  }
224  }
225  // The thumbnail is read and output to the browser
226  if ($fd = @fopen($this->output, 'rb')) {
227  $fileModificationTime = filemtime($this->output);
228  header('Content-Type: image/' . ($outext === 'jpg' ? 'jpeg' : $outext));
229  header('Last-Modified: ' . date('r', $fileModificationTime));
230  header('ETag: ' . md5($this->output) . '-' . $fileModificationTime);
231  // Expiration time is chosen arbitrary to 1 month
232  header('Expires: ' . date('r', ($fileModificationTime + 30 * 24 * 60 * 60)));
233  fpassthru($fd);
234  fclose($fd);
235  } else {
236  $this->errorGif('Read problem!', '', $this->output);
237  }
238  } else {
239  die;
240  }
241  } else {
242  $this->errorGif('No valid', 'inputfile!', basename($this->image));
243  }
244  }
245 
246  /***************************
247  *
248  * OTHER FUNCTIONS:
249  *
250  ***************************/
261  public function errorGif($l1, $l2, $l3)
262  {
263  if (!$GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib']) {
264  throw new \RuntimeException('TYPO3 Fatal Error: No gdlib. ' . $l1 . ' ' . $l2 . ' ' . $l3, 1270853954);
265  }
266  // Creates the basis for the error image
267  $basePath = \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath('core') . 'Resources/Public/Images/';
268  if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib_png']) {
269  header('Content-type: image/png');
270  $im = imagecreatefrompng($basePath . 'NotFound.png');
271  } else {
272  header('Content-type: image/gif');
273  $im = imagecreatefromgif($basePath . 'NotFound.gif');
274  }
275  // Sets background color and print color.
276  $white = imagecolorallocate($im, 255, 255, 255);
277  $black = imagecolorallocate($im, 0, 0, 0);
278  // Prints the text strings with the build-in font functions of GD
279  $x = 0;
280  $font = 0;
281  if ($l1) {
282  imagefilledrectangle($im, $x, 9, 56, 16, $white);
283  imagestring($im, $font, $x, 9, $l1, $black);
284  }
285  if ($l2) {
286  imagefilledrectangle($im, $x, 19, 56, 26, $white);
287  imagestring($im, $font, $x, 19, $l2, $black);
288  }
289  if ($l3) {
290  imagefilledrectangle($im, $x, 29, 56, 36, $white);
291  imagestring($im, $font, $x, 29, substr($l3, -14), $black);
292  }
293  // Outputting the image stream and exit
294  if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib_png']) {
295  imagepng($im);
296  } else {
297  imagegif($im);
298  }
299  imagedestroy($im);
300  die;
301  }
302 
312  public function fontGif($font)
313  {
314  if (!$GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib']) {
315  throw new \RuntimeException('TYPO3 Fatal Error: No gdlib.', 1270853953);
316  }
317  // Create image and set background color to white.
318  $im = imagecreate(250, 76);
319  $white = imagecolorallocate($im, 255, 255, 255);
320  $col = imagecolorallocate($im, 0, 0, 0);
321  // The test string and offset in x-axis.
322  $string = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZzÆæØøÅåÄäÖöÜüß';
323  $x = 13;
324  // Print (with non-ttf font) the size displayed
325  imagestring($im, 1, 0, 2, '10', $col);
326  imagestring($im, 1, 0, 15, '12', $col);
327  imagestring($im, 1, 0, 30, '14', $col);
328  imagestring($im, 1, 0, 47, '18', $col);
329  imagestring($im, 1, 0, 68, '24', $col);
330  // Print with ttf-font the test string
331  imagettftext($im, GeneralUtility::freetypeDpiComp(10), 0, $x, 8, $col, $font, $string);
332  imagettftext($im, GeneralUtility::freetypeDpiComp(12), 0, $x, 21, $col, $font, $string);
333  imagettftext($im, GeneralUtility::freetypeDpiComp(14), 0, $x, 36, $col, $font, $string);
334  imagettftext($im, GeneralUtility::freetypeDpiComp(18), 0, $x, 53, $col, $font, $string);
335  imagettftext($im, GeneralUtility::freetypeDpiComp(24), 0, $x, 74, $col, $font, $string);
336  // Output PNG or GIF based on $GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib_png']
337  if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib_png']) {
338  header('Content-type: image/png');
339  imagepng($im);
340  } else {
341  header('Content-type: image/gif');
342  imagegif($im);
343  }
344  imagedestroy($im);
345  die;
346  }
347 }
static imageMagickCommand($command, $parameters, $path='')
static forceIntegerInRange($theInt, $min, $max=2000000000, $defaultValue=0)
Definition: MathUtility.php:31
static exec($command, &$output=null, &$returnValue=0)
static trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
static fixPermissions($path, $recursive=false)
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']