Test Failed
Push — master ( 398493...d4ef72 )
by Michael
11:04
created

phpthumb::ImageResizeFunction()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 8
nc 4
nop 10
dl 0
loc 12
rs 8.8571
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 19 and the first side effect is on line 12.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
//////////////////////////////////////////////////////////////
3
//   phpThumb() by James Heinrich <[email protected]>   //
4
//        available at http://phpthumb.sourceforge.net      //
5
//         and/or https://github.com/JamesHeinrich/phpThumb //
6
//////////////////////////////////////////////////////////////
7
///                                                         //
8
// See: phpthumb.readme.txt for usage instructions          //
9
//                                                         ///
10
//////////////////////////////////////////////////////////////
11
12
ob_start();
13
if (!include_once( __DIR__ .'/phpthumb.functions.php')) {
14
	ob_end_flush();
15
	die('failed to include_once("'. __DIR__ .'/phpthumb.functions.php")');
16
}
17
ob_end_clean();
18
19
class phpthumb {
20
21
	// public:
22
	// START PARAMETERS (for object mode and phpThumb.php)
23
	// See phpthumb.readme.txt for descriptions of what each of these values are
24
	public $src  = null;     // SouRCe filename
25
	public $new  = null;     // NEW image (phpThumb.php only)
26
	public $w    = null;     // Width
27
	public $h    = null;     // Height
28
	public $wp   = null;     // Width  (Portrait Images Only)
29
	public $hp   = null;     // Height (Portrait Images Only)
30
	public $wl   = null;     // Width  (Landscape Images Only)
31
	public $hl   = null;     // Height (Landscape Images Only)
32
	public $ws   = null;     // Width  (Square Images Only)
33
	public $hs   = null;     // Height (Square Images Only)
34
	public $f    = null;     // output image Format
35
	public $q    = 75;       // jpeg output Quality
36
	public $sx   = null;     // Source crop top-left X position
37
	public $sy   = null;     // Source crop top-left Y position
38
	public $sw   = null;     // Source crop Width
39
	public $sh   = null;     // Source crop Height
40
	public $zc   = null;     // Zoom Crop
41
	public $bc   = null;     // Border Color
42
	public $bg   = null;     // BackGround color
43
	public $fltr = array();  // FiLTeRs
44
	public $goto = null;     // GO TO url after processing
45
	public $err  = null;     // default ERRor image filename
46
	public $xto  = null;     // extract eXif Thumbnail Only
47
	public $ra   = null;     // Rotate by Angle
48
	public $ar   = null;     // Auto Rotate
49
	public $aoe  = null;     // Allow Output Enlargement
50
	public $far  = null;     // Fixed Aspect Ratio
51
	public $iar  = null;     // Ignore Aspect Ratio
52
	public $maxb = null;     // MAXimum Bytes
53
	public $down = null;     // DOWNload thumbnail filename
54
	public $md5s = null;     // MD5 hash of Source image
55
	public $sfn  = 0;        // Source Frame Number
56
	public $dpi  = 150;      // Dots Per Inch for vector source formats
57
	public $sia  = null;     // Save Image As filename
58
59
	public $file = null;     // >>>deprecated, DO NOT USE, will be removed in future versions<<<
60
61
	public $phpThumbDebug = null;
62
	// END PARAMETERS
63
64
65
	// public:
66
	// START CONFIGURATION OPTIONS (for object mode only)
67
	// See phpThumb.config.php for descriptions of what each of these settings do
68
69
	// * Directory Configuration
70
	public $config_cache_directory                      = null;
71
	public $config_cache_directory_depth                = 0;
72
	public $config_cache_disable_warning                = true;
73
	public $config_cache_source_enabled                 = false;
74
	public $config_cache_source_directory               = null;
75
	public $config_temp_directory                       = null;
76
	public $config_document_root                        = null;
77
78
	// * Default output configuration:
79
	public $config_output_format                        = 'jpeg';
80
	public $config_output_maxwidth                      = 0;
81
	public $config_output_maxheight                     = 0;
82
	public $config_output_interlace                     = true;
83
84
	// * Error message configuration
85
	public $config_error_image_width                    = 400;
86
	public $config_error_image_height                   = 100;
87
	public $config_error_message_image_default          = '';
88
	public $config_error_bgcolor                        = 'CCCCFF';
89
	public $config_error_textcolor                      = 'FF0000';
90
	public $config_error_fontsize                       = 1;
91
	public $config_error_die_on_error                   = false;
92
	public $config_error_silent_die_on_error            = false;
93
	public $config_error_die_on_source_failure          = true;
94
95
	// * Anti-Hotlink Configuration:
96
	public $config_nohotlink_enabled                    = true;
97
	public $config_nohotlink_valid_domains              = array();
98
	public $config_nohotlink_erase_image                = true;
99
	public $config_nohotlink_text_message               = 'Off-server thumbnailing is not allowed';
100
	// * Off-server Linking Configuration:
101
	public $config_nooffsitelink_enabled                = false;
102
	public $config_nooffsitelink_valid_domains          = array();
103
	public $config_nooffsitelink_require_refer          = false;
104
	public $config_nooffsitelink_erase_image            = true;
105
	public $config_nooffsitelink_watermark_src          = '';
106
	public $config_nooffsitelink_text_message           = 'Off-server linking is not allowed';
107
108
	// * Border & Background default colors
109
	public $config_border_hexcolor                      = '000000';
110
	public $config_background_hexcolor                  = 'FFFFFF';
111
112
	// * TrueType Fonts
113
	public $config_ttf_directory                        = './fonts';
114
115
	public $config_max_source_pixels                    = null;
116
	public $config_use_exif_thumbnail_for_speed         = false;
117
	public $config_allow_local_http_src                 = false;
118
119
	public $config_imagemagick_path                     = null;
120
	public $config_prefer_imagemagick                   = true;
121
	public $config_imagemagick_use_thumbnail            = true;
122
123
	public $config_cache_maxage                         = null;
124
	public $config_cache_maxsize                        = null;
125
	public $config_cache_maxfiles                       = null;
126
	public $config_cache_source_filemtime_ignore_local  = false;
127
	public $config_cache_source_filemtime_ignore_remote = true;
128
	public $config_cache_default_only_suffix            = false;
129
	public $config_cache_force_passthru                 = true;
130
	public $config_cache_prefix                         = '';    // default value set in the constructor below
131
132
	// * MySQL
133
	public $config_mysql_extension                      = null;
134
	public $config_mysql_query                          = null;
135
	public $config_mysql_hostname                       = null;
136
	public $config_mysql_username                       = null;
137
	public $config_mysql_password                       = null;
138
	public $config_mysql_database                       = null;
139
140
	// * Security
141
	public $config_high_security_enabled                = true;
142
	public $config_high_security_password               = null;
143
	public $config_high_security_url_separator          = '&';
144
	public $config_disable_debug                        = true;
145
	public $config_allow_src_above_docroot              = false;
146
	public $config_allow_src_above_phpthumb             = true;
147
	public $config_auto_allow_symlinks                  = true;    // allow symlink target directories without explicitly whitelisting them
148
	public $config_additional_allowed_dirs              = array(); // additional directories to allow source images to be read from
149
	public $config_file_create_mask                     = 0755;
150
	public $config_dir_create_mask                      = 0755;
151
152
	// * HTTP fopen
153
	public $config_http_fopen_timeout                   = 10;
154
	public $config_http_follow_redirect                 = true;
155
156
	// * Compatability
157
	public $config_disable_pathinfo_parsing             = false;
158
	public $config_disable_imagecopyresampled           = false;
159
	public $config_disable_onlycreateable_passthru      = false;
160
	public $config_disable_realpath                     = false;
161
162
	public $config_http_user_agent                      = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.12) Gecko/20050915 Firefox/1.0.7';
163
164
	// END CONFIGURATION OPTIONS
165
166
167
	// public: error messages (read-only; persistant)
168
	public $debugmessages = array();
169
	public $debugtiming   = array();
170
	public $fatalerror    = null;
171
172
173
	// private: (should not be modified directly)
174
	public $thumbnailQuality = 75;
175
	public $thumbnailFormat  = null;
176
177
	public $sourceFilename   = null;
178
	public $rawImageData     = null;
179
	public $IMresizedData    = null;
180
	public $outputImageData  = null;
181
182
	public $useRawIMoutput   = false;
183
184
	public $gdimg_output     = null;
185
	public $gdimg_source     = null;
186
187
	public $getimagesizeinfo = null;
188
189
	public $source_width  = null;
190
	public $source_height = null;
191
192
	public $thumbnailCropX = null;
193
	public $thumbnailCropY = null;
194
	public $thumbnailCropW = null;
195
	public $thumbnailCropH = null;
196
197
	public $exif_thumbnail_width  = null;
198
	public $exif_thumbnail_height = null;
199
	public $exif_thumbnail_type   = null;
200
	public $exif_thumbnail_data   = null;
201
	public $exif_raw_data         = null;
202
203
	public $thumbnail_width        = null;
204
	public $thumbnail_height       = null;
205
	public $thumbnail_image_width  = null;
206
	public $thumbnail_image_height = null;
207
208
	public $tempFilesToDelete = array();
209
	public $cache_filename    = null;
210
211
	public $AlphaCapableFormats = array( 'png', 'ico', 'gif');
212
	public $is_alpha = false;
213
214
	public $iswindows        = null;
215
	public $issafemode       = null;
216
	public $php_memory_limit = null;
217
218
	public $phpthumb_version = '1.7.15-201802181529';
219
220
	//////////////////////////////////////////////////////////////////////
221
222
	// public: constructor
223
	public function __construct() {
224
		$this->phpThumb();
225
	}
