[TASK] Move t3lib/stddb files to ext:core
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / View / ThumbnailView.php
1 <?php
2 namespace TYPO3\CMS\Backend\View;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 1999-2011 Kasper Skårhøj (kasperYYYY@typo3.com)
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 * A copy is found in the textfile GPL.txt and important notices to the license
19 * from the author is found in LICENSE.txt distributed with these scripts.
20 *
21 *
22 * This script is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * This copyright notice MUST APPEAR in all copies of the script!
28 ***************************************************************/
29 /**
30 * Generates a thumbnail and returns an image stream, either GIF/PNG or JPG
31 *
32 * Revised for TYPO3 3.6 July/2003 by Kasper Skårhøj
33 *
34 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
35 */
36 /**
37 * Class for generating a thumbnail from the input parameters given to the script
38 *
39 * Input GET var, &file: relative or absolute reference to an imagefile. WILL be validated against PATH_site / lockRootPath
40 * Input GET var, &size: integer-values defining size of thumbnail, format '[int]' or '[int]x[int]'
41 *
42 * Relative paths MUST BE the first two characters ONLY: eg: '../dir/file.gif', otherwise it is expect to be absolute
43 *
44 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
45 */
46 class ThumbnailView {
47
48 /**
49 * @todo Define visibility
50 */
51 public $include_once = array();
52
53 // The output directory of temporary files in PATH_site
54 /**
55 * @todo Define visibility
56 */
57 public $outdir = 'typo3temp/';
58
59 /**
60 * @todo Define visibility
61 */
62 public $output = '';
63
64 /**
65 * @todo Define visibility
66 */
67 public $sizeDefault = '64x64';
68
69 // Coming from $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext']
70 /**
71 * @todo Define visibility
72 */
73 public $imageList;
74
75 /**
76 * will hold the file Object
77 *
78 * @var \TYPO3\CMS\Core\Resource\File $input
79 * @todo Define visibility
80 */
81 public $image;
82
83 // Internal, static: GPvar:
84 // Holds the input filename (GET: file)
85 /**
86 * @todo Define visibility
87 */
88 public $file;
89
90 // Holds the input size (GET: size)
91 /**
92 * @todo Define visibility
93 */
94 public $size;
95
96 // Last modification time of the supplied file
97 /**
98 * @todo Define visibility
99 */
100 public $mTime = 0;
101
102 /**
103 * Initialize; reading parameters with GPvar and checking file path
104 * Results in internal var, $this->file, being set to the file object
105 * which should be used to make a thumbnail.
106 *
107 * @return void
108 * @todo Define visibility
109 */
110 public function init() {
111 // Setting GPvars:
112 // Only needed for MD5 sum calculation of backwards-compatibility uploads/ files thumbnails.
113 $size = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('size');
114 $filePathOrCombinedFileIdentifier = rawurldecode(\TYPO3\CMS\Core\Utility\GeneralUtility::_GP('file'));
115 $md5sum = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('md5sum');
116 // Image extension list is set:
117 // valid extensions. OBS: No spaces in the list, all lowercase...
118 $this->imageList = $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'];
119 // Check if we got a combined file identifier of the form storageUid:fileIdentifer.
120 // We need to distinguish it from absolute Windows paths by cbecking for an integer as first part.
121 $parts = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(':', $filePathOrCombinedFileIdentifier);
122 // Best case: we get a sys_file UID
123 if (\TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($filePathOrCombinedFileIdentifier)) {
124 /** @var \TYPO3\CMS\Core\Resource\File $filePathOrCombinedFileIdentifier */
125 $fileObject = \TYPO3\CMS\Core\Resource\ResourceFactory::getInstance()->getFileObject($filePathOrCombinedFileIdentifier);
126 } elseif (count($parts) <= 1 || !\TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($parts[0])) {
127 // TODO: Historically, the input parameter could also be an absolute path. This should be supported again to stay compatible.
128 // We assume the FilePath to be a relative file path (as in backwards compatibility mode)
129 $relativeFilePath = $filePathOrCombinedFileIdentifier;
130 // The incoming relative path is relative to the typo3/ directory, but we need it relative to PATH_site. This is corrected here:
131 if (substr($relativeFilePath, 0, 3) == '../') {
132 $relativeFilePath = substr($relativeFilePath, 3);
133 } else {
134 $relativeFilePath = 'typo3/' . $relativeFilePath;
135 }
136 $relativeFilePath = ltrim($relativeFilePath, '/');
137 $mTime = 0;
138 // Checking for backpath and double slashes + the thumbnail can be made from files which are in the PATH_site OR the lockRootPath only!
139 if (\TYPO3\CMS\Core\Utility\GeneralUtility::isAllowedAbsPath(PATH_site . $relativeFilePath)) {
140 $mTime = filemtime(PATH_site . $relativeFilePath);
141 }
142 if (strstr($relativeFilePath, '../') !== FALSE) {
143 // Maybe this could be relaxed to not throw an error as long as the path is still within PATH_site
144 $this->errorGif('File path', 'must not contain', '"../"');
145 }
146 if ($relativeFilePath && file_exists(PATH_site . $relativeFilePath)) {
147 // Check file extension:
148 $reg = array();
149 if (preg_match('/(.*)\\.([^\\.]*$)/', $relativeFilePath, $reg)) {
150 $ext = strtolower($reg[2]);
151 $ext = $ext == 'jpeg' ? 'jpg' : $ext;
152 if (!\TYPO3\CMS\Core\Utility\GeneralUtility::inList($this->imageList, $ext)) {
153 $this->errorGif('Not imagefile!', $ext, basename($relativeFilePath));
154 }
155 } else {
156 $this->errorGif('Not imagefile!', 'No ext!', basename($relativeFilePath));
157 }
158 } else {
159 $this->errorGif('Input file not found.', 'not found in thumbs.php', basename($relativeFilePath));
160 }
161 // Do an MD5 check to prevent viewing of images without permission
162 $OK = FALSE;
163 if ($mTime) {
164 // Always use the absolute path for this check!
165 $check = basename($relativeFilePath) . ':' . $mTime . ':' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'];
166 $md5_real = \TYPO3\CMS\Core\Utility\GeneralUtility::shortMD5($check);
167 if (!strcmp($md5_real, $md5sum)) {
168 $OK = TRUE;
169 }
170 }
171 $combinedIdentifier = '0:' . $relativeFilePath;
172 } else {
173 $combinedIdentifier = $filePathOrCombinedFileIdentifier;
174 $OK = FALSE;
175 }
176 if (empty($fileObject)) {
177 $fileObject = \TYPO3\CMS\Core\Resource\ResourceFactory::getInstance()->getFileObjectFromCombinedIdentifier($combinedIdentifier);
178 }
179 if (empty($OK)) {
180 $OK = $fileObject !== NULL && $fileObject->checkActionPermission('read') && $fileObject->calculateChecksum() == $md5sum;
181 }
182 if ($OK) {
183 $this->image = $fileObject;
184 $this->size = $size;
185 } else {
186 // Hide the path to the document root;
187 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);
188 }
189 }
190
191 /**
192 * Create the thumbnail
193 * Will exit before return if all is well.
194 *
195 * @return void
196 * @todo Define visibility
197 */
198 public function main() {
199 // If file exists, we make a thumbnail of the file.
200 if (is_object($this->image)) {
201 // Check file extension:
202 if ($this->image->getExtension() == 'ttf') {
203 // Make font preview... (will not return)
204 $this->fontGif($this->image);
205 } elseif ($this->image->getType() != \TYPO3\CMS\Core\Resource\File::FILETYPE_IMAGE && !\TYPO3\CMS\Core\Utility\GeneralUtility::inList($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'], $this->image->getExtension())) {
206 $this->errorGif('Not imagefile!', 'No ext!', $this->image->getName());
207 }
208 // ... so we passed the extension test meaning that we are going to make a thumbnail here:
209 // default
210 if (!$this->size) {
211 $this->size = $this->sizeDefault;
212 }
213 // I added extra check, so that the size input option could not be fooled to pass other values.
214 // That means the value is exploded, evaluated to an integer and the imploded to [value]x[value].
215 // Furthermore you can specify: size=340 and it'll be translated to 340x340.
216 // explodes the input size (and if no "x" is found this will add size again so it is the same for both dimensions)
217 $sizeParts = explode('x', $this->size . 'x' . $this->size);
218 // Cleaning it up, only two parameters now.
219 $sizeParts = array(\TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange($sizeParts[0], 1, 1000), \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange($sizeParts[1], 1, 1000));
220 // Imploding the cleaned size-value back to the internal variable
221 $this->size = implode('x', $sizeParts);
222 // Getting max value
223 $sizeMax = max($sizeParts);
224 // Init
225 $outpath = PATH_site . $this->outdir;
226 // Should be - ? 'png' : 'gif' - , but doesn't work (ImageMagick prob.?)
227 // René: png work for me
228 $thmMode = \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange($GLOBALS['TYPO3_CONF_VARS']['GFX']['thumbnails_png'], 0);
229 $outext = $this->image->getExtension() != 'jpg' || $thmMode & 2 ? ($thmMode & 1 ? 'png' : 'gif') : 'jpg';
230 $outfile = 'tmb_' . substr(md5(($this->image->getName() . $this->mtime . $this->size)), 0, 10) . '.' . $outext;
231 $this->output = $outpath . $outfile;
232 if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['im']) {
233 // If thumbnail does not exist, we generate it
234 if (!file_exists($this->output)) {
235 $parameters = '-sample ' . $this->size . ' ' . $this->wrapFileName($this->image->getForLocalProcessing(FALSE)) . '[0] ' . $this->wrapFileName($this->output);
236 $cmd = \TYPO3\CMS\Core\Utility\GeneralUtility::imageMagickCommand('convert', $parameters);
237 \TYPO3\CMS\Core\Utility\CommandUtility::exec($cmd);
238 if (!file_exists($this->output)) {
239 $this->errorGif('No thumb', 'generated!', $this->image->getName());
240 } else {
241 \TYPO3\CMS\Core\Utility\GeneralUtility::fixPermissions($this->output);
242 }
243 }
244 // The thumbnail is read and output to the browser
245 if ($fd = @fopen($this->output, 'rb')) {
246 $fileModificationTime = filemtime($this->output);
247 header('Content-type: image/' . $outext);
248 header('Last-Modified: ' . date('r', $fileModificationTime));
249 header('Etag: ' . md5($this->output) . '-' . $fileModificationTime);
250 // Expiration time is choosen arbitrary to 1 month
251 header('Expires: ' . date('r', ($fileModificationTime + 30 * 24 * 60 * 60)));
252 fpassthru($fd);
253 fclose($fd);
254 } else {
255 $this->errorGif('Read problem!', '', $this->output);
256 }
257 } else {
258 die;
259 }
260 } else {
261 $this->errorGif('No valid', 'inputfile!', basename($this->image));
262 }
263 }
264
265 /***************************
266 *
267 * OTHER FUNCTIONS:
268 *
269 ***************************/
270 /**
271 * Creates error image based on gfx/notfound_thumb.png
272 * Requires GD lib enabled, otherwise it will exit with the three textstrings outputted as text.
273 * Outputs the image stream to browser and exits!
274 *
275 * @param string $l1 Text line 1
276 * @param string $l2 Text line 2
277 * @param string $l3 Text line 3
278 * @return void
279 * @todo Define visibility
280 */
281 public function errorGif($l1, $l2, $l3) {
282 if (!$GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib']) {
283 throw new \RuntimeException('TYPO3 Fatal Error: No gdlib. ' . $l1 . ' ' . $l2 . ' ' . $l3, 1270853952);
284 }
285 // Creates the basis for the error image
286 if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib_png']) {
287 header('Content-type: image/png');
288 $im = imagecreatefrompng(PATH_typo3 . 'gfx/notfound_thumb.png');
289 } else {
290 header('Content-type: image/gif');
291 $im = imagecreatefromgif(PATH_typo3 . 'gfx/notfound_thumb.gif');
292 }
293 // Sets background color and print color.
294 $white = imageColorAllocate($im, 255, 255, 255);
295 $black = imageColorAllocate($im, 0, 0, 0);
296 // Prints the text strings with the build-in font functions of GD
297 $x = 0;
298 $font = 0;
299 if ($l1) {
300 imagefilledrectangle($im, $x, 9, 56, 16, $white);
301 imageString($im, $font, $x, 9, $l1, $black);
302 }
303 if ($l2) {
304 imagefilledrectangle($im, $x, 19, 56, 26, $white);
305 imageString($im, $font, $x, 19, $l2, $black);
306 }
307 if ($l3) {
308 imagefilledrectangle($im, $x, 29, 56, 36, $white);
309 imageString($im, $font, $x, 29, substr($l3, -14), $black);
310 }
311 // Outputting the image stream and exit
312 if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib_png']) {
313 imagePng($im);
314 } else {
315 imageGif($im);
316 }
317 imagedestroy($im);
318 die;
319 }
320
321 /**
322 * Creates a font-preview thumbnail.
323 * This means a PNG/GIF file with the text "AaBbCc...." set with the font-file given as input and in various sizes to show how the font looks
324 * Requires GD lib enabled.
325 * Outputs the image stream to browser and exits!
326 *
327 * @param string $font The filepath to the font file (absolute, probably)
328 * @return void
329 * @todo Define visibility
330 */
331 public function fontGif($font) {
332 if (!$GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib']) {
333 throw new \RuntimeException('TYPO3 Fatal Error: No gdlib.', 1270853953);
334 }
335 // Create image and set background color to white.
336 $im = imageCreate(250, 76);
337 $white = imageColorAllocate($im, 255, 255, 255);
338 $col = imageColorAllocate($im, 0, 0, 0);
339 // The test string and offset in x-axis.
340 $string = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZzÆæØøÅåÄäÖöÜüß';
341 $x = 13;
342 // Print (with non-ttf font) the size displayed
343 imagestring($im, 1, 0, 2, '10', $col);
344 imagestring($im, 1, 0, 15, '12', $col);
345 imagestring($im, 1, 0, 30, '14', $col);
346 imagestring($im, 1, 0, 47, '18', $col);
347 imagestring($im, 1, 0, 68, '24', $col);
348 // Print with ttf-font the test string
349 imagettftext($im, \TYPO3\CMS\Core\Utility\GeneralUtility::freetypeDpiComp(10), 0, $x, 8, $col, $font, $string);
350 imagettftext($im, \TYPO3\CMS\Core\Utility\GeneralUtility::freetypeDpiComp(12), 0, $x, 21, $col, $font, $string);
351 imagettftext($im, \TYPO3\CMS\Core\Utility\GeneralUtility::freetypeDpiComp(14), 0, $x, 36, $col, $font, $string);
352 imagettftext($im, \TYPO3\CMS\Core\Utility\GeneralUtility::freetypeDpiComp(18), 0, $x, 53, $col, $font, $string);
353 imagettftext($im, \TYPO3\CMS\Core\Utility\GeneralUtility::freetypeDpiComp(24), 0, $x, 74, $col, $font, $string);
354 // Output PNG or GIF based on $GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib_png']
355 if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib_png']) {
356 header('Content-type: image/png');
357 imagePng($im);
358 } else {
359 header('Content-type: image/gif');
360 imageGif($im);
361 }
362 imagedestroy($im);
363 die;
364 }
365
366 /**
367 * Escapes a file name so it can safely be used on the command line.
368 *
369 * @param string $inputName Filename to safeguard, must not be empty
370 * @return string $inputName escaped as needed
371 */
372 protected function wrapFileName($inputName) {
373 if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['UTF8filesystem']) {
374 $currentLocale = setlocale(LC_CTYPE, 0);
375 setlocale(LC_CTYPE, $GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLocale']);
376 }
377 $escapedInputName = escapeshellarg($inputName);
378 if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['UTF8filesystem']) {
379 setlocale(LC_CTYPE, $currentLocale);
380 }
381 return $escapedInputName;
382 }
383
384 }
385
386
387 ?>