226
227
	public function phpThumb() {
228
		$this->DebugTimingMessage('phpThumb() constructor', __FILE__, __LINE__);
229
		$this->DebugMessage('phpThumb() v'.$this->phpthumb_version, __FILE__, __LINE__);
230
231
		foreach (array(ini_get('memory_limit'), get_cfg_var('memory_limit')) as $php_config_memory_limit) {
232
			if ('' !== $php_config_memory_limit) {
233
				if (strtoupper($php_config_memory_limit[ strlen($php_config_memory_limit) - 1 ]) == 'G') { // PHP memory limit expressed in Gigabytes
234
					$php_config_memory_limit = (int) substr($php_config_memory_limit, 0, -1) * 1073741824;
235
				} elseif (strtoupper($php_config_memory_limit[ strlen($php_config_memory_limit) - 1 ]) == 'M') { // PHP memory limit expressed in Megabytes
236
					$php_config_memory_limit = (int) substr($php_config_memory_limit, 0, -1) * 1048576;
237
				}
238
				$this->php_memory_limit = max($this->php_memory_limit, $php_config_memory_limit);
239
			}
240
		}
241
		if ($this->php_memory_limit > 0) { // could be "-1" for "no limit"
242
			$this->config_max_source_pixels = round($this->php_memory_limit * 0.20); // 20% of memory_limit
243
		}
244
245
		$this->iswindows  = (bool) (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN');
246
		$this->issafemode = (bool) preg_match('#(1|ON)#i', ini_get('safe_mode'));
247
		$this->config_document_root = (!empty($_SERVER['DOCUMENT_ROOT']) ? $_SERVER['DOCUMENT_ROOT']   : $this->config_document_root);
248
		$this->config_cache_prefix  = ( isset($_SERVER['SERVER_NAME'])   ? $_SERVER['SERVER_NAME'].'_' : '');
249
250
		$this->purgeTempFiles(); // purge existing temp files if re-initializing object
251
252
		$php_sapi_name = strtolower(function_exists('php_sapi_name') ? PHP_SAPI : '');
253
		if ($php_sapi_name == 'cli') {
254
			$this->config_allow_src_above_docroot = true;
255
		}
256
257
		if (!$this->config_disable_debug) {
258
			// if debug mode is enabled, force phpThumbDebug output, do not allow normal thumbnails to be generated
259
			$this->phpThumbDebug = (null === $this->phpThumbDebug ? 9 : max(1, (int) $this->phpThumbDebug));
260
		}
261
	}
262
263
	public function __destruct() {
264
		$this->purgeTempFiles();
265
	}
266
267
	// public:
268
	public function purgeTempFiles() {
269
		foreach ($this->tempFilesToDelete as $tempFileToDelete) {
270
			if (file_exists($tempFileToDelete)) {
271
				$this->DebugMessage('Deleting temp file "'.$tempFileToDelete.'"', __FILE__, __LINE__);
272
				@unlink($tempFileToDelete);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for unlink(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

272
				/** @scrutinizer ignore-unhandled */ @unlink($tempFileToDelete);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
273
			}
274
		}
275
		$this->tempFilesToDelete = array();
276
		return true;
277
	}
278
279
	// public:
280
	public function setSourceFilename($sourceFilename) {
281
		//$this->resetObject();
282
		//$this->rawImageData   = null;
283
		$this->sourceFilename = $sourceFilename;
284
		$this->src            = $sourceFilename;
285
		if (null === $this->config_output_format) {
286
			$sourceFileExtension = strtolower(substr(strrchr($sourceFilename, '.'), 1));
287
			if (preg_match('#^[a-z]{3,4}$#', $sourceFileExtension)) {
288
				$this->config_output_format = $sourceFileExtension;
289
				$this->DebugMessage('setSourceFilename('.$sourceFilename.') set $this->config_output_format to "'.$sourceFileExtension.'"', __FILE__, __LINE__);
290
			} else {
291
				$this->DebugMessage('setSourceFilename('.$sourceFilename.') did NOT set $this->config_output_format to "'.$sourceFileExtension.'" because it did not seem like an appropriate image format', __FILE__, __LINE__);
292
			}
293
		}
294
		$this->DebugMessage('setSourceFilename('.$sourceFilename.') set $this->sourceFilename to "'.$this->sourceFilename.'"', __FILE__, __LINE__);
295
		return true;
296
	}
297
298
	// public:
299
	public function setSourceData($rawImageData, $sourceFilename='') {
300
		//$this->resetObject();
301
		//$this->sourceFilename = null;
302
		$this->rawImageData   = $rawImageData;
303
		$this->DebugMessage('setSourceData() setting $this->rawImageData ('.strlen($this->rawImageData).' bytes; magic="'.substr($this->rawImageData, 0, 4).'" ('.phpthumb_functions::HexCharDisplay(substr($this->rawImageData, 0, 4)).'))', __FILE__, __LINE__);
304
		if ($this->config_cache_source_enabled) {
305
			$sourceFilename = ($sourceFilename ? $sourceFilename : md5($rawImageData));
306
			if (!is_dir($this->config_cache_source_directory)) {
307
				$this->ErrorImage('$this->config_cache_source_directory ('.$this->config_cache_source_directory.') is not a directory');
308
			} elseif (!@is_writable($this->config_cache_source_directory)) {
309
				$this->ErrorImage('$this->config_cache_source_directory ('.$this->config_cache_source_directory.') is not writable');
310
			}
311
			$this->DebugMessage('setSourceData() attempting to save source image to "'.$this->config_cache_source_directory.DIRECTORY_SEPARATOR.urlencode($sourceFilename).'"', __FILE__, __LINE__);
312
			if ($fp = @fopen($this->config_cache_source_directory.DIRECTORY_SEPARATOR.urlencode($sourceFilename), 'wb')) {
313
				fwrite($fp, $rawImageData);
314
				fclose($fp);
315
			} elseif (!$this->phpThumbDebug) {
316
				$this->ErrorImage('setSourceData() failed to write to source cache ('.$this->config_cache_source_directory.DIRECTORY_SEPARATOR.urlencode($sourceFilename).')');
317
			}
318
		}
319
		return true;
320
	}
321
322
	// public:
323
	public function setSourceImageResource($gdimg) {
324
		//$this->resetObject();
325
		$this->gdimg_source = $gdimg;
326
		return true;
327
	}
328
329
	// public:
330
	public function setParameter($param, $value) {
331
		if ($param == 'src') {
332
			$this->setSourceFilename($this->ResolveFilenameToAbsolute($value));
333
		} elseif (@is_array($this->$param)) {
334
			if (is_array($value)) {
335
				foreach ($value as $arraykey => $arrayvalue) {
336
					array_push($this->$param, $arrayvalue);
337
				}
338
			} else {
339
				array_push($this->$param, $value);
340
			}
341
		} else {
342
			$this->$param = $value;
343
		}
344
		return true;
345
	}
346
347
	// public:
348
	public function getParameter($param) {
349
		//if (property_exists('phpThumb', $param)) {
350
			return $this->$param;
351
		//}
352
		//$this->DebugMessage('setParameter() attempting to get non-existant parameter "'.$param.'"', __FILE__, __LINE__);
353
		//return false;
354
	}
355
356
357
	// public:
358
	public function GenerateThumbnail() {
359
360
		$this->setOutputFormat();
361
			$this->phpThumbDebug('8a');
362
		$this->ResolveSource();
363
			$this->phpThumbDebug('8b');
364
		$this->SetCacheFilename();
365
			$this->phpThumbDebug('8c');
366
		$this->ExtractEXIFgetImageSize();
367
			$this->phpThumbDebug('8d');
368
		if ($this->useRawIMoutput) {
369
			$this->DebugMessage('Skipping rest of GenerateThumbnail() because ($this->useRawIMoutput == true)', __FILE__, __LINE__);
370
			return true;
371
		}
372
			$this->phpThumbDebug('8e');
373
		if (!$this->SourceImageToGD()) {
374
			$this->DebugMessage('SourceImageToGD() failed', __FILE__, __LINE__);
375
			return false;
376
		}
377
			$this->phpThumbDebug('8f');
378
		$this->Rotate();
379
			$this->phpThumbDebug('8g');
380
		$this->CreateGDoutput();
381
			$this->phpThumbDebug('8h');
382
383
		// default values, also applicable for far="C"
384
		$destination_offset_x = round(($this->thumbnail_width  - $this->thumbnail_image_width)  / 2);
385
		$destination_offset_y = round(($this->thumbnail_height - $this->thumbnail_image_height) / 2);
386
		if (($this->far == 'L') || ($this->far == 'TL') || ($this->far == 'BL')) {
387
			$destination_offset_x = 0;
388
		}
389
		if (($this->far == 'R') || ($this->far == 'TR') || ($this->far == 'BR')) {
390
			$destination_offset_x =  round($this->thumbnail_width  - $this->thumbnail_image_width);
391
		}
392
		if (($this->far == 'T') || ($this->far == 'TL') || ($this->far == 'TR')) {
393
			$destination_offset_y = 0;
394
		}
395
		if (($this->far == 'B') || ($this->far == 'BL') || ($this->far == 'BR')) {
396
			$destination_offset_y =  round($this->thumbnail_height - $this->thumbnail_image_height);
397
		}
398
399
//		// copy/resize image to appropriate dimensions
400
//		$borderThickness = 0;
401
//		if (!empty($this->fltr)) {
402
//			foreach ($this->fltr as $key => $value) {
403
//				if (preg_match('#^bord\|([0-9]+)#', $value, $matches)) {
404
//					$borderThickness = $matches[1];
405
//					break;
406
//				}
407
//			}
408
//		}
409
//		if ($borderThickness > 0) {
410
//			//$this->DebugMessage('Skipping ImageResizeFunction() because BorderThickness="'.$borderThickness.'"', __FILE__, __LINE__);
411
//			$this->thumbnail_image_height /= 2;
412
//		}
413
		$this->ImageResizeFunction(
414
			$this->gdimg_output,
415
			$this->gdimg_source,
416
			$destination_offset_x,
417
			$destination_offset_y,
418
			$this->thumbnailCropX,
419
			$this->thumbnailCropY,
420
			$this->thumbnail_image_width,
421
			$this->thumbnail_image_height,
422
			$this->thumbnailCropW,
423
			$this->thumbnailCropH
424
		);
425
426
		$this->DebugMessage('memory_get_usage() after copy-resize = '.(function_exists('memory_get_usage') ? @memory_get_usage() : 'n/a'), __FILE__, __LINE__);
427
		imagedestroy($this->gdimg_source);
428
		$this->DebugMessage('memory_get_usage() after imagedestroy = '.(function_exists('memory_get_usage') ? @memory_get_usage() : 'n/a'), __FILE__, __LINE__);
429
430
			$this->phpThumbDebug('8i');
431
		$this->AntiOffsiteLinking();
432
			$this->phpThumbDebug('8j');
433
		$this->ApplyFilters();
434
			$this->phpThumbDebug('8k');
435
		$this->AlphaChannelFlatten();
436
			$this->phpThumbDebug('8l');
437
		$this->MaxFileSize();
438
			$this->phpThumbDebug('8m');
439
440
		$this->DebugMessage('GenerateThumbnail() completed successfully', __FILE__, __LINE__);
441
		return true;
442
	}
443
444
445
	// public:
446
	public function RenderOutput() {
447
		if (!$this->useRawIMoutput && !is_resource($this->gdimg_output)) {
448
			$this->DebugMessage('RenderOutput() failed because !is_resource($this->gdimg_output)', __FILE__, __LINE__);
449
			return false;
450
		}
451
		if (!$this->thumbnailFormat) {
452
			$this->DebugMessage('RenderOutput() failed because $this->thumbnailFormat is empty', __FILE__, __LINE__);
453
			return false;
454
		}
455
		if ($this->useRawIMoutput) {
456
			$this->DebugMessage('RenderOutput copying $this->IMresizedData ('.strlen($this->IMresizedData).' bytes) to $this->outputImage', __FILE__, __LINE__);
457
			$this->outputImageData = $this->IMresizedData;
458
			return true;
459
		}
460
461
		$builtin_formats = array();
462
		if (function_exists('imagetypes')) {
463
			$imagetypes = imagetypes();
464
			$builtin_formats['wbmp'] = (bool) ($imagetypes & IMG_WBMP);
465
			$builtin_formats['jpg']  = (bool) ($imagetypes & IMG_JPG);
466
			$builtin_formats['gif']  = (bool) ($imagetypes & IMG_GIF);
467
			$builtin_formats['png']  = (bool) ($imagetypes & IMG_PNG);
468
		}
469
470
		$this->DebugMessage('imageinterlace($this->gdimg_output, '. (int) $this->config_output_interlace .')', __FILE__, __LINE__);
471
		imageinterlace($this->gdimg_output, (int) $this->config_output_interlace);
472
473
		$this->DebugMessage('RenderOutput() attempting image'.strtolower(@$this->thumbnailFormat).'($this->gdimg_output)', __FILE__, __LINE__);
474
		ob_start();
475
		switch ($this->thumbnailFormat) {
476
			case 'wbmp':
477
				if (empty($builtin_formats['wbmp'])) {
478
					$this->DebugMessage('GD does not have required built-in support for WBMP output', __FILE__, __LINE__);
479
					ob_end_clean();
480
					return false;
481
				}
482
				imagejpeg($this->gdimg_output, null, $this->thumbnailQuality);
483
				$this->outputImageData = ob_get_contents();
484
				break;
485
486
			case 'jpeg':
487
			case 'jpg':  // should be "jpeg" not "jpg" but just in case...
488
				if (empty($builtin_formats['jpg'])) {
489
					$this->DebugMessage('GD does not have required built-in support for JPEG output', __FILE__, __LINE__);
490
					ob_end_clean();
491
					return false;
492
				}
493
				imagejpeg($this->gdimg_output, null, $this->thumbnailQuality);
494
				$this->outputImageData = ob_get_contents();
495
				break;
496
497
			case 'png':
498
				if (empty($builtin_formats['png'])) {
499
					$this->DebugMessage('GD does not have required built-in support for PNG output', __FILE__, __LINE__);
500
					ob_end_clean();
501
					return false;
502
				}
503
				if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.1.2', '>=')) {
504
					// https://github.com/JamesHeinrich/phpThumb/issues/24
505
506
					/* http://php.net/manual/en/function.imagepng.php:
507
					from php source (gd.h):
508
					2.0.12: Compression level: 0-9 or -1, where 0 is NO COMPRESSION at all,
509
					:: 1 is FASTEST but produces larger files, 9 provides the best
510
					:: compression (smallest files) but takes a long time to compress, and
511
					:: -1 selects the default compiled into the zlib library.
512
					Conclusion: Based on the Zlib manual (http://www.zlib.net/manual.html) the default compression level is set to 6.
513
					*/
514
					if (($this->thumbnailQuality >= -1) && ($this->thumbnailQuality <= 9)) {
515
						$PNGquality = $this->thumbnailQuality;
516
					} else {
517
						$this->DebugMessage('Specified thumbnailQuality "'.$this->thumbnailQuality.'" is outside the accepted range (0-9, or -1). Using 6 as default value.', __FILE__, __LINE__);
518
						$PNGquality = 6;
519
					}
520
					imagepng($this->gdimg_output, null, $PNGquality);
521
				} else {
522
					imagepng($this->gdimg_output);
523
				}
524
				$this->outputImageData = ob_get_contents();
525
				break;
526
527
			case 'gif':
528
				if (empty($builtin_formats['gif'])) {
529
					$this->DebugMessage('GD does not have required built-in support for GIF output', __FILE__, __LINE__);
530
					ob_end_clean();
531
					return false;
532
				}
533
				imagegif($this->gdimg_output);
534
				$this->outputImageData = ob_get_contents();
535
				break;
536
537
			case 'bmp':
538
				if (!@include_once( __DIR__ .'/phpthumb.bmp.php')) {
539
					$this->DebugMessage('Error including "'. __DIR__ .'/phpthumb.bmp.php" which is required for BMP format output', __FILE__, __LINE__);
540
					ob_end_clean();
541
					return false;
542
				}
543
				$phpthumb_bmp = new phpthumb_bmp();
544
				$this->outputImageData = $phpthumb_bmp->GD2BMPstring($this->gdimg_output);
545
				unset($phpthumb_bmp);
546
				break;
547
548
			case 'ico':
549
				if (!@include_once( __DIR__ .'/phpthumb.ico.php')) {
550
					$this->DebugMessage('Error including "'. __DIR__ .'/phpthumb.ico.php" which is required for ICO format output', __FILE__, __LINE__);
551
					ob_end_clean();
552
					return false;
553
				}
554
				$phpthumb_ico = new phpthumb_ico();
555
				$arrayOfOutputImages = array($this->gdimg_output);
556
				$this->outputImageData = $phpthumb_ico->GD2ICOstring($arrayOfOutputImages);
557
				unset($phpthumb_ico);
558
				break;
559
560
			default:
561
				$this->DebugMessage('RenderOutput failed because $this->thumbnailFormat "'.$this->thumbnailFormat.'" is not valid', __FILE__, __LINE__);
562
				ob_end_clean();
563
				return false;
564
		}
565
		ob_end_clean();
566
		if (!$this->outputImageData) {
567
			$this->DebugMessage('RenderOutput() for "'.$this->thumbnailFormat.'" failed', __FILE__, __LINE__);
568
			ob_end_clean();
569
			return false;
570
		}
571
		$this->DebugMessage('RenderOutput() completing with $this->outputImageData = '.strlen($this->outputImageData).' bytes', __FILE__, __LINE__);
572
		return true;
573
	}
574
575
576
	// public:
577
	public function RenderToFile($filename) {
578
		if (preg_match('#^[a-z0-9]+://#i', $filename)) {
579
			$this->DebugMessage('RenderToFile() failed because $filename ('.$filename.') is a URL', __FILE__, __LINE__);
580
			return false;
581
		}
582
		// render thumbnail to this file only, do not cache, do not output to browser
583
		//$renderfilename = $this->ResolveFilenameToAbsolute(dirname($filename)).DIRECTORY_SEPARATOR.basename($filename);
584
		$renderfilename = $filename;
585
		if (($filename{0} != '/') && ($filename{0} != '\\') && ($filename{1} != ':')) {
586
			$renderfilename = $this->ResolveFilenameToAbsolute($renderfilename);
587
		}
588
		if (!@is_writable(dirname($renderfilename))) {
589
			$this->DebugMessage('RenderToFile() failed because "'.dirname($renderfilename).'/" is not writable', __FILE__, __LINE__);
590
			return false;
591
		}
592
		if (@is_file($renderfilename) && !@is_writable($renderfilename)) {
593
			$this->DebugMessage('RenderToFile() failed because "'.$renderfilename.'" is not writable', __FILE__, __LINE__);
594
			return false;
595
		}
596
597
		if ($this->RenderOutput()) {
598
			if (file_put_contents($renderfilename, $this->outputImageData)) {
599
				@chmod($renderfilename, $this->getParameter('config_file_create_mask'));
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for chmod(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

599
				/** @scrutinizer ignore-unhandled */ @chmod($renderfilename, $this->getParameter('config_file_create_mask'));

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
600
				$this->DebugMessage('RenderToFile('.$renderfilename.') succeeded', __FILE__, __LINE__);
601
				return true;
602
			}
603
			if (!@file_exists($renderfilename)) {
604
				$this->DebugMessage('RenderOutput ['.$this->thumbnailFormat.'('.$renderfilename.')] did not appear to fail, but the output image does not exist either...', __FILE__, __LINE__);
605
			}
606
		} else {
607
			$this->DebugMessage('RenderOutput ['.$this->thumbnailFormat.'('.$renderfilename.')] failed', __FILE__, __LINE__);
608
		}
609
		return false;
610
	}
611
612
613
	// public:
614
	public function OutputThumbnail() {
615
		$this->purgeTempFiles();
616
617
		if (!$this->useRawIMoutput && !is_resource($this->gdimg_output)) {
618
			$this->DebugMessage('OutputThumbnail() failed because !is_resource($this->gdimg_output)', __FILE__, __LINE__);
619
			return false;
620
		}
621
		if (headers_sent()) {
622
			return $this->ErrorImage('OutputThumbnail() failed - headers already sent');
623
		}
624
625
		$downloadfilename = phpthumb_functions::SanitizeFilename(is_string($this->sia) ? $this->sia : ($this->down ? $this->down : 'phpThumb_generated_thumbnail'.'.'.$this->thumbnailFormat));
626
		$this->DebugMessage('Content-Disposition header filename set to "'.$downloadfilename.'"', __FILE__, __LINE__);
627
		if ($downloadfilename) {
628
			header('Content-Disposition: '.($this->down ? 'attachment' : 'inline').'; filename="'.$downloadfilename.'"');
629
		} else {
630
			$this->DebugMessage('failed to send Content-Disposition header because $downloadfilename is empty', __FILE__, __LINE__);
631
		}
632
633
		if ($this->useRawIMoutput) {
634
635
			header('Content-Type: '.phpthumb_functions::ImageTypeToMIMEtype($this->thumbnailFormat));
0 ignored issues
show
Bug introduced by
Are you sure phpthumb_functions::Imag...$this->thumbnailFormat) of type mixed|false|string can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

635
			header('Content-Type: './** @scrutinizer ignore-type */ phpthumb_functions::ImageTypeToMIMEtype($this->thumbnailFormat));
Loading history...
636
			echo $this->IMresizedData;
637
638
		} else {
639
640
			$this->DebugMessage('imageinterlace($this->gdimg_output, '. (int) $this->config_output_interlace .')', __FILE__, __LINE__);
641
			imageinterlace($this->gdimg_output, (int) $this->config_output_interlace);
642
			switch ($this->thumbnailFormat) {
643
				case 'jpeg':
644
					header('Content-Type: '.phpthumb_functions::ImageTypeToMIMEtype($this->thumbnailFormat));
645
					$ImageOutFunction = 'image'.$this->thumbnailFormat;
646
					@$ImageOutFunction($this->gdimg_output, null, $this->thumbnailQuality);
647
					break;
648
649
				case 'png':
650
				case 'gif':
651
					header('Content-Type: '.phpthumb_functions::ImageTypeToMIMEtype($this->thumbnailFormat));
652
					$ImageOutFunction = 'image'.$this->thumbnailFormat;
653
					@$ImageOutFunction($this->gdimg_output);
654
					break;
655
656
				case 'bmp':
657
					if (!@include_once( __DIR__ .'/phpthumb.bmp.php')) {
658
						$this->DebugMessage('Error including "'. __DIR__ .'/phpthumb.bmp.php" which is required for BMP format output', __FILE__, __LINE__);
659
						return false;
660
					}
661
					$phpthumb_bmp = new phpthumb_bmp();
662
					if (is_object($phpthumb_bmp)) {
663
						$bmp_data = $phpthumb_bmp->GD2BMPstring($this->gdimg_output);
664
						unset($phpthumb_bmp);
665
						if (!$bmp_data) {
666
							$this->DebugMessage('$phpthumb_bmp->GD2BMPstring() failed', __FILE__, __LINE__);
667
							return false;
668
						}
669
						header('Content-Type: '.phpthumb_functions::ImageTypeToMIMEtype($this->thumbnailFormat));
670
						echo $bmp_data;
671
					} else {
672
						$this->DebugMessage('new phpthumb_bmp() failed', __FILE__, __LINE__);
673
						return false;
674
					}
675
					break;
676
677
				case 'ico':
678
					if (!@include_once( __DIR__ .'/phpthumb.ico.php')) {
679
						$this->DebugMessage('Error including "'. __DIR__ .'/phpthumb.ico.php" which is required for ICO format output', __FILE__, __LINE__);
680
						return false;
681
					}
682
					$phpthumb_ico = new phpthumb_ico();
683
					if (is_object($phpthumb_ico)) {
684
						$arrayOfOutputImages = array($this->gdimg_output);
685
						$ico_data = $phpthumb_ico->GD2ICOstring($arrayOfOutputImages);
686
						unset($phpthumb_ico);
687
						if (!$ico_data) {
688
							$this->DebugMessage('$phpthumb_ico->GD2ICOstring() failed', __FILE__, __LINE__);
689
							return false;
690
						}
691
						header('Content-Type: '.phpthumb_functions::ImageTypeToMIMEtype($this->thumbnailFormat));
692
						echo $ico_data;
693
					} else {
694
						$this->DebugMessage('new phpthumb_ico() failed', __FILE__, __LINE__);
695
						return false;
696
					}
697
					break;
698
699
				default:
700
					$this->DebugMessage('OutputThumbnail failed because $this->thumbnailFormat "'.$this->thumbnailFormat.'" is not valid', __FILE__, __LINE__);
701
					return false;
702
					break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
703
			}
704
705
		}
706
		return true;
707
	}
708
709
710
	// public:
711
	public function CleanUpCacheDirectory() {
712
		$this->DebugMessage('CleanUpCacheDirectory() set to purge ('.(null === $this->config_cache_maxage ? 'NULL' : number_format($this->config_cache_maxage / 86400, 1)).' days; '.(null === $this->config_cache_maxsize ? 'NULL' : number_format($this->config_cache_maxsize / 1048576, 2)).' MB; '.(null === $this->config_cache_maxfiles ? 'NULL' : number_format($this->config_cache_maxfiles)).' files)', __FILE__, __LINE__);
713
714
		if (!is_writable($this->config_cache_directory)) {
715
			$this->DebugMessage('CleanUpCacheDirectory() skipped because "'.$this->config_cache_directory.'" is not writable', __FILE__, __LINE__);
716
			return true;
717
		}
718
719
		// cache status of cache directory for 1 hour to avoid hammering the filesystem functions
720
		$phpThumbCacheStats_filename = $this->config_cache_directory.DIRECTORY_SEPARATOR.'phpThumbCacheStats.txt';
721
		if (file_exists($phpThumbCacheStats_filename) && is_readable($phpThumbCacheStats_filename) && (filemtime($phpThumbCacheStats_filename) >= (time() - 3600))) {
722
			$this->DebugMessage('CleanUpCacheDirectory() skipped because "'.$phpThumbCacheStats_filename.'" is recently modified', __FILE__, __LINE__);
723
			return true;
724
		}
725
		if (!@touch($phpThumbCacheStats_filename)) {
726
			$this->DebugMessage('touch('.$phpThumbCacheStats_filename.') failed', __FILE__, __LINE__);
727
		}
728
729
		$DeletedKeys = array();
730
		$AllFilesInCacheDirectory = array();
731
		if (($this->config_cache_maxage > 0) || ($this->config_cache_maxsize > 0) || ($this->config_cache_maxfiles > 0)) {
732
			$CacheDirOldFilesAge  = array();
733
			$CacheDirOldFilesSize = array();
734
			$AllFilesInCacheDirectory = phpthumb_functions::GetAllFilesInSubfolders($this->config_cache_directory);
735
			foreach ($AllFilesInCacheDirectory as $fullfilename) {
736
				if (preg_match('#'.preg_quote($this->config_cache_prefix).'#i', $fullfilename) && file_exists($fullfilename)) {
737
					$CacheDirOldFilesAge[$fullfilename] = @fileatime($fullfilename);
738
					if ($CacheDirOldFilesAge[$fullfilename] == 0) {
739
						$CacheDirOldFilesAge[$fullfilename] = @filemtime($fullfilename);
740
					}
741
					$CacheDirOldFilesSize[$fullfilename] = @filesize($fullfilename);
742
				}
743
			}
744
			if (empty($CacheDirOldFilesSize)) {
745
				$this->DebugMessage('CleanUpCacheDirectory() skipped because $CacheDirOldFilesSize is empty (phpthumb_functions::GetAllFilesInSubfolders('.$this->config_cache_directory.') found no files)', __FILE__, __LINE__);
746
				return true;
747
			}
748
			$DeletedKeys['zerobyte'] = array();
749
			foreach ($CacheDirOldFilesSize as $fullfilename => $filesize) {
750
				// purge all zero-size files more than an hour old (to prevent trying to delete just-created and/or in-use files)
751
				$cutofftime = time() - 3600;
752
				if (($filesize == 0) && ($CacheDirOldFilesAge[$fullfilename] < $cutofftime)) {
753
					$this->DebugMessage('deleting "'.$fullfilename.'"', __FILE__, __LINE__);
754
					if (@unlink($fullfilename)) {
755
						$DeletedKeys['zerobyte'][] = $fullfilename;
756
						unset($CacheDirOldFilesSize[$fullfilename]);
757
						unset($CacheDirOldFilesAge[$fullfilename]);
758
					}
759
				}
760
			}
761
			$this->DebugMessage('CleanUpCacheDirectory() purged '.count($DeletedKeys['zerobyte']).' zero-byte files', __FILE__, __LINE__);
762
			asort($CacheDirOldFilesAge);
763
764
			if ($this->config_cache_maxfiles > 0) {
765
				$TotalCachedFiles = count($CacheDirOldFilesAge);
766
				$DeletedKeys['maxfiles'] = array();
767
				foreach ($CacheDirOldFilesAge as $fullfilename => $filedate) {
768
					if ($TotalCachedFiles > $this->config_cache_maxfiles) {
769
						$this->DebugMessage('deleting "'.$fullfilename.'"', __FILE__, __LINE__);
770
						if (@unlink($fullfilename)) {
771
							$TotalCachedFiles--;
772
							$DeletedKeys['maxfiles'][] = $fullfilename;
773
						}
774
					} else {
775
						// there are few enough files to keep the rest
776
						break;
777
					}
778
				}
779
				$this->DebugMessage('CleanUpCacheDirectory() purged '.count($DeletedKeys['maxfiles']).' files based on (config_cache_maxfiles='.$this->config_cache_maxfiles.')', __FILE__, __LINE__);
780
				foreach ($DeletedKeys['maxfiles'] as $fullfilename) {
781
					unset($CacheDirOldFilesAge[$fullfilename]);
782
					unset($CacheDirOldFilesSize[$fullfilename]);
783
				}
784
			}
785
786
			if ($this->config_cache_maxage > 0) {
787
				$mindate = time() - $this->config_cache_maxage;
788
				$DeletedKeys['maxage'] = array();
789
				foreach ($CacheDirOldFilesAge as $fullfilename => $filedate) {
790
					if ($filedate > 0) {
791
						if ($filedate < $mindate) {
792
							$this->DebugMessage('deleting "'.$fullfilename.'"', __FILE__, __LINE__);
793
							if (@unlink($fullfilename)) {
794
								$DeletedKeys['maxage'][] = $fullfilename;
795
							}
796
						} else {
797
							// the rest of the files are new enough to keep
798
							break;
799
						}
800
					}
801
				}
802
				$this->DebugMessage('CleanUpCacheDirectory() purged '.count($DeletedKeys['maxage']).' files based on (config_cache_maxage='.$this->config_cache_maxage.')', __FILE__, __LINE__);
803
				foreach ($DeletedKeys['maxage'] as $fullfilename) {
804
					unset($CacheDirOldFilesAge[$fullfilename]);
805
					unset($CacheDirOldFilesSize[$fullfilename]);
806
				}
807
			}
808
809
			if ($this->config_cache_maxsize > 0) {
810
				$TotalCachedFileSize = array_sum($CacheDirOldFilesSize);
811
				$DeletedKeys['maxsize'] = array();
812
				foreach ($CacheDirOldFilesAge as $fullfilename => $filedate) {
813
					if ($TotalCachedFileSize > $this->config_cache_maxsize) {
814
						$this->DebugMessage('deleting "'.$fullfilename.'"', __FILE__, __LINE__);
815
						if (@unlink($fullfilename)) {
816
							$TotalCachedFileSize -= $CacheDirOldFilesSize[$fullfilename];
817
							$DeletedKeys['maxsize'][] = $fullfilename;
818
						}
819
					} else {
820
						// the total filesizes are small enough to keep the rest of the files
821
						break;
822
					}
823
				}
824
				$this->DebugMessage('CleanUpCacheDirectory() purged '.count($DeletedKeys['maxsize']).' files based on (config_cache_maxsize='.$this->config_cache_maxsize.')', __FILE__, __LINE__);
825
				foreach ($DeletedKeys['maxsize'] as $fullfilename) {
826
					unset($CacheDirOldFilesAge[$fullfilename]);
827
					unset($CacheDirOldFilesSize[$fullfilename]);
828
				}
829
			}
830
831
		} else {
832
			$this->DebugMessage('skipping CleanUpCacheDirectory() because config set to not use it', __FILE__, __LINE__);
833
		}
834
		$totalpurged = 0;
835
		foreach ($DeletedKeys as $key => $value) {
836
			$totalpurged += count($value);
837
		}
838
		$this->DebugMessage('CleanUpCacheDirectory() purged '.$totalpurged.' files (from '.count($AllFilesInCacheDirectory).') based on config settings', __FILE__, __LINE__);
839
		if ($totalpurged > 0) {
840
			$empty_dirs = array();
841
			foreach ($AllFilesInCacheDirectory as $fullfilename) {
842
				if (is_dir($fullfilename)) {
843
					$empty_dirs[$this->realPathSafe($fullfilename)] = 1;
844
				} else {
845
					unset($empty_dirs[$this->realPathSafe(dirname($fullfilename))]);
846
				}
847
			}
848
			krsort($empty_dirs);
849
			$totalpurgeddirs = 0;
850
			foreach ($empty_dirs as $empty_dir => $dummy) {
851
				if ($empty_dir == $this->config_cache_directory) {
852
					// shouldn't happen, but just in case, don't let it delete actual cache directory
853
					continue;
854
				} elseif (@rmdir($empty_dir)) {
855
					$totalpurgeddirs++;
856
				} else {
857
					$this->DebugMessage('failed to rmdir('.$empty_dir.')', __FILE__, __LINE__);
858
				}
859
			}
860
			$this->DebugMessage('purged '.$totalpurgeddirs.' empty directories', __FILE__, __LINE__);
861
		}
862
		return true;
863
	}
864
865
	//////////////////////////////////////////////////////////////////////
866
867
	// private: re-initializator (call between rendering multiple images with one object)
868
	public function resetObject() {
869
		$class_vars = get_class_vars(get_class($this));
870
		foreach ($class_vars as $key => $value) {
871
			// do not clobber debug or config info
872
			if (!preg_match('#^(config_|debug|fatalerror)#i', $key)) {
873
				$this->$key = $value;
874
			}
875
		}
876
		$this->phpThumb(); // re-initialize some class variables
877
		return true;
878
	}
879
880
	//////////////////////////////////////////////////////////////////////
881
882
	public function ResolveSource() {
883
		if (is_resource($this->gdimg_source)) {
884
			$this->DebugMessage('ResolveSource() exiting because is_resource($this->gdimg_source)', __FILE__, __LINE__);
885
			return true;
886
		}
887
		if ($this->rawImageData) {
888
			$this->sourceFilename = null;
889
			$this->DebugMessage('ResolveSource() exiting because $this->rawImageData is set ('.number_format(strlen($this->rawImageData)).' bytes)', __FILE__, __LINE__);
890
			return true;
891
		}
892
		if ($this->sourceFilename) {
893
			$this->sourceFilename = $this->ResolveFilenameToAbsolute($this->sourceFilename);
894
			$this->DebugMessage('$this->sourceFilename set to "'.$this->sourceFilename.'"', __FILE__, __LINE__);
895
		} elseif ($this->src) {
896
			$this->sourceFilename = $this->ResolveFilenameToAbsolute($this->src);
897
			$this->DebugMessage('$this->sourceFilename set to "'.$this->sourceFilename.'" from $this->src ('.$this->src.')', __FILE__, __LINE__);
898
		} else {
899
			return $this->ErrorImage('$this->sourceFilename and $this->src are both empty');
900
		}
901
		if ($this->iswindows && ((substr($this->sourceFilename, 0, 2) == '//') || (substr($this->sourceFilename, 0, 2) == '\\\\'))) {
0 ignored issues
show
Bug introduced by
It seems like $this->sourceFilename can also be of type false; however, parameter $string of substr() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

901
		if ($this->iswindows && ((substr(/** @scrutinizer ignore-type */ $this->sourceFilename, 0, 2) == '//') || (substr($this->sourceFilename, 0, 2) == '\\\\'))) {
Loading history...
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
902
			// Windows \\share\filename.ext
903
		} elseif (preg_match('#^[a-z0-9]+://#i', $this->sourceFilename, $protocol_matches)) {
0 ignored issues
show
Bug introduced by
It seems like $this->sourceFilename can also be of type false; however, parameter $subject of preg_match() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

903
		} elseif (preg_match('#^[a-z0-9]+://#i', /** @scrutinizer ignore-type */ $this->sourceFilename, $protocol_matches)) {
Loading history...
904
			if (preg_match('#^(f|ht)tps?\://#i', $this->sourceFilename)) {
905
				// URL
906
				if ($this->config_http_user_agent) {
907
					ini_set('user_agent', $this->config_http_user_agent);
908
				}
909
			} else {
910
				return $this->ErrorImage('only FTP and HTTP/HTTPS protocols are allowed, "'.$protocol_matches[1].'" is not');
911
		}
912
		} elseif (!@file_exists($this->sourceFilename)) {
0 ignored issues
show
Bug introduced by
It seems like $this->sourceFilename can also be of type false; however, parameter $filename of file_exists() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

912
		} elseif (!@file_exists(/** @scrutinizer ignore-type */ $this->sourceFilename)) {
Loading history...
913
			return $this->ErrorImage('"'.$this->sourceFilename.'" does not exist');
914
		} elseif (!@is_file($this->sourceFilename)) {
0 ignored issues
show
Bug introduced by
It seems like $this->sourceFilename can also be of type false; however, parameter $filename of is_file() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

914
		} elseif (!@is_file(/** @scrutinizer ignore-type */ $this->sourceFilename)) {
Loading history...
915
			return $this->ErrorImage('"'.$this->sourceFilename.'" is not a file');
916
		}
917
		return true;
918
	}
919
920
921
	public function setOutputFormat() {
922
		static $alreadyCalled = false;
923
		if ($this->thumbnailFormat && $alreadyCalled) {
924
			return true;
925
		}
926
		$alreadyCalled = true;
927
928
		$AvailableImageOutputFormats = array();
929
		$AvailableImageOutputFormats[] = 'text';
930
		if (@is_readable( __DIR__ .'/phpthumb.ico.php')) {
931
			$AvailableImageOutputFormats[] = 'ico';
932
		}
933
		if (@is_readable( __DIR__ .'/phpthumb.bmp.php')) {
934
			$AvailableImageOutputFormats[] = 'bmp';
935
		}
936
937
		$this->thumbnailFormat = 'ico';
938
939
		// Set default output format based on what image types are available
940
		if (function_exists('imagetypes')) {
941
			$imagetypes = imagetypes();
942
			if ($imagetypes & IMG_WBMP) {
943
				$this->thumbnailFormat         = 'wbmp';
944
				$AvailableImageOutputFormats[] = 'wbmp';
945
			}
946
			if ($imagetypes & IMG_GIF) {
947
				$this->thumbnailFormat         = 'gif';
948
				$AvailableImageOutputFormats[] = 'gif';
949
			}
950
			if ($imagetypes & IMG_PNG) {
951
				$this->thumbnailFormat         = 'png';
952
				$AvailableImageOutputFormats[] = 'png';
953
			}
954
			if ($imagetypes & IMG_JPG) {
955
				$this->thumbnailFormat         = 'jpeg';
956
				$AvailableImageOutputFormats[] = 'jpeg';
957
			}
958
		} else {
959
			$this->DebugMessage('imagetypes() does not exist - GD support might not be enabled?',  __FILE__, __LINE__);
960
		}
961
		if ($this->ImageMagickVersion()) {
962
			$IMformats = array('jpeg', 'png', 'gif', 'bmp', 'ico', 'wbmp');
963
			$this->DebugMessage('Addding ImageMagick formats to $AvailableImageOutputFormats ('.implode(';', $AvailableImageOutputFormats).')', __FILE__, __LINE__);
964
			foreach ($IMformats as $key => $format) {
965
				$AvailableImageOutputFormats[] = $format;
966
			}
967
		}
968
		$AvailableImageOutputFormats = array_unique($AvailableImageOutputFormats);
969
		$this->DebugMessage('$AvailableImageOutputFormats = array('.implode(';', $AvailableImageOutputFormats).')', __FILE__, __LINE__);
970
971
		$this->f = preg_replace('#[^a-z]#', '', strtolower($this->f));
972
		if (strtolower($this->config_output_format) == 'jpg') {
973
			$this->config_output_format = 'jpeg';
974
		}
975
		if (strtolower($this->f) == 'jpg') {
976
			$this->f = 'jpeg';
977
		}
978
		if (phpthumb_functions::CaseInsensitiveInArray($this->config_output_format, $AvailableImageOutputFormats)) {
979
			// set output format to config default if that format is available
980
			$this->DebugMessage('$this->thumbnailFormat set to $this->config_output_format "'.strtolower($this->config_output_format).'"', __FILE__, __LINE__);
981
			$this->thumbnailFormat = strtolower($this->config_output_format);
982
		} elseif ($this->config_output_format) {
983
			$this->DebugMessage('$this->thumbnailFormat staying as "'.$this->thumbnailFormat.'" because $this->config_output_format ('.strtolower($this->config_output_format).') is not in $AvailableImageOutputFormats', __FILE__, __LINE__);
984
		}
985
		if ($this->f && (phpthumb_functions::CaseInsensitiveInArray($this->f, $AvailableImageOutputFormats))) {
986
			// override output format if $this->f is set and that format is available
987
			$this->DebugMessage('$this->thumbnailFormat set to $this->f "'.strtolower($this->f).'"', __FILE__, __LINE__);
988
			$this->thumbnailFormat = strtolower($this->f);
989
		} elseif ($this->f) {
990
			$this->DebugMessage('$this->thumbnailFormat staying as "'.$this->thumbnailFormat.'" because $this->f ('.strtolower($this->f).') is not in $AvailableImageOutputFormats', __FILE__, __LINE__);
991
		}
992
993
		// for JPEG images, quality 1 (worst) to 99 (best)
994
		// quality < 25 is nasty, with not much size savings - not recommended
995
		// problems with 100 - invalid JPEG?
996
		$this->thumbnailQuality = max(1, min(99, ($this->q ? (int) $this->q : 75)));
997
		$this->DebugMessage('$this->thumbnailQuality set to "'.$this->thumbnailQuality.'"', __FILE__, __LINE__);
998
999
		return true;
1000
	}
1001
1002
1003
	public function setCacheDirectory() {
1004
		// resolve cache directory to absolute pathname
1005
		$this->DebugMessage('setCacheDirectory() starting with config_cache_directory = "'.$this->config_cache_directory.'"', __FILE__, __LINE__);
1006
		if ($this->config_cache_directory[ 0 ] == '.') {
1007
			if (preg_match('#^(f|ht)tps?\://#i', $this->src)) {
1008
				if (!$this->config_cache_disable_warning) {
1009
					$this->ErrorImage('$this->config_cache_directory ('.$this->config_cache_directory.') cannot be used for remote images. Adjust "cache_directory" or "cache_disable_warning" in phpThumb.config.php');
1010
				}
1011
			} elseif ($this->src) {
1012
				// resolve relative cache directory to source image
1013
				$this->config_cache_directory = dirname($this->ResolveFilenameToAbsolute($this->src)).DIRECTORY_SEPARATOR.$this->config_cache_directory;
0 ignored issues
show
Bug introduced by
It seems like $this->ResolveFilenameToAbsolute($this->src) can also be of type false; however, parameter $path of dirname() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1013
				$this->config_cache_directory = dirname(/** @scrutinizer ignore-type */ $this->ResolveFilenameToAbsolute($this->src)).DIRECTORY_SEPARATOR.$this->config_cache_directory;
Loading history...
1014
			} else {
0 ignored issues
show
Unused Code introduced by
This else statement is empty and can be removed.

This check looks for the else branches of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These else branches can be removed.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

Loading history...
1015
				// $this->new is probably set
1016
			}
1017
		}
1018
		if (substr($this->config_cache_directory, -1) == '/') {
1019
			$this->config_cache_directory = substr($this->config_cache_directory, 0, -1);
1020
		}
1021
		if ($this->iswindows) {
1022
			$this->config_cache_directory = str_replace('/', DIRECTORY_SEPARATOR, $this->config_cache_directory);
1023
		}
1024
		if ($this->config_cache_directory) {
1025
			$real_cache_path = $this->realPathSafe($this->config_cache_directory);
1026
			if (!$real_cache_path) {
1027
				$this->DebugMessage('$this->realPathSafe($this->config_cache_directory) failed for "'.$this->config_cache_directory.'"', __FILE__, __LINE__);
1028
				if (!is_dir($this->config_cache_directory)) {
1029
					$this->DebugMessage('!is_dir('.$this->config_cache_directory.')', __FILE__, __LINE__);
1030
				}
1031
			}
1032
			if ($real_cache_path) {
1033
				$this->DebugMessage('setting config_cache_directory to $this->realPathSafe('.$this->config_cache_directory.') = "'.$real_cache_path.'"', __FILE__, __LINE__);
1034
				$this->config_cache_directory = $real_cache_path;
1035
			}
1036
		}
1037
		if (!is_dir($this->config_cache_directory)) {
1038
			if (!$this->config_cache_disable_warning) {
1039
				$this->ErrorImage('$this->config_cache_directory ('.$this->config_cache_directory.') does not exist. Adjust "cache_directory" or "cache_disable_warning" in phpThumb.config.php');
1040
			}
1041
			$this->DebugMessage('$this->config_cache_directory ('.$this->config_cache_directory.') is not a directory', __FILE__, __LINE__);
1042
			$this->config_cache_directory = null;
1043
		} elseif (!@is_writable($this->config_cache_directory)) {
1044
			$this->DebugMessage('$this->config_cache_directory is not writable ('.$this->config_cache_directory.')', __FILE__, __LINE__);
1045
		}
1046
1047
		$this->InitializeTempDirSetting();
1048
		if (!@is_dir($this->config_temp_directory) && !@is_writable($this->config_temp_directory) && @is_dir($this->config_cache_directory) && @is_writable($this->config_cache_directory)) {
1049
			$this->DebugMessage('setting $this->config_temp_directory = $this->config_cache_directory ('.$this->config_cache_directory.')', __FILE__, __LINE__);
1050
			$this->config_temp_directory = $this->config_cache_directory;
1051
		}
1052
		return true;
1053
	}
1054
1055
	/* Takes the array of path segments up to now, and the next segment (maybe a modifier: empty, . or ..)
1056
	   Applies it, adding or removing from $segments as a result. Returns nothing. */
1057
	// http://support.silisoftware.com/phpBB3/viewtopic.php?t=961
1058
	public function applyPathSegment(&$segments, $segment) {
1059
		if ($segment == '.') {
1060
			return; // always remove
1061
		}
1062
		if ($segment == '') {
1063
			$test = array_pop($segments);
1064
			if (null === $test) {
1065
				$segments[] = $segment; // keep the first empty block
1066
			} elseif ($test == '') {
1067
				$test = array_pop($segments);
1068
				if (null === $test) {
1069
					$segments[] = $test;
1070
					$segments[] = $segment; // keep the second one too
1071
				} else { // put both back and ignore segment
1072
					$segments[] = $test;
1073
					$segments[] = $test;
1074
				}
1075
			} else {
1076
				$segments[] = $test; // ignore empty blocks
1077
			}
1078
		} else {
1079
			if ($segment == '..') {
1080
				$test = array_pop($segments);
1081
				if (null === $test) {
1082
					$segments[] = $segment;
1083
				} elseif ($test == '..') {
1084
					$segments[] = $test;
1085
					$segments[] = $segment;
1086
				} else {
1087
					if ($test == '') {
1088
						$segments[] = $test;
1089
					} // else nothing, remove both
1090
				}
1091
			} else {
1092
				$segments[] = $segment;
1093
			}
1094
		}
1095
	}
1096
1097
	/* Takes array of path components, normalizes it: removes empty slots and '.', collapses '..' and folder names.  Returns array. */
1098
	// http://support.silisoftware.com/phpBB3/viewtopic.php?t=961
1099
	public function normalizePath($segments) {
1100
		$parts = array();
1101
		foreach ($segments as $segment) {
1102
			$this->applyPathSegment($parts, $segment);
1103
		}
1104
		return $parts;
1105
	}
1106
1107
	/* True if the provided path points (without resolving symbolic links) into one of the allowed directories. */
1108
	// http://support.silisoftware.com/phpBB3/viewtopic.php?t=961
1109
	public function matchPath($path, $allowed_dirs) {
1110
		if (!empty($allowed_dirs)) {
1111
			foreach ($allowed_dirs as $one_dir) {
1112
				if (preg_match('#^'.preg_quote(str_replace(DIRECTORY_SEPARATOR, '/', $this->realPathSafe($one_dir))).'#', $path)) {
1113
					return true;
1114
				}
1115
			}
1116
		}
1117
		return false;
1118
	}
1119
1120
	/* True if the provided path points inside one of open_basedirs (or if open_basedirs are disabled) */
1121
	// http://support.silisoftware.com/phpBB3/viewtopic.php?t=961
1122
	public function isInOpenBasedir($path) {
1123
		static $open_basedirs = null;
1124
		if (null === $open_basedirs) {
1125
			$ini_text = ini_get('open_basedir');
1126
			$this->DebugMessage('open_basedir: "'.$ini_text.'"', __FILE__, __LINE__);
1127
			$open_basedirs = array();
1128
			if (strlen($ini_text) > 0) {
1129
				foreach (preg_split('#[;:]#', $ini_text) as $key => $value) {
1130
					$open_basedirs[$key] = $this->realPathSafe($value);
1131
				}
1132
			}
1133
		}
1134
		return (empty($open_basedirs) || $this->matchPath($path, $open_basedirs));
1135
	}
1136
1137
	/* Resolves all symlinks in $path, checking that each continuous part ends in an allowed zone. Returns null, if any component leads outside of allowed zone. */
1138
	// http://support.silisoftware.com/phpBB3/viewtopic.php?t=961
1139
	public function resolvePath($path, $allowed_dirs) {
1140
		$this->DebugMessage('resolvePath: '.$path.' (allowed_dirs: '.print_r($allowed_dirs, true).')', __FILE__, __LINE__);
1141
1142
		// add base path to the top of the list
1143
		if (!$this->config_allow_src_above_docroot) {
1144
			array_unshift($allowed_dirs, $this->realPathSafe($this->config_document_root));
1145
		} else {
1146
			if (!$this->config_allow_src_above_phpthumb) {
1147
				array_unshift($allowed_dirs, $this->realPathSafe( __DIR__ ));
1148
			} else {
1149
				// no checks are needed, offload the work to realpath and forget about it
1150
				$this->DebugMessage('resolvePath: checks disabled, returning '.$this->realPathSafe($path), __FILE__, __LINE__);
1151
				return $this->realPathSafe($path);
1152
			}
1153
		}
1154
		if ($path == '') {
1155
			return null; // save us trouble
1156
		}
1157
1158
		do {
1159
			$this->DebugMessage('resolvePath: iteration, path='.$path.', base path = '.$allowed_dirs[0], __FILE__, __LINE__);
1160
1161
			$parts = array();
1162
			// do not use "cleaner" foreach version of this loop as later code relies on both $segments and $i
1163
			// http://support.silisoftware.com/phpBB3/viewtopic.php?t=964
1164
			$segments = explode(DIRECTORY_SEPARATOR, $path);
1165
			for ($i = 0, $iMax = count($segments); $i < $iMax; $i++) {
1166
				$this->applyPathSegment($parts, $segments[$i]);
1167
				$thispart = implode(DIRECTORY_SEPARATOR, $parts);
1168
				if ($this->isInOpenBasedir($thispart)) {
1169
					if (is_link($thispart)) {
1170
						break;
1171
					}
1172
				}
1173
			}
1174
1175
			$this->DebugMessage('resolvePath: stop at component '.$i, __FILE__, __LINE__);
1176
			// test the part up to here
1177
			$path = implode(DIRECTORY_SEPARATOR, $parts);
1178
			$this->DebugMessage('resolvePath: stop at path='.$path, __FILE__, __LINE__);
1179
			if (!$this->matchPath($path, $allowed_dirs)) {
1180
				$this->DebugMessage('resolvePath: no match, returning null', __FILE__, __LINE__);
1181
				return null;
1182
			}
1183
			if ($i >= count($segments)) { // reached end
1184
				$this->DebugMessage('resolvePath: path parsed, over', __FILE__, __LINE__);
1185
				break;
1186
			}
1187
			// else it's symlink, rewrite path
1188
			$path = readlink($path);
1189
			$this->DebugMessage('resolvePath: symlink matched, target='.$path, __FILE__, __LINE__);
1190
1191
			/*
1192
			Replace base path with symlink target.
1193
			Assuming:
1194
			  /www/img/external -> /external
1195
			This is allowed:
1196
			  GET /www/img/external/../external/test/pic.jpg
1197
			This isn't:
1198
			  GET /www/img/external/../www/img/pic.jpg
1199
			So there's only one base path which is the last symlink target, but any number of stable whitelisted paths.
1200
			*/
1201
			if ($this->config_auto_allow_symlinks) {
1202
				$allowed_dirs[0] = $path;
1203
			}
1204
			$path = $path.DIRECTORY_SEPARATOR.implode(DIRECTORY_SEPARATOR, array_slice($segments,$i + 1));
1205
		} while (true);
1206
		return $path;
1207
	}
1208
1209
1210
	public function realPathSafe($filename) {
1211
		// http://php.net/manual/en/function.realpath.php -- "Note: The running script must have executable permissions on all directories in the hierarchy, otherwise realpath() will return FALSE"
1212
		// realPathSafe() provides a reasonable facsimile of realpath() but does not resolve symbolic links, nor does it check that the file/path actually exists
1213
		if (!$this->config_disable_realpath) {
1214
			return realpath($filename);
1215
		}
1216
1217
		// http://stackoverflow.com/questions/21421569
1218
		$newfilename = preg_replace('#[\\/]+#', DIRECTORY_SEPARATOR, $filename);
1219
		if (!preg_match('#^'.DIRECTORY_SEPARATOR.'#', $newfilename)) {
1220
			$newfilename =  __DIR__ .DIRECTORY_SEPARATOR.$newfilename;
1221
		}
1222
		do {
1223
			$beforeloop = $newfilename;
1224
1225
			// Replace all sequences of more than one / with a single one [[ If you're working on a system that treats // at the start of a path as special, make sure you replace multiple / characters at the start with two of them. This is the only place where POSIX allows (but does not mandate) special handling for multiples, in all other cases, multiple / characters are equivalent to a single one.]]
1226
			$newfilename = preg_replace('#'.DIRECTORY_SEPARATOR.'+#', DIRECTORY_SEPARATOR, $newfilename);
1227
1228
			// Replace all occurrences of /./ with /
1229
			$newfilename = preg_replace('#'.DIRECTORY_SEPARATOR.'\\.'.DIRECTORY_SEPARATOR.'#', DIRECTORY_SEPARATOR, $newfilename);
1230
1231
			// Remove ./ if at the start
1232
			$newfilename = preg_replace('#^\\.'.DIRECTORY_SEPARATOR.'#', '', $newfilename);
1233
1234
			// Remove /. if at the end
1235
			$newfilename = preg_replace('#'.DIRECTORY_SEPARATOR.'\\.$#', '', $newfilename);
1236
1237
			// Replace /anything/../ with /
1238
			$newfilename = preg_replace('#'.DIRECTORY_SEPARATOR.'[^'.DIRECTORY_SEPARATOR.']+'.DIRECTORY_SEPARATOR.'\\.\\.'.DIRECTORY_SEPARATOR.'#', DIRECTORY_SEPARATOR, $newfilename);
1239
1240
			// Remove /anything/.. if at the end
1241
			$newfilename = preg_replace('#'.DIRECTORY_SEPARATOR.'[^'.DIRECTORY_SEPARATOR.']+'.DIRECTORY_SEPARATOR.'\\.\\.$#', '', $newfilename);
1242
1243
		} while ($newfilename != $beforeloop);
1244
		return $newfilename;
1245
	}
1246
1247
1248
	public function ResolveFilenameToAbsolute($filename) {
1249
		if (empty($filename)) {
1250
			return false;
1251
		}
1252
1253
		if (preg_match('#^[a-z0-9]+\:/{1,2}#i', $filename)) {
1254
			// eg: http://host/path/file.jpg (HTTP URL)
1255
			// eg: ftp://host/path/file.jpg  (FTP URL)
1256
			// eg: data1:/path/file.jpg      (Netware path)
1257
1258
			//$AbsoluteFilename = $filename;
1259
			return $filename;
1260
1261
		} elseif ($this->iswindows && isset($filename{1}) && ($filename{1} == ':')) {
1262
1263
			// absolute pathname (Windows)
1264
			$AbsoluteFilename = $filename;
1265
1266
		} elseif ($this->iswindows && ((substr($filename, 0, 2) == '//') || (substr($filename, 0, 2) == '\\\\'))) {
1267
1268
			// absolute pathname (Windows)
1269
			$AbsoluteFilename = $filename;
1270
1271
		} elseif ($filename{0} == '/') {
1272
1273
			if (@is_readable($filename) && !@is_readable($this->config_document_root.$filename)) {
0 ignored issues
show
Bug introduced by
Are you sure $this->config_document_root of type mixed can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1273
			if (@is_readable($filename) && !@is_readable(/** @scrutinizer ignore-type */ $this->config_document_root.$filename)) {
Loading history...
1274
1275
				// absolute filename (*nix)
1276
				$AbsoluteFilename = $filename;
1277
1278
			} elseif (isset($filename{1}) && ($filename{1} == '~')) {
1279
1280
				// /~user/path
1281
				if ($ApacheLookupURIarray = phpthumb_functions::ApacheLookupURIarray($filename)) {
1282
					$AbsoluteFilename = $ApacheLookupURIarray['filename'];
1283
				} else {
1284
					$AbsoluteFilename = $this->realPathSafe($filename);
1285
					if (@is_readable($AbsoluteFilename)) {
1286
						$this->DebugMessage('phpthumb_functions::ApacheLookupURIarray() failed for "'.$filename.'", but the correct filename ('.$AbsoluteFilename.') seems to have been resolved with $this->realPathSafe($filename)', __FILE__, __LINE__);
1287
					} elseif (is_dir(dirname($AbsoluteFilename))) {
1288
						$this->DebugMessage('phpthumb_functions::ApacheLookupURIarray() failed for "'.dirname($filename).'", but the correct directory ('.dirname($AbsoluteFilename).') seems to have been resolved with $this->realPathSafe(.)', __FILE__, __LINE__);
1289
					} else {
1290
						return $this->ErrorImage('phpthumb_functions::ApacheLookupURIarray() failed for "'.$filename.'". This has been known to fail on Apache2 - try using the absolute filename for the source image (ex: "/home/user/httpdocs/image.jpg" instead of "/~user/image.jpg")');
1291
					}
1292
				}
1293
1294
			} else {
1295
1296
				// relative filename (any OS)
1297
				if (preg_match('#^'.preg_quote($this->config_document_root).'#', $filename)) {
0 ignored issues
show
Bug introduced by
It seems like $this->config_document_root can also be of type mixed; however, parameter $str of preg_quote() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1297
				if (preg_match('#^'.preg_quote(/** @scrutinizer ignore-type */ $this->config_document_root).'#', $filename)) {
Loading history...
1298
					$AbsoluteFilename = $filename;
1299
					$this->DebugMessage('ResolveFilenameToAbsolute() NOT prepending $this->config_document_root ('.$this->config_document_root.') to $filename ('.$filename.') resulting in ($AbsoluteFilename = "'.$AbsoluteFilename.'")', __FILE__, __LINE__);
1300
				} else {
1301
					$AbsoluteFilename = $this->config_document_root.$filename;
1302
					$this->DebugMessage('ResolveFilenameToAbsolute() prepending $this->config_document_root ('.$this->config_document_root.') to $filename ('.$filename.') resulting in ($AbsoluteFilename = "'.$AbsoluteFilename.'")', __FILE__, __LINE__);
1303
				}
1304
1305
			}
1306
1307
		} else {
1308
1309
			// relative to current directory (any OS)
1310
			$AbsoluteFilename =  __DIR__ .DIRECTORY_SEPARATOR.preg_replace('#[/\\\\]#', DIRECTORY_SEPARATOR, $filename);
1311
1312
			if (substr(dirname(@$_SERVER['PHP_SELF']), 0, 2) == '/~') {
1313
				if ($ApacheLookupURIarray = phpthumb_functions::ApacheLookupURIarray(dirname(@$_SERVER['PHP_SELF']))) {
1314
					$AbsoluteFilename = $ApacheLookupURIarray['filename'].DIRECTORY_SEPARATOR.$filename;
1315
				} else {
1316
					$AbsoluteFilename = $this->realPathSafe('.').DIRECTORY_SEPARATOR.$filename;
1317
					if (@is_readable($AbsoluteFilename)) {
1318
						$this->DebugMessage('phpthumb_functions::ApacheLookupURIarray() failed for "'.dirname(@$_SERVER['PHP_SELF']).'", but the correct filename ('.$AbsoluteFilename.') seems to have been resolved with $this->realPathSafe(.)/$filename', __FILE__, __LINE__);
1319
					} elseif (is_dir(dirname($AbsoluteFilename))) {
1320
						$this->DebugMessage('phpthumb_functions::ApacheLookupURIarray() failed for "'.dirname(@$_SERVER['PHP_SELF']).'", but the correct directory ('.dirname($AbsoluteFilename).') seems to have been resolved with $this->realPathSafe(.)', __FILE__, __LINE__);
1321
					} else {
1322
						return $this->ErrorImage('phpthumb_functions::ApacheLookupURIarray() failed for "'.dirname(@$_SERVER['PHP_SELF']).'". This has been known to fail on Apache2 - try using the absolute filename for the source image');
1323
					}
1324
				}
1325
			}
1326
1327
		}
1328
		/*
1329
		// removed 2014-May-30: http://support.silisoftware.com/phpBB3/viewtopic.php?t=961
1330
		if (is_link($AbsoluteFilename)) {
1331
			$this->DebugMessage('is_link()==true, changing "'.$AbsoluteFilename.'" to "'.readlink($AbsoluteFilename).'"', __FILE__, __LINE__);
1332
			$AbsoluteFilename = readlink($AbsoluteFilename);
1333
		}
1334
		if ($this->realPathSafe($AbsoluteFilename)) {
1335
			$AbsoluteFilename = $this->realPathSafe($AbsoluteFilename);
1336
		}
1337
		*/
1338
		if ($this->iswindows) {
1339
			$AbsoluteFilename = preg_replace('#^'.preg_quote($this->realPathSafe($this->config_document_root)).'#i', str_replace('\\', '\\\\', $this->realPathSafe($this->config_document_root)), $AbsoluteFilename);
1340
			$AbsoluteFilename = str_replace(DIRECTORY_SEPARATOR, '/', $AbsoluteFilename);
1341
		}
1342
		$resolvedAbsoluteFilename = $this->resolvePath($AbsoluteFilename, $this->config_additional_allowed_dirs);
1343
		if (!$this->config_allow_src_above_docroot && !preg_match('#^'.preg_quote(str_replace(DIRECTORY_SEPARATOR, '/', $this->realPathSafe($this->config_document_root))).'#', $resolvedAbsoluteFilename)) {
1344
			$this->DebugMessage('!$this->config_allow_src_above_docroot therefore setting "'.$AbsoluteFilename.'" (outside "'.$this->realPathSafe($this->config_document_root).'") to null', __FILE__, __LINE__);
1345
			return false;
1346
		}
1347
		if (!$this->config_allow_src_above_phpthumb && !preg_match('#^'.preg_quote(str_replace(DIRECTORY_SEPARATOR, '/',  __DIR__ )).'#', $resolvedAbsoluteFilename)) {
1348
			$this->DebugMessage('!$this->config_allow_src_above_phpthumb therefore setting "'.$AbsoluteFilename.'" (outside "'. __DIR__ .'") to null', __FILE__, __LINE__);
1349
			return false;
1350
		}
1351
		return $resolvedAbsoluteFilename;
1352
	}
1353
1354
1355
	public function file_exists_ignoreopenbasedir($filename, $cached=true) {
1356
		static $open_basedirs = null;
1357
		static $file_exists_cache = array();
1358
		if (!$cached || !isset($file_exists_cache[$filename])) {
1359
			if (null === $open_basedirs) {
1360
				$open_basedirs = preg_split('#[;:]#', ini_get('open_basedir'));
1361
			}
1362
			if (empty($open_basedirs) || in_array(dirname($filename), $open_basedirs)) {
1363
				$file_exists_cache[$filename] = file_exists($filename);
1364
			} elseif ($this->iswindows) {
1365
				$ls_filename = trim(phpthumb_functions::SafeExec('dir /b '.phpthumb_functions::escapeshellarg_replacement($filename)));
0 ignored issues
show
Bug introduced by
It seems like phpthumb_functions::Safe...replacement($filename)) can also be of type false; however, parameter $str of trim() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1365
				$ls_filename = trim(/** @scrutinizer ignore-type */ phpthumb_functions::SafeExec('dir /b '.phpthumb_functions::escapeshellarg_replacement($filename)));
Loading history...
1366
				$file_exists_cache[$filename] = ($ls_filename == basename($filename));  // command dir /b return only filename without path
1367
			} else {
1368
				$ls_filename = trim(phpthumb_functions::SafeExec('ls '.phpthumb_functions::escapeshellarg_replacement($filename)));
1369
				$file_exists_cache[$filename] = ($ls_filename == $filename);
1370
			}
1371
		}
1372
		return $file_exists_cache[$filename];
1373
	}
1374
1375
1376
	public function ImageMagickWhichConvert() {
1377
		static $WhichConvert = null;
1378
		if (null === $WhichConvert) {
1379
			if ($this->iswindows) {
1380
				$WhichConvert = false;
1381
			} else {
1382
				$IMwhichConvertCacheFilename = $this->config_cache_directory.DIRECTORY_SEPARATOR.'phpThumbCacheIMwhichConvert.txt';
1383
				if (($cachedwhichconvertstring = @file_get_contents($IMwhichConvertCacheFilename)) !== false) {
1384
					$WhichConvert = $cachedwhichconvertstring;
1385
				} else {
1386
					$WhichConvert = trim(phpthumb_functions::SafeExec('which convert'));
0 ignored issues
show
Bug introduced by
It seems like phpthumb_functions::SafeExec('which convert') can also be of type false; however, parameter $str of trim() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1386
					$WhichConvert = trim(/** @scrutinizer ignore-type */ phpthumb_functions::SafeExec('which convert'));
Loading history...
1387
					@file_put_contents($IMwhichConvertCacheFilename, $WhichConvert);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for file_put_contents(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

1387
					/** @scrutinizer ignore-unhandled */ @file_put_contents($IMwhichConvertCacheFilename, $WhichConvert);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1388
					@chmod($IMwhichConvertCacheFilename, $this->getParameter('config_file_create_mask'));
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for chmod(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

1388
					/** @scrutinizer ignore-unhandled */ @chmod($IMwhichConvertCacheFilename, $this->getParameter('config_file_create_mask'));

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1389
				}
1390
			}
1391
		}
1392
		return $WhichConvert;
1393
	}
1394
1395
1396
	public function ImageMagickCommandlineBase() {
1397
		static $commandline = null;
1398
		if (null === $commandline) {
1399
			if ($this->issafemode) {
1400
				$commandline = '';
1401
				return $commandline;
1402
			}
1403
1404
			$IMcommandlineBaseCacheFilename = $this->config_cache_directory.DIRECTORY_SEPARATOR.'phpThumbCacheIMcommandlineBase.txt';
1405
			if (($commandline = @file_get_contents($IMcommandlineBaseCacheFilename)) !== false) {
1406
				return $commandline;
1407
			}
1408
1409
			$commandline = (null !== $this->config_imagemagick_path ? $this->config_imagemagick_path : '');
0 ignored issues
show
Unused Code introduced by
The assignment to $commandline is dead and can be removed.
Loading history...
1410
1411
			if ($this->config_imagemagick_path && ($this->config_imagemagick_path != $this->realPathSafe($this->config_imagemagick_path))) {
1412
				if (@is_executable($this->realPathSafe($this->config_imagemagick_path))) {
1413
					$this->DebugMessage('Changing $this->config_imagemagick_path ('.$this->config_imagemagick_path.') to $this->realPathSafe($this->config_imagemagick_path) ('.$this->realPathSafe($this->config_imagemagick_path).')', __FILE__, __LINE__);
1414
					$this->config_imagemagick_path = $this->realPathSafe($this->config_imagemagick_path);
1415
				} else {
1416
					$this->DebugMessage('Leaving $this->config_imagemagick_path as ('.$this->config_imagemagick_path.') because !is_execuatable($this->realPathSafe($this->config_imagemagick_path)) ('.$this->realPathSafe($this->config_imagemagick_path).')', __FILE__, __LINE__);
1417
				}
1418
			}
1419
			$this->DebugMessage('                  file_exists('.$this->config_imagemagick_path.') = '. (int) (@file_exists($this->config_imagemagick_path)), __FILE__, __LINE__);
1420
			$this->DebugMessage('file_exists_ignoreopenbasedir('.$this->config_imagemagick_path.') = '. (int) $this->file_exists_ignoreopenbasedir($this->config_imagemagick_path), __FILE__, __LINE__);
1421
			$this->DebugMessage('                      is_file('.$this->config_imagemagick_path.') = '. (int) (@is_file($this->config_imagemagick_path)), __FILE__, __LINE__);
1422
			$this->DebugMessage('                is_executable('.$this->config_imagemagick_path.') = '. (int) (@is_executable($this->config_imagemagick_path)), __FILE__, __LINE__);
1423
1424
			if ($this->file_exists_ignoreopenbasedir($this->config_imagemagick_path)) {
1425
1426
				$this->DebugMessage('using ImageMagick path from $this->config_imagemagick_path ('.$this->config_imagemagick_path.')', __FILE__, __LINE__);
1427
				if ($this->iswindows) {
1428
					$commandline = substr($this->config_imagemagick_path, 0, 2).' && cd '.phpthumb_functions::escapeshellarg_replacement(str_replace('/', DIRECTORY_SEPARATOR, substr(dirname($this->config_imagemagick_path), 2))).' && '.phpthumb_functions::escapeshellarg_replacement(basename($this->config_imagemagick_path));
1429
				} else {
1430
					$commandline = phpthumb_functions::escapeshellarg_replacement($this->config_imagemagick_path);
1431
				}
1432
1433
			} else {
1434
1435
				$which_convert = $this->ImageMagickWhichConvert();
1436
				$IMversion     = $this->ImageMagickVersion();
1437
1438
				if ($which_convert && ($which_convert{0} == '/') && $this->file_exists_ignoreopenbasedir($which_convert)) {
1439
1440
					// `which convert` *should* return the path if "convert" exist, or nothing if it doesn't
1441
					// other things *may* get returned, like "sh: convert: not found" or "no convert in /usr/local/bin /usr/sbin /usr/bin /usr/ccs/bin"
1442
					// so only do this if the value returned exists as a file
1443
					$this->DebugMessage('using ImageMagick path from `which convert` ('.$which_convert.')', __FILE__, __LINE__);
1444
					$commandline = 'convert';
1445
1446
				} elseif ($IMversion) {
1447
1448
					$this->DebugMessage('setting ImageMagick path to $this->config_imagemagick_path ('.$this->config_imagemagick_path.') ['.$IMversion.']', __FILE__, __LINE__);
1449
					$commandline = $this->config_imagemagick_path;
1450
1451
				} else {
1452
1453
					$this->DebugMessage('ImageMagickThumbnailToGD() aborting because cannot find convert in $this->config_imagemagick_path ('.$this->config_imagemagick_path.'), and `which convert` returned ('.$which_convert.')', __FILE__, __LINE__);
1454
					$commandline = '';
1455
1456
				}
1457
1458
			}
1459
1460
			@file_put_contents($IMcommandlineBaseCacheFilename, $commandline);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for file_put_contents(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

1460
			/** @scrutinizer ignore-unhandled */ @file_put_contents($IMcommandlineBaseCacheFilename, $commandline);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1461
			@chmod($IMcommandlineBaseCacheFilename, $this->getParameter('config_file_create_mask'));
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for chmod(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

1461
			/** @scrutinizer ignore-unhandled */ @chmod($IMcommandlineBaseCacheFilename, $this->getParameter('config_file_create_mask'));

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1462
		}
1463
		return $commandline;
1464
	}
1465
1466
1467
	public function ImageMagickVersion($returnRAW=false) {
1468
		static $versionstring = null;
1469
		if (null === $versionstring) {
1470
			$versionstring = array(0=>false, 1=>false);
1471
1472
			$IMversionCacheFilename = $this->config_cache_directory.DIRECTORY_SEPARATOR.'phpThumbCacheIMversion.txt';
1473
			if ($cachedversionstring = @file_get_contents($IMversionCacheFilename)) {
1474
1475
				$versionstring = explode("\n", $cachedversionstring, 2);
1476
				$versionstring[0] = ($versionstring[0] ? $versionstring[0] : false); // "false" is stored as an empty string in the cache file
1477
				$versionstring[1] = ($versionstring[1] ? $versionstring[1] : false); // "false" is stored as an empty string in the cache file
1478
1479
			} else {
1480
1481
				$commandline = $this->ImageMagickCommandlineBase();
1482
				$commandline = (null !== $commandline ? $commandline : '');
1483
				if ($commandline) {
1484
					$commandline .= ' --version';
1485
					$this->DebugMessage('ImageMagick version checked with "'.$commandline.'"', __FILE__, __LINE__);
1486
					$versionstring[1] = trim(phpthumb_functions::SafeExec($commandline));
0 ignored issues
show
Bug introduced by
It seems like phpthumb_functions::SafeExec($commandline) can also be of type false; however, parameter $str of trim() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1486
					$versionstring[1] = trim(/** @scrutinizer ignore-type */ phpthumb_functions::SafeExec($commandline));
Loading history...
1487
					if (preg_match('#^Version: [^0-9]*([ 0-9\\.\\:Q/\\-]+)#i', $versionstring[1], $matches)) {
1488
						$versionstring[0] = trim($matches[1]);
1489
					} else {
1490
						$versionstring[0] = false;
1491
						$this->DebugMessage('ImageMagick did not return recognized version string ('.$versionstring[1].')', __FILE__, __LINE__);
1492
					}
1493
					$this->DebugMessage('ImageMagick convert --version says "'.@$matches[0].'"', __FILE__, __LINE__);
1494
				}
1495
1496
				@file_put_contents($IMversionCacheFilename, $versionstring[0]."\n".$versionstring[1]);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for file_put_contents(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

1496
				/** @scrutinizer ignore-unhandled */ @file_put_contents($IMversionCacheFilename, $versionstring[0]."\n".$versionstring[1]);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1497
				@chmod($IMversionCacheFilename, $this->getParameter('config_file_create_mask'));
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for chmod(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

1497
				/** @scrutinizer ignore-unhandled */ @chmod($IMversionCacheFilename, $this->getParameter('config_file_create_mask'));

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1498
1499
			}
1500
		}
1501
		return $versionstring[ (int) $returnRAW ];
1502
	}
1503
1504
1505
	public function ImageMagickSwitchAvailable($switchname) {
1506
		static $IMoptions = null;
1507
		if (null === $IMoptions) {
1508
			$IMoptions = array();
1509
			$commandline = $this->ImageMagickCommandlineBase();
1510
			if (null !== $commandline) {
1511
				$commandline .= ' -help';
1512
				$IMhelp_lines = explode("\n", phpthumb_functions::SafeExec($commandline));
0 ignored issues
show
Bug introduced by
It seems like phpthumb_functions::SafeExec($commandline) can also be of type false; however, parameter $string of explode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1512
				$IMhelp_lines = explode("\n", /** @scrutinizer ignore-type */ phpthumb_functions::SafeExec($commandline));
Loading history...
1513
				foreach ($IMhelp_lines as $line) {
1514
					if (preg_match('#^[\\+\\-]([a-z\\-]+) #', trim($line), $matches)) {
1515
						$IMoptions[$matches[1]] = true;
1516
					}
1517
				}
1518
			}
1519
		}
1520
		if (is_array($switchname)) {
1521
			$allOK = true;
1522
			foreach ($switchname as $key => $value) {
1523
				if (!isset($IMoptions[$value])) {
1524
					$allOK = false;
1525
					break;
1526
				}
1527
			}
1528
			$this->DebugMessage('ImageMagickSwitchAvailable('.implode(';', $switchname).') = '. (int) $allOK .'', __FILE__, __LINE__);
1529
		} else {
1530
			$allOK = isset($IMoptions[$switchname]);
1531
			$this->DebugMessage('ImageMagickSwitchAvailable('.$switchname.') = '. (int) $allOK .'', __FILE__, __LINE__);
1532
		}
1533
		return $allOK;
1534
	}
1535
1536
1537
	public function ImageMagickFormatsList() {
1538
		static $IMformatsList = null;
1539
		if (null === $IMformatsList) {
1540
			$IMformatsList = '';
1541
			$commandline = $this->ImageMagickCommandlineBase();
1542
			if (null !== $commandline) {
1543
				$commandline = dirname($commandline).DIRECTORY_SEPARATOR.str_replace('convert', 'identify', basename($commandline));
1544
				$commandline .= ' -list format';
1545
				$IMformatsList = phpthumb_functions::SafeExec($commandline);
1546
			}
1547
		}
1548
		return $IMformatsList;
1549
	}
1550
1551
1552
	public function SourceDataToTempFile() {
1553
		if ($IMtempSourceFilename = $this->phpThumb_tempnam()) {
1554
			$IMtempSourceFilename = $this->realPathSafe($IMtempSourceFilename);
1555
			ob_start();
1556
			$fp_tempfile = fopen($IMtempSourceFilename, 'wb');
1557
			$tempfile_open_error  = ob_get_contents();
1558
			ob_end_clean();
1559
			if ($fp_tempfile) {
0 ignored issues
show
introduced by
$fp_tempfile is of type resource|false, thus it always evaluated to false.
Loading history...
1560
				fwrite($fp_tempfile, $this->rawImageData);
1561
				fclose($fp_tempfile);
1562
				@chmod($IMtempSourceFilename, $this->getParameter('config_file_create_mask'));
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for chmod(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

1562
				/** @scrutinizer ignore-unhandled */ @chmod($IMtempSourceFilename, $this->getParameter('config_file_create_mask'));

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1563
				$this->sourceFilename = $IMtempSourceFilename;
1564
				$this->DebugMessage('ImageMagickThumbnailToGD() setting $this->sourceFilename to "'.$IMtempSourceFilename.'" from $this->rawImageData ('.strlen($this->rawImageData).' bytes)', __FILE__, __LINE__);
1565
			} else {
1566
				$this->DebugMessage('ImageMagickThumbnailToGD() FAILED setting $this->sourceFilename to "'.$IMtempSourceFilename.'" (failed to open for writing: "'.$tempfile_open_error.'")', __FILE__, __LINE__);
1567
			}
1568
			unset($tempfile_open_error, $IMtempSourceFilename);
1569
			return true;
1570
		}
1571
		$this->DebugMessage('SourceDataToTempFile() FAILED because $this->phpThumb_tempnam() failed', __FILE__, __LINE__);
1572
		return false;
1573
	}
1574
1575
1576
	public function ImageMagickThumbnailToGD() {
1577
		// http://www.imagemagick.org/script/command-line-options.php
1578
1579
		$this->useRawIMoutput = true;
1580
		if (phpthumb_functions::gd_version()) {
1581
			// if GD is not available, must use whatever ImageMagick can output
1582
1583
			// $UnAllowedParameters contains options that can only be processed in GD, not ImageMagick
1584
			// note: 'fltr' *may* need to be processed by GD, but we'll check that in more detail below
1585
			$UnAllowedParameters = array('xto', 'ar', 'bg', 'bc');
1586
			// 'ra' may be part of this list, if not a multiple of 90 degrees
1587
			foreach ($UnAllowedParameters as $parameter) {
1588
				if (isset($this->$parameter)) {
1589
					$this->DebugMessage('$this->useRawIMoutput=false because "'.$parameter.'" is set', __FILE__, __LINE__);
1590
					$this->useRawIMoutput = false;
1591
					break;
1592
				}
1593
			}
1594
		}
1595
		$this->DebugMessage('$this->useRawIMoutput='.($this->useRawIMoutput ? 'true' : 'false').' after checking $UnAllowedParameters', __FILE__, __LINE__);
1596
		$ImageCreateFunction = '';
1597
		$outputFormat = $this->thumbnailFormat;
1598
		if (phpthumb_functions::gd_version()) {
1599
			if ($this->useRawIMoutput) {
1600
				switch ($this->thumbnailFormat) {
1601
					case 'gif':
1602
						$ImageCreateFunction = 'imagecreatefromgif';
1603
						$this->is_alpha = true;
1604
						break;
1605
					case 'png':
1606
						$ImageCreateFunction = 'imagecreatefrompng';
1607
						$this->is_alpha = true;
1608
						break;
1609
					case 'jpg':
1610
					case 'jpeg':
1611
						$ImageCreateFunction = 'imagecreatefromjpeg';
1612
						break;
1613
					default:
1614
						$this->DebugMessage('Forcing output to PNG because $this->thumbnailFormat ('.$this->thumbnailFormat.' is not a GD-supported format)', __FILE__, __LINE__);
1615
						$outputFormat = 'png';
1616
						$ImageCreateFunction = 'imagecreatefrompng';
1617
						$this->is_alpha = true;
1618
						$this->useRawIMoutput = false;
1619
						break;
1620
				}
1621
				if (!function_exists(@$ImageCreateFunction)) {
1622
					// ImageMagickThumbnailToGD() depends on imagecreatefrompng/imagecreatefromgif
1623
					//$this->DebugMessage('ImageMagickThumbnailToGD() aborting because '.@$ImageCreateFunction.'() is not available', __FILE__, __LINE__);
1624
					$this->useRawIMoutput = true;
1625
					//return false;
1626
				}
1627
			} else {
1628
				$outputFormat = 'png';
1629
				$ImageCreateFunction = 'imagecreatefrompng';
1630
				$this->is_alpha = true;
1631
				$this->useRawIMoutput = false;
1632
			}
1633
		}
1634
1635
		// http://freealter.org/doc_distrib/ImageMagick-5.1.1/www/convert.html
1636
		if (!$this->sourceFilename && $this->rawImageData) {
1637
			$this->SourceDataToTempFile();
1638
		}
1639
		if (!$this->sourceFilename) {
1640
			$this->DebugMessage('ImageMagickThumbnailToGD() aborting because $this->sourceFilename is empty', __FILE__, __LINE__);
1641
			$this->useRawIMoutput = false;
1642
			return false;
1643
		}
1644
		if ($this->issafemode) {
1645
			$this->DebugMessage('ImageMagickThumbnailToGD() aborting because safe_mode is enabled', __FILE__, __LINE__);
1646
			$this->useRawIMoutput = false;
1647
			return false;
1648
		}
1649
// TO BE FIXED
1650
//if (true) {
1651
//	$this->DebugMessage('ImageMagickThumbnailToGD() aborting it is broken right now', __FILE__, __LINE__);
1652
//	$this->useRawIMoutput = false;
1653
//	return false;
1654
//}
1655
1656
		$commandline = $this->ImageMagickCommandlineBase();
1657
		if ($commandline) {
1658
			$commandline .= ' '.phpthumb_functions::escapeshellarg_replacement(preg_replace('#[/\\\\]#', DIRECTORY_SEPARATOR, $this->sourceFilename).(($outputFormat == 'gif') ? '' : '['. (int) $this->sfn .']')); // [0] means first frame of (GIF) animation, can be ignored
1659
			if ($IMtempfilename = $this->phpThumb_tempnam()) {
1660
				$IMtempfilename = $this->realPathSafe($IMtempfilename);
1661
1662
				$IMuseExplicitImageOutputDimensions = false;
1663
				if ($this->ImageMagickSwitchAvailable('thumbnail') && $this->config_imagemagick_use_thumbnail) {
1664
					$IMresizeParameter = 'thumbnail';
1665
				} else {
1666
					$IMresizeParameter = 'resize';
1667
1668
					// some (older? around 2002) versions of IM won't accept "-resize 100x" but require "-resize 100x100"
1669
					$commandline_test = $this->ImageMagickCommandlineBase().' logo: -resize 1x '.phpthumb_functions::escapeshellarg_replacement($IMtempfilename).' 2>&1';
1670
					$IMresult_test = phpthumb_functions::SafeExec($commandline_test);
1671
					$IMuseExplicitImageOutputDimensions = preg_match('#image dimensions are zero#i', $IMresult_test);
0 ignored issues
show
Bug introduced by
It seems like $IMresult_test can also be of type false; however, parameter $subject of preg_match() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1671
					$IMuseExplicitImageOutputDimensions = preg_match('#image dimensions are zero#i', /** @scrutinizer ignore-type */ $IMresult_test);
Loading history...
1672
					$this->DebugMessage('IMuseExplicitImageOutputDimensions = '. (int) $IMuseExplicitImageOutputDimensions, __FILE__, __LINE__);
1673
					if ($fp_im_temp = @fopen($IMtempfilename, 'wb')) {
1674
						// erase temp image so ImageMagick logo doesn't get output if other processing fails
1675
						fclose($fp_im_temp);
1676
						@chmod($IMtempfilename, $this->getParameter('config_file_create_mask'));
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for chmod(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

1676
						/** @scrutinizer ignore-unhandled */ @chmod($IMtempfilename, $this->getParameter('config_file_create_mask'));

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1677
					}
1678
				}
1679
1680
1681
				ob_start();
1682
				$getimagesize = getimagesize($this->sourceFilename);
1683
				$GetImageSizeError = ob_get_contents();
1684
				ob_end_clean();
1685
				if (is_array($getimagesize)) {
1686
					$this->DebugMessage('getimagesize('.$this->sourceFilename.') SUCCEEDED: '.print_r($getimagesize, true), __FILE__, __LINE__);
1687
				} else {
1688
					$this->DebugMessage('getimagesize('.$this->sourceFilename.') FAILED with error "'.$GetImageSizeError.'"', __FILE__, __LINE__);
1689
				}
1690
				if (null !== $this->dpi && $this->ImageMagickSwitchAvailable('density')) {
1691
					// for vector source formats only (WMF, PDF, etc)
1692
					if (is_array($getimagesize) && isset($getimagesize[2]) && ($getimagesize[2] == IMAGETYPE_PNG)) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
1693
						// explicitly exclude PNG from "-flatten" to make sure transparency is preserved
1694
						// https://github.com/JamesHeinrich/phpThumb/issues/65
1695
					} else {
1696
						$commandline .= ' -flatten';
1697
						$commandline .= ' -density '.phpthumb_functions::escapeshellarg_replacement($this->dpi);
1698
					}
1699
				}
1700
				if (is_array($getimagesize)) {
1701
					$this->DebugMessage('getimagesize('.$this->sourceFilename.') returned [w='.$getimagesize[0].';h='.$getimagesize[1].';f='.$getimagesize[2].']', __FILE__, __LINE__);
1702
					$this->source_width  = $getimagesize[0];
1703
					$this->source_height = $getimagesize[1];
1704
					$this->DebugMessage('source dimensions set to '.$this->source_width.'x'.$this->source_height, __FILE__, __LINE__);
1705
					$this->SetOrientationDependantWidthHeight();
1706
1707
					if (!preg_match('#('.implode('|', $this->AlphaCapableFormats).')#i', $outputFormat)) {
1708
						// not a transparency-capable format
1709
						$commandline .= ' -background '.phpthumb_functions::escapeshellarg_replacement('#'.($this->bg ? $this->bg : 'FFFFFF'));
1710
						if ($getimagesize[2] == IMAGETYPE_GIF) {
1711
							$commandline .= ' -flatten';
1712
						}
1713
					} else {
1714
						if ($getimagesize[2] == IMAGETYPE_PNG && !$this->bg) {
1715
							$commandline .= ' -background none';
1716
						}
1717
					}
1718
					if ($getimagesize[2] == IMAGETYPE_GIF) {
1719
						$commandline .= ' -coalesce'; // may be needed for animated GIFs
1720
					}
1721
					if ($this->source_width || $this->source_height) {
1722
						if ($this->zc) {
1723
1724
							$borderThickness = 0;
1725
							if (!empty($this->fltr)) {
1726
								foreach ($this->fltr as $key => $value) {
1727
									if (preg_match('#^bord\|([0-9]+)#', $value, $matches)) {
1728
										$borderThickness = $matches[1];
1729
										break;
1730
									}
1731
								}
1732
							}
1733
							$wAll = (int) max($this->w, $this->wp, $this->wl, $this->ws) - (2 * $borderThickness);
1734
							$hAll = (int) max($this->h, $this->hp, $this->hl, $this->hs) - (2 * $borderThickness);
1735
							$imAR = $this->source_width / $this->source_height;
1736
							$zcAR = (($wAll && $hAll) ? $wAll / $hAll : 1);
1737
							$side  = phpthumb_functions::nonempty_min($this->source_width, $this->source_height, max($wAll, $hAll));
1738
							$sideX = phpthumb_functions::nonempty_min($this->source_width,                       $wAll, round($hAll * $zcAR));
0 ignored issues
show
Unused Code introduced by
The assignment to $sideX is dead and can be removed.
Loading history...
1739
							$sideY = phpthumb_functions::nonempty_min(                     $this->source_height, $hAll, round($wAll / $zcAR));
1740
1741
							$thumbnailH = round(max($sideY, ($sideY * $zcAR) / $imAR));
1742
							if ($this->aoe == 1) {
1743
								$commandline .= ' -'.$IMresizeParameter.' "'.$wAll.'x'.$hAll.'^"';
1744
							} else {
1745
								$commandline .= ' -'.$IMresizeParameter.' '.phpthumb_functions::escapeshellarg_replacement(($IMuseExplicitImageOutputDimensions ? $thumbnailH : '').'x'.$thumbnailH);
1746
							}
1747
1748
							switch (strtoupper($this->zc)) {
1749
								case 'T':
1750
									$commandline .= ' -gravity north';
1751
									break;
1752
								case 'B':
1753
									$commandline .= ' -gravity south';
1754
									break;
1755
								case 'L':
1756
									$commandline .= ' -gravity west';
1757
									break;
1758
								case 'R':
1759
									$commandline .= ' -gravity east';
1760
									break;
1761
								case 'TL':
1762
									$commandline .= ' -gravity northwest';
1763
									break;
1764
								case 'TR':
1765
									$commandline .= ' -gravity northeast';
1766
									break;
1767
								case 'BL':
1768
									$commandline .= ' -gravity southwest';
1769
									break;
1770
								case 'BR':
1771
									$commandline .= ' -gravity southeast';
1772
									break;
1773
								case '1':
1774
								case 'C':
1775
								default:
1776
									$commandline .= ' -gravity center';
1777
									break;
1778
							}
1779
1780
							if (($wAll > 0) && ($hAll > 0)) {
1781
								$commandline .= ' -crop '.phpthumb_functions::escapeshellarg_replacement($wAll.'x'.$hAll.'+0+0');
1782
							} else {
1783
								$commandline .= ' -crop '.phpthumb_functions::escapeshellarg_replacement($side.'x'.$side.'+0+0');
1784
							}
1785
							if ($this->ImageMagickSwitchAvailable('repage')) {
1786
								$commandline .= ' +repage';
1787
							} else {
1788
								$this->DebugMessage('Skipping "+repage" because ImageMagick (v'.$this->ImageMagickVersion().') does not support it', __FILE__, __LINE__);
1789
							}
1790
1791
						} elseif ($this->sw || $this->sh || $this->sx || $this->sy) {
1792
1793
							$crop_param   = '';
1794
							$crop_param  .=     ($this->sw ? (($this->sw < 2) ? round($this->sw * $this->source_width)  : $this->sw) : $this->source_width);
1795
							$crop_param  .= 'x'.($this->sh ? (($this->sh < 2) ? round($this->sh * $this->source_height) : $this->sh) : $this->source_height);
1796
							$crop_param  .= '+'.(($this->sx < 2) ? round($this->sx * $this->source_width)  : $this->sx);
1797
							$crop_param  .= '+'.(($this->sy < 2) ? round($this->sy * $this->source_height) : $this->sy);
1798
// TO BE FIXED
1799
// makes 1x1 output
1800
// http://trainspotted.com/phpThumb/phpThumb.php?src=/content/CNR/47/CNR-4728-LD-L-20110723-898.jpg&w=100&h=100&far=1&f=png&fltr[]=lvl&sx=0.05&sy=0.25&sw=0.92&sh=0.42
1801
// '/usr/bin/convert' -density 150 -thumbnail 100x100 -contrast-stretch '0.1%' '/var/www/vhosts/trainspotted.com/httpdocs/content/CNR/47/CNR-4728-LD-L-20110723-898.jpg[0]' png:'/var/www/vhosts/trainspotted.com/httpdocs/phpThumb/_cache/pThumbIIUlvj'
1802
							$commandline .= ' -crop '.phpthumb_functions::escapeshellarg_replacement($crop_param);
1803
1804
							// this is broken for aoe=1, but unsure how to fix. Send advice to [email protected]
1805
							if ($this->w || $this->h) {
1806
								//if ($this->ImageMagickSwitchAvailable('repage')) {
1807
if (false) {
0 ignored issues
show
Bug introduced by
Avoid IF statements that are always true or false
Loading history...
1808
// TO BE FIXED
1809
// newer versions of ImageMagick require -repage <geometry>
1810
									$commandline .= ' -repage';
1811
								} else {
1812
									$this->DebugMessage('Skipping "-repage" because ImageMagick (v'.$this->ImageMagickVersion().') does not support it', __FILE__, __LINE__);
1813
								}
1814
								if ($IMuseExplicitImageOutputDimensions) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $IMuseExplicitImageOutputDimensions of type integer|false is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
1815
									if ($this->w && !$this->h) {
1816
										$this->h = ceil($this->w / ($this->source_width / $this->source_height));
1817
									} elseif ($this->h && !$this->w) {
1818
										$this->w = ceil($this->h * ($this->source_width / $this->source_height));
1819
									}
1820
								}
1821
								$commandline .= ' -'.$IMresizeParameter.' '.phpthumb_functions::escapeshellarg_replacement($this->w.'x'.$this->h);
1822
							}
1823
1824
						} else {
1825
1826
							if ($this->iar && ((int) $this->w > 0) && ((int) $this->h > 0)) {
1827
1828
								list($nw, $nh) = phpthumb_functions::TranslateWHbyAngle($this->w, $this->h, $this->ra);
1829
								$nw = ((round($nw) != 0) ? round($nw) : '');
1830
								$nh = ((round($nh) != 0) ? round($nh) : '');
1831
								$commandline .= ' -'.$IMresizeParameter.' '.phpthumb_functions::escapeshellarg_replacement($nw.'x'.$nh.'!');
1832
1833
							} elseif ($this->far && ((int) $this->w > 0) && ((int) $this->h > 0)) {
1834
1835
								$commandline .= ' -'.$IMresizeParameter.' '.phpthumb_functions::escapeshellarg_replacement(phpthumb_functions::nonempty_min($this->w, $getimagesize[0]).'x'.phpthumb_functions::nonempty_min($this->h, $getimagesize[1]));
1836
								$commandline .= ' -gravity center';
1837
								$commandline .= ' -background '.phpthumb_functions::escapeshellarg_replacement('#'.$this->bg);
1838
								$commandline .= ' -extent '.phpthumb_functions::escapeshellarg_replacement($this->w.'x'.$this->h);
0 ignored issues
show
Bug introduced by
Are you sure $this->h of type mixed|false can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1838
								$commandline .= ' -extent '.phpthumb_functions::escapeshellarg_replacement($this->w.'x'./** @scrutinizer ignore-type */ $this->h);
Loading history...
Bug introduced by
Are you sure $this->w of type mixed|false can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1838
								$commandline .= ' -extent '.phpthumb_functions::escapeshellarg_replacement(/** @scrutinizer ignore-type */ $this->w.'x'.$this->h);
Loading history...
1839
1840
							} else {
1841
1842
								$this->w = (($this->aoe && $this->w) ? $this->w : ($this->w ? phpthumb_functions::nonempty_min($this->w, $getimagesize[0]) : ''));
1843
								$this->h = (($this->aoe && $this->h) ? $this->h : ($this->h ? phpthumb_functions::nonempty_min($this->h, $getimagesize[1]) : ''));
1844
								if ($this->w || $this->h) {
1845
									if ($IMuseExplicitImageOutputDimensions) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $IMuseExplicitImageOutputDimensions of type integer|false is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
1846
										if ($this->w && !$this->h) {
1847
											$this->h = ceil($this->w / ($this->source_width / $this->source_height));
1848
										} elseif ($this->h && !$this->w) {
1849
											$this->w = ceil($this->h * ($this->source_width / $this->source_height));
1850
										}
1851
									}
1852
									list($nw, $nh) = phpthumb_functions::TranslateWHbyAngle($this->w, $this->h, $this->ra);
1853
									$nw = ((round($nw) != 0) ? round($nw) : '');
1854
									$nh = ((round($nh) != 0) ? round($nh) : '');
1855
									$commandline .= ' -'.$IMresizeParameter.' '.phpthumb_functions::escapeshellarg_replacement($nw.'x'.$nh);
1856
								}
1857
1858
							}
1859
						}
1860
					}
1861
1862
				} else {
1863
1864
					$this->DebugMessage('getimagesize('.$this->sourceFilename.') failed', __FILE__, __LINE__);
1865
					if ($this->w || $this->h) {
1866
						$exactDimensionsBang = (($this->iar && ((int) $this->w > 0) && ((int) $this->h > 0)) ? '!' : '');
1867
						if ($IMuseExplicitImageOutputDimensions) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $IMuseExplicitImageOutputDimensions of type integer|false is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
1868
							// unknown source aspect ratio, just put large number and hope IM figures it out
1869
							$commandline .= ' -'.$IMresizeParameter.' '.phpthumb_functions::escapeshellarg_replacement(($this->w ? $this->w : '9999').'x'.($this->h ? $this->h : '9999').$exactDimensionsBang);
1870
						} else {
1871
							$commandline .= ' -'.$IMresizeParameter.' '.phpthumb_functions::escapeshellarg_replacement($this->w.'x'.$this->h.$exactDimensionsBang);
1872
						}
1873
					}
1874
1875
				}
1876
1877
				if ($this->ra) {
1878
					$this->ra = (int) $this->ra;
1879
					if ($this->ImageMagickSwitchAvailable('rotate')) {
1880
						if (!preg_match('#('.implode('|', $this->AlphaCapableFormats).')#i', $outputFormat) || phpthumb_functions::version_compare_replacement($this->ImageMagickVersion(), '6.3.7', '>=')) {
1881
							$this->DebugMessage('Using ImageMagick rotate', __FILE__, __LINE__);
1882
							$commandline .= ' -rotate '.phpthumb_functions::escapeshellarg_replacement($this->ra);
1883
							if (($this->ra % 90) != 0) {
1884
								if (preg_match('#('.implode('|', $this->AlphaCapableFormats).')#i', $outputFormat)) {
1885
									// alpha-capable format
1886
									$commandline .= ' -background rgba(255,255,255,0)';
1887
								} else {
1888
									$commandline .= ' -background '.phpthumb_functions::escapeshellarg_replacement('#'.($this->bg ? $this->bg : 'FFFFFF'));
1889
								}
1890
							}
1891
							$this->ra = 0;
1892
						} else {
1893
							$this->DebugMessage('Not using ImageMagick rotate because alpha background buggy before v6.3.7', __FILE__, __LINE__);
1894
						}
1895
					} else {
1896
						$this->DebugMessage('Not using ImageMagick rotate because not supported', __FILE__, __LINE__);
1897
					}
1898
				}
1899
1900
				$successfullyProcessedFilters = array();
1901
				foreach ($this->fltr as $filterkey => $filtercommand) {
1902
					@list($command, $parameter) = explode('|', $filtercommand, 2);
1903
					switch ($command) {
1904
						case 'brit':
1905
							if ($this->ImageMagickSwitchAvailable('modulate')) {
1906
								$commandline .= ' -modulate '.phpthumb_functions::escapeshellarg_replacement((100 + (int) $parameter).',100,100');
1907
								$successfullyProcessedFilters[] = $filterkey;
1908
							}
1909
							break;
1910
1911
						case 'cont':
1912
							if ($this->ImageMagickSwitchAvailable('contrast')) {
1913
								$contDiv10 = round((int) $parameter / 10);
1914
								if ($contDiv10 > 0) {
1915
									$contDiv10 = min($contDiv10, 100);
1916
									for ($i = 0; $i < $contDiv10; $i++) {
1917
										$commandline .= ' -contrast'; // increase contrast by 10%
1918
									}
1919
								} elseif ($contDiv10 < 0) {
1920
									$contDiv10 = max($contDiv10, -100);
1921
									for ($i = $contDiv10; $i < 0; $i++) {
1922
										$commandline .= ' +contrast'; // decrease contrast by 10%
1923
									}
1924
								} else {
0 ignored issues
show
Unused Code introduced by
This else statement is empty and can be removed.

This check looks for the else branches of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These else branches can be removed.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

Loading history...
1925
									// do nothing
1926
								}
1927
								$successfullyProcessedFilters[] = $filterkey;
1928
							}
1929
							break;
1930
1931
						case 'ds':
1932
							if ($this->ImageMagickSwitchAvailable(array('colorspace', 'modulate'))) {
1933
								if ($parameter == 100) {
1934
									$commandline .= ' -colorspace GRAY';
1935
									$commandline .= ' -modulate 100,0,100';
1936
								} else {
1937
									$commandline .= ' -modulate '.phpthumb_functions::escapeshellarg_replacement('100,'.(100 - (int) $parameter).',100');
1938
								}
1939
								$successfullyProcessedFilters[] = $filterkey;
1940
							}
1941
							break;
1942
1943
						case 'sat':
1944
							if ($this->ImageMagickSwitchAvailable(array('colorspace', 'modulate'))) {
1945
								if ($parameter == -100) {
1946
									$commandline .= ' -colorspace GRAY';
1947
									$commandline .= ' -modulate 100,0,100';
1948
								} else {
1949
									$commandline .= ' -modulate '.phpthumb_functions::escapeshellarg_replacement('100,'.(100 + (int) $parameter).',100');
1950
								}
1951
								$successfullyProcessedFilters[] = $filterkey;
1952
							}
1953
							break;
1954
1955
						case 'gray':
1956
							if ($this->ImageMagickSwitchAvailable(array('colorspace', 'modulate'))) {
1957
								$commandline .= ' -colorspace GRAY';
1958
								$commandline .= ' -modulate 100,0,100';
1959
								$successfullyProcessedFilters[] = $filterkey;
1960
							}
1961
							break;
1962
1963
						case 'clr':
1964
							if ($this->ImageMagickSwitchAvailable(array('fill', 'colorize'))) {
1965
								@list($amount, $color) = explode('|', $parameter);
1966
								$commandline .= ' -fill '.phpthumb_functions::escapeshellarg_replacement('#'.preg_replace('#[^0-9A-F]#i', '', $color));
1967
								$commandline .= ' -colorize '.phpthumb_functions::escapeshellarg_replacement(min(max((int) $amount, 0), 100));
1968
							}
1969
							break;
1970
1971
						case 'sep':
1972
							if ($this->ImageMagickSwitchAvailable('sepia-tone')) {
1973
								@list($amount, $color) = explode('|', $parameter);
1974
								$amount = ($amount ? $amount : 80);
1975
								if (!$color) {
1976
									$commandline .= ' -sepia-tone '.phpthumb_functions::escapeshellarg_replacement(min(max((int) $amount, 0), 100).'%');
1977
									$successfullyProcessedFilters[] = $filterkey;
1978
								}
1979
							}
1980
							break;
1981
1982
						case 'gam':
1983
							@list($amount) = explode('|', $parameter);
1984
							$amount = min(max((float) $amount, 0.001), 10);
1985
							if (number_format($amount, 3) != '1.000') {
1986
								if ($this->ImageMagickSwitchAvailable('gamma')) {
1987
									$commandline .= ' -gamma '.phpthumb_functions::escapeshellarg_replacement($amount);
1988
									$successfullyProcessedFilters[] = $filterkey;
1989
								}
1990
							}
1991
							break;
1992
1993
						case 'neg':
1994
							if ($this->ImageMagickSwitchAvailable('negate')) {
1995
								$commandline .= ' -negate';
1996
								$successfullyProcessedFilters[] = $filterkey;
1997
							}
1998
							break;
1999
2000
						case 'th':
2001
							@list($amount) = explode('|', $parameter);
2002
							if ($this->ImageMagickSwitchAvailable(array('threshold', 'dither', 'monochrome'))) {
2003
								$commandline .= ' -threshold '.phpthumb_functions::escapeshellarg_replacement(round(min(max((int) $amount, 0), 255) / 2.55).'%');
2004
								$commandline .= ' -dither';
2005
								$commandline .= ' -monochrome';
2006
								$successfullyProcessedFilters[] = $filterkey;
2007
							}
2008
							break;
2009
2010
						case 'rcd':
2011
							if ($this->ImageMagickSwitchAvailable(array('colors', 'dither'))) {
2012
								@list($colors, $dither) = explode('|', $parameter);
2013
								$colors = ($colors                ?  (int) $colors : 256);
2014
								$dither  = ((strlen($dither) > 0) ? (bool) $dither : true);
2015
								$commandline .= ' -colors '.phpthumb_functions::escapeshellarg_replacement(max($colors, 8)); // ImageMagick will otherwise fail with "cannot quantize to fewer than 8 colors"
2016
								$commandline .= ($dither ? ' -dither' : ' +dither');
2017
								$successfullyProcessedFilters[] = $filterkey;
2018
							}
2019
							break;
2020
2021
						case 'flip':
2022
							if ($this->ImageMagickSwitchAvailable(array('flip', 'flop'))) {
2023
								if (strpos(strtolower($parameter), 'x') !== false) {
2024
									$commandline .= ' -flop';
2025
								}
2026
								if (strpos(strtolower($parameter), 'y') !== false) {
2027
									$commandline .= ' -flip';
2028
								}
2029
								$successfullyProcessedFilters[] = $filterkey;
2030
							}
2031
							break;
2032
2033
						case 'edge':
2034
							if ($this->ImageMagickSwitchAvailable('edge')) {
2035
								$parameter = (!empty($parameter) ? $parameter : 2);
2036
								$commandline .= ' -edge '.phpthumb_functions::escapeshellarg_replacement(!empty($parameter) ? (int) $parameter : 1);
2037
								$successfullyProcessedFilters[] = $filterkey;
2038
							}
2039
							break;
2040
2041
						case 'emb':
2042
							if ($this->ImageMagickSwitchAvailable(array('emboss', 'negate'))) {
2043
								$parameter = (!empty($parameter) ? $parameter : 2);
2044
								$commandline .= ' -emboss '.phpthumb_functions::escapeshellarg_replacement((int) $parameter);
2045
								if ($parameter < 2) {
2046
									$commandline .= ' -negate'; // ImageMagick negates the image for some reason with '-emboss 1';
2047
								}
2048
								$successfullyProcessedFilters[] = $filterkey;
2049
							}
2050
							break;
2051
2052
						case 'lvl':
2053
							@list($band, $method, $threshold) = explode('|', $parameter);
2054
							$band      = ($band ? preg_replace('#[^RGBA\\*]#', '', strtoupper($band))       : '*');
2055
							$method    = ((strlen($method) > 0)    ? (int) $method :   2);
2056
							$threshold = ((strlen($threshold) > 0) ? min(max((float) $threshold, 0), 100) : 0.1);
2057
2058
							$band = preg_replace('#[^RGBA\\*]#', '', strtoupper($band));
2059
2060
							if (($method > 1) && !$this->ImageMagickSwitchAvailable(array('channel', 'contrast-stretch'))) {
2061
								// Because ImageMagick processing happens before PHP-GD filters, and because some
2062
								// clipping is involved in the "lvl" filter, if "lvl" happens before "wb" then the
2063
								// "wb" filter will have (almost) no effect. Therefore, if "wb" is enabled then
2064
								// force the "lvl" filter to be processed by GD, not ImageMagick.
2065
								foreach ($this->fltr as $fltr_key => $fltr_value) {
2066
									list($fltr_cmd) = explode('|', $fltr_value);
2067
									if ($fltr_cmd == 'wb') {
2068
										$this->DebugMessage('Setting "lvl" filter method to "0" (from "'.$method.'") because white-balance filter also enabled', __FILE__, __LINE__);
2069
										$method = 0;
2070
									}
2071
								}
2072
							}
2073
2074
							switch ($method) {
2075
								case 0: // internal RGB
2076
								case 1: // internal grayscale
2077
									break;
2078
								case 2: // ImageMagick "contrast-stretch"
2079
									if ($this->ImageMagickSwitchAvailable('contrast-stretch')) {
2080
										if ($band != '*') {
2081
											$commandline .= ' -channel '.phpthumb_functions::escapeshellarg_replacement(strtoupper($band));
2082
										}
2083
										$threshold = preg_replace('#[^0-9\\.]#', '', $threshold); // should be unneccesary, but just to be double-sure
2084
										//$commandline .= ' -contrast-stretch '.phpthumb_functions::escapeshellarg_replacement($threshold.'%');
2085
										$commandline .= ' -contrast-stretch \''.$threshold.'%\'';
2086
										if ($band != '*') {
2087
											$commandline .= ' +channel';
2088
										}
2089
										$successfullyProcessedFilters[] = $filterkey;
2090
									}
2091
									break;
2092
								case 3: // ImageMagick "normalize"
2093
									if ($this->ImageMagickSwitchAvailable('normalize')) {
2094
										if ($band != '*') {
2095
											$commandline .= ' -channel '.phpthumb_functions::escapeshellarg_replacement(strtoupper($band));
2096
										}
2097
										$commandline .= ' -normalize';
2098
										if ($band != '*') {
2099
											$commandline .= ' +channel';
2100
										}
2101
										$successfullyProcessedFilters[] = $filterkey;
2102
									}
2103
									break;
2104
								default:
2105
									$this->DebugMessage('unsupported method ('.$method.') for "lvl" filter', __FILE__, __LINE__);
2106
									break;
2107
							}
2108
							if (isset($this->fltr[$filterkey]) && ($method > 1)) {
2109
								$this->fltr[$filterkey] = $command.'|'.$band.'|0|'.$threshold;
2110
								$this->DebugMessage('filter "lvl" remapped from method "'.$method.'" to method "0" because ImageMagick support is missing', __FILE__, __LINE__);
2111
							}
2112
							break;
2113
2114
						case 'wb':
2115
							if ($this->ImageMagickSwitchAvailable(array('channel', 'contrast-stretch'))) {
2116
								@list($threshold) = explode('|', $parameter);
2117
								$threshold = (!empty($threshold) ? min(max((float) $threshold, 0), 100) : 0.1);
2118
								$threshold = preg_replace('#[^0-9\\.]#', '', $threshold); // should be unneccesary, but just to be double-sure
2119
								//$commandline .= ' -channel R -contrast-stretch '.phpthumb_functions::escapeshellarg_replacement($threshold.'%'); // doesn't work on Windows because most versions of PHP do not properly
2120
								//$commandline .= ' -channel G -contrast-stretch '.phpthumb_functions::escapeshellarg_replacement($threshold.'%'); // escape special characters (such as %) and just replace them with spaces
2121
								//$commandline .= ' -channel B -contrast-stretch '.phpthumb_functions::escapeshellarg_replacement($threshold.'%'); // https://bugs.php.net/bug.php?id=43261
2122
								$commandline .= ' -channel R -contrast-stretch \''.$threshold.'%\'';
2123
								$commandline .= ' -channel G -contrast-stretch \''.$threshold.'%\'';
2124
								$commandline .= ' -channel B -contrast-stretch \''.$threshold.'%\'';
2125
								$commandline .= ' +channel';
2126
								$successfullyProcessedFilters[] = $filterkey;
2127
							}
2128
							break;
2129
2130
						case 'blur':
2131
							if ($this->ImageMagickSwitchAvailable('blur')) {
2132
								@list($radius) = explode('|', $parameter);
2133
								$radius = (!empty($radius) ? min(max((int) $radius, 0), 25) : 1);
2134
								$commandline .= ' -blur '.phpthumb_functions::escapeshellarg_replacement($radius);
2135
								$successfullyProcessedFilters[] = $filterkey;
2136
							}
2137
							break;
2138
2139
						case 'gblr':
2140
							@list($radius) = explode('|', $parameter);
2141
							$radius = (!empty($radius) ? min(max((int) $radius, 0), 25) : 1);
2142
							// "-gaussian" changed to "-gaussian-blur" sometime around 2009
2143
							if ($this->ImageMagickSwitchAvailable('gaussian-blur')) {
2144
								$commandline .= ' -gaussian-blur '.phpthumb_functions::escapeshellarg_replacement($radius);
2145
								$successfullyProcessedFilters[] = $filterkey;
2146
							} elseif ($this->ImageMagickSwitchAvailable('gaussian')) {
2147
								$commandline .= ' -gaussian '.phpthumb_functions::escapeshellarg_replacement($radius);
2148
								$successfullyProcessedFilters[] = $filterkey;
2149
							}
2150
							break;
2151
2152
						case 'usm':
2153
							if ($this->ImageMagickSwitchAvailable('unsharp')) {
2154
								@list($amount, $radius, $threshold) = explode('|', $parameter);
2155
								$amount    = ($amount            ? min(max((int) $amount,    0), 255) : 80);
2156
								$radius    = ($radius            ? min(max((int) $radius,    0),  10) : 0.5);
2157
								$threshold = (strlen($threshold) ? min(max((int) $threshold, 0),  50) : 3);
2158
								$commandline .= ' -unsharp '.phpthumb_functions::escapeshellarg_replacement(number_format(($radius * 2) - 1, 2, '.', '').'x1+'.number_format($amount / 100, 2, '.', '').'+'.number_format($threshold / 100, 2, '.', ''));
2159
								$successfullyProcessedFilters[] = $filterkey;
2160
							}
2161
							break;
2162
2163
						case 'bord':
2164
							if ($this->ImageMagickSwitchAvailable(array('border', 'bordercolor', 'thumbnail', 'crop'))) {
2165
								if (!$this->zc) {
2166
									@list($width, $rX, $rY, $color) = explode('|', $parameter);
2167
									$width = (int) $width;
2168
									$rX    = (int) $rX;
2169
									$rY    = (int) $rY;
2170
									if ($width && !$rX && !$rY) {
2171
										if (!phpthumb_functions::IsHexColor($color)) {
2172
											$color = ((!empty($this->bc) && phpthumb_functions::IsHexColor($this->bc)) ? $this->bc : '000000');
2173
										}
2174
										$commandline .= ' -border '.phpthumb_functions::escapeshellarg_replacement((int) $width);
2175
										$commandline .= ' -bordercolor '.phpthumb_functions::escapeshellarg_replacement('#'.$color);
2176
2177
										if (preg_match('# \\-crop "([0-9]+)x([0-9]+)\\+0\\+0" #', $commandline, $matches)) {
2178
											$commandline = str_replace(' -crop "'.$matches[1].'x'.$matches[2].'+0+0" ', ' -crop '.phpthumb_functions::escapeshellarg_replacement(($matches[1] - (2 * $width)).'x'.($matches[2] - (2 * $width)).'+0+0').' ', $commandline);
2179
										} elseif (preg_match('# \\-'.$IMresizeParameter.' "([0-9]+)x([0-9]+)" #', $commandline, $matches)) {
2180
											$commandline = str_replace(' -'.$IMresizeParameter.' "'.$matches[1].'x'.$matches[2].'" ', ' -'.$IMresizeParameter.' '.phpthumb_functions::escapeshellarg_replacement(($matches[1] - (2 * $width)).'x'.($matches[2] - (2 * $width))).' ', $commandline);
2181
										}
2182
										$successfullyProcessedFilters[] = $filterkey;
2183
									}
2184
								}
2185
							}
2186
							break;
2187
2188
						case 'crop':
2189
							break;
2190
2191
						case 'sblr':
2192
							break;
2193
2194
						case 'mean':
2195
							break;
2196
2197
						case 'smth':
2198
							break;
2199
2200
						case 'bvl':
2201
							break;
2202
2203
						case 'wmi':
2204
							break;
2205
2206
						case 'wmt':
2207
							break;
2208
2209
						case 'over':
2210
							break;
2211
2212
						case 'hist':
2213
							break;
2214
2215
						case 'fram':
2216
							break;
2217
2218
						case 'drop':
2219
							break;
2220
2221
						case 'mask':
2222
							break;
2223
2224
						case 'elip':
2225
							break;
2226
2227
						case 'ric':
2228
							break;
2229
2230
						case 'stc':
2231
							break;
2232
2233
						case 'size':
2234
							break;
2235
2236
						default:
2237
							$this->DebugMessage('Unknown $this->fltr['.$filterkey.'] ('.$filtercommand.') -- deleting filter command', __FILE__, __LINE__);
2238
							$successfullyProcessedFilters[] = $filterkey;
2239
							break;
2240
					}
2241
					if (!isset($this->fltr[$filterkey])) {
2242
						$this->DebugMessage('Processed $this->fltr['.$filterkey.'] ('.$filtercommand.') with ImageMagick', __FILE__, __LINE__);
2243
					} else {
2244
						$this->DebugMessage('Skipping $this->fltr['.$filterkey.'] ('.$filtercommand.') with ImageMagick', __FILE__, __LINE__);
2245
					}
2246
				}
2247
				$this->DebugMessage('Remaining $this->fltr after ImageMagick: ('.$this->phpThumbDebugVarDump($this->fltr).')', __FILE__, __LINE__);
2248
				if (count($this->fltr) > 0) {
2249
					$this->useRawIMoutput = false;
2250
				}
2251
2252
				if (preg_match('#jpe?g#i', $outputFormat) && $this->q) {
2253
					if ($this->ImageMagickSwitchAvailable(array('quality', 'interlace'))) {
2254
						$commandline .= ' -quality '.phpthumb_functions::escapeshellarg_replacement($this->thumbnailQuality);
2255
						if ($this->config_output_interlace) {
2256
							// causes weird things with animated GIF... leave for JPEG only
2257
							$commandline .= ' -interlace line '; // Use Line or Plane to create an interlaced PNG or GIF or progressive JPEG image
2258
						}
2259
					}
2260
				}
2261
				$commandline .= ' '.$outputFormat.':'.phpthumb_functions::escapeshellarg_replacement($IMtempfilename);
2262
				if (!$this->iswindows) {
2263
					$commandline .= ' 2>&1';
2264
				}
2265
				$this->DebugMessage('ImageMagick called as ('.$commandline.')', __FILE__, __LINE__);
2266
				$IMresult = phpthumb_functions::SafeExec($commandline);
2267
				clearstatcache();
2268
				if (!@file_exists($IMtempfilename) || !@filesize($IMtempfilename)) {
2269
					$this->FatalError('ImageMagick failed with message ('.trim($IMresult).')');
0 ignored issues
show
Bug introduced by
It seems like $IMresult can also be of type false; however, parameter $str of trim() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

2269
					$this->FatalError('ImageMagick failed with message ('.trim(/** @scrutinizer ignore-type */ $IMresult).')');
Loading history...
2270
					$this->DebugMessage('ImageMagick failed with message ('.trim($IMresult).')', __FILE__, __LINE__);
2271
					if ($this->iswindows && !$IMresult) {
2272
						$this->DebugMessage('Check to make sure that PHP has read+write permissions to "'.dirname($IMtempfilename).'"', __FILE__, __LINE__);
2273
					}
2274
2275
				} else {
2276
2277
					foreach ($successfullyProcessedFilters as $dummy => $filterkey) {
2278
						unset($this->fltr[$filterkey]);
2279
					}
2280
					$this->IMresizedData = file_get_contents($IMtempfilename);
2281
					$getimagesize_imresized = @getimagesize($IMtempfilename);
2282
					$this->DebugMessage('getimagesize('.$IMtempfilename.') returned [w='.$getimagesize_imresized[0].';h='.$getimagesize_imresized[1].';f='.$getimagesize_imresized[2].']', __FILE__, __LINE__);
2283
					if (($this->config_max_source_pixels > 0) && (($getimagesize_imresized[0] * $getimagesize_imresized[1]) > $this->config_max_source_pixels)) {
2284
						$this->DebugMessage('skipping ImageMagickThumbnailToGD::'.$ImageCreateFunction.'() because IM output is too large ('.$getimagesize_imresized[0].'x'.$getimagesize_imresized[0].' = '.($getimagesize_imresized[0] * $getimagesize_imresized[1]).' > '.$this->config_max_source_pixels.')', __FILE__, __LINE__);
2285
					} elseif (function_exists(@$ImageCreateFunction) && ($this->gdimg_source = @$ImageCreateFunction($IMtempfilename))) {
2286
						$this->source_width  = imagesx($this->gdimg_source);
2287
						$this->source_height = imagesy($this->gdimg_source);
2288
						$this->DebugMessage('ImageMagickThumbnailToGD::'.$ImageCreateFunction.'() succeeded, $this->gdimg_source is now ('.$this->source_width.'x'.$this->source_height.')', __FILE__, __LINE__);
2289
						$this->DebugMessage('ImageMagickThumbnailToGD() returning $this->IMresizedData ('.strlen($this->IMresizedData).' bytes)', __FILE__, __LINE__);
2290
					} else {
2291
						$this->useRawIMoutput = true;
2292
						$this->DebugMessage('$this->useRawIMoutput set to TRUE because '.@$ImageCreateFunction.'('.$IMtempfilename.') failed', __FILE__, __LINE__);
2293
					}
2294
					if (file_exists($IMtempfilename)) {
2295
						$this->DebugMessage('deleting "'.$IMtempfilename.'"', __FILE__, __LINE__);
2296
						@unlink($IMtempfilename);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for unlink(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

2296
						/** @scrutinizer ignore-unhandled */ @unlink($IMtempfilename);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
2297
					}
2298
					return true;
2299
2300
				}
2301
				if (file_exists($IMtempfilename)) {
2302
					$this->DebugMessage('deleting "'.$IMtempfilename.'"', __FILE__, __LINE__);
2303
					@unlink($IMtempfilename);
2304
				}
2305
2306
			} elseif ($this->issafemode) {
2307
				$this->DebugMessage('ImageMagickThumbnailToGD() aborting because PHP safe_mode is enabled and phpThumb_tempnam() failed', __FILE__, __LINE__);
2308
				$this->useRawIMoutput = false;
2309
			} else {
2310
				if (file_exists($IMtempfilename)) {
2311
					$this->DebugMessage('deleting "'.$IMtempfilename.'"', __FILE__, __LINE__);
2312
					@unlink($IMtempfilename);
2313
				}
2314
				$this->DebugMessage('ImageMagickThumbnailToGD() aborting, phpThumb_tempnam() failed', __FILE__, __LINE__);
2315
			}
2316
		} else {
2317
			$this->DebugMessage('ImageMagickThumbnailToGD() aborting because ImageMagickCommandlineBase() failed', __FILE__, __LINE__);
2318
		}
2319
		$this->useRawIMoutput = false;
2320
		return false;
2321
	}
2322
2323
2324
	public function Rotate() {
2325
		if ($this->ra || $this->ar) {
2326
			if (!function_exists('imagerotate')) {
2327
				$this->DebugMessage('!function_exists(imagerotate)', __FILE__, __LINE__);
2328
				return false;
2329
			}
2330
			if (!include_once( __DIR__ .'/phpthumb.filters.php')) {
2331
				$this->DebugMessage('Error including "'. __DIR__ .'/phpthumb.filters.php" which is required for applying filters ('.implode(';', $this->fltr).')', __FILE__, __LINE__);
2332
				return false;
2333
			}
2334
2335
			$this->config_background_hexcolor = ($this->bg ? $this->bg : $this->config_background_hexcolor);
2336
			if (!phpthumb_functions::IsHexColor($this->config_background_hexcolor)) {
2337
				return $this->ErrorImage('Invalid hex color string "'.$this->config_background_hexcolor.'" for parameter "bg"');
2338
			}
2339
2340
			$rotate_angle = 0;
2341
			if ($this->ra) {
2342
2343
				$rotate_angle = (float) $this->ra;
2344
2345
			} else {
2346
2347
				if ($this->ar == 'x') {
2348
					if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '4.2.0', '>=')) {
2349
						if ($this->sourceFilename) {
2350
							if (function_exists('exif_read_data')) {
2351
								if ($exif_data = @exif_read_data($this->sourceFilename, 'IFD0')) {
2352
									// http://sylvana.net/jpegcrop/exif_orientation.html
2353
									switch (@$exif_data['Orientation']) {
2354
										case 1:
2355
											$rotate_angle = 0;
2356
											break;
2357
										case 3:
2358
											$rotate_angle = 180;
2359
											break;
2360
										case 6:
2361
											$rotate_angle = 270;
2362
											break;
2363
										case 8:
2364
											$rotate_angle = 90;
2365
											break;
2366
2367
										default:
2368
											$this->DebugMessage('EXIF auto-rotate failed because unknown $exif_data[Orientation] "'.@$exif_data['Orientation'].'"', __FILE__, __LINE__);
2369
											return false;
2370
											break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
2371
									}
2372
									$this->DebugMessage('EXIF auto-rotate set to '.$rotate_angle.' degrees ($exif_data[Orientation] = "'.@$exif_data['Orientation'].'")', __FILE__, __LINE__);
2373
								} else {
2374
									$this->DebugMessage('failed: exif_read_data('.$this->sourceFilename.')', __FILE__, __LINE__);
2375
									return false;
2376
								}
2377
							} else {
2378
								$this->DebugMessage('!function_exists(exif_read_data)', __FILE__, __LINE__);
2379
								return false;
2380
							}
2381
						} else {
2382
							$this->DebugMessage('Cannot auto-rotate from EXIF data because $this->sourceFilename is empty', __FILE__, __LINE__);
2383
							return false;
2384
						}
2385
					} else {
2386
						$this->DebugMessage('Cannot auto-rotate from EXIF data because PHP is less than v4.2.0 ('. PHP_VERSION .')', __FILE__, __LINE__);
2387
						return false;
2388
					}
2389
				} elseif (($this->ar == 'l') && ($this->source_height > $this->source_width)) {
2390
					$rotate_angle = 270;
2391
				} elseif (($this->ar == 'L') && ($this->source_height > $this->source_width)) {
2392
					$rotate_angle = 90;
2393
				} elseif (($this->ar == 'p') && ($this->source_width > $this->source_height)) {
2394
					$rotate_angle = 90;
2395
				} elseif (($this->ar == 'P') && ($this->source_width > $this->source_height)) {
2396
					$rotate_angle = 270;
2397
				}
2398
2399
			}
2400
			if ($rotate_angle % 90) {
2401
				$this->is_alpha = true;
2402
			}
2403
			phpthumb_filters::ImprovedImageRotate($this->gdimg_source, $rotate_angle, $this->config_background_hexcolor, $this->bg, $this);
2404
			$this->source_width  = imagesx($this->gdimg_source);
2405
			$this->source_height = imagesy($this->gdimg_source);
2406
		}
2407
		return true;
2408
	}
2409
2410
2411
	public function FixedAspectRatio() {
2412
		// optional fixed-dimension images (regardless of aspect ratio)
2413
2414
		if (!$this->far) {
2415
			// do nothing
2416
			return true;
2417
		}
2418
2419
		if (!$this->w || !$this->h) {
2420
			return false;
2421
		}
2422
		$this->thumbnail_width  = $this->w;
2423
		$this->thumbnail_height = $this->h;
2424
		$this->is_alpha = true;
2425
		if ($this->thumbnail_image_width >= $this->thumbnail_width) {
2426
2427
			$aspectratio = $this->thumbnail_image_height / $this->thumbnail_image_width;
2428
			if ($this->w) {
2429
				$this->thumbnail_image_height = round($this->thumbnail_image_width * $aspectratio);
2430
				$this->thumbnail_height = ($this->h ? $this->h : $this->thumbnail_image_height);
2431
			} elseif ($this->thumbnail_image_height < $this->thumbnail_height) {
2432
				$this->thumbnail_image_height = $this->thumbnail_height;
2433
				$this->thumbnail_image_width  = round($this->thumbnail_image_height / $aspectratio);
2434
			}
2435
2436
		} else {
2437
2438
			$aspectratio = $this->thumbnail_image_width / $this->thumbnail_image_height;
2439
			if ($this->h) {
2440
				$this->thumbnail_image_width = round($this->thumbnail_image_height * $aspectratio);
2441
			} elseif ($this->thumbnail_image_width < $this->thumbnail_width) {
2442
				$this->thumbnail_image_width = $this->thumbnail_width;
2443
				$this->thumbnail_image_height  = round($this->thumbnail_image_width / $aspectratio);
2444
			}
2445
2446
		}
2447
		return true;
2448
	}
2449
2450
2451
	public function OffsiteDomainIsAllowed($hostname, $allowed_domains) {
2452
		static $domain_is_allowed = array();
2453
		$hostname = strtolower($hostname);
2454
		if (!isset($domain_is_allowed[$hostname])) {
2455
			$domain_is_allowed[$hostname] = false;
2456
			foreach ($allowed_domains as $valid_domain) {
2457
				$starpos = strpos($valid_domain, '*');
2458
				if ($starpos !== false) {
2459
					$valid_domain = substr($valid_domain, $starpos + 1);
2460
					if (preg_match('#'.preg_quote($valid_domain).'$#', $hostname)) {
2461
						$domain_is_allowed[$hostname] = true;
2462
						break;
2463
					}
2464
				} else {
2465
					if (strtolower($valid_domain) === $hostname) {
2466
						$domain_is_allowed[$hostname] = true;
2467
						break;
2468
					}
2469
				}
2470
			}
2471
		}
2472
		return $domain_is_allowed[$hostname];
2473
	}
2474
2475
2476
	public function AntiOffsiteLinking() {
2477
		// Optional anti-offsite hijacking of the thumbnail script
2478
		$allow   = true;
2479
		if ($allow && $this->config_nooffsitelink_enabled && (@$_SERVER['HTTP_REFERER'] || $this->config_nooffsitelink_require_refer)) {
2480
			$this->DebugMessage('AntiOffsiteLinking() checking $_SERVER[HTTP_REFERER] "'.@$_SERVER['HTTP_REFERER'].'"', __FILE__, __LINE__);
2481
			foreach ($this->config_nooffsitelink_valid_domains as $key => $valid_domain) {
2482
				// $_SERVER['HTTP_HOST'] contains the port number, so strip it out here to make default configuration work
2483
				list($clean_domain) = explode(':', $valid_domain);
2484
				$this->config_nooffsitelink_valid_domains[$key] = $clean_domain;
2485
			}
2486
			$parsed_url = phpthumb_functions::ParseURLbetter(@$_SERVER['HTTP_REFERER']);
2487
			if (!$this->OffsiteDomainIsAllowed(@$parsed_url['host'], $this->config_nooffsitelink_valid_domains)) {
2488
				$allow   = false;
2489
				//$this->DebugMessage('AntiOffsiteLinking() - "'.@$parsed_url['host'].'" is NOT in $this->config_nooffsitelink_valid_domains ('.implode(';', $this->config_nooffsitelink_valid_domains).')', __FILE__, __LINE__);
2490
				$this->ErrorImage('AntiOffsiteLinking() - "'.@$parsed_url['host'].'" is NOT in $this->config_nooffsitelink_valid_domains ('.implode(';', $this->config_nooffsitelink_valid_domains).')');
2491
			} else {
2492
				$this->DebugMessage('AntiOffsiteLinking() - "'.@$parsed_url['host'].'" is in $this->config_nooffsitelink_valid_domains ('.implode(';', $this->config_nooffsitelink_valid_domains).')', __FILE__, __LINE__);
2493
			}
2494
		}
2495
2496
		if ($allow && $this->config_nohotlink_enabled && preg_match('#^(f|ht)tps?\://#i', $this->src)) {
2497
			$parsed_url = phpthumb_functions::ParseURLbetter($this->src);
2498
			//if (!phpthumb_functions::CaseInsensitiveInArray(@$parsed_url['host'], $this->config_nohotlink_valid_domains)) {
2499
			if (!$this->OffsiteDomainIsAllowed(@$parsed_url['host'], $this->config_nohotlink_valid_domains)) {
2500
				// This domain is not allowed
2501
				$allow = false;
2502
				$this->DebugMessage('AntiOffsiteLinking() - "'.$parsed_url['host'].'" is NOT in $this->config_nohotlink_valid_domains ('.implode(';', $this->config_nohotlink_valid_domains).')', __FILE__, __LINE__);
2503
			} else {
2504
				$this->DebugMessage('AntiOffsiteLinking() - "'.$parsed_url['host'].'" is in $this->config_nohotlink_valid_domains ('.implode(';', $this->config_nohotlink_valid_domains).')', __FILE__, __LINE__);
2505
			}
2506
		}
2507
2508
		if ($allow) {
2509
			$this->DebugMessage('AntiOffsiteLinking() says this is allowed', __FILE__, __LINE__);
2510
			return true;
2511
		}
2512
2513
		if (!phpthumb_functions::IsHexColor($this->config_error_bgcolor)) {
2514
			return $this->ErrorImage('Invalid hex color string "'.$this->config_error_bgcolor.'" for $this->config_error_bgcolor');
2515
		}
2516
		if (!phpthumb_functions::IsHexColor($this->config_error_textcolor)) {
2517
			return $this->ErrorImage('Invalid hex color string "'.$this->config_error_textcolor.'" for $this->config_error_textcolor');
2518
		}
2519
		if ($this->config_nooffsitelink_erase_image) {
2520
2521
			return $this->ErrorImage($this->config_nooffsitelink_text_message, $this->thumbnail_width, $this->thumbnail_height);
2522
2523
		} else {
2524
2525
			$this->config_nooffsitelink_watermark_src = $this->ResolveFilenameToAbsolute($this->config_nooffsitelink_watermark_src);
2526
			if (is_file($this->config_nooffsitelink_watermark_src)) {
0 ignored issues
show
Bug introduced by
It seems like $this->config_nooffsitelink_watermark_src can also be of type false; however, parameter $filename of is_file() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

2526
			if (is_file(/** @scrutinizer ignore-type */ $this->config_nooffsitelink_watermark_src)) {
Loading history...
2527
2528
				if (!include_once( __DIR__ .'/phpthumb.filters.php')) {
2529
					$this->DebugMessage('Error including "'. __DIR__ .'/phpthumb.filters.php" which is required for applying watermark', __FILE__, __LINE__);
2530
					return false;
2531
				}
2532
				$watermark_img = $this->ImageCreateFromStringReplacement(file_get_contents($this->config_nooffsitelink_watermark_src));
0 ignored issues
show
Bug introduced by
It seems like $this->config_nooffsitelink_watermark_src can also be of type false; however, parameter $filename of file_get_contents() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

2532
				$watermark_img = $this->ImageCreateFromStringReplacement(file_get_contents(/** @scrutinizer ignore-type */ $this->config_nooffsitelink_watermark_src));
Loading history...
Bug introduced by
file_get_contents($this-...sitelink_watermark_src) cannot be passed to phpthumb::ImageCreateFromStringReplacement() as the parameter $RawImageData expects a reference. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

2532
				$watermark_img = $this->ImageCreateFromStringReplacement(/** @scrutinizer ignore-type */ file_get_contents($this->config_nooffsitelink_watermark_src));
Loading history...
2533
				$phpthumbFilters = new phpthumb_filters();
2534
				$phpthumbFilters->phpThumbObject = &$this;
2535
				$opacity = 50;
2536
				$margin  = 5;
2537
				$phpthumbFilters->WatermarkOverlay($this->gdimg_output, $watermark_img, '*', $opacity, $margin);
2538
				imagedestroy($watermark_img);
2539
				unset($phpthumbFilters);
2540
2541
			} else {
2542
2543
				$nohotlink_text_array = explode("\n", wordwrap($this->config_nooffsitelink_text_message, floor($this->thumbnail_width / imagefontwidth($this->config_error_fontsize)), "\n"));
0 ignored issues
show
Bug introduced by
floor($this->thumbnail_w...config_error_fontsize)) of type double is incompatible with the type integer expected by parameter $width of wordwrap(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

2543
				$nohotlink_text_array = explode("\n", wordwrap($this->config_nooffsitelink_text_message, /** @scrutinizer ignore-type */ floor($this->thumbnail_width / imagefontwidth($this->config_error_fontsize)), "\n"));
Loading history...
2544
				$nohotlink_text_color = phpthumb_functions::ImageHexColorAllocate($this->gdimg_output, $this->config_error_textcolor);
2545
2546
				$topoffset = round(($this->thumbnail_height - (count($nohotlink_text_array) * imagefontheight($this->config_error_fontsize))) / 2);
2547
2548
				$rowcounter = 0;
2549
				$this->DebugMessage('AntiOffsiteLinking() writing '.count($nohotlink_text_array).' lines of text "'.$this->config_nooffsitelink_text_message.'" (in #'.$this->config_error_textcolor.') on top of image', __FILE__, __LINE__);
2550
				foreach ($nohotlink_text_array as $textline) {
2551
					$leftoffset = max(0, round(($this->thumbnail_width - (strlen($textline) * imagefontwidth($this->config_error_fontsize))) / 2));
2552
					imagestring($this->gdimg_output, $this->config_error_fontsize, $leftoffset, $topoffset + ($rowcounter++ * imagefontheight($this->config_error_fontsize)), $textline, $nohotlink_text_color);
2553
				}
2554
2555
			}
2556
2557
		}
2558
		return true;
2559
	}
2560
2561
2562
	public function AlphaChannelFlatten() {
2563
		if (!$this->is_alpha) {
2564
			// image doesn't have alpha transparency, no need to flatten
2565
			$this->DebugMessage('skipping AlphaChannelFlatten() because !$this->is_alpha', __FILE__, __LINE__);
2566
			return false;
2567
		}
2568
		switch ($this->thumbnailFormat) {
2569
			case 'png':
2570
			case 'ico':
2571
				// image has alpha transparency, but output as PNG or ICO which can handle it
2572
				$this->DebugMessage('skipping AlphaChannelFlatten() because ($this->thumbnailFormat == "'.$this->thumbnailFormat.'")', __FILE__, __LINE__);
2573
				return false;
2574
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
2575
2576
			case 'gif':
2577
				// image has alpha transparency, but output as GIF which can handle only single-color transparency
2578
				$CurrentImageColorTransparent = imagecolortransparent($this->gdimg_output);
2579
				if ($CurrentImageColorTransparent == -1) {
2580
					// no transparent color defined
2581
2582
					if (phpthumb_functions::gd_version() < 2.0) {
2583
						$this->DebugMessage('AlphaChannelFlatten() failed because GD version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
2584
						return false;
2585
					}
2586
2587
					if ($img_alpha_mixdown_dither = @imagecreatetruecolor(imagesx($this->gdimg_output), imagesy($this->gdimg_output))) {
2588
2589
						$dither_color = array();
2590
						for ($i = 0; $i <= 255; $i++) {
2591
							$dither_color[$i] = imagecolorallocate($img_alpha_mixdown_dither, $i, $i, $i);
2592
						}
2593
2594
						// scan through current truecolor image copy alpha channel to temp image as grayscale
2595
						for ($x = 0; $x < $this->thumbnail_width; $x++) {
2596
							for ($y = 0; $y < $this->thumbnail_height; $y++) {
2597
								$PixelColor = phpthumb_functions::GetPixelColor($this->gdimg_output, $x, $y);
2598
								imagesetpixel($img_alpha_mixdown_dither, $x, $y, $dither_color[($PixelColor['alpha'] * 2)]);
2599
							}
2600
						}
2601
2602
						// dither alpha channel grayscale version down to 2 colors
2603
						imagetruecolortopalette($img_alpha_mixdown_dither, true, 2);
2604
2605
						// reduce color palette to 256-1 colors (leave one palette position for transparent color)
2606
						imagetruecolortopalette($this->gdimg_output, true, 255);
2607
2608
						// allocate a new color for transparent color index
2609
						$TransparentColor = imagecolorallocate($this->gdimg_output, 1, 254, 253);
2610
						imagecolortransparent($this->gdimg_output, $TransparentColor);
2611
2612
						// scan through alpha channel image and note pixels with >50% transparency
2613
						for ($x = 0; $x < $this->thumbnail_width; $x++) {
2614
							for ($y = 0; $y < $this->thumbnail_height; $y++) {
2615
								$AlphaChannelPixel = phpthumb_functions::GetPixelColor($img_alpha_mixdown_dither, $x, $y);
2616
								if ($AlphaChannelPixel['red'] > 127) {
2617
									imagesetpixel($this->gdimg_output, $x, $y, $TransparentColor);
2618
								}
2619
							}
2620
						}
2621
						imagedestroy($img_alpha_mixdown_dither);
2622
2623
						$this->DebugMessage('AlphaChannelFlatten() set image to 255+1 colors with transparency for GIF output', __FILE__, __LINE__);
2624
						return true;
2625
2626
					} else {
2627
						$this->DebugMessage('AlphaChannelFlatten() failed imagecreate('.imagesx($this->gdimg_output).', '.imagesy($this->gdimg_output).')', __FILE__, __LINE__);
2628
						return false;
2629
					}
2630
2631
				} else {
2632
					// a single transparent color already defined, leave as-is
2633
					$this->DebugMessage('skipping AlphaChannelFlatten() because ($this->thumbnailFormat == "'.$this->thumbnailFormat.'") and imagecolortransparent() returned "'.$CurrentImageColorTransparent.'"', __FILE__, __LINE__);
2634
					return true;
2635
				}
2636
				break;
2637
		}
2638
		$this->DebugMessage('continuing AlphaChannelFlatten() for output format "'.$this->thumbnailFormat.'"', __FILE__, __LINE__);
2639
		// image has alpha transparency, and is being output in a format that doesn't support it -- flatten
2640
		if ($gdimg_flatten_temp = phpthumb_functions::ImageCreateFunction($this->thumbnail_width, $this->thumbnail_height)) {
2641
2642
			$this->config_background_hexcolor = ($this->bg ? $this->bg : $this->config_background_hexcolor);
2643
			if (!phpthumb_functions::IsHexColor($this->config_background_hexcolor)) {
2644
				return $this->ErrorImage('Invalid hex color string "'.$this->config_background_hexcolor.'" for parameter "bg"');
2645
			}
2646
			$background_color = phpthumb_functions::ImageHexColorAllocate($this->gdimg_output, $this->config_background_hexcolor);
2647
			imagefilledrectangle($gdimg_flatten_temp, 0, 0, $this->thumbnail_width, $this->thumbnail_height, $background_color);
2648
			imagecopy($gdimg_flatten_temp, $this->gdimg_output, 0, 0, 0, 0, $this->thumbnail_width, $this->thumbnail_height);
2649
2650
			imagealphablending($this->gdimg_output, true);
2651
			imagesavealpha($this->gdimg_output, false);
2652
			imagecolortransparent($this->gdimg_output, -1);
2653
			imagecopy($this->gdimg_output, $gdimg_flatten_temp, 0, 0, 0, 0, $this->thumbnail_width, $this->thumbnail_height);
2654
2655
			imagedestroy($gdimg_flatten_temp);
2656
			return true;
2657
2658
		} else {
2659
			$this->DebugMessage('ImageCreateFunction() failed', __FILE__, __LINE__);
2660
		}
2661
		return false;
2662
	}
2663
2664
2665
	public function ApplyFilters() {
2666
		if ($this->fltr && is_array($this->fltr)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->fltr of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
2667
			if (!include_once( __DIR__ .'/phpthumb.filters.php')) {
2668
				$this->DebugMessage('Error including "'. __DIR__ .'/phpthumb.filters.php" which is required for applying filters ('.implode(';', $this->fltr).')', __FILE__, __LINE__);
2669
				return false;
2670
			}
2671
			$phpthumbFilters = new phpthumb_filters();
2672
			$phpthumbFilters->phpThumbObject = &$this;
2673
			foreach ($this->fltr as $filtercommand) {
2674
				@list($command, $parameter) = explode('|', $filtercommand, 2);
2675
				$this->DebugMessage('Attempting to process filter command "'.$command.'('.$parameter.')"', __FILE__, __LINE__);
2676
				switch ($command) {
2677
					case 'brit': // Brightness
2678
						$phpthumbFilters->Brightness($this->gdimg_output, $parameter);
2679
						break;
2680
2681
					case 'cont': // Contrast
2682
						$phpthumbFilters->Contrast($this->gdimg_output, $parameter);
2683
						break;
2684
2685
					case 'ds': // Desaturation
2686
						$phpthumbFilters->Desaturate($this->gdimg_output, $parameter, '');
2687
						break;
2688
2689
					case 'sat': // Saturation
2690
						$phpthumbFilters->Saturation($this->gdimg_output, $parameter, '');
2691
						break;
2692
2693
					case 'gray': // Grayscale
2694
						$phpthumbFilters->Grayscale($this->gdimg_output);
2695
						break;
2696
2697
					case 'clr': // Colorize
2698
						if (phpthumb_functions::gd_version() < 2) {
2699
							$this->DebugMessage('Skipping Colorize() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
2700
							break;
2701
						}
2702
						@list($amount, $color) = explode('|', $parameter, 2);
2703
						$phpthumbFilters->Colorize($this->gdimg_output, $amount, $color);
2704
						break;
2705
2706
					case 'sep': // Sepia
2707
						if (phpthumb_functions::gd_version() < 2) {
2708
							$this->DebugMessage('Skipping Sepia() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
2709
							break;
2710
						}
2711
						@list($amount, $color) = explode('|', $parameter, 2);
2712
						$phpthumbFilters->Sepia($this->gdimg_output, $amount, $color);
2713
						break;
2714
2715
					case 'gam': // Gamma correction
2716
						$phpthumbFilters->Gamma($this->gdimg_output, $parameter);
2717
						break;
2718
2719
					case 'neg': // Negative colors
2720
						$phpthumbFilters->Negative($this->gdimg_output);
2721
						break;
2722
2723
					case 'th': // Threshold
2724
						$phpthumbFilters->Threshold($this->gdimg_output, $parameter);
2725
						break;
2726
2727
					case 'rcd': // ReduceColorDepth
2728
						if (phpthumb_functions::gd_version() < 2) {
2729
							$this->DebugMessage('Skipping ReduceColorDepth() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
2730
							break;
2731
						}
2732
						@list($colors, $dither) = explode('|', $parameter, 2);
2733
						$colors = ($colors                ?  (int) $colors : 256);
2734
						$dither  = ((strlen($dither) > 0) ? (bool) $dither : true);
2735
						$phpthumbFilters->ReduceColorDepth($this->gdimg_output, $colors, $dither);
2736
						break;
2737
2738
					case 'flip': // Flip
2739
						$phpthumbFilters->Flip($this->gdimg_output, (strpos(strtolower($parameter), 'x') !== false), (strpos(strtolower($parameter), 'y') !== false));
2740
						break;
2741
2742
					case 'edge': // EdgeDetect
2743
						$phpthumbFilters->EdgeDetect($this->gdimg_output);
2744
						break;
2745
2746
					case 'emb': // Emboss
2747
						$phpthumbFilters->Emboss($this->gdimg_output);
2748
						break;
2749
2750
					case 'bvl': // Bevel
2751
						@list($width, $color1, $color2) = explode('|', $parameter, 3);
2752
						$phpthumbFilters->Bevel($this->gdimg_output, $width, $color1, $color2);
2753
						break;
2754
2755
					case 'lvl': // autoLevels
2756
						@list($band, $method, $threshold) = explode('|', $parameter, 3);
2757
						$band      = ($band ? preg_replace('#[^RGBA\\*]#', '', strtoupper($band)) : '*');
2758
						$method    = ((strlen($method) > 0)    ? (int) $method :   2);
2759
						$threshold = ((strlen($threshold) > 0) ? (float) $threshold : 0.1);
2760
2761
						$phpthumbFilters->HistogramStretch($this->gdimg_output, $band, $method, $threshold);
2762
						break;
2763
2764
					case 'wb': // WhiteBalance
2765
						$phpthumbFilters->WhiteBalance($this->gdimg_output, $parameter);
2766
						break;
2767
2768
					case 'hist': // Histogram overlay
2769
						if (phpthumb_functions::gd_version() < 2) {
2770
							$this->DebugMessage('Skipping HistogramOverlay() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
2771
							break;
2772
						}
2773
						@list($bands, $colors, $width, $height, $alignment, $opacity, $margin_x, $margin_y) = explode('|', $parameter, 8);
2774
						$bands     = ($bands     ? $bands     :  '*');
2775
						$colors    = ($colors    ? $colors    :   '');
2776
						$width     = ($width     ? $width     : 0.25);
2777
						$height    = ($height    ? $height    : 0.25);
2778
						$alignment = ($alignment ? $alignment : 'BR');
2779
						$opacity   = ($opacity   ? $opacity   :   50);
2780
						$margin_x  = ($margin_x  ? $margin_x  :    5);
2781
						// $margin_y -- it wasn't forgotten, let the value always pass unchanged
2782
						$phpthumbFilters->HistogramOverlay($this->gdimg_output, $bands, $colors, $width, $height, $alignment, $opacity, $margin_x, $margin_y);
2783
						break;
2784
2785
					case 'fram': // Frame
2786
						@list($frame_width, $edge_width, $color_frame, $color1, $color2) = explode('|', $parameter, 5);
2787
						$phpthumbFilters->Frame($this->gdimg_output, $frame_width, $edge_width, $color_frame, $color1, $color2);
2788
						break;
2789
2790
					case 'drop': // DropShadow
2791
						if (phpthumb_functions::gd_version() < 2) {
2792
							$this->DebugMessage('Skipping DropShadow() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
2793
							return false;
2794
						}
2795
						$this->is_alpha = true;
2796
						@list($distance, $width, $color, $angle, $fade) = explode('|', $parameter, 5);
2797
						$phpthumbFilters->DropShadow($this->gdimg_output, $distance, $width, $color, $angle, $fade);
2798
						break;
2799
2800
					case 'mask': // Mask cropping
2801
						if (phpthumb_functions::gd_version() < 2) {
2802
							$this->DebugMessage('Skipping Mask() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
2803
							return false;
2804
						}
2805
						@list($mask_filename, $invert) = explode('|', $parameter, 2);
2806
						$mask_filename = $this->ResolveFilenameToAbsolute($mask_filename);
2807
						if (@is_readable($mask_filename) && ($fp_mask = @fopen($mask_filename, 'rb'))) {
0 ignored issues
show
Bug introduced by
It seems like $mask_filename can also be of type false; however, parameter $filename of fopen() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

2807
						if (@is_readable($mask_filename) && ($fp_mask = @fopen(/** @scrutinizer ignore-type */ $mask_filename, 'rb'))) {
Loading history...
Bug introduced by
It seems like $mask_filename can also be of type false; however, parameter $filename of is_readable() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

2807
						if (@is_readable(/** @scrutinizer ignore-type */ $mask_filename) && ($fp_mask = @fopen($mask_filename, 'rb'))) {
Loading history...
2808
							$MaskImageData = '';
2809
							do {
2810
								$buffer = fread($fp_mask, 8192);
2811
								$MaskImageData .= $buffer;
2812
							} while (strlen($buffer) > 0);
2813
							fclose($fp_mask);
2814
							if ($gdimg_mask = $this->ImageCreateFromStringReplacement($MaskImageData)) {
2815
								if ($invert && phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.0.0', '>=') && phpthumb_functions::gd_is_bundled()) {
2816
									imagefilter($gdimg_mask, IMG_FILTER_NEGATE);
2817
								}
2818
								$this->is_alpha = true;
2819
								$phpthumbFilters->ApplyMask($gdimg_mask, $this->gdimg_output);
2820
								imagedestroy($gdimg_mask);
2821
							} else {
2822
								$this->DebugMessage('ImageCreateFromStringReplacement() failed for "'.$mask_filename.'"', __FILE__, __LINE__);
2823
							}
2824
						} else {
2825
							$this->DebugMessage('Cannot open mask file "'.$mask_filename.'"', __FILE__, __LINE__);
2826
						}
2827
						break;
2828
2829
					case 'elip': // Ellipse cropping
2830
						if (phpthumb_functions::gd_version() < 2) {
2831
							$this->DebugMessage('Skipping Ellipse() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
2832
							return false;
2833
						}
2834
						$this->is_alpha = true;
2835
						$phpthumbFilters->Ellipse($this->gdimg_output);
2836
						break;
2837
2838
					case 'ric': // RoundedImageCorners
2839
						if (phpthumb_functions::gd_version() < 2) {
2840
							$this->DebugMessage('Skipping RoundedImageCorners() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
2841
							return false;
2842
						}
2843
						@list($radius_x, $radius_y) = explode('|', $parameter, 2);
2844
						if (($radius_x < 1) || ($radius_y < 1)) {
2845
							$this->DebugMessage('Skipping RoundedImageCorners('.$radius_x.', '.$radius_y.') because x/y radius is less than 1', __FILE__, __LINE__);
2846
							break;
2847
						}
2848
						$this->is_alpha = true;
2849
						$phpthumbFilters->RoundedImageCorners($this->gdimg_output, $radius_x, $radius_y);
2850
						break;
2851
2852
					case 'crop': // Crop
2853
						@list($left, $right, $top, $bottom) = explode('|', $parameter, 4);
2854
						$phpthumbFilters->Crop($this->gdimg_output, $left, $right, $top, $bottom);
2855
						break;
2856
2857
					case 'bord': // Border
2858
						@list($border_width, $radius_x, $radius_y, $hexcolor_border) = explode('|', $parameter, 4);
2859
						$this->is_alpha = true;
2860
						$phpthumbFilters->ImageBorder($this->gdimg_output, $border_width, $radius_x, $radius_y, $hexcolor_border);
2861
						break;
2862
2863
					case 'over': // Overlay
2864
						@list($filename, $underlay, $margin, $opacity) = explode('|', $parameter, 4);
2865
						$underlay = (bool) ($underlay              ? $underlay : false);
2866
						$margin   =        ((strlen($margin)  > 0) ? $margin   : ($underlay ? 0.1 : 0.0));
2867
						$opacity  =        ((strlen($opacity) > 0) ? $opacity  : 100);
2868
						if (($margin > 0) && ($margin < 1)) {
2869
							$margin = min(0.499, $margin);
2870
						} elseif (($margin > -1) && ($margin < 0)) {
2871
							$margin = max(-0.499, $margin);
2872
						}
2873
2874
						$filename = $this->ResolveFilenameToAbsolute($filename);
2875
						if (@is_readable($filename) && ($fp_watermark = @fopen($filename, 'rb'))) {
2876
							$WatermarkImageData = '';
2877
							do {
2878
								$buffer = fread($fp_watermark, 8192);
2879
								$WatermarkImageData .= $buffer;
2880
							} while (strlen($buffer) > 0);
2881
							fclose($fp_watermark);
2882
							if ($img_watermark = $this->ImageCreateFromStringReplacement($WatermarkImageData)) {
2883
								if (($margin > 0) && ($margin < 1)) {
2884
									$resized_x = max(1, imagesx($this->gdimg_output) - round(2 * (imagesx($this->gdimg_output) * $margin)));
2885
									$resized_y = max(1, imagesy($this->gdimg_output) - round(2 * (imagesy($this->gdimg_output) * $margin)));
2886
								} else {
2887
									$resized_x = max(1, imagesx($this->gdimg_output) - round(2 * $margin));
2888
									$resized_y = max(1, imagesy($this->gdimg_output) - round(2 * $margin));
2889
								}
2890
2891
								if ($underlay) {
2892
2893
									if ($img_watermark_resized = phpthumb_functions::ImageCreateFunction(imagesx($this->gdimg_output), imagesy($this->gdimg_output))) {
2894
										imagealphablending($img_watermark_resized, false);
2895
										imagesavealpha($img_watermark_resized, true);
2896
										$this->ImageResizeFunction($img_watermark_resized, $img_watermark, 0, 0, 0, 0, imagesx($img_watermark_resized), imagesy($img_watermark_resized), imagesx($img_watermark), imagesy($img_watermark));
2897
										if ($img_source_resized = phpthumb_functions::ImageCreateFunction($resized_x, $resized_y)) {
2898
											imagealphablending($img_source_resized, false);
2899
											imagesavealpha($img_source_resized, true);
2900
											$this->ImageResizeFunction($img_source_resized, $this->gdimg_output, 0, 0, 0, 0, imagesx($img_source_resized), imagesy($img_source_resized), imagesx($this->gdimg_output), imagesy($this->gdimg_output));
2901
											$phpthumbFilters->WatermarkOverlay($img_watermark_resized, $img_source_resized, 'C', $opacity, $margin);
2902
											imagecopy($this->gdimg_output, $img_watermark_resized, 0, 0, 0, 0, imagesx($this->gdimg_output), imagesy($this->gdimg_output));
2903
										} else {
2904
											$this->DebugMessage('phpthumb_functions::ImageCreateFunction('.$resized_x.', '.$resized_y.')', __FILE__, __LINE__);
2905
										}
2906
										imagedestroy($img_watermark_resized);
2907
									} else {
2908
										$this->DebugMessage('phpthumb_functions::ImageCreateFunction('.imagesx($this->gdimg_output).', '.imagesy($this->gdimg_output).')', __FILE__, __LINE__);
2909
									}
2910
2911
								} else { // overlay
2912
2913
									if ($img_watermark_resized = phpthumb_functions::ImageCreateFunction($resized_x, $resized_y)) {
2914
										imagealphablending($img_watermark_resized, false);
2915
										imagesavealpha($img_watermark_resized, true);
2916
										$this->ImageResizeFunction($img_watermark_resized, $img_watermark, 0, 0, 0, 0, imagesx($img_watermark_resized), imagesy($img_watermark_resized), imagesx($img_watermark), imagesy($img_watermark));
2917
										$phpthumbFilters->WatermarkOverlay($this->gdimg_output, $img_watermark_resized, 'C', $opacity, $margin);
2918
										imagedestroy($img_watermark_resized);
2919
									} else {
2920
										$this->DebugMessage('phpthumb_functions::ImageCreateFunction('.$resized_x.', '.$resized_y.')', __FILE__, __LINE__);
2921
									}
2922
2923
								}
2924
								imagedestroy($img_watermark);
2925
2926
							} else {
2927
								$this->DebugMessage('ImageCreateFromStringReplacement() failed for "'.$filename.'"', __FILE__, __LINE__);
2928
							}
2929
						} else {
2930
							$this->DebugMessage('Cannot open overlay file "'.$filename.'"', __FILE__, __LINE__);
2931
						}
2932
						break;
2933
2934
					case 'wmi': // WaterMarkImage
2935
						@list($filename, $alignment, $opacity, $margin['x'], $margin['y'], $rotate_angle) = explode('|', $parameter, 6);
2936
						// $margin can be pixel margin or percent margin if $alignment is text, or max width/height if $alignment is position like "50x75"
2937
						$alignment    = ($alignment            ? $alignment            : 'BR');
2938
						$opacity      = (strlen($opacity)      ? (int) $opacity : 50);
2939
						$rotate_angle = (strlen($rotate_angle) ? (int) $rotate_angle : 0);
2940
						if (!preg_match('#^([0-9\\.\\-]*)x([0-9\\.\\-]*)$#i', $alignment, $matches)) {
2941
							$margins = array('x', 'y');
2942
							foreach ($margins as $xy) {
2943
								$margin[$xy] = (strlen($margin[$xy]) ? $margin[$xy] : 5);
2944
								if (($margin[$xy] > 0) && ($margin[$xy] < 1)) {
2945
									$margin[$xy] = min(0.499, $margin[$xy]);
2946
								} elseif (($margin[$xy] > -1) && ($margin[$xy] < 0)) {
2947
									$margin[$xy] = max(-0.499, $margin[$xy]);
2948
								}
2949
							}
2950
						}
2951
2952
						$filename = $this->ResolveFilenameToAbsolute($filename);
2953
						if (@is_readable($filename)) {
2954
							if ($img_watermark = $this->ImageCreateFromFilename($filename)) {
2955
								if ($rotate_angle !== 0) {
2956
									$phpthumbFilters->ImprovedImageRotate($img_watermark, $rotate_angle, 'FFFFFF', null, $this);
2957
								}
2958
								if (preg_match('#^([0-9\\.\\-]*)x([0-9\\.\\-]*)$#i', $alignment, $matches)) {
2959
									$watermark_max_width  = (int) ($margin[ 'x'] ? $margin[ 'x'] : imagesx($img_watermark));
2960
									$watermark_max_height = (int) ($margin[ 'y'] ? $margin[ 'y'] : imagesy($img_watermark));
2961
									$scale = phpthumb_functions::ScaleToFitInBox(imagesx($img_watermark), imagesy($img_watermark), $watermark_max_width, $watermark_max_height, true, true);
2962
									$this->DebugMessage('Scaling watermark by a factor of '.number_format($scale, 4), __FILE__, __LINE__);
2963
									if (($scale > 1) || ($scale < 1)) {
2964
										if ($img_watermark2 = phpthumb_functions::ImageCreateFunction($scale * imagesx($img_watermark), $scale * imagesy($img_watermark))) {
2965
											imagealphablending($img_watermark2, false);
2966
											imagesavealpha($img_watermark2, true);
2967
											$this->ImageResizeFunction($img_watermark2, $img_watermark, 0, 0, 0, 0, imagesx($img_watermark2), imagesy($img_watermark2), imagesx($img_watermark), imagesy($img_watermark));
2968
											$img_watermark = $img_watermark2;
2969
										} else {
2970
											$this->DebugMessage('ImageCreateFunction('.($scale * imagesx($img_watermark)).', '.($scale * imagesx($img_watermark)).') failed', __FILE__, __LINE__);
2971
										}
2972
									}
2973
									$watermark_dest_x = round($matches[1] - (imagesx($img_watermark) / 2));
2974
									$watermark_dest_y = round($matches[2] - (imagesy($img_watermark) / 2));
2975
									$alignment = $watermark_dest_x.'x'.$watermark_dest_y;
2976
								}
2977
								$phpthumbFilters->WatermarkOverlay($this->gdimg_output, $img_watermark, $alignment, $opacity, $margin['x'], $margin['y']);
2978
								imagedestroy($img_watermark);
2979
								if (isset($img_watermark2) && is_resource($img_watermark2)) {
2980
									imagedestroy($img_watermark2);
2981
								}
2982
							} else {
2983
								$this->DebugMessage('ImageCreateFromFilename() failed for "'.$filename.'"', __FILE__, __LINE__);
2984
							}
2985
						} else {
2986
							$this->DebugMessage('!is_readable('.$filename.')', __FILE__, __LINE__);
2987
						}
2988
						break;
2989
2990
					case 'wmt': // WaterMarkText
2991
						@list($text, $size, $alignment, $hex_color, $ttffont, $opacity, $margin, $angle, $bg_color, $bg_opacity, $fillextend, $lineheight) = explode('|', $parameter, 12);
2992
						$text       = ($text            ? $text       : '');
2993
						$size       = ($size            ? $size       : 3);
2994
						$alignment  = ($alignment       ? $alignment  : 'BR');
2995
						$hex_color  = ($hex_color       ? $hex_color  : '000000');
2996
						$ttffont    = ($ttffont         ? $ttffont    : '');
2997
						$opacity    = (strlen($opacity) ? $opacity    : 50);
2998
						$margin     = (strlen($margin)  ? $margin     : 5);
2999
						$angle      = (strlen($angle)   ? $angle      : 0);
3000
						$bg_color   = ($bg_color        ? $bg_color   : false);
3001
						$bg_opacity = ($bg_opacity      ? $bg_opacity : 0);
3002
						$fillextend = ($fillextend      ? $fillextend : '');
3003
						$lineheight = ($lineheight      ? $lineheight : 1.0);
3004
3005
						if (basename($ttffont) == $ttffont) {
3006
							$ttffont = $this->realPathSafe($this->config_ttf_directory.DIRECTORY_SEPARATOR.$ttffont);
3007
						} else {
3008
							$ttffont = $this->ResolveFilenameToAbsolute($ttffont);
3009
						}
3010
						$phpthumbFilters->WatermarkText($this->gdimg_output, $text, $size, $alignment, $hex_color, $ttffont, $opacity, $margin, $angle, $bg_color, $bg_opacity, $fillextend, $lineheight);
3011
						break;
3012
3013
					case 'blur': // Blur
3014
						@list($radius) = explode('|', $parameter, 1);
3015
						$radius = ($radius ? $radius : 1);
3016
						if (phpthumb_functions::gd_version() >= 2) {
3017
							$phpthumbFilters->Blur($this->gdimg_output, $radius);
3018
						} else {
3019
							$this->DebugMessage('Skipping Blur() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
3020
						}
3021
						break;
3022
3023
					case 'gblr': // Gaussian Blur
3024
						$phpthumbFilters->BlurGaussian($this->gdimg_output);
3025
						break;
3026
3027
					case 'sblr': // Selective Blur
3028
						$phpthumbFilters->BlurSelective($this->gdimg_output);
3029
						break;
3030
3031
					case 'mean': // MeanRemoval blur
3032
						$phpthumbFilters->MeanRemoval($this->gdimg_output);
3033
						break;
3034
3035
					case 'smth': // Smooth blur
3036
						$phpthumbFilters->Smooth($this->gdimg_output, $parameter);
3037
						break;
3038
3039
					case 'usm': // UnSharpMask sharpening
3040
						@list($amount, $radius, $threshold) = explode('|', $parameter, 3);
3041
						$amount    = ($amount            ? $amount    : 80);
3042
						$radius    = ($radius            ? $radius    : 0.5);
3043
						$threshold = (strlen($threshold) ? $threshold : 3);
3044
						if (phpthumb_functions::gd_version() >= 2.0) {
3045
							ob_start();
3046
							if (!@include_once( __DIR__ .'/phpthumb.unsharp.php')) {
3047
								$include_error = ob_get_contents();
3048
								if ($include_error) {
3049
									$this->DebugMessage('include_once("'. __DIR__ .'/phpthumb.unsharp.php") generated message: "'.$include_error.'"', __FILE__, __LINE__);
3050
								}
3051
								$this->DebugMessage('Error including "'. __DIR__ .'/phpthumb.unsharp.php" which is required for unsharp masking', __FILE__, __LINE__);
3052
								ob_end_clean();
3053
								return false;
3054
							}
3055
							ob_end_clean();
3056
							phpUnsharpMask::applyUnsharpMask($this->gdimg_output, $amount, $radius, $threshold);
3057
						} else {
3058
							$this->DebugMessage('Skipping unsharp mask because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
3059
							return false;
3060
						}
3061
						break;
3062
3063
					case 'size': // Resize
3064
						@list($newwidth, $newheight, $stretch) = explode('|', $parameter);
3065
						$newwidth  = (!$newwidth  ? imagesx($this->gdimg_output) : ((($newwidth  > 0) && ($newwidth  < 1)) ? round($newwidth  * imagesx($this->gdimg_output)) : round($newwidth)));
0 ignored issues
show
Bug introduced by
$newwidth of type string is incompatible with the type double expected by parameter $val of round(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

3065
						$newwidth  = (!$newwidth  ? imagesx($this->gdimg_output) : ((($newwidth  > 0) && ($newwidth  < 1)) ? round($newwidth  * imagesx($this->gdimg_output)) : round(/** @scrutinizer ignore-type */ $newwidth)));
Loading history...
3066
						$newheight = (!$newheight ? imagesy($this->gdimg_output) : ((($newheight > 0) && ($newheight < 1)) ? round($newheight * imagesy($this->gdimg_output)) : round($newheight)));
3067
						$stretch   = ($stretch ? true : false);
3068
						if ($stretch) {
3069
							$scale_x = phpthumb_functions::ScaleToFitInBox(imagesx($this->gdimg_output), imagesx($this->gdimg_output), $newwidth,  $newwidth,  true, true);
3070
							$scale_y = phpthumb_functions::ScaleToFitInBox(imagesy($this->gdimg_output), imagesy($this->gdimg_output), $newheight, $newheight, true, true);
3071
						} else {
3072
							$scale_x = phpthumb_functions::ScaleToFitInBox(imagesx($this->gdimg_output), imagesy($this->gdimg_output), $newwidth, $newheight, true, true);
3073
							$scale_y = $scale_x;
3074
						}
3075
						$this->DebugMessage('Scaling watermark ('.($stretch ? 'with' : 'without').' stretch) by a factor of "'.number_format($scale_x, 4).' x '.number_format($scale_y, 4).'"', __FILE__, __LINE__);
3076
						if (($scale_x > 1) || ($scale_x < 1) || ($scale_y > 1) || ($scale_y < 1)) {
3077
							if ($img_temp = phpthumb_functions::ImageCreateFunction(imagesx($this->gdimg_output), imagesy($this->gdimg_output))) {
3078
								imagecopy($img_temp, $this->gdimg_output, 0, 0, 0, 0, imagesx($this->gdimg_output), imagesy($this->gdimg_output));
3079
								if ($this->gdimg_output = phpthumb_functions::ImageCreateFunction($scale_x * imagesx($img_temp), $scale_y * imagesy($img_temp))) {
3080
									imagealphablending($this->gdimg_output, false);
3081
									imagesavealpha($this->gdimg_output, true);
3082
									$this->ImageResizeFunction($this->gdimg_output, $img_temp, 0, 0, 0, 0, imagesx($this->gdimg_output), imagesy($this->gdimg_output), imagesx($img_temp), imagesy($img_temp));
3083
								} else {
3084
									$this->DebugMessage('ImageCreateFunction('.($scale_x * imagesx($img_temp)).', '.($scale_y * imagesy($img_temp)).') failed', __FILE__, __LINE__);
3085
								}
3086
								imagedestroy($img_temp);
3087
							} else {
3088
								$this->DebugMessage('ImageCreateFunction('.imagesx($this->gdimg_output).', '.imagesy($this->gdimg_output).') failed', __FILE__, __LINE__);
3089
							}
3090
						}
3091
						break;
3092
3093
					case 'rot': // ROTate
3094
						@list($angle, $bgcolor) = explode('|', $parameter, 2);
3095
						$phpthumbFilters->ImprovedImageRotate($this->gdimg_output, $angle, $bgcolor, null, $this);
3096
						break;
3097
3098
					case 'stc': // Source Transparent Color
3099
						@list($hexcolor, $min_limit, $max_limit) = explode('|', $parameter, 3);
3100
						if (!phpthumb_functions::IsHexColor($hexcolor)) {
3101
							$this->DebugMessage('Skipping SourceTransparentColor hex color is invalid ('.$hexcolor.')', __FILE__, __LINE__);
3102
							return false;
3103
						}
3104
						$min_limit = (strlen($min_limit) ? $min_limit :  5);
3105
						$max_limit = (strlen($max_limit) ? $max_limit : 10);
3106
						if ($gdimg_mask = $phpthumbFilters->SourceTransparentColorMask($this->gdimg_output, $hexcolor, $min_limit, $max_limit)) {
3107
							$this->is_alpha = true;
3108
							$phpthumbFilters->ApplyMask($gdimg_mask, $this->gdimg_output);
3109
							imagedestroy($gdimg_mask);
3110
						} else {
3111
							$this->DebugMessage('SourceTransparentColorMask() failed for "'.$hexcolor.','.$min_limit.','.$max_limit.'"', __FILE__, __LINE__);
3112
						}
3113
						break;
3114
				}
3115
				$this->DebugMessage('Finished processing filter command "'.$command.'('.$parameter.')"', __FILE__, __LINE__);
3116
			}
3117
		}
3118
		return true;
3119
	}
3120
3121
3122
	public function MaxFileSize() {
3123
		if (phpthumb_functions::gd_version() < 2) {
3124
			$this->DebugMessage('Skipping MaxFileSize() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
3125
			return false;
3126
		}
3127
		if ($this->maxb > 0) {
3128
			switch ($this->thumbnailFormat) {
3129
				case 'png':
3130
				case 'gif':
3131
					$imgRenderFunction = 'image'.$this->thumbnailFormat;
3132
3133
					ob_start();
3134
					$imgRenderFunction($this->gdimg_output);
3135
					$imgdata = ob_get_contents();
3136
					ob_end_clean();
3137
3138
					if (strlen($imgdata) > $this->maxb) {
3139
						for ($i = 8; $i >= 1; $i--) {
3140
							$tempIMG = imagecreatetruecolor(imagesx($this->gdimg_output), imagesy($this->gdimg_output));
3141
							imagecopy($tempIMG, $this->gdimg_output, 0, 0, 0, 0, imagesx($this->gdimg_output), imagesy($this->gdimg_output));
3142
							imagetruecolortopalette($tempIMG, true, pow(2, $i));
3143
							ob_start();
3144
							$imgRenderFunction($tempIMG);
3145
							$imgdata = ob_get_contents();
3146
							ob_end_clean();
3147
3148
							if (strlen($imgdata) <= $this->maxb) {
3149
								imagetruecolortopalette($this->gdimg_output, true, pow(2, $i));
3150
								break;
3151
							}
3152
						}
3153
					}
3154
					break;
3155
3156
				case 'jpeg':
3157
					ob_start();
3158
					imagejpeg($this->gdimg_output);
3159
					$imgdata = ob_get_contents();
3160
					ob_end_clean();
3161
3162
					if (strlen($imgdata) > $this->maxb) {
3163
						for ($i = 3; $i < 20; $i++) {
3164
							$q = round(100 * (1 - log10($i / 2)));
3165
							ob_start();
3166
							imagejpeg($this->gdimg_output, null, $q);
0 ignored issues
show
Bug introduced by
$q of type double is incompatible with the type integer expected by parameter $quality of imagejpeg(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

3166
							imagejpeg($this->gdimg_output, null, /** @scrutinizer ignore-type */ $q);
Loading history...
3167
							$imgdata = ob_get_contents();
3168
							ob_end_clean();
3169
3170
							$this->thumbnailQuality = $q;
3171
							if (strlen($imgdata) <= $this->maxb) {
3172
								break;
3173
							}
3174
						}
3175
					}
3176
					if (strlen($imgdata) > $this->maxb) {
3177
						return false;
3178
					}
3179
					break;
3180
3181
				default:
3182
					return false;
3183
			}
3184
		}
3185
		return true;
3186
	}
3187
3188
3189
	public function CalculateThumbnailDimensions() {
3190
		$this->DebugMessage('CalculateThumbnailDimensions() starting with [W,H,sx,sy,sw,sh] initially set to ['.$this->source_width.','.$this->source_height.','.$this->sx.','.$this->sy.','.$this->sw.','.$this->sh.']', __FILE__, __LINE__);
3191
//echo $this->source_width.'x'.$this->source_height.'<hr>';
3192
		$this->thumbnailCropX = ($this->sx ? (($this->sx >= 2) ? $this->sx : round($this->sx * $this->source_width))  : 0);
3193
//echo $this->thumbnailCropX.'<br>';
3194
		$this->thumbnailCropY = ($this->sy ? (($this->sy >= 2) ? $this->sy : round($this->sy * $this->source_height)) : 0);
3195
//echo $this->thumbnailCropY.'<br>';
3196
		$this->thumbnailCropW = ($this->sw ? (($this->sw >= 2) ? $this->sw : round($this->sw * $this->source_width))  : $this->source_width);
3197
//echo $this->thumbnailCropW.'<br>';
3198
		$this->thumbnailCropH = ($this->sh ? (($this->sh >= 2) ? $this->sh : round($this->sh * $this->source_height)) : $this->source_height);
3199
//echo $this->thumbnailCropH.'<hr>';
3200
3201
		// limit source area to original image area
3202
		$this->thumbnailCropW = max(1, min($this->thumbnailCropW, $this->source_width  - $this->thumbnailCropX));
3203
		$this->thumbnailCropH = max(1, min($this->thumbnailCropH, $this->source_height - $this->thumbnailCropY));
3204
3205
		$this->DebugMessage('CalculateThumbnailDimensions() starting with [x,y,w,h] initially set to ['.$this->thumbnailCropX.','.$this->thumbnailCropY.','.$this->thumbnailCropW.','.$this->thumbnailCropH.']', __FILE__, __LINE__);
3206
3207
3208
		if ($this->zc && $this->w && $this->h) {
3209
			// Zoom Crop
3210
			// retain proportional resizing we did above, but crop off larger dimension so smaller
3211
			// dimension fully fits available space
3212
3213
			$scaling_X = $this->source_width  / $this->w;
3214
			$scaling_Y = $this->source_height / $this->h;
3215
			if ($scaling_X > $scaling_Y) {
3216
				// some of the width will need to be cropped
3217
				$allowable_width = $this->source_width / $scaling_X * $scaling_Y;
3218
				$this->thumbnailCropW = round($allowable_width);
3219
				$this->thumbnailCropX = round(($this->source_width - $allowable_width) / 2);
3220
3221
			} elseif ($scaling_Y > $scaling_X) {
3222
				// some of the height will need to be cropped
3223
				$allowable_height = $this->source_height / $scaling_Y * $scaling_X;
3224
				$this->thumbnailCropH = round($allowable_height);
3225
				$this->thumbnailCropY = round(($this->source_height - $allowable_height) / 2);
3226
3227
			} else {
0 ignored issues
show
Unused Code introduced by
This else statement is empty and can be removed.

This check looks for the else branches of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These else branches can be removed.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

Loading history...
3228
				// image fits perfectly, no cropping needed
3229
			}
3230
			$this->thumbnail_width  = $this->w;
3231
			$this->thumbnail_height = $this->h;
3232
			$this->thumbnail_image_width  = $this->thumbnail_width;
3233
			$this->thumbnail_image_height = $this->thumbnail_height;
3234
3235
		} elseif ($this->iar && $this->w && $this->h) {
3236
3237
			// Ignore Aspect Ratio
3238
			// stretch image to fit exactly 'w' x 'h'
3239
			$this->thumbnail_width  = $this->w;
3240
			$this->thumbnail_height = $this->h;
3241
			$this->thumbnail_image_width  = $this->thumbnail_width;
3242
			$this->thumbnail_image_height = $this->thumbnail_height;
3243
3244
		} else {
3245
3246
			$original_aspect_ratio = $this->thumbnailCropW / $this->thumbnailCropH;
3247
			if ($this->aoe) {
3248
				if ($this->w && $this->h) {
3249
					$maxwidth  = min($this->w, $this->h * $original_aspect_ratio);
3250
					$maxheight = min($this->h, $this->w / $original_aspect_ratio);
3251
				} elseif ($this->w) {
3252
					$maxwidth  = $this->w;
3253
					$maxheight = $this->w / $original_aspect_ratio;
3254
				} elseif ($this->h) {
3255
					$maxwidth  = $this->h * $original_aspect_ratio;
3256
					$maxheight = $this->h;
3257
				} else {
3258
					$maxwidth  = $this->thumbnailCropW;
3259
					$maxheight = $this->thumbnailCropH;
3260
				}
3261
			} else {
3262
				$maxwidth  = phpthumb_functions::nonempty_min($this->w, $this->thumbnailCropW, $this->config_output_maxwidth);
3263
				$maxheight = phpthumb_functions::nonempty_min($this->h, $this->thumbnailCropH, $this->config_output_maxheight);
3264
//echo $maxwidth.'x'.$maxheight.'<br>';
3265
				$maxwidth  = min($maxwidth, $maxheight * $original_aspect_ratio);
3266
				$maxheight = min($maxheight, $maxwidth / $original_aspect_ratio);
3267
//echo $maxwidth.'x'.$maxheight.'<hr>';
3268
			}
3269
3270
			$this->thumbnail_image_width  = $maxwidth;
3271
			$this->thumbnail_image_height = $maxheight;
3272
			$this->thumbnail_width  = $maxwidth;
3273
			$this->thumbnail_height = $maxheight;
3274
3275
			$this->FixedAspectRatio();
3276
		}
3277
3278
		$this->thumbnail_width  = max(1, floor($this->thumbnail_width));
3279
		$this->thumbnail_height = max(1, floor($this->thumbnail_height));
3280
		return true;
3281
	}
3282
3283
3284
	public function CreateGDoutput() {
3285
		$this->CalculateThumbnailDimensions();
3286
3287
		// create the GD image (either true-color or 256-color, depending on GD version)
3288
		$this->gdimg_output = phpthumb_functions::ImageCreateFunction($this->thumbnail_width, $this->thumbnail_height);
3289
3290
		// images that have transparency must have the background filled with the configured 'bg' color otherwise the transparent color will appear as black
3291
		imagesavealpha($this->gdimg_output, true);
3292
		if ($this->is_alpha && phpthumb_functions::gd_version() >= 2) {
3293
3294
			imagealphablending($this->gdimg_output, false);
3295
			$output_full_alpha = phpthumb_functions::ImageColorAllocateAlphaSafe($this->gdimg_output, 255, 255, 255, 127);
3296
			imagefilledrectangle($this->gdimg_output, 0, 0, $this->thumbnail_width, $this->thumbnail_height, $output_full_alpha);
3297
3298
		} else {
3299
3300
			$current_transparent_color = imagecolortransparent($this->gdimg_source);
3301
			if ($this->bg || (@$current_transparent_color >= 0)) {
3302
3303
				$this->config_background_hexcolor = ($this->bg ? $this->bg : $this->config_background_hexcolor);
3304
				if (!phpthumb_functions::IsHexColor($this->config_background_hexcolor)) {
3305
					return $this->ErrorImage('Invalid hex color string "'.$this->config_background_hexcolor.'" for parameter "bg"');
3306
				}
3307
				$background_color = phpthumb_functions::ImageHexColorAllocate($this->gdimg_output, $this->config_background_hexcolor);
3308
				imagefilledrectangle($this->gdimg_output, 0, 0, $this->thumbnail_width, $this->thumbnail_height, $background_color);
3309
3310
			}
3311
3312
		}
3313
		$this->DebugMessage('CreateGDoutput() returning canvas "'.$this->thumbnail_width.'x'.$this->thumbnail_height.'"', __FILE__, __LINE__);
3314
		return true;
3315
	}
3316
3317
	public function SetOrientationDependantWidthHeight() {
3318
		$this->DebugMessage('SetOrientationDependantWidthHeight() starting with "'.$this->source_width.'"x"'.$this->source_height.'"', __FILE__, __LINE__);
3319
		if ($this->source_height > $this->source_width) {
3320
			// portrait
3321
			$this->w = phpthumb_functions::OneOfThese($this->wp, $this->w, $this->ws, $this->wl);
3322
			$this->h = phpthumb_functions::OneOfThese($this->hp, $this->h, $this->hs, $this->hl);
3323
		} elseif ($this->source_height < $this->source_width) {
3324
			// landscape
3325
			$this->w = phpthumb_functions::OneOfThese($this->wl, $this->w, $this->ws, $this->wp);
3326
			$this->h = phpthumb_functions::OneOfThese($this->hl, $this->h, $this->hs, $this->hp);
3327
		} else {
3328
			// square
3329
			$this->w = phpthumb_functions::OneOfThese($this->ws, $this->w, $this->wl, $this->wp);
3330
			$this->h = phpthumb_functions::OneOfThese($this->hs, $this->h, $this->hl, $this->hp);
3331
		}
3332
		//$this->w = round($this->w ? $this->w : (($this->h && $this->source_height) ? $this->h * $this->source_width  / $this->source_height : $this->w));
3333
		//$this->h = round($this->h ? $this->h : (($this->w && $this->source_width)  ? $this->w * $this->source_height / $this->source_width  : $this->h));
3334
		$this->DebugMessage('SetOrientationDependantWidthHeight() setting w="'. (int) $this->w .'", h="'. (int) $this->h .'"', __FILE__, __LINE__);
3335
		return true;
3336
	}
3337
3338
	public function ExtractEXIFgetImageSize() {
3339
		$this->DebugMessage('starting ExtractEXIFgetImageSize()', __FILE__, __LINE__);
3340
3341
		if (preg_match('#^http:#i', $this->src) && !$this->sourceFilename && $this->rawImageData) {
3342
			$this->SourceDataToTempFile();
3343
		}
3344
		if (null === $this->getimagesizeinfo) {
3345
			if ($this->sourceFilename) {
3346
				$this->getimagesizeinfo = @getimagesize($this->sourceFilename);
3347
				$this->source_width  = $this->getimagesizeinfo[0];
3348
				$this->source_height = $this->getimagesizeinfo[1];
3349
				$this->DebugMessage('getimagesize('.$this->sourceFilename.') says image is '.$this->source_width.'x'.$this->source_height, __FILE__, __LINE__);
3350
			} else {
3351
				$this->DebugMessage('skipping getimagesize() because $this->sourceFilename is empty', __FILE__, __LINE__);
3352
			}
3353
		} else {
3354
			$this->DebugMessage('skipping getimagesize() because !is_null($this->getimagesizeinfo)', __FILE__, __LINE__);
3355
		}
3356
3357
		if (is_resource($this->gdimg_source)) {
3358
3359
			$this->source_width  = imagesx($this->gdimg_source);
3360
			$this->source_height = imagesy($this->gdimg_source);
3361
3362
			$this->SetOrientationDependantWidthHeight();
3363
3364
		} elseif ($this->rawImageData && !$this->sourceFilename) {
3365
3366
			if ($this->SourceImageIsTooLarge($this->source_width, $this->source_height)) {
3367
				$this->DebugMessage('NOT bypassing EXIF and getimagesize sections because source image is too large for GD ('.$this->source_width.'x'.$this->source_width.'='.($this->source_width * $this->source_height * 5).'MB)', __FILE__, __LINE__);
3368
			} else {
3369
				$this->DebugMessage('bypassing EXIF and getimagesize sections because $this->rawImageData is set, and $this->sourceFilename is not set, and source image is not too large for GD ('.$this->source_width.'x'.$this->source_width.'='.($this->source_width * $this->source_height * 5).'MB)', __FILE__, __LINE__);
3370
			}
3371
3372
		}
3373
3374
		if (!empty($this->getimagesizeinfo)) {
3375
			// great
3376
			$this->getimagesizeinfo['filesize'] = @filesize($this->sourceFilename);
3377
		} elseif (!$this->rawImageData) {
3378
			$this->DebugMessage('getimagesize("'.$this->sourceFilename.'") failed', __FILE__, __LINE__);
3379
		}
3380
3381
		if ($this->config_prefer_imagemagick) {
3382
			if ($this->ImageMagickThumbnailToGD()) {
3383
				return true;
3384
			}
3385
			$this->DebugMessage('ImageMagickThumbnailToGD() failed', __FILE__, __LINE__);
3386
		}
3387
3388
		$this->source_width  = $this->getimagesizeinfo[0];
3389
		$this->source_height = $this->getimagesizeinfo[1];
3390
3391
		$this->SetOrientationDependantWidthHeight();
3392
3393
		if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '4.2.0', '>=') && function_exists('exif_read_data')) {
3394
			switch ($this->getimagesizeinfo[2]) {
3395
				case IMAGETYPE_JPEG:
3396
				case IMAGETYPE_TIFF_II:
3397
				case IMAGETYPE_TIFF_MM:
3398
					$this->exif_raw_data = @exif_read_data($this->sourceFilename, 0, true);
3399
					break;
3400
			}
3401
		}
3402
		if (function_exists('exif_thumbnail') && ($this->getimagesizeinfo[2] == IMAGETYPE_JPEG)) {
3403
			// Extract EXIF info from JPEGs
3404
3405
			$this->exif_thumbnail_width  = '';
3406
			$this->exif_thumbnail_height = '';
3407
			$this->exif_thumbnail_type   = '';
3408
3409
			// The parameters width, height and imagetype are available since PHP v4.3.0
3410
			if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '4.3.0', '>=')) {
3411
3412
				$this->exif_thumbnail_data = @exif_thumbnail($this->sourceFilename, $this->exif_thumbnail_width, $this->exif_thumbnail_height, $this->exif_thumbnail_type);
0 ignored issues
show
Bug introduced by
$this->exif_thumbnail_width of type string is incompatible with the type integer expected by parameter $width of exif_thumbnail(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

3412
				$this->exif_thumbnail_data = @exif_thumbnail($this->sourceFilename, /** @scrutinizer ignore-type */ $this->exif_thumbnail_width, $this->exif_thumbnail_height, $this->exif_thumbnail_type);
Loading history...
Bug introduced by
$this->exif_thumbnail_type of type string is incompatible with the type integer expected by parameter $imagetype of exif_thumbnail(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

3412
				$this->exif_thumbnail_data = @exif_thumbnail($this->sourceFilename, $this->exif_thumbnail_width, $this->exif_thumbnail_height, /** @scrutinizer ignore-type */ $this->exif_thumbnail_type);
Loading history...
Bug introduced by
$this->exif_thumbnail_height of type string is incompatible with the type integer expected by parameter $height of exif_thumbnail(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

3412
				$this->exif_thumbnail_data = @exif_thumbnail($this->sourceFilename, $this->exif_thumbnail_width, /** @scrutinizer ignore-type */ $this->exif_thumbnail_height, $this->exif_thumbnail_type);
Loading history...
3413
3414
			} else {
3415
3416
				// older versions of exif_thumbnail output an error message but NOT return false on failure
3417
				ob_start();
3418
				$this->exif_thumbnail_data = exif_thumbnail($this->sourceFilename);
3419
				$exit_thumbnail_error = ob_get_contents();
3420
				ob_end_clean();
3421
				if (!$exit_thumbnail_error && $this->exif_thumbnail_data) {
3422
3423
					if ($gdimg_exif_temp = $this->ImageCreateFromStringReplacement($this->exif_thumbnail_data, false)) {
3424
						$this->exif_thumbnail_width  = imagesx($gdimg_exif_temp);
3425
						$this->exif_thumbnail_height = imagesy($gdimg_exif_temp);
3426
						$this->exif_thumbnail_type   = 2; // (2 == JPEG) before PHP v4.3.0 only JPEG format EXIF thumbnails are returned
3427
						unset($gdimg_exif_temp);
3428
					} else {
3429
						return $this->ErrorImage('Failed - $this->ImageCreateFromStringReplacement($this->exif_thumbnail_data) in '.__FILE__.' on line '.__LINE__);
3430
					}
3431
3432
				}
3433
3434
			}
3435
3436
		} elseif (!function_exists('exif_thumbnail')) {
3437
3438
			$this->DebugMessage('exif_thumbnail() does not exist, cannot extract EXIF thumbnail', __FILE__, __LINE__);
3439
3440
		}
3441
3442
		$this->DebugMessage('EXIF thumbnail extraction: (size='.strlen($this->exif_thumbnail_data).'; type="'.$this->exif_thumbnail_type.'"; '. (int) $this->exif_thumbnail_width .'x'. (int) $this->exif_thumbnail_height .')', __FILE__, __LINE__);
3443
3444
		// see if EXIF thumbnail can be used directly with no processing
3445
		if ($this->config_use_exif_thumbnail_for_speed && $this->exif_thumbnail_data) {
3446
			while (true) {
3447
				if (!$this->xto) {
3448
					$source_ar = $this->source_width / $this->source_height;
3449
					$exif_ar = $this->exif_thumbnail_width / $this->exif_thumbnail_height;
3450
					if (number_format($source_ar, 2) != number_format($exif_ar, 2)) {
3451
						$this->DebugMessage('not using EXIF thumbnail because $source_ar != $exif_ar ('.$source_ar.' != '.$exif_ar.')', __FILE__, __LINE__);
3452
						break;
3453
					}
3454
					if ($this->w && ($this->w != $this->exif_thumbnail_width)) {
3455
						$this->DebugMessage('not using EXIF thumbnail because $this->w != $this->exif_thumbnail_width ('.$this->w.' != '.$this->exif_thumbnail_width.')', __FILE__, __LINE__);
3456
						break;
3457
					}
3458
					if ($this->h && ($this->h != $this->exif_thumbnail_height)) {
3459
						$this->DebugMessage('not using EXIF thumbnail because $this->h != $this->exif_thumbnail_height ('.$this->h.' != '.$this->exif_thumbnail_height.')', __FILE__, __LINE__);
3460
						break;
3461
					}
3462
					$CannotBeSetParameters = array('sx', 'sy', 'sh', 'sw', 'far', 'bg', 'bc', 'fltr', 'phpThumbDebug');
3463
					foreach ($CannotBeSetParameters as $parameter) {
3464
						if ($this->$parameter) {
3465
							break 2;
3466
						}
3467
					}
3468
				}
3469
3470
				$this->DebugMessage('setting $this->gdimg_source = $this->ImageCreateFromStringReplacement($this->exif_thumbnail_data)', __FILE__, __LINE__);
3471
				$this->gdimg_source = $this->ImageCreateFromStringReplacement($this->exif_thumbnail_data);
3472
				$this->source_width  = imagesx($this->gdimg_source);
3473
				$this->source_height = imagesy($this->gdimg_source);
3474
				return true;
3475
			}
3476
		}
3477
3478
		if (($this->config_max_source_pixels > 0) && (($this->source_width * $this->source_height) > $this->config_max_source_pixels)) {
3479
3480
			// Source image is larger than would fit in available PHP memory.
3481
			// If ImageMagick is installed, use it to generate the thumbnail.
3482
			// Else, if an EXIF thumbnail is available, use that as the source image.
3483
			// Otherwise, no choice but to fail with an error message
3484
			$this->DebugMessage('image is '.$this->source_width.'x'.$this->source_height.' and therefore contains more pixels ('.($this->source_width * $this->source_height).') than $this->config_max_source_pixels setting ('.$this->config_max_source_pixels.')', __FILE__, __LINE__);
3485
			if (!$this->config_prefer_imagemagick && $this->ImageMagickThumbnailToGD()) {
3486
				// excellent, we have a thumbnailed source image
3487
				return true;
3488
			}
3489
3490
		}
3491
		return true;
3492
	}
3493
3494
3495
	public function SetCacheFilename() {
3496
		if (null !== $this->cache_filename) {
3497
			$this->DebugMessage('$this->cache_filename already set, skipping SetCacheFilename()', __FILE__, __LINE__);
3498
			return true;
3499
		}
3500
		if (null === $this->config_cache_directory) {
3501
			$this->setCacheDirectory();
3502
			if (!$this->config_cache_directory) {
3503
				$this->DebugMessage('SetCacheFilename() failed because $this->config_cache_directory is empty', __FILE__, __LINE__);
3504
				return false;
3505
			}
3506
		}
3507
		$this->setOutputFormat();
3508
3509
		if (!$this->sourceFilename && !$this->rawImageData && $this->src) {
3510
			$this->sourceFilename = $this->ResolveFilenameToAbsolute($this->src);
3511
		}
3512
3513
		if ($this->config_cache_default_only_suffix && $this->sourceFilename) {
3514
			// simplified cache filenames:
3515
			// only use default parameters in phpThumb.config.php
3516
			// substitute source filename into * in $this->config_cache_default_only_suffix
3517
			// (eg: '*_thumb' becomes 'picture_thumb.jpg')
3518
			if (strpos($this->config_cache_default_only_suffix, '*') === false) {
0 ignored issues
show
Bug introduced by
$this->config_cache_default_only_suffix of type true is incompatible with the type string expected by parameter $haystack of strpos(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

3518
			if (strpos(/** @scrutinizer ignore-type */ $this->config_cache_default_only_suffix, '*') === false) {
Loading history...
3519
				$this->DebugMessage('aborting simplified caching filename because no * in "'.$this->config_cache_default_only_suffix.'"', __FILE__, __LINE__);
0 ignored issues
show
Bug introduced by
Are you sure $this->config_cache_default_only_suffix of type true can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

3519
				$this->DebugMessage('aborting simplified caching filename because no * in "'./** @scrutinizer ignore-type */ $this->config_cache_default_only_suffix.'"', __FILE__, __LINE__);
Loading history...
3520
			} else {
3521
				preg_match('#(.+)(\\.[a-z0-9]+)?$#i', basename($this->sourceFilename), $matches);
3522
				$this->cache_filename = $this->config_cache_directory.DIRECTORY_SEPARATOR.rawurlencode(str_replace('*', @$matches[1], $this->config_cache_default_only_suffix)).'.'.strtolower($this->thumbnailFormat);
3523
				return true;
3524
			}
3525
		}
3526
3527
		$this->cache_filename = '';
3528
		if ($this->new) {
3529
			$broad_directory_name = strtolower(md5($this->new));
3530
			$this->cache_filename .= '_new'.$broad_directory_name;
3531
		} elseif ($this->md5s) {
3532
			// source image MD5 hash provided
3533
			$this->DebugMessage('SetCacheFilename() _raw set from $this->md5s = "'.$this->md5s.'"', __FILE__, __LINE__);
3534
			$broad_directory_name = $this->md5s;
3535
			$this->cache_filename .= '_raw'.$this->md5s;
3536
		} elseif (!$this->src && $this->rawImageData) {
3537
			$this->DebugMessage('SetCacheFilename() _raw set from md5($this->rawImageData) = "'.md5($this->rawImageData).'"', __FILE__, __LINE__);
3538
			$broad_directory_name = strtolower(md5($this->rawImageData));
3539
			$this->cache_filename .= '_raw'.$broad_directory_name;
3540
		} else {
3541
			$this->DebugMessage('SetCacheFilename() _src set from md5($this->sourceFilename) "'.$this->sourceFilename.'" = "'.md5($this->sourceFilename).'"', __FILE__, __LINE__);
3542
			$broad_directory_name = strtolower(md5($this->sourceFilename));
3543
			$this->cache_filename .= '_src'.$broad_directory_name;
3544
		}
3545
		if (!empty($_SERVER['HTTP_REFERER']) && $this->config_nooffsitelink_enabled) {
3546
			$parsed_url1 = @phpthumb_functions::ParseURLbetter(@$_SERVER['HTTP_REFERER']);
3547
			$parsed_url2 = @phpthumb_functions::ParseURLbetter('http://'.@$_SERVER['HTTP_HOST']);
3548
			if (@$parsed_url1['host'] && @$parsed_url2['host'] && ($parsed_url1['host'] != $parsed_url2['host'])) {
3549
				// include "_offsite" only if nooffsitelink_enabled and if referrer doesn't match the domain of the current server
3550
				$this->cache_filename .= '_offsite';
3551
			}
3552
		}
3553
3554
		$ParametersString = '';
3555
		if ($this->fltr && is_array($this->fltr)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->fltr of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
3556
			$ParametersString .= '_fltr'.implode('_fltr', $this->fltr);
3557
		}
3558
		$FilenameParameters1 = array('ar', 'bg', 'bc', 'far', 'sx', 'sy', 'sw', 'sh', 'zc');
3559
		foreach ($FilenameParameters1 as $key) {
3560
			if ($this->$key) {
3561
				$ParametersString .= '_'.$key.$this->$key;
3562
			}
3563
		}
3564
		$FilenameParameters2 = array('h', 'w', 'wl', 'wp', 'ws', 'hp', 'hs', 'xto', 'ra', 'iar', 'aoe', 'maxb', 'sfn', 'dpi');
3565
		foreach ($FilenameParameters2 as $key) {
3566
			if ($this->$key) {
3567
				$ParametersString .= '_'.$key. (int) $this->$key;
3568
			}
3569
		}
3570
		if ($this->thumbnailFormat == 'jpeg') {
3571
			// only JPEG output has variable quality option
3572
			$ParametersString .= '_q'. (int) $this->thumbnailQuality;
3573
		}
3574
		$this->DebugMessage('SetCacheFilename() _par set from md5('.$ParametersString.')', __FILE__, __LINE__);
3575
		$this->cache_filename .= '_par'.strtolower(md5($ParametersString));
3576
3577
		if ($this->md5s) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
3578
			// source image MD5 hash provided
3579
			// do not source image modification date --
3580
			// cached image will be used even if file was modified or removed
3581
		} elseif (!$this->config_cache_source_filemtime_ignore_remote && preg_match('#^(f|ht)tps?\://#i', $this->src)) {
3582
			$this->cache_filename .= '_dat'. (int) phpthumb_functions::filedate_remote($this->src);
3583
		} elseif (!$this->config_cache_source_filemtime_ignore_local && $this->src && !$this->rawImageData) {
3584
			$this->cache_filename .= '_dat'. (int) (@filemtime($this->sourceFilename));
3585
		}
3586
3587
		$this->cache_filename .= '.'.strtolower($this->thumbnailFormat);
3588
		$broad_directories = '';
3589
		for ($i = 0; $i < $this->config_cache_directory_depth; $i++) {
3590
			$broad_directories .= DIRECTORY_SEPARATOR.substr($broad_directory_name, 0, $i + 1);
3591
		}
3592
3593
		$this->cache_filename = $this->config_cache_directory.$broad_directories.DIRECTORY_SEPARATOR.$this->config_cache_prefix.rawurlencode($this->cache_filename);
3594
		return true;
3595
	}
3596
3597
3598
	public function SourceImageIsTooLarge($width, $height) {
3599
		if (!$this->config_max_source_pixels) {
3600
			return false;
3601
		}
3602
		if ($this->php_memory_limit && function_exists('memory_get_usage')) {
3603
			$available_memory = $this->php_memory_limit - memory_get_usage();
3604
			return (bool) (($width * $height * 5) > $available_memory);
3605
		}
3606
		return (bool) (($width * $height) > $this->config_max_source_pixels);
3607
	}
3608
3609
	public function ImageCreateFromFilename($filename) {
3610
		// try to create GD image source directly via GD, if possible,
3611
		// rather than buffering to memory and creating with imagecreatefromstring
3612
		$ImageCreateWasAttempted = false;
3613
		$gd_image = false;
3614
3615
		$this->DebugMessage('starting ImageCreateFromFilename('.$filename.')', __FILE__, __LINE__);
3616
		if ($filename && ($getimagesizeinfo = @getimagesize($filename))) {
3617
			if (!$this->SourceImageIsTooLarge($getimagesizeinfo[0], $getimagesizeinfo[1])) {
3618
				$ImageCreateFromFunction = array(
3619
					1  => 'imagecreatefromgif',
3620
					2  => 'imagecreatefromjpeg',
3621
					3  => 'imagecreatefrompng',
3622
					15 => 'imagecreatefromwbmp',
3623
				);
3624
				$this->DebugMessage('ImageCreateFromFilename found ($getimagesizeinfo[2]=='.@$getimagesizeinfo[2].')', __FILE__, __LINE__);
3625
				switch (@$getimagesizeinfo[2]) {
3626
					case 1:  // GIF
3627
					case 2:  // JPEG
3628
					case 3:  // PNG
3629
					case 15: // WBMP
3630
						$ImageCreateFromFunctionName = $ImageCreateFromFunction[$getimagesizeinfo[2]];
3631
						if (function_exists($ImageCreateFromFunctionName)) {
3632
							$this->DebugMessage('Calling '.$ImageCreateFromFunctionName.'('.$filename.')', __FILE__, __LINE__);
3633
							$ImageCreateWasAttempted = true;
3634
							$gd_image = $ImageCreateFromFunctionName($filename);
3635
						} else {
3636
							$this->DebugMessage('NOT calling '.$ImageCreateFromFunctionName.'('.$filename.') because !function_exists('.$ImageCreateFromFunctionName.')', __FILE__, __LINE__);
3637
						}
3638
						break;
3639
3640
					case 4:  // SWF
3641
					case 5:  // PSD
3642
					case 6:  // BMP
3643
					case 7:  // TIFF (LE)
3644
					case 8:  // TIFF (BE)
3645
					case 9:  // JPC
3646
					case 10: // JP2
3647
					case 11: // JPX
3648
					case 12: // JB2
3649
					case 13: // SWC
3650
					case 14: // IFF
3651
					case 16: // XBM
3652
						$this->DebugMessage('No built-in image creation function for image type "'.@$getimagesizeinfo[2].'" ($getimagesizeinfo[2])', __FILE__, __LINE__);
3653
						break;
3654
3655
					default:
3656
						$this->DebugMessage('Unknown value for $getimagesizeinfo[2]: "'.@$getimagesizeinfo[2].'"', __FILE__, __LINE__);
3657
						break;
3658
				}
3659
			} else {
3660
				$this->DebugMessage('image is '.$getimagesizeinfo[0].'x'.$getimagesizeinfo[1].' and therefore contains more pixels ('.($getimagesizeinfo[0] * $getimagesizeinfo[1]).') than $this->config_max_source_pixels setting ('.$this->config_max_source_pixels.')', __FILE__, __LINE__);
3661
				return false;
3662
			}
3663
		} else {
3664
			$this->DebugMessage('empty $filename or getimagesize('.$filename.') failed', __FILE__, __LINE__);
3665
		}
3666
3667
		if (!$gd_image) {
3668
			// cannot create from filename, attempt to create source image with imagecreatefromstring, if possible
3669
			if ($ImageCreateWasAttempted) {
3670
				$this->DebugMessage($ImageCreateFromFunctionName.'() was attempted but FAILED', __FILE__, __LINE__);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $ImageCreateFromFunctionName does not seem to be defined for all execution paths leading up to this point.
Loading history...
3671
			}
3672
			$this->DebugMessage('Populating $rawimagedata', __FILE__, __LINE__);
3673
			$rawimagedata = '';
3674
			if ($fp = @fopen($filename, 'rb')) {
3675
				$filesize = filesize($filename);
3676
				$blocksize = 8192;
3677
				$blockreads = ceil($filesize / $blocksize);
3678
				for ($i = 0; $i < $blockreads; $i++) {
3679
					$rawimagedata .= fread($fp, $blocksize);
3680
				}
3681
				fclose($fp);
3682
			} else {
3683
				$this->DebugMessage('cannot fopen('.$filename.')', __FILE__, __LINE__);
3684
			}
3685
			if ($rawimagedata) {
3686
				$this->DebugMessage('attempting ImageCreateFromStringReplacement($rawimagedata ('.strlen($rawimagedata).' bytes), true)', __FILE__, __LINE__);
3687
				$gd_image = $this->ImageCreateFromStringReplacement($rawimagedata, true);
3688
			}
3689
		}
3690
		return $gd_image;
3691
	}
3692
3693
	public function SourceImageToGD() {
3694
		if (is_resource($this->gdimg_source)) {
3695
			$this->source_width  = imagesx($this->gdimg_source);
3696
			$this->source_height = imagesy($this->gdimg_source);
3697
			$this->DebugMessage('skipping SourceImageToGD() because $this->gdimg_source is already a resource ('.$this->source_width.'x'.$this->source_height.')', __FILE__, __LINE__);
3698
			return true;
3699
		}
3700
		$this->DebugMessage('starting SourceImageToGD()', __FILE__, __LINE__);
3701
3702
		if ($this->config_prefer_imagemagick) {
3703
			if (empty($this->sourceFilename) && !empty($this->rawImageData)) {
3704
				$this->DebugMessage('Copying raw image data to temp file and trying again with ImageMagick', __FILE__, __LINE__);
3705
				if ($tempnam = $this->phpThumb_tempnam()) {
3706
					if (file_put_contents($tempnam, $this->rawImageData)) {
3707
						$this->sourceFilename = $tempnam;
3708
						if ($this->ImageMagickThumbnailToGD()) {
3709
							// excellent, we have a thumbnailed source image
3710
							$this->DebugMessage('ImageMagickThumbnailToGD() succeeded', __FILE__, __LINE__);
3711
						} else {
3712
							$this->DebugMessage('ImageMagickThumbnailToGD() failed', __FILE__, __LINE__);
3713
						}
3714
						@chmod($tempnam, $this->getParameter('config_file_create_mask'));
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for chmod(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

3714
						/** @scrutinizer ignore-unhandled */ @chmod($tempnam, $this->getParameter('config_file_create_mask'));

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
3715
					} else {
3716
						$this->DebugMessage('failed to put $this->rawImageData into temp file "'.$tempnam.'"', __FILE__, __LINE__);
3717
					}
3718
				} else {
3719
					$this->DebugMessage('failed to generate temp file name', __FILE__, __LINE__);
3720
				}
3721
			}
3722
		}
3723
		if (!$this->gdimg_source && $this->rawImageData) {
3724
3725
			if ($this->SourceImageIsTooLarge($this->source_width, $this->source_height)) {
3726
				$memory_get_usage = (function_exists('memory_get_usage') ? memory_get_usage() : 0);
3727
				return $this->ErrorImage('Source image is too large ('.$this->source_width.'x'.$this->source_height.' = '.number_format($this->source_width * $this->source_height / 1000000, 1).'Mpx, max='.number_format($this->config_max_source_pixels / 1000000, 1).'Mpx) for GD creation (either install ImageMagick or increase PHP memory_limit to at least '.ceil(($memory_get_usage + (5 * $this->source_width * $this->source_height)) / 1048576).'M).');
3728
			}
3729
			if ($this->md5s && ($this->md5s != md5($this->rawImageData))) {
3730
				return $this->ErrorImage('$this->md5s != md5($this->rawImageData)'."\n".'"'.$this->md5s.'" != '."\n".'"'.md5($this->rawImageData).'"');
3731
			}
3732
			//if ($this->issafemode) {
3733
			//	return $this->ErrorImage('Cannot generate thumbnails from raw image data when PHP SAFE_MODE enabled');
3734
			//}
3735
			$this->gdimg_source = $this->ImageCreateFromStringReplacement($this->rawImageData);
3736
			if (!$this->gdimg_source) {
3737
				if (substr($this->rawImageData, 0, 2) === 'BM') {
3738
					$this->getimagesizeinfo[2] = 6; // BMP
3739
				} elseif (substr($this->rawImageData, 0, 4) === 'II'."\x2A\x00") {
3740
					$this->getimagesizeinfo[2] = 7; // TIFF (littlendian)
3741
				} elseif (substr($this->rawImageData, 0, 4) === 'MM'."\x00\x2A") {
3742
					$this->getimagesizeinfo[2] = 8; // TIFF (bigendian)
3743
				}
3744
				$this->DebugMessage('SourceImageToGD.ImageCreateFromStringReplacement() failed with unknown image type "'.substr($this->rawImageData, 0, 4).'" ('.phpthumb_functions::HexCharDisplay(substr($this->rawImageData, 0, 4)).')', __FILE__, __LINE__);
3745
//				return $this->ErrorImage('Unknown image type identified by "'.substr($this->rawImageData, 0, 4).'" ('.phpthumb_functions::HexCharDisplay(substr($this->rawImageData, 0, 4)).') in SourceImageToGD()['.__LINE__.']');
3746
			}
3747
3748
		} elseif (!$this->gdimg_source && $this->sourceFilename) {
3749
3750
			if ($this->md5s && ($this->md5s != phpthumb_functions::md5_file_safe($this->sourceFilename))) {
3751
				return $this->ErrorImage('$this->md5s != md5(sourceFilename)'."\n".'"'.$this->md5s.'" != '."\n".'"'.phpthumb_functions::md5_file_safe($this->sourceFilename).'"');
0 ignored issues
show
Bug introduced by
Are you sure phpthumb_functions::md5_...($this->sourceFilename) of type false|string can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

3751
				return $this->ErrorImage('$this->md5s != md5(sourceFilename)'."\n".'"'.$this->md5s.'" != '."\n".'"'./** @scrutinizer ignore-type */ phpthumb_functions::md5_file_safe($this->sourceFilename).'"');
Loading history...
3752
			}
3753
			switch (@$this->getimagesizeinfo[2]) {
3754
				case 1:
3755
				case 3:
3756
					// GIF or PNG input file may have transparency
3757
					$this->is_alpha = true;
3758
					break;
3759
			}
3760
			if (!$this->SourceImageIsTooLarge($this->source_width, $this->source_height)) {
3761
				$this->gdimg_source = $this->ImageCreateFromFilename($this->sourceFilename);
3762
			}
3763
3764
		}
3765
3766
		while (true) {
3767
			if ($this->gdimg_source) {
3768
				$this->DebugMessage('Not using EXIF thumbnail data because $this->gdimg_source is already set', __FILE__, __LINE__);
3769
				break;
3770
			}
3771
			if (!$this->exif_thumbnail_data) {
3772
				$this->DebugMessage('Not using EXIF thumbnail data because $this->exif_thumbnail_data is empty', __FILE__, __LINE__);
3773
				break;
3774
			}
3775
			if (ini_get('safe_mode')) {
3776
				if (!$this->SourceImageIsTooLarge($this->source_width, $this->source_height)) {
3777
					$this->DebugMessage('Using EXIF thumbnail data because source image too large and safe_mode enabled', __FILE__, __LINE__);
3778
					$this->aoe = true;
3779
				} else {
3780
					break;
3781
				}
3782
			} else {
3783
				if (!$this->config_use_exif_thumbnail_for_speed) {
3784
					$this->DebugMessage('Not using EXIF thumbnail data because $this->config_use_exif_thumbnail_for_speed is FALSE', __FILE__, __LINE__);
3785
					break;
3786
				}
3787
				if (($this->thumbnailCropX != 0) || ($this->thumbnailCropY != 0)) {
3788
					$this->DebugMessage('Not using EXIF thumbnail data because source cropping is enabled ('.$this->thumbnailCropX.','.$this->thumbnailCropY.')', __FILE__, __LINE__);
3789
					break;
3790
				}
3791
				if (($this->w > $this->exif_thumbnail_width) || ($this->h > $this->exif_thumbnail_height)) {
3792
					$this->DebugMessage('Not using EXIF thumbnail data because EXIF thumbnail is too small ('.$this->exif_thumbnail_width.'x'.$this->exif_thumbnail_height.' vs '.$this->w.'x'.$this->h.')', __FILE__, __LINE__);
3793
					break;
3794
				}
3795
				$source_ar = $this->source_width / $this->source_height;
3796
				$exif_ar   = $this->exif_thumbnail_width / $this->exif_thumbnail_height;
3797
				if (number_format($source_ar, 2) != number_format($exif_ar, 2)) {
3798
					$this->DebugMessage('not using EXIF thumbnail because $source_ar != $exif_ar ('.$source_ar.' != '.$exif_ar.')', __FILE__, __LINE__);
3799
					break;
3800
				}
3801
			}
3802
3803
			// EXIF thumbnail exists, and is equal to or larger than destination thumbnail, and will be use as source image
3804
			$this->DebugMessage('Trying to use EXIF thumbnail as source image', __FILE__, __LINE__);
3805
3806
			if ($gdimg_exif_temp = $this->ImageCreateFromStringReplacement($this->exif_thumbnail_data, false)) {
3807
3808
				$this->DebugMessage('Successfully using EXIF thumbnail as source image', __FILE__, __LINE__);
3809
				$this->gdimg_source   = $gdimg_exif_temp;
3810
				$this->source_width   = $this->exif_thumbnail_width;
3811
				$this->source_height  = $this->exif_thumbnail_height;
3812
				$this->thumbnailCropW = $this->source_width;
3813
				$this->thumbnailCropH = $this->source_height;
3814
				return true;
3815
3816
			} else {
3817
				$this->DebugMessage('$this->ImageCreateFromStringReplacement($this->exif_thumbnail_data, false) failed', __FILE__, __LINE__);
3818
			}
3819
3820
			break;
3821
		}
3822
3823
		if (!$this->gdimg_source) {
3824
			$this->DebugMessage('$this->gdimg_source is still empty', __FILE__, __LINE__);
3825
3826
			$this->DebugMessage('ImageMagickThumbnailToGD() failed', __FILE__, __LINE__);
3827
3828
			$imageHeader = '';
3829
			$gd_info = gd_info();
3830
			$GDreadSupport = false;
3831
			switch (@$this->getimagesizeinfo[2]) {
3832
				case 1:
3833
					$imageHeader = 'Content-Type: image/gif';
3834
					$GDreadSupport = (bool) @$gd_info['GIF Read Support'];
3835
					break;
3836
				case 2:
3837
					$imageHeader = 'Content-Type: image/jpeg';
3838
					$GDreadSupport = (bool) @$gd_info['JPG Support'];
3839
					break;
3840
				case 3:
3841
					$imageHeader = 'Content-Type: image/png';
3842
					$GDreadSupport = (bool) @$gd_info['PNG Support'];
3843
					break;
3844
			}
3845
			if ($imageHeader) {
3846
				// cannot create image for whatever reason (maybe imagecreatefromjpeg et al are not available?)
3847
				// and ImageMagick is not available either, no choice but to output original (not resized/modified) data and exit
3848
				if ($this->config_error_die_on_source_failure) {
3849
					$errormessages = array();
3850
					$errormessages[] = 'All attempts to create GD image source failed.';
3851
					if ($this->fatalerror) {
3852
						$errormessages[] = $this->fatalerror;
3853
					}
3854
					if ($this->issafemode) {
3855
						$errormessages[] = 'Safe Mode enabled, therefore ImageMagick is unavailable. (disable Safe Mode if possible)';
3856
					} elseif (!$this->ImageMagickVersion()) {
3857
						$errormessages[] = 'ImageMagick is not installed (it is highly recommended that you install it).';
3858
					}
3859
					if ($this->SourceImageIsTooLarge($this->getimagesizeinfo[0], $this->getimagesizeinfo[1])) {
3860
						$memory_get_usage = (function_exists('memory_get_usage') ? memory_get_usage() : 0);
3861
						$errormessages[] = 'Source image is too large ('.$this->getimagesizeinfo[0].'x'.$this->getimagesizeinfo[1].' = '.number_format($this->getimagesizeinfo[0] * $this->getimagesizeinfo[1] / 1000000, 1).'Mpx, max='.number_format($this->config_max_source_pixels / 1000000, 1).'Mpx) for GD creation (either install ImageMagick or increase PHP memory_limit to at least '.ceil(($memory_get_usage + (5 * $this->getimagesizeinfo[0] * $this->getimagesizeinfo[1])) / 1048576).'M).';
3862
					} elseif (!$GDreadSupport) {
3863
						$errormessages[] = 'GD does not have read support for "'.$imageHeader.'".';
3864
					} else {
3865
						$errormessages[] = 'Source image probably corrupt.';
3866
					}
3867
					$this->ErrorImage(implode("\n", $errormessages));
3868
3869
				} else {
3870
					$this->DebugMessage('All attempts to create GD image source failed ('.(ini_get('safe_mode') ? 'Safe Mode enabled, ImageMagick unavailable and source image probably too large for GD': ($GDreadSupport ? 'source image probably corrupt' : 'GD does not have read support for "'.$imageHeader.'"')).'), cannot generate thumbnail');
3871
					//$this->DebugMessage('All attempts to create GD image source failed ('.($GDreadSupport ? 'source image probably corrupt' : 'GD does not have read support for "'.$imageHeader.'"').'), outputing raw image', __FILE__, __LINE__);
3872
					//if (!$this->phpThumbDebug) {
3873
					//	header($imageHeader);
3874
					//	echo $this->rawImageData;
3875
					//	exit;
3876
					//}
3877
					return false;
3878
				}
3879
			}
3880
3881
			//switch (substr($this->rawImageData, 0, 2)) {
3882
			//	case 'BM':
3883
			switch (@$this->getimagesizeinfo[2]) {
3884
				case 6:
3885
					ob_start();
3886
					if (!@include_once( __DIR__ .'/phpthumb.bmp.php')) {
3887
						ob_end_clean();
3888
						return $this->ErrorImage('include_once('. __DIR__ .'/phpthumb.bmp.php) failed');
3889
					}
3890
					ob_end_clean();
3891
					if ($fp = @fopen($this->sourceFilename, 'rb')) {
3892
						$this->rawImageData = '';
3893
						while (!feof($fp)) {
3894
							$this->rawImageData .= fread($fp, 32768);
3895
						}
3896
						fclose($fp);
3897
					}
3898
					$phpthumb_bmp = new phpthumb_bmp();
3899
					$this->gdimg_source = $phpthumb_bmp->phpthumb_bmp2gd($this->rawImageData, (phpthumb_functions::gd_version() >= 2.0));
3900
					unset($phpthumb_bmp);
3901
					if ($this->gdimg_source) {
3902
						$this->DebugMessage('$phpthumb_bmp->phpthumb_bmp2gd() succeeded', __FILE__, __LINE__);
3903
					} else {
3904
						return $this->ErrorImage($this->ImageMagickVersion() ? 'ImageMagick failed on BMP source conversion' : 'phpthumb_bmp2gd() failed');
3905
					}
3906
					break;
3907
			//}
3908
			//switch (substr($this->rawImageData, 0, 4)) {
3909
			//	case 'II'."\x2A\x00":
3910
			//	case 'MM'."\x00\x2A":
3911
				case 7:
3912
				case 8:
3913
					return $this->ErrorImage($this->ImageMagickVersion() ? 'ImageMagick failed on TIFF source conversion' : 'ImageMagick is unavailable and phpThumb() does not support TIFF source images without it');
3914
					break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
3915
3916
				//case "\xD7\xCD\xC6\x9A":
3917
				//	return $this->ErrorImage($this->ImageMagickVersion() ? 'ImageMagick failed on WMF source conversion' : 'ImageMagick is unavailable and phpThumb() does not support WMF source images without it');
3918
				//	break;
3919
			}
3920
3921
			if (!$this->gdimg_source) {
3922
				if ($this->rawImageData) {
3923
					$HeaderFourBytes = substr($this->rawImageData, 0, 4);
3924
				} elseif ($this->sourceFilename) {
3925
					if ($fp = @fopen($this->sourceFilename, 'rb')) {
3926
						$HeaderFourBytes = fread($fp, 4);
3927
						fclose($fp);
3928
					} else {
3929
						return $this->ErrorImage('failed to open "'.$this->sourceFilename.'" SourceImageToGD() ['.__LINE__.']');
3930
					}
3931
				} else {
3932
					return $this->ErrorImage('Unable to create image, neither filename nor image data suppplied in SourceImageToGD() ['.__LINE__.']');
3933
				}
3934
				if (!$this->ImageMagickVersion() && !phpthumb_functions::gd_version()) {
3935
					return $this->ErrorImage('Neither GD nor ImageMagick seem to be installed on this server. At least one (preferably GD), or better both, MUST be installed for phpThumb to work.');
3936
				} elseif ($HeaderFourBytes == "\xD7\xCD\xC6\x9A") { // WMF
3937
					return $this->ErrorImage($this->ImageMagickVersion() ? 'ImageMagick failed on WMF source conversion' : 'ImageMagick is unavailable and phpThumb() does not support WMF source images without it');
3938
				} elseif ($HeaderFourBytes == '%PDF') { // "%PDF"
3939
					return $this->ErrorImage($this->ImageMagickVersion() ? 'ImageMagick and GhostScript are both required for PDF source images; GhostScript may not be properly configured' : 'ImageMagick and/or GhostScript are unavailable and phpThumb() does not support PDF source images without them');
3940
				} elseif (substr($HeaderFourBytes, 0, 3) == "\xFF\xD8\xFF") { // JPEG
3941
					return $this->ErrorImage('Image (JPEG) is too large for PHP-GD memory_limit, please install ImageMagick or increase php.ini memory_limit setting');
3942
				} elseif ($HeaderFourBytes == '%PNG') { // "%PNG"
3943
					return $this->ErrorImage('Image (PNG) is too large for PHP-GD memory_limit, please install ImageMagick or increase php.ini memory_limit setting');
3944
				} elseif (substr($HeaderFourBytes, 0, 3) == 'GIF') { // GIF
3945
					return $this->ErrorImage('Image (GIF) is too large for PHP-GD memory_limit, please install ImageMagick or increase php.ini memory_limit setting');
3946
				}
3947
				return $this->ErrorImage('Unknown image type identified by "'.$HeaderFourBytes.'" ('.phpthumb_functions::HexCharDisplay($HeaderFourBytes).') in SourceImageToGD() ['.__LINE__.']');
3948
			}
3949
		}
3950
3951
		if (!$this->gdimg_source) {
3952
			if ($gdimg_exif_temp = $this->ImageCreateFromStringReplacement($this->exif_thumbnail_data, false)) {
3953
				$this->DebugMessage('All other attempts failed, but successfully using EXIF thumbnail as source image', __FILE__, __LINE__);
3954
				$this->gdimg_source = $gdimg_exif_temp;
3955
				// override allow-enlarging setting if EXIF thumbnail is the only source available
3956
				// otherwise thumbnails larger than the EXIF thumbnail will be created at EXIF size
3957
				$this->aoe = true;
3958
				return true;
3959
			}
3960
			return false;
3961
		}
3962
3963
		$this->source_width  = imagesx($this->gdimg_source);
3964
		$this->source_height = imagesy($this->gdimg_source);
3965
		return true;
3966
	}
3967
3968
3969
	public function phpThumbDebugVarDump($var) {
3970
		if (null === $var) {
3971
			return 'NULL';
3972
		} elseif (is_bool($var)) {
3973
			return ($var ? 'TRUE' : 'FALSE');
3974
		} elseif (is_string($var)) {
3975
			return 'string('.strlen($var).')'.str_repeat(' ', max(0, 3 - strlen(strlen($var)))).' "'.$var.'"';
3976
		} elseif (is_int($var)) {
3977
			return 'integer     '.$var;
3978
		} elseif (is_float($var)) {
3979
			return 'float       '.$var;
3980
		} elseif (is_array($var)) {
3981
			ob_start();
3982
			var_dump($var);
0 ignored issues
show
Security Debugging Code introduced by
var_dump($var) looks like debug code. Are you sure you do not want to remove it?
Loading history...
3983
			$vardumpoutput = ob_get_contents();
3984
			ob_end_clean();
3985
			return strtr($vardumpoutput, "\n\r\t", '   ');
3986
		}
3987
		return gettype($var);
3988
	}
3989
3990
	public function phpThumbDebug($level='') {
3991
		if ($level && ($this->phpThumbDebug !== $level)) {
3992
			return true;
3993
		}
3994
		if ($this->config_disable_debug) {
3995
			return $this->ErrorImage('phpThumbDebug disabled');
3996
		}
3997
3998
		$FunctionsExistance  = array('exif_thumbnail', 'gd_info', 'image_type_to_mime_type', 'getimagesize', 'imagecopyresampled', 'imagecopyresized', 'imagecreate', 'imagecreatefromstring', 'imagecreatetruecolor', 'imageistruecolor', 'imagerotate', 'imagetypes', 'version_compare', 'imagecreatefromgif', 'imagecreatefromjpeg', 'imagecreatefrompng', 'imagecreatefromwbmp', 'imagecreatefromxbm', 'imagecreatefromxpm', 'imagecreatefromstring', 'imagecreatefromgd', 'imagecreatefromgd2', 'imagecreatefromgd2part', 'imagejpeg', 'imagegif', 'imagepng', 'imagewbmp');
3999
		$ParameterNames      = array('src', 'new', 'w', 'h', 'f', 'q', 'sx', 'sy', 'sw', 'sh', 'far', 'bg', 'bc', 'file', 'goto', 'err', 'xto', 'ra', 'ar', 'aoe', 'iar', 'maxb');
4000
		$ConfigVariableNames = array('document_root', 'temp_directory', 'output_format', 'output_maxwidth', 'output_maxheight', 'error_message_image_default', 'error_bgcolor', 'error_textcolor', 'error_fontsize', 'error_die_on_error', 'error_silent_die_on_error', 'error_die_on_source_failure', 'nohotlink_enabled', 'nohotlink_valid_domains', 'nohotlink_erase_image', 'nohotlink_text_message', 'nooffsitelink_enabled', 'nooffsitelink_valid_domains', 'nooffsitelink_require_refer', 'nooffsitelink_erase_image', 'nooffsitelink_text_message', 'high_security_enabled', 'allow_src_above_docroot', 'allow_src_above_phpthumb', 'max_source_pixels', 'use_exif_thumbnail_for_speed', 'border_hexcolor', 'background_hexcolor', 'ttf_directory', 'disable_pathinfo_parsing', 'disable_imagecopyresampled');
4001
		$OtherVariableNames  = array('phpThumbDebug', 'thumbnailQuality', 'thumbnailFormat', 'gdimg_output', 'gdimg_source', 'sourceFilename', 'source_width', 'source_height', 'thumbnailCropX', 'thumbnailCropY', 'thumbnailCropW', 'thumbnailCropH', 'exif_thumbnail_width', 'exif_thumbnail_height', 'exif_thumbnail_type', 'thumbnail_width', 'thumbnail_height', 'thumbnail_image_width', 'thumbnail_image_height');
4002
4003
		$DebugOutput = array();
4004
		$DebugOutput[] = 'phpThumb() version          = '.$this->phpthumb_version;
4005
		$DebugOutput[] = 'phpversion()                = '.@PHP_VERSION;
4006
		$DebugOutput[] = 'PHP_OS                      = '.PHP_OS;
4007
		$DebugOutput[] = '$_SERVER[SERVER_SOFTWARE]   = '.@$_SERVER['SERVER_SOFTWARE'];
4008
		$DebugOutput[] = '__FILE__                    = '.__FILE__;
4009
		$DebugOutput[] = 'realpath(.)                 = '.@realpath('.');
4010
		$DebugOutput[] = '$_SERVER[PHP_SELF]          = '.@$_SERVER['PHP_SELF'];
4011
		$DebugOutput[] = '$_SERVER[HOST_NAME]         = '.@$_SERVER['HOST_NAME'];
4012
		$DebugOutput[] = '$_SERVER[HTTP_REFERER]      = '.@$_SERVER['HTTP_REFERER'];
4013
		$DebugOutput[] = '$_SERVER[QUERY_STRING]      = '.@$_SERVER['QUERY_STRING'];
4014
		$DebugOutput[] = '$_SERVER[PATH_INFO]         = '.@$_SERVER['PATH_INFO'];
4015
		$DebugOutput[] = '$_SERVER[DOCUMENT_ROOT]     = '.@$_SERVER['DOCUMENT_ROOT'];
4016
		$DebugOutput[] = 'getenv(DOCUMENT_ROOT)       = '.@getenv('DOCUMENT_ROOT');
4017
		$DebugOutput[] = '';
4018
4019
		$DebugOutput[] = 'get_magic_quotes_gpc()         = '.$this->phpThumbDebugVarDump(@get_magic_quotes_gpc());
4020
		$DebugOutput[] = 'get_magic_quotes_runtime()     = '.$this->phpThumbDebugVarDump(@get_magic_quotes_runtime());
4021
		$DebugOutput[] = 'error_reporting()              = '.$this->phpThumbDebugVarDump(error_reporting());
4022
		$DebugOutput[] = 'ini_get(error_reporting)       = '.$this->phpThumbDebugVarDump(@ini_get('error_reporting'));
4023
		$DebugOutput[] = 'ini_get(display_errors)        = '.$this->phpThumbDebugVarDump(@ini_get('display_errors'));
4024
		$DebugOutput[] = 'ini_get(allow_url_fopen)       = '.$this->phpThumbDebugVarDump(@ini_get('allow_url_fopen'));
4025
		$DebugOutput[] = 'ini_get(disable_functions)     = '.$this->phpThumbDebugVarDump(@ini_get('disable_functions'));
4026
		$DebugOutput[] = 'get_cfg_var(disable_functions) = '.$this->phpThumbDebugVarDump(@get_cfg_var('disable_functions'));
4027
		$DebugOutput[] = 'ini_get(safe_mode)             = '.$this->phpThumbDebugVarDump(@ini_get('safe_mode'));
4028
		$DebugOutput[] = 'ini_get(open_basedir)          = '.$this->phpThumbDebugVarDump(@ini_get('open_basedir'));
4029
		$DebugOutput[] = 'ini_get(max_execution_time)    = '.$this->phpThumbDebugVarDump(@ini_get('max_execution_time'));
4030
		$DebugOutput[] = 'ini_get(memory_limit)          = '.$this->phpThumbDebugVarDump(@ini_get('memory_limit'));
4031
		$DebugOutput[] = 'get_cfg_var(memory_limit)      = '.$this->phpThumbDebugVarDump(@get_cfg_var('memory_limit'));
4032
		$DebugOutput[] = 'memory_get_usage()             = '.(function_exists('memory_get_usage') ? $this->phpThumbDebugVarDump(@memory_get_usage()) : 'n/a');
4033
		$DebugOutput[] = '';
4034
4035
		$DebugOutput[] = '$this->config_prefer_imagemagick            = '.$this->phpThumbDebugVarDump($this->config_prefer_imagemagick);
4036
		$DebugOutput[] = '$this->config_imagemagick_path              = '.$this->phpThumbDebugVarDump($this->config_imagemagick_path);
4037
		$DebugOutput[] = '$this->ImageMagickWhichConvert()            = '.$this->ImageMagickWhichConvert();
4038
		$IMpathUsed = ($this->config_imagemagick_path ? $this->config_imagemagick_path : $this->ImageMagickWhichConvert());
4039
		$DebugOutput[] = '[actual ImageMagick path used]              = '.$this->phpThumbDebugVarDump($IMpathUsed);
4040
		$DebugOutput[] = 'file_exists([actual ImageMagick path used]) = '.$this->phpThumbDebugVarDump(@file_exists($IMpathUsed));
4041
		$DebugOutput[] = 'ImageMagickVersion(false)                   = '.$this->ImageMagickVersion(false);
4042
		$DebugOutput[] = 'ImageMagickVersion(true)                    = '.$this->ImageMagickVersion(true);
4043
		$DebugOutput[] = '';
4044
4045
		$DebugOutput[] = '$this->config_cache_directory               = '.$this->phpThumbDebugVarDump($this->config_cache_directory);
4046
		$DebugOutput[] = '$this->config_cache_directory_depth         = '.$this->phpThumbDebugVarDump($this->config_cache_directory_depth);
4047
		$DebugOutput[] = '$this->config_cache_disable_warning         = '.$this->phpThumbDebugVarDump($this->config_cache_disable_warning);
4048
		$DebugOutput[] = '$this->config_cache_maxage                  = '.$this->phpThumbDebugVarDump($this->config_cache_maxage);
4049
		$DebugOutput[] = '$this->config_cache_maxsize                 = '.$this->phpThumbDebugVarDump($this->config_cache_maxsize);
4050
		$DebugOutput[] = '$this->config_cache_maxfiles                = '.$this->phpThumbDebugVarDump($this->config_cache_maxfiles);
4051
		$DebugOutput[] = '$this->config_cache_force_passthru          = '.$this->phpThumbDebugVarDump($this->config_cache_force_passthru);
4052
		$DebugOutput[] = '$this->cache_filename                       = '.$this->phpThumbDebugVarDump($this->cache_filename);
4053
		$DebugOutput[] = 'is_readable($this->config_cache_directory)  = '.$this->phpThumbDebugVarDump(@is_readable($this->config_cache_directory));
4054
		$DebugOutput[] = 'is_writable($this->config_cache_directory)  = '.$this->phpThumbDebugVarDump(@is_writable($this->config_cache_directory));
4055
		$DebugOutput[] = 'is_readable($this->cache_filename)          = '.$this->phpThumbDebugVarDump(@is_readable($this->cache_filename));
4056
		$DebugOutput[] = 'is_writable($this->cache_filename)          = '.(@file_exists($this->cache_filename) ? $this->phpThumbDebugVarDump(@is_writable($this->cache_filename)) : 'n/a');
4057
		$DebugOutput[] = '';
4058
4059
		foreach ($ConfigVariableNames as $varname) {
4060
			$varname = 'config_'.$varname;
4061
			$value = $this->$varname;
4062
			$DebugOutput[] = '$this->'.str_pad($varname, 37, ' ', STR_PAD_RIGHT).' = '.$this->phpThumbDebugVarDump($value);
4063
		}
4064
		$DebugOutput[] = '';
4065
		foreach ($OtherVariableNames as $varname) {
4066
			$value = $this->$varname;
4067
			$DebugOutput[] = '$this->'.str_pad($varname, 27, ' ', STR_PAD_RIGHT).' = '.$this->phpThumbDebugVarDump($value);
4068
		}
4069
		$DebugOutput[] = 'strlen($this->rawImageData)        = '.strlen(@$this->rawImageData);
4070
		$DebugOutput[] = 'strlen($this->exif_thumbnail_data) = '.strlen(@$this->exif_thumbnail_data);
4071
		$DebugOutput[] = '';
4072
4073
		foreach ($ParameterNames as $varname) {
4074
			$value = $this->$varname;
4075
			$DebugOutput[] = '$this->'.str_pad($varname, 4, ' ', STR_PAD_RIGHT).' = '.$this->phpThumbDebugVarDump($value);
4076
		}
4077
		$DebugOutput[] = '';
4078
4079
		foreach ($FunctionsExistance as $functionname) {
4080
			$DebugOutput[] = 'builtin_function_exists('.$functionname.')'.str_repeat(' ', 23 - strlen($functionname)).' = '.$this->phpThumbDebugVarDump(phpthumb_functions::builtin_function_exists($functionname));
4081
		}
4082
		$DebugOutput[] = '';
4083
4084
		$gd_info = gd_info();
4085
		foreach ($gd_info as $key => $value) {
4086
			$DebugOutput[] = 'gd_info.'.str_pad($key, 34, ' ', STR_PAD_RIGHT).' = '.$this->phpThumbDebugVarDump($value);
4087
		}
4088
		$DebugOutput[] = '';
4089
4090
		$exif_info = phpthumb_functions::exif_info();
4091
		foreach ($exif_info as $key => $value) {
4092
			$DebugOutput[] = 'exif_info.'.str_pad($key, 26, ' ', STR_PAD_RIGHT).' = '.$this->phpThumbDebugVarDump($value);
4093
		}
4094
		$DebugOutput[] = '';
4095
4096
		if ($ApacheLookupURIarray = phpthumb_functions::ApacheLookupURIarray(dirname(@$_SERVER['PHP_SELF']))) {
4097
			foreach ($ApacheLookupURIarray as $key => $value) {
4098
				$DebugOutput[] = 'ApacheLookupURIarray.'.str_pad($key, 15, ' ', STR_PAD_RIGHT).' = '.$this->phpThumbDebugVarDump($value);
4099
			}
4100
		} else {
4101
				$DebugOutput[] = 'ApacheLookupURIarray() -- FAILED';
4102
		}
4103
		$DebugOutput[] = '';
4104
4105
		if (isset($_GET) && is_array($_GET)) {
4106
			foreach ($_GET as $key => $value) {
4107
				$DebugOutput[] = '$_GET['.$key.']'.str_repeat(' ', 30 - strlen($key)).'= '.$this->phpThumbDebugVarDump($value);
4108
			}
4109
		}
4110
		if (isset($_POST) && is_array($_POST)) {
4111
			foreach ($_POST as $key => $value) {
4112
				$DebugOutput[] = '$_POST['.$key.']'.str_repeat(' ', 29 - strlen($key)).'= '.$this->phpThumbDebugVarDump($value);
4113
			}
4114
		}
4115
		$DebugOutput[] = '';
4116
4117
		$DebugOutput[] = '$this->debugmessages:';
4118
		foreach ($this->debugmessages as $errorstring) {
4119
			$DebugOutput[] = '  * '.$errorstring;
4120
		}
4121
		$DebugOutput[] = '';
4122
4123
		$DebugOutput[] = '$this->debugtiming:';
4124
		foreach ($this->debugtiming as $timestamp => $timingstring) {
4125
			$DebugOutput[] = '  * '.$timestamp.' '.$timingstring;
4126
		}
4127
		$DebugOutput[] = '  * Total processing time: '.number_format(max(array_keys($this->debugtiming)) - min(array_keys($this->debugtiming)), 6);
4128
4129
		$this->f = (isset($_GET['f']) ? $_GET['f'] : $this->f); // debug modes 0-2 don't recognize text mode otherwise
4130
		return $this->ErrorImage(implode("\n", $DebugOutput), 700, 500, true);
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->ErrorImage(implod...utput), 700, 500, true) targeting phpthumb::ErrorImage() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
4131
	}
4132
4133
	public function FatalError($text) {
4134
		if (null === $this->fatalerror) {
4135
			$this->fatalerror = $text;
4136
		}
4137
		return true;
4138
	}
4139
4140
	public function ErrorImage($text, $width=0, $height=0, $forcedisplay=false) {
4141
		$width  = ($width  ? $width  : $this->config_error_image_width);
4142
		$height = ($height ? $height : $this->config_error_image_height);
4143
4144
		$text = 'phpThumb() v'.$this->phpthumb_version."\n".'http://phpthumb.sourceforge.net'."\n\n".($this->config_disable_debug ? 'Error messages disabled.'."\n\n".'edit phpThumb.config.php and (temporarily) set'."\n".'$PHPTHUMB_CONFIG[\'disable_debug\'] = false;'."\n".'to view the details of this error' : $text);
4145
4146
		$this->FatalError($text);
4147
		$this->DebugMessage($text, __FILE__, __LINE__);
4148
		$this->purgeTempFiles();
4149
		if ($this->config_error_silent_die_on_error) {
4150
			exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
4151
		}
4152
		if ($this->phpThumbDebug && !$forcedisplay) {
4153
			return false;
4154
		}
4155
		if (!$this->config_error_die_on_error && !$forcedisplay) {
4156
			return false;
4157
		}
4158
		if ($this->err || $this->config_error_message_image_default) {
4159
			// Show generic custom error image instead of error message
4160
			// for use on production sites where you don't want debug messages
4161
			if (($this->err == 'showerror') || $this->phpThumbDebug) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
4162
				// fall through and actually show error message even if default error image is set
4163
			} else {
4164
				header('Location: '.($this->err ? $this->err : $this->config_error_message_image_default));
4165
				exit;
4166
			}
4167
		}
4168
		$this->setOutputFormat();
4169
		if (!$this->thumbnailFormat || !$this->config_disable_debug || (phpthumb_functions::gd_version() < 1)) {
4170
			$this->thumbnailFormat = 'text';
4171
		}
4172
		if (@$this->thumbnailFormat == 'text') {
4173
			// bypass all GD functions and output text error message
4174
			if (!headers_sent()) {
4175
				header('Content-type: text/plain');
4176
				echo $text;
4177
			} else {
4178
				echo '<pre>'.htmlspecialchars($text).'</pre>';
4179
			}
4180
			exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
4181
		}
4182
4183
		$FontWidth  = imagefontwidth($this->config_error_fontsize);
4184
		$FontHeight = imagefontheight($this->config_error_fontsize);
4185
4186
		$LinesOfText = explode("\n", @wordwrap($text, floor($width / $FontWidth), "\n", true));
0 ignored issues
show
Bug introduced by
floor($width / $FontWidth) of type double is incompatible with the type integer expected by parameter $width of wordwrap(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

4186
		$LinesOfText = explode("\n", @wordwrap($text, /** @scrutinizer ignore-type */ floor($width / $FontWidth), "\n", true));
Loading history...
4187
		$height = max($height, count($LinesOfText) * $FontHeight);
4188
4189
		$headers_file = '';
4190
		$headers_line = '';
4191
		if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '4.3.0', '>=') && headers_sent($headers_file, $headers_line)) {
0 ignored issues
show
Bug introduced by
$headers_line of type string is incompatible with the type integer expected by parameter $line of headers_sent(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

4191
		if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '4.3.0', '>=') && headers_sent($headers_file, /** @scrutinizer ignore-type */ $headers_line)) {
Loading history...
4192
4193
			echo "\n".'**Headers already sent in file "'.$headers_file.'" on line "'.$headers_line.'", dumping error message as text:**<br><pre>'."\n\n".$text."\n".'</pre>';
4194
4195
		} elseif (headers_sent()) {
4196
4197
			echo "\n".'**Headers already sent, dumping error message as text:**<br><pre>'."\n\n".$text."\n".'</pre>';
4198
4199
		} elseif ($gdimg_error = imagecreate($width, $height)) {
4200
4201
			$background_color = phpthumb_functions::ImageHexColorAllocate($gdimg_error, $this->config_error_bgcolor,   true);
4202
			$text_color       = phpthumb_functions::ImageHexColorAllocate($gdimg_error, $this->config_error_textcolor, true);
4203
			imagefilledrectangle($gdimg_error, 0, 0, $width, $height, $background_color);
4204
			$lineYoffset = 0;
4205
			foreach ($LinesOfText as $line) {
4206
				imagestring($gdimg_error, $this->config_error_fontsize, 2, $lineYoffset, $line, $text_color);
4207
				$lineYoffset += $FontHeight;
4208
			}
4209
			if (function_exists('imagetypes')) {
4210
				$imagetypes = imagetypes();
4211
				if ($imagetypes & IMG_PNG) {
4212
					header('Content-Type: image/png');
4213
					imagepng($gdimg_error);
4214
				} elseif ($imagetypes & IMG_GIF) {
4215
					header('Content-Type: image/gif');
4216
					imagegif($gdimg_error);
4217
				} elseif ($imagetypes & IMG_JPG) {
4218
					header('Content-Type: image/jpeg');
4219
					imagejpeg($gdimg_error);
4220
				} elseif ($imagetypes & IMG_WBMP) {
4221
					header('Content-Type: image/vnd.wap.wbmp');
4222
					imagewbmp($gdimg_error);
4223
				}
4224
			}
4225
			imagedestroy($gdimg_error);
4226
4227
		}
4228
		if (!headers_sent()) {
4229
			echo "\n".'**Failed to send graphical error image, dumping error message as text:**<br>'."\n\n".$text;
4230
		}
4231
		exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
4232
	}
4233
4234
	public function ImageCreateFromStringReplacement(&$RawImageData, $DieOnErrors=false) {
4235
		// there are serious bugs in the non-bundled versions of GD which may cause
4236
		// PHP to segfault when calling imagecreatefromstring() - avoid if at all possible
4237
		// when not using a bundled version of GD2
4238
		if (!phpthumb_functions::gd_version()) {
4239
			if ($DieOnErrors) {
4240
				if (!headers_sent()) {
4241
					// base64-encoded error image in GIF format
4242
					$ERROR_NOGD = 'R0lGODlhIAAgALMAAAAAABQUFCQkJDY2NkZGRldXV2ZmZnJycoaGhpSUlKWlpbe3t8XFxdXV1eTk5P7+/iwAAAAAIAAgAAAE/vDJSau9WILtTAACUinDNijZtAHfCojS4W5H+qxD8xibIDE9h0OwWaRWDIljJSkUJYsN4bihMB8th3IToAKs1VtYM75cyV8sZ8vygtOE5yMKmGbO4jRdICQCjHdlZzwzNW4qZSQmKDaNjhUMBX4BBAlmMywFSRWEmAI6b5gAlhNxokGhooAIK5o/pi9vEw4Lfj4OLTAUpj6IabMtCwlSFw0DCKBoFqwAB04AjI54PyZ+yY3TD0ss2YcVmN/gvpcu4TOyFivWqYJlbAHPpOntvxNAACcmGHjZzAZqzSzcq5fNjxFmAFw9iFRunD1epU6tsIPmFCAJnWYE0FURk7wJDA0MTKpEzoWAAskiAAA7';
4243
					header('Content-Type: image/gif');
4244
					echo base64_decode($ERROR_NOGD);
4245
				} else {
4246
					echo '*** ERROR: No PHP-GD support available ***';
4247
				}
4248
				exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
4249
			} else {
4250
				$this->DebugMessage('ImageCreateFromStringReplacement() failed: gd_version says "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
4251
				return false;
4252
			}
4253
		}
4254
		if (phpthumb_functions::gd_is_bundled()) {
4255
			$this->DebugMessage('ImageCreateFromStringReplacement() calling built-in imagecreatefromstring()', __FILE__, __LINE__);
4256
			return @imagecreatefromstring($RawImageData);
4257
		}
4258
		if ($this->issafemode) {
4259
			$this->DebugMessage('ImageCreateFromStringReplacement() failed: cannot create temp file in SAFE_MODE', __FILE__, __LINE__);
4260
			return false;
4261
		}
4262
4263
		switch (substr($RawImageData, 0, 3)) {
4264
			case 'GIF':
4265
				$ICFSreplacementFunctionName = 'imagecreatefromgif';
4266
				break;
4267
			case "\xFF\xD8\xFF":
4268
				$ICFSreplacementFunctionName = 'imagecreatefromjpeg';
4269
				break;
4270
			case "\x89".'PN':
4271
				$ICFSreplacementFunctionName = 'imagecreatefrompng';
4272
				break;
4273
			default:
4274
				$this->DebugMessage('ImageCreateFromStringReplacement() failed: unknown fileformat signature "'.phpthumb_functions::HexCharDisplay(substr($RawImageData, 0, 3)).'"', __FILE__, __LINE__);
4275
				return false;
4276
				break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
4277
		}
4278
		$ErrorMessage = '';
4279
		if ($tempnam = $this->phpThumb_tempnam()) {
4280
			if ($fp_tempnam = @fopen($tempnam, 'wb')) {
4281
				fwrite($fp_tempnam, $RawImageData);
4282
				fclose($fp_tempnam);
4283
				@chmod($tempnam, $this->getParameter('config_file_create_mask'));
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for chmod(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

4283
				/** @scrutinizer ignore-unhandled */ @chmod($tempnam, $this->getParameter('config_file_create_mask'));

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
4284
				if (($ICFSreplacementFunctionName == 'imagecreatefromgif') && !function_exists($ICFSreplacementFunctionName)) {
4285
4286
					// Need to create from GIF file, but imagecreatefromgif does not exist
4287
					ob_start();
4288
					if (!@include_once( __DIR__ .'/phpthumb.gif.php')) {
4289
						$ErrorMessage = 'Failed to include required file "'. __DIR__ .'/phpthumb.gif.php" in '.__FILE__.' on line '.__LINE__;
4290
						$this->DebugMessage($ErrorMessage, __FILE__, __LINE__);
4291
					}
4292
					ob_end_clean();
4293
					// gif_loadFileToGDimageResource() cannot read from raw data, write to file first
4294
					if ($tempfilename = $this->phpThumb_tempnam()) {
4295
						if ($fp_tempfile = @fopen($tempfilename, 'wb')) {
4296
							fwrite($fp_tempfile, $RawImageData);
4297
							fclose($fp_tempfile);
4298
							$gdimg_source = gif_loadFileToGDimageResource($tempfilename);
4299
							$this->DebugMessage('gif_loadFileToGDimageResource('.$tempfilename.') completed', __FILE__, __LINE__);
4300
							$this->DebugMessage('deleting "'.$tempfilename.'"', __FILE__, __LINE__);
4301
							unlink($tempfilename);
4302
							return $gdimg_source;
4303
						} else {
4304
							$ErrorMessage = 'Failed to open tempfile in '.__FILE__.' on line '.__LINE__;
4305
							$this->DebugMessage($ErrorMessage, __FILE__, __LINE__);
4306
						}
4307
					} else {
4308
						$ErrorMessage = 'Failed to open generate tempfile name in '.__FILE__.' on line '.__LINE__;
4309
						$this->DebugMessage($ErrorMessage, __FILE__, __LINE__);
4310
					}
4311
4312
				} elseif (function_exists($ICFSreplacementFunctionName) && ($gdimg_source = @$ICFSreplacementFunctionName($tempnam))) {
4313
4314
					// great
4315
					$this->DebugMessage($ICFSreplacementFunctionName.'('.$tempnam.') succeeded', __FILE__, __LINE__);
4316
					$this->DebugMessage('deleting "'.$tempnam.'"', __FILE__, __LINE__);
4317
					unlink($tempnam);
4318
					return $gdimg_source;
4319
4320
				} else {
4321
4322
					// GD functions not available, or failed to create image
4323
					$this->DebugMessage($ICFSreplacementFunctionName.'('.$tempnam.') '.(function_exists($ICFSreplacementFunctionName) ? 'failed' : 'does not exist'), __FILE__, __LINE__);
4324
					if (isset($_GET['phpThumbDebug'])) {
4325
						$this->phpThumbDebug();
4326
					}
4327
4328
				}
4329
			} else {
4330
				$ErrorMessage = 'Failed to fopen('.$tempnam.', "wb") in '.__FILE__.' on line '.__LINE__."\n".'You may need to set $PHPTHUMB_CONFIG[temp_directory] in phpThumb.config.php';
4331
				if ($this->issafemode) {
4332
					$ErrorMessage = 'ImageCreateFromStringReplacement() failed in '.__FILE__.' on line '.__LINE__.': cannot create temp file in SAFE_MODE';
4333
				}
4334
				$this->DebugMessage($ErrorMessage, __FILE__, __LINE__);
4335
			}
4336
			$this->DebugMessage('deleting "'.$tempnam.'"', __FILE__, __LINE__);
4337
			@unlink($tempnam);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for unlink(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

4337
			/** @scrutinizer ignore-unhandled */ @unlink($tempnam);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
4338
		} else {
4339
			$ErrorMessage = 'Failed to generate phpThumb_tempnam() in '.__FILE__.' on line '.__LINE__."\n".'You may need to set $PHPTHUMB_CONFIG[temp_directory] in phpThumb.config.php';
4340
			if ($this->issafemode) {
4341
				$ErrorMessage = 'ImageCreateFromStringReplacement() failed in '.__FILE__.' on line '.__LINE__.': cannot create temp file in SAFE_MODE';
4342
			}
4343
		}
4344
		if ($DieOnErrors && $ErrorMessage) {
4345
			return $this->ErrorImage($ErrorMessage);
4346
		}
4347
		return false;
4348
	}
4349
4350
	public function ImageResizeFunction(&$dst_im, &$src_im, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH) {
4351
		$this->DebugMessage('ImageResizeFunction($o, $s, '.$dstX.', '.$dstY.', '.$srcX.', '.$srcY.', '.$dstW.', '.$dstH.', '.$srcW.', '.$srcH.')', __FILE__, __LINE__);
4352
		if (($dstW == $srcW) && ($dstH == $srcH)) {
4353
			return imagecopy($dst_im, $src_im, $dstX, $dstY, $srcX, $srcY, $srcW, $srcH);
4354
		}
4355
		if (phpthumb_functions::gd_version() >= 2.0) {
4356
			if ($this->config_disable_imagecopyresampled) {
4357
				return phpthumb_functions::ImageCopyResampleBicubic($dst_im, $src_im, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH);
4358
			}
4359
			return imagecopyresampled($dst_im, $src_im, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH);
4360
		}
4361
		return imagecopyresized($dst_im, $src_im, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH);
4362
	}
4363
4364
	public function InitializeTempDirSetting() {
4365
		$this->config_temp_directory = ($this->config_temp_directory ? $this->config_temp_directory : $this->realPathSafe((function_exists('sys_get_temp_dir') ? sys_get_temp_dir() : ''))); // sys_get_temp_dir added in PHP v5.2.1
4366
		$this->config_temp_directory = ($this->config_temp_directory ? $this->config_temp_directory : $this->realPathSafe(ini_get('upload_tmp_dir')));
4367
		$this->config_temp_directory = ($this->config_temp_directory ? $this->config_temp_directory : $this->realPathSafe(getenv('TMPDIR')));
4368
		$this->config_temp_directory = ($this->config_temp_directory ? $this->config_temp_directory : $this->realPathSafe(getenv('TMP')));
4369
		return true;
4370
	}
4371
4372
	public function phpThumb_tempnam() {
4373
		$this->InitializeTempDirSetting();
4374
		$tempnam = $this->realPathSafe(tempnam($this->config_temp_directory, 'pThumb'));
4375
		$this->tempFilesToDelete[$tempnam] = $tempnam;
4376
		$this->DebugMessage('phpThumb_tempnam() returning "'.$tempnam.'"', __FILE__, __LINE__);
4377
		return $tempnam;
4378
	}
4379
4380
	public function DebugMessage($message, $file='', $line='') {
4381
		$this->debugmessages[] = $message.($file ? ' in file "'.(basename($file) ? basename($file) : $file).'"' : '').($line ? ' on line '.$line : '');
4382
		return true;
4383
	}
4384
4385
	public function DebugTimingMessage($message, $file='', $line='', $timestamp=0) {
4386
		if (!$timestamp) {
4387
			$timestamp = array_sum(explode(' ', microtime()));
4388
		}
4389
		$this->debugtiming[number_format($timestamp, 6, '.', '')] = ': '.$message.($file ? ' in file "'.(basename($file) ? basename($file) : $file).'"' : '').($line ? ' on line '.$line : '');
4390
		return true;
4391
	}
4392
4393
}
4394