Issues (807)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  Header Injection
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

phpthumb/phpthumb.class.php (79 issues)

1
<?php
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
if (!class_exists('phpthumb_functions', false)) {
13
    ob_start();
14
    if (!include_once __DIR__ . '/phpthumb.functions.php') {
15
        ob_end_flush();
16
        die('failed to include_once("' . __DIR__ . '/phpthumb.functions.php")');
17
    }
18
    ob_end_clean();
19
}
20
21
class phpthumb
22
{
23
    // public:
24
    // START PARAMETERS (for object mode and phpThumb.php)
25
    // See phpthumb.readme.txt for descriptions of what each of these values are
26
    public $src           = null;     // SouRCe filename
27
    public $new           = null;     // NEW image (phpThumb.php only)
28
    public $w             = null;     // Width
29
    public $h             = null;     // Height
30
    public $wp            = null;     // Width  (Portrait Images Only)
31
    public $hp            = null;     // Height (Portrait Images Only)
32
    public $wl            = null;     // Width  (Landscape Images Only)
33
    public $hl            = null;     // Height (Landscape Images Only)
34
    public $ws            = null;     // Width  (Square Images Only)
35
    public $hs            = null;     // Height (Square Images Only)
36
    public $f             = null;     // output image Format
37
    public $q             = 75;       // jpeg output Quality
38
    public $sx            = null;     // Source crop top-left X position
39
    public $sy            = null;     // Source crop top-left Y position
40
    public $sw            = null;     // Source crop Width
41
    public $sh            = null;     // Source crop Height
42
    public $zc            = null;     // Zoom Crop
43
    public $ica           = null;     // Image Crop Auto
44
    public $bc            = null;     // Border Color
45
    public $bg            = null;     // BackGround color
46
    public $fltr          = [];  // FiLTeRs
47
    public $goto          = null;     // GO TO url after processing
48
    public $err           = null;     // default ERRor image filename
49
    public $xto           = null;     // extract eXif Thumbnail Only
50
    public $ra            = null;     // Rotate by Angle
51
    public $ar            = null;     // Auto Rotate
52
    public $aoe           = null;     // Allow Output Enlargement
53
    public $far           = null;     // Fixed Aspect Ratio
54
    public $iar           = null;     // Ignore Aspect Ratio
55
    public $maxb          = null;     // MAXimum Bytes
56
    public $down          = null;     // DOWNload thumbnail filename
57
    public $md5s          = null;     // MD5 hash of Source image
58
    public $sfn           = 0;        // Source Frame Number
59
    public $dpi           = 150;      // Dots Per Inch for vector source formats
60
    public $sia           = null;     // Save Image As filename
61
    public $file          = null;     // >>>deprecated, DO NOT USE, will be removed in future versions<<<
62
    public $phpThumbDebug = null;
63
    // END PARAMETERS
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
    // * Default output configuration:
78
    public $config_output_format    = 'jpeg';
79
    public $config_output_maxwidth  = 0;
80
    public $config_output_maxheight = 0;
81
    public $config_output_interlace = true;
82
    // * Error message configuration
83
    public $config_error_image_width           = 400;
84
    public $config_error_image_height          = 100;
85
    public $config_error_message_image_default = '';
86
    public $config_error_bgcolor               = 'CCCCFF';
87
    public $config_error_textcolor             = 'FF0000';
88
    public $config_error_fontsize              = 1;
89
    public $config_error_die_on_error          = false;
90
    public $config_error_silent_die_on_error   = false;
91
    public $config_error_die_on_source_failure = true;
92
    // * Anti-Hotlink Configuration:
93
    public $config_nohotlink_enabled       = true;
94
    public $config_nohotlink_valid_domains = [];
95
    public $config_nohotlink_erase_image   = true;
96
    public $config_nohotlink_text_message  = 'Off-server thumbnailing is not allowed';
97
    // * Off-server Linking Configuration:
98
    public $config_nooffsitelink_enabled       = false;
99
    public $config_nooffsitelink_valid_domains = [];
100
    public $config_nooffsitelink_require_refer = false;
101
    public $config_nooffsitelink_erase_image   = true;
102
    public $config_nooffsitelink_watermark_src = '';
103
    public $config_nooffsitelink_text_message  = 'Off-server linking is not allowed';
104
    // * Border & Background default colors
105
    public $config_border_hexcolor     = '000000';
106
    public $config_background_hexcolor = 'FFFFFF';
107
    // * TrueType Fonts
108
    public $config_ttf_directory                        = './fonts';
109
    public $config_max_source_pixels                    = null;
110
    public $config_use_exif_thumbnail_for_speed         = false;
111
    public $config_allow_local_http_src                 = false;
112
    public $config_imagemagick_path                     = null;
113
    public $config_prefer_imagemagick                   = true;
114
    public $config_imagemagick_use_thumbnail            = true;
115
    public $config_cache_maxage                         = null;
116
    public $config_cache_maxsize                        = null;
117
    public $config_cache_maxfiles                       = null;
118
    public $config_cache_source_filemtime_ignore_local  = false;
119
    public $config_cache_source_filemtime_ignore_remote = true;
120
    public $config_cache_default_only_suffix            = false;
121
    public $config_cache_force_passthru                 = true;
122
    public $config_cache_prefix                         = '';    // default value set in the constructor below
123
    // * MySQL
124
    public $config_mysql_extension = null;
125
    public $config_mysql_query     = null;
126
    public $config_mysql_hostname  = null;
127
    public $config_mysql_username  = null;
128
    public $config_mysql_password  = null;
129
    public $config_mysql_database  = null;
130
    // * Security
131
    public $config_high_security_enabled       = true;
132
    public $config_high_security_password      = null;
133
    public $config_high_security_url_separator = '&';
134
    public $config_disable_debug               = true;
135
    public $config_allow_src_above_docroot     = false;
136
    public $config_allow_src_above_phpthumb    = true;
137
    public $config_auto_allow_symlinks         = true;    // allow symlink target directories without explicitly whitelisting them
138
    public $config_additional_allowed_dirs     = []; // additional directories to allow source images to be read from
139
    public $config_file_create_mask            = 0755;
140
    public $config_dir_create_mask             = 0755;
141
    // * HTTP fopen
142
    public $config_http_fopen_timeout   = 10;
143
    public $config_http_follow_redirect = true;
144
    // * Compatability
145
    public $config_disable_pathinfo_parsing        = false;
146
    public $config_disable_imagecopyresampled      = false;
147
    public $config_disable_onlycreateable_passthru = false;
148
    public $config_disable_realpath                = false;
149
    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';
150
    // END CONFIGURATION OPTIONS
151
152
    // public: error messages (read-only; persistant)
153
    public $debugmessages = [];
154
    public $debugtiming   = [];
155
    public $fatalerror    = null;
156
    // private: (should not be modified directly)
157
    public $thumbnailQuality       = 75;
158
    public $thumbnailFormat        = null;
159
    public $sourceFilename         = null;
160
    public $rawImageData           = null;
161
    public $IMresizedData          = null;
162
    public $outputImageData        = null;
163
    public $useRawIMoutput         = false;
164
    public $gdimg_output           = null;
165
    public $gdimg_source           = null;
166
    public $getimagesizeinfo       = null;
167
    public $source_width           = null;
168
    public $source_height          = null;
169
    public $thumbnailCropX         = null;
170
    public $thumbnailCropY         = null;
171
    public $thumbnailCropW         = null;
172
    public $thumbnailCropH         = null;
173
    public $exif_thumbnail_width   = null;
174
    public $exif_thumbnail_height  = null;
175
    public $exif_thumbnail_type    = null;
176
    public $exif_thumbnail_data    = null;
177
    public $exif_raw_data          = null;
178
    public $thumbnail_width        = null;
179
    public $thumbnail_height       = null;
180
    public $thumbnail_image_width  = null;
181
    public $thumbnail_image_height = null;
182
    public $tempFilesToDelete      = [];
183
    public $cache_filename         = null;
184
    public $AlphaCapableFormats    = ['png', 'ico', 'gif', 'webp'];
185
    public $is_alpha               = false;
186
    public $iswindows              = null;
187
    public $issafemode             = null;
188
    public $php_memory_limit       = null;
189
    public $phpthumb_version       = '1.7.17-202107271830';
190
    //////////////////////////////////////////////////////////////////////
191
192
    // public: constructor
193
    public function __construct()
194
    {
195
        $this->phpThumb();
196
    }
197
198
    public function phpThumb()
199
    {
200
        $this->DebugTimingMessage('phpThumb() constructor', __FILE__, __LINE__);
201
        $this->DebugMessage('phpThumb() v' . $this->phpthumb_version, __FILE__, __LINE__);
202
203
        foreach ([ini_get('memory_limit'), get_cfg_var('memory_limit')] as $php_config_memory_limit) {
204
            if (!empty($php_config_memory_limit)) {
205
                if (strtoupper($php_config_memory_limit[strlen($php_config_memory_limit) - 1]) == 'G') { // PHP memory limit expressed in Gigabytes
0 ignored issues
show
It seems like $php_config_memory_limit can also be of type array; however, parameter $string of strlen() 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

205
                if (strtoupper($php_config_memory_limit[strlen(/** @scrutinizer ignore-type */ $php_config_memory_limit) - 1]) == 'G') { // PHP memory limit expressed in Gigabytes
Loading history...
206
                    $php_config_memory_limit = (int)substr($php_config_memory_limit, 0, -1) * 1073741824;
0 ignored issues
show
It seems like $php_config_memory_limit can also be of type array; 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

206
                    $php_config_memory_limit = (int)substr(/** @scrutinizer ignore-type */ $php_config_memory_limit, 0, -1) * 1073741824;
Loading history...
207
                } elseif (strtoupper($php_config_memory_limit[strlen($php_config_memory_limit) - 1]) == 'M') { // PHP memory limit expressed in Megabytes
208
                    $php_config_memory_limit = (int)substr($php_config_memory_limit, 0, -1) * 1048576;
209
                }
210
                $this->php_memory_limit = max($this->php_memory_limit, $php_config_memory_limit);
211
            }
212
        }
213
        if ($this->php_memory_limit > 0) { // could be "-1" for "no limit"
214
            $this->config_max_source_pixels = round($this->php_memory_limit * 0.20); // 20% of memory_limit
215
        }
216
217
        $this->iswindows            = (bool)(strtoupper(substr(PHP_OS, 0, 3)) == 'WIN');
218
        $this->issafemode           = (bool)preg_match('#(1|ON)#i', ini_get('safe_mode'));
219
        $this->config_document_root = (!empty($_SERVER['DOCUMENT_ROOT']) ? $_SERVER['DOCUMENT_ROOT'] : $this->config_document_root);
220
        $this->config_cache_prefix  = (isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] . '_' : '');
221
222
        $this->purgeTempFiles(); // purge existing temp files if re-initializing object
223
224
        $php_sapi_name = strtolower(function_exists('php_sapi_name') ? PHP_SAPI : '');
225
        if ($php_sapi_name == 'cli') {
226
            $this->config_allow_src_above_docroot = true;
227
        }
228
229
        if (!$this->config_disable_debug) {
230
            // if debug mode is enabled, force phpThumbDebug output, do not allow normal thumbnails to be generated
231
            $this->phpThumbDebug = (null === $this->phpThumbDebug ? 9 : max(1, (int)$this->phpThumbDebug));
232
        }
233
    }
234
235
    public function __destruct()
236
    {
237
        $this->purgeTempFiles();
238
    }
239
240
    // public:
241
    public function purgeTempFiles()
242
    {
243
        foreach ($this->tempFilesToDelete as $tempFileToDelete) {
244
            if (file_exists($tempFileToDelete)) {
245
                $this->DebugMessage('Deleting temp file "' . $tempFileToDelete . '"', __FILE__, __LINE__);
246
                @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

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

601
                /** @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...
602
                $this->DebugMessage('RenderToFile(' . $renderfilename . ') succeeded', __FILE__, __LINE__);
603
                return true;
604
            }
605
            if (!@file_exists($renderfilename)) {
606
                $this->DebugMessage('RenderOutput [' . $this->thumbnailFormat . '(' . $renderfilename . ')] did not appear to fail, but the output image does not exist either...', __FILE__, __LINE__);
607
            }
608
        } else {
609
            $this->DebugMessage('RenderOutput [' . $this->thumbnailFormat . '(' . $renderfilename . ')] failed', __FILE__, __LINE__);
610
        }
611
        return false;
612
    }
613
614
    // public:
615
    public function OutputThumbnail()
616
    {
617
        $this->purgeTempFiles();
618
619
        if (!$this->useRawIMoutput && !(is_resource($this->gdimg_output) || (is_object($this->gdimg_source) && $this->gdimg_source instanceof \GdImage))) {
620
            $this->DebugMessage('OutputThumbnail() failed because !is_resource($this->gdimg_output)', __FILE__, __LINE__);
621
            return false;
622
        }
623
        if (headers_sent()) {
624
            return $this->ErrorImage('OutputThumbnail() failed - headers already sent');
625
        }
626
627
        $downloadfilename = phpthumb_functions::SanitizeFilename(is_string($this->sia) ? $this->sia : ($this->down ? $this->down : 'phpThumb_generated_thumbnail' . '.' . $this->thumbnailFormat));
628
        $this->DebugMessage('Content-Disposition header filename set to "' . $downloadfilename . '"', __FILE__, __LINE__);
629
        if ($downloadfilename) {
630
            header('Content-Disposition: ' . ($this->down ? 'attachment' : 'inline') . '; filename="' . $downloadfilename . '"');
631
        } else {
632
            $this->DebugMessage('failed to send Content-Disposition header because $downloadfilename is empty', __FILE__, __LINE__);
633
        }
634
635
        if ($this->useRawIMoutput) {
636
            header('Content-Type: ' . phpthumb_functions::ImageTypeToMIMEtype($this->thumbnailFormat));
0 ignored issues
show
Are you sure phpthumb_functions::Imag...$this->thumbnailFormat) of type false|mixed|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

636
            header('Content-Type: ' . /** @scrutinizer ignore-type */ phpthumb_functions::ImageTypeToMIMEtype($this->thumbnailFormat));
Loading history...
637
            echo $this->IMresizedData;
638
        } else {
639
            $this->DebugMessage('imageinterlace($this->gdimg_output, ' . (int)$this->config_output_interlace . ')', __FILE__, __LINE__);
640
            imageinterlace($this->gdimg_output, (int)$this->config_output_interlace);
641
            switch ($this->thumbnailFormat) {
642
                case 'gif':
643
                case 'jpeg':
644
                case 'png':
645
                case 'webp':
646
                    $ImageOutFunction = 'image' . $this->thumbnailFormat;
647
                    if (!function_exists($ImageOutFunction)) {
648
                        $this->DebugMessage($ImageOutFunction . ' is not available', __FILE__, __LINE__);
649
                        return false;
650
                    }
651
                    header('Content-Type: ' . phpthumb_functions::ImageTypeToMIMEtype($this->thumbnailFormat));
652
                    if ($this->thumbnailFormat == 'gif') {
653
                        @$ImageOutFunction($this->gdimg_output);
654
                    } else {
655
                        @$ImageOutFunction($this->gdimg_output, null, $this->thumbnailQuality);
656
                    }
657
                    break;
658
659
                case 'bmp':
660
                    if (function_exists('imagebmp')) {
661
                        header('Content-Type: ' . phpthumb_functions::ImageTypeToMIMEtype($this->thumbnailFormat));
662
                        imagebmp($this->gdimg_output);
663
                        break;
664
                    }
665
                    if (!@include_once __DIR__ . '/phpthumb.bmp.php') {
666
                        $this->DebugMessage('Error including "' . __DIR__ . '/phpthumb.bmp.php" which is required for BMP format output', __FILE__, __LINE__);
667
                        return false;
668
                    }
669
                    $phpthumb_bmp = new phpthumb_bmp();
670
                    if (is_object($phpthumb_bmp)) {
671
                        $bmp_data = $phpthumb_bmp->GD2BMPstring($this->gdimg_output);
672
                        unset($phpthumb_bmp);
673
                        if (!$bmp_data) {
674
                            $this->DebugMessage('$phpthumb_bmp->GD2BMPstring() failed', __FILE__, __LINE__);
675
                            return false;
676
                        }
677
                        header('Content-Type: ' . phpthumb_functions::ImageTypeToMIMEtype($this->thumbnailFormat));
678
                        echo $bmp_data;
679
                    } else {
680
                        $this->DebugMessage('new phpthumb_bmp() failed', __FILE__, __LINE__);
681
                        return false;
682
                    }
683
                    break;
684
685
                case 'ico':
686
                    if (!@include_once __DIR__ . '/phpthumb.ico.php') {
687
                        $this->DebugMessage('Error including "' . __DIR__ . '/phpthumb.ico.php" which is required for ICO format output', __FILE__, __LINE__);
688
                        return false;
689
                    }
690
                    $phpthumb_ico = new phpthumb_ico();
691
                    if (is_object($phpthumb_ico)) {
692
                        $arrayOfOutputImages = [$this->gdimg_output];
693
                        $ico_data            = $phpthumb_ico->GD2ICOstring($arrayOfOutputImages);
694
                        unset($phpthumb_ico);
695
                        if (!$ico_data) {
696
                            $this->DebugMessage('$phpthumb_ico->GD2ICOstring() failed', __FILE__, __LINE__);
697
                            return false;
698
                        }
699
                        header('Content-Type: ' . phpthumb_functions::ImageTypeToMIMEtype($this->thumbnailFormat));
700
                        echo $ico_data;
701
                    } else {
702
                        $this->DebugMessage('new phpthumb_ico() failed', __FILE__, __LINE__);
703
                        return false;
704
                    }
705
                    break;
706
707
                default:
708
                    $this->DebugMessage('OutputThumbnail failed because $this->thumbnailFormat "' . $this->thumbnailFormat . '" is not valid', __FILE__, __LINE__);
709
                    return false;
710
                    break;
0 ignored issues
show
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...
711
            }
712
        }
713
        return true;
714
    }
715
716
    // public:
717
    public function CleanUpCacheDirectory()
718
    {
719
        $this->DebugMessage(
720
            '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
721
                                                                                                                                                                                                                                                                                                  === $this->config_cache_maxfiles ? 'NULL' : number_format(
722
                $this->config_cache_maxfiles
723
            )) . ' files)',
724
            __FILE__,
725
            __LINE__
726
        );
727
728
        if (!is_writable($this->config_cache_directory)) {
729
            $this->DebugMessage('CleanUpCacheDirectory() skipped because "' . $this->config_cache_directory . '" is not writable', __FILE__, __LINE__);
730
            return true;
731
        }
732
733
        // cache status of cache directory for 1 hour to avoid hammering the filesystem functions
734
        $phpThumbCacheStats_filename = $this->config_cache_directory . DIRECTORY_SEPARATOR . 'phpThumbCacheStats.txt';
735
        if (file_exists($phpThumbCacheStats_filename) && is_readable($phpThumbCacheStats_filename) && (filemtime($phpThumbCacheStats_filename) >= (time() - 3600))) {
736
            $this->DebugMessage('CleanUpCacheDirectory() skipped because "' . $phpThumbCacheStats_filename . '" is recently modified', __FILE__, __LINE__);
737
            return true;
738
        }
739
        if (!@touch($phpThumbCacheStats_filename)) {
740
            $this->DebugMessage('touch(' . $phpThumbCacheStats_filename . ') failed', __FILE__, __LINE__);
741
        }
742
743
        $DeletedKeys              = [];
744
        $AllFilesInCacheDirectory = [];
745
        if (($this->config_cache_maxage > 0) || ($this->config_cache_maxsize > 0) || ($this->config_cache_maxfiles > 0)) {
746
            $CacheDirOldFilesAge      = [];
747
            $CacheDirOldFilesSize     = [];
748
            $AllFilesInCacheDirectory = phpthumb_functions::GetAllFilesInSubfolders($this->config_cache_directory);
749
            foreach ($AllFilesInCacheDirectory as $fullfilename) {
750
                if (preg_match('#' . preg_quote($this->config_cache_prefix) . '#i', $fullfilename) && file_exists($fullfilename)) {
751
                    $CacheDirOldFilesAge[$fullfilename] = @fileatime($fullfilename);
752
                    if ($CacheDirOldFilesAge[$fullfilename] == 0) {
753
                        $CacheDirOldFilesAge[$fullfilename] = @filemtime($fullfilename);
754
                    }
755
                    $CacheDirOldFilesSize[$fullfilename] = @filesize($fullfilename);
756
                }
757
            }
758
            if (empty($CacheDirOldFilesSize)) {
759
                $this->DebugMessage('CleanUpCacheDirectory() skipped because $CacheDirOldFilesSize is empty (phpthumb_functions::GetAllFilesInSubfolders(' . $this->config_cache_directory . ') found no files)', __FILE__, __LINE__);
760
                return true;
761
            }
762
            $DeletedKeys['zerobyte'] = [];
763
            foreach ($CacheDirOldFilesSize as $fullfilename => $filesize) {
764
                // purge all zero-size files more than an hour old (to prevent trying to delete just-created and/or in-use files)
765
                $cutofftime = time() - 3600;
766
                if (($filesize == 0) && ($CacheDirOldFilesAge[$fullfilename] < $cutofftime)) {
767
                    $this->DebugMessage('deleting "' . $fullfilename . '"', __FILE__, __LINE__);
768
                    if (@unlink($fullfilename)) {
769
                        $DeletedKeys['zerobyte'][] = $fullfilename;
770
                        unset($CacheDirOldFilesSize[$fullfilename]);
771
                        unset($CacheDirOldFilesAge[$fullfilename]);
772
                    }
773
                }
774
            }
775
            $this->DebugMessage('CleanUpCacheDirectory() purged ' . count($DeletedKeys['zerobyte']) . ' zero-byte files', __FILE__, __LINE__);
776
            asort($CacheDirOldFilesAge);
777
778
            if ($this->config_cache_maxfiles > 0) {
779
                $TotalCachedFiles        = count($CacheDirOldFilesAge);
780
                $DeletedKeys['maxfiles'] = [];
781
                foreach ($CacheDirOldFilesAge as $fullfilename => $filedate) {
782
                    if ($TotalCachedFiles > $this->config_cache_maxfiles) {
783
                        $this->DebugMessage('deleting "' . $fullfilename . '"', __FILE__, __LINE__);
784
                        if (@unlink($fullfilename)) {
785
                            $TotalCachedFiles--;
786
                            $DeletedKeys['maxfiles'][] = $fullfilename;
787
                        }
788
                    } else {
789
                        // there are few enough files to keep the rest
790
                        break;
791
                    }
792
                }
793
                $this->DebugMessage('CleanUpCacheDirectory() purged ' . count($DeletedKeys['maxfiles']) . ' files based on (config_cache_maxfiles=' . $this->config_cache_maxfiles . ')', __FILE__, __LINE__);
794
                foreach ($DeletedKeys['maxfiles'] as $fullfilename) {
795
                    unset($CacheDirOldFilesAge[$fullfilename]);
796
                    unset($CacheDirOldFilesSize[$fullfilename]);
797
                }
798
            }
799
800
            if ($this->config_cache_maxage > 0) {
801
                $mindate               = time() - $this->config_cache_maxage;
802
                $DeletedKeys['maxage'] = [];
803
                foreach ($CacheDirOldFilesAge as $fullfilename => $filedate) {
804
                    if ($filedate > 0) {
805
                        if ($filedate < $mindate) {
806
                            $this->DebugMessage('deleting "' . $fullfilename . '"', __FILE__, __LINE__);
807
                            if (@unlink($fullfilename)) {
808
                                $DeletedKeys['maxage'][] = $fullfilename;
809
                            }
810
                        } else {
811
                            // the rest of the files are new enough to keep
812
                            break;
813
                        }
814
                    }
815
                }
816
                $this->DebugMessage('CleanUpCacheDirectory() purged ' . count($DeletedKeys['maxage']) . ' files based on (config_cache_maxage=' . $this->config_cache_maxage . ')', __FILE__, __LINE__);
817
                foreach ($DeletedKeys['maxage'] as $fullfilename) {
818
                    unset($CacheDirOldFilesAge[$fullfilename]);
819
                    unset($CacheDirOldFilesSize[$fullfilename]);
820
                }
821
            }
822
823
            if ($this->config_cache_maxsize > 0) {
824
                $TotalCachedFileSize    = array_sum($CacheDirOldFilesSize);
825
                $DeletedKeys['maxsize'] = [];
826
                foreach ($CacheDirOldFilesAge as $fullfilename => $filedate) {
827
                    if ($TotalCachedFileSize > $this->config_cache_maxsize) {
828
                        $this->DebugMessage('deleting "' . $fullfilename . '"', __FILE__, __LINE__);
829
                        if (@unlink($fullfilename)) {
830
                            $TotalCachedFileSize      -= $CacheDirOldFilesSize[$fullfilename];
831
                            $DeletedKeys['maxsize'][] = $fullfilename;
832
                        }
833
                    } else {
834
                        // the total filesizes are small enough to keep the rest of the files
835
                        break;
836
                    }
837
                }
838
                $this->DebugMessage('CleanUpCacheDirectory() purged ' . count($DeletedKeys['maxsize']) . ' files based on (config_cache_maxsize=' . $this->config_cache_maxsize . ')', __FILE__, __LINE__);
839
                foreach ($DeletedKeys['maxsize'] as $fullfilename) {
840
                    unset($CacheDirOldFilesAge[$fullfilename]);
841
                    unset($CacheDirOldFilesSize[$fullfilename]);
842
                }
843
            }
844
        } else {
845
            $this->DebugMessage('skipping CleanUpCacheDirectory() because config set to not use it', __FILE__, __LINE__);
846
        }
847
        $totalpurged = 0;
848
        foreach ($DeletedKeys as $key => $value) {
849
            $totalpurged += count($value);
850
        }
851
        $this->DebugMessage('CleanUpCacheDirectory() purged ' . $totalpurged . ' files (from ' . count($AllFilesInCacheDirectory) . ') based on config settings', __FILE__, __LINE__);
852
        if ($totalpurged > 0) {
853
            $empty_dirs = [];
854
            foreach ($AllFilesInCacheDirectory as $fullfilename) {
855
                if (is_dir($fullfilename)) {
856
                    $empty_dirs[$this->realPathSafe($fullfilename)] = 1;
857
                } else {
858
                    unset($empty_dirs[$this->realPathSafe(dirname($fullfilename))]);
859
                }
860
            }
861
            krsort($empty_dirs);
862
            $totalpurgeddirs = 0;
863
            foreach ($empty_dirs as $empty_dir => $dummy) {
864
                if ($empty_dir == $this->config_cache_directory) {
865
                    // shouldn't happen, but just in case, don't let it delete actual cache directory
866
                    continue;
867
                } elseif (@rmdir($empty_dir)) {
868
                    $totalpurgeddirs++;
869
                } else {
870
                    $this->DebugMessage('failed to rmdir(' . $empty_dir . ')', __FILE__, __LINE__);
871
                }
872
            }
873
            $this->DebugMessage('purged ' . $totalpurgeddirs . ' empty directories', __FILE__, __LINE__);
874
        }
875
        return true;
876
    }
877
878
    //////////////////////////////////////////////////////////////////////
879
880
    // private: re-initializator (call between rendering multiple images with one object)
881
    public function resetObject()
882
    {
883
        $class_vars = get_class_vars(get_class($this));
884
        foreach ($class_vars as $key => $value) {
885
            // do not clobber debug or config info
886
            if (!preg_match('#^(config_|debug|fatalerror)#i', $key)) {
887
                $this->$key = $value;
888
            }
889
        }
890
        $this->phpThumb(); // re-initialize some class variables
891
        return true;
892
    }
893
894
    //////////////////////////////////////////////////////////////////////
895
896
    public function ResolveSource()
897
    {
898
        if (is_resource($this->gdimg_source) || (is_object($this->gdimg_source) && $this->gdimg_source instanceof \GdImage)) {
899
            $this->DebugMessage('ResolveSource() exiting because is_resource($this->gdimg_source)', __FILE__, __LINE__);
900
            return true;
901
        }
902
        if ($this->rawImageData) {
903
            $this->sourceFilename = null;
904
            $this->DebugMessage('ResolveSource() exiting because $this->rawImageData is set (' . number_format(strlen($this->rawImageData)) . ' bytes)', __FILE__, __LINE__);
905
            return true;
906
        }
907
        if ($this->sourceFilename) {
908
            $this->sourceFilename = $this->ResolveFilenameToAbsolute($this->sourceFilename);
909
            $this->DebugMessage('$this->sourceFilename set to "' . $this->sourceFilename . '"', __FILE__, __LINE__);
910
        } elseif ($this->src) {
911
            $this->sourceFilename = $this->ResolveFilenameToAbsolute($this->src);
912
            $this->DebugMessage('$this->sourceFilename set to "' . $this->sourceFilename . '" from $this->src (' . $this->src . ')', __FILE__, __LINE__);
913
        } else {
914
            return $this->ErrorImage('$this->sourceFilename and $this->src are both empty');
915
        }
916
        if ($this->iswindows && ((substr($this->sourceFilename, 0, 2) == '//') || (substr($this->sourceFilename, 0, 2) == '\\\\'))) {
0 ignored issues
show
It seems like $this->sourceFilename can also be of type false and null; 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

916
        if ($this->iswindows && ((substr(/** @scrutinizer ignore-type */ $this->sourceFilename, 0, 2) == '//') || (substr($this->sourceFilename, 0, 2) == '\\\\'))) {
Loading history...
917
            // Windows \\share\filename.ext
918
        } elseif (preg_match('#^[a-z0-9]+://#i', $this->sourceFilename, $protocol_matches)) {
0 ignored issues
show
It seems like $this->sourceFilename can also be of type false and null; 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

918
        } elseif (preg_match('#^[a-z0-9]+://#i', /** @scrutinizer ignore-type */ $this->sourceFilename, $protocol_matches)) {
Loading history...
919
            if (preg_match('#^(f|ht)tps?\://#i', $this->sourceFilename)) {
920
                // URL
921
                if ($this->config_http_user_agent) {
922
                    ini_set('user_agent', $this->config_http_user_agent);
923
                }
924
            } else {
925
                return $this->ErrorImage('only FTP and HTTP/HTTPS protocols are allowed, "' . $protocol_matches[1] . '" is not');
926
            }
927
        } elseif (!@file_exists($this->sourceFilename)) {
0 ignored issues
show
It seems like $this->sourceFilename can also be of type false and null; 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

927
        } elseif (!@file_exists(/** @scrutinizer ignore-type */ $this->sourceFilename)) {
Loading history...
928
            return $this->ErrorImage('"' . $this->sourceFilename . '" does not exist');
929
        } elseif (!@is_file($this->sourceFilename)) {
0 ignored issues
show
It seems like $this->sourceFilename can also be of type false and null; 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

929
        } elseif (!@is_file(/** @scrutinizer ignore-type */ $this->sourceFilename)) {
Loading history...
930
            return $this->ErrorImage('"' . $this->sourceFilename . '" is not a file');
931
        }
932
        return true;
933
    }
934
935
    public function setOutputFormat()
936
    {
937
        static $alreadyCalled = false;
938
        if ($this->thumbnailFormat && $alreadyCalled) {
939
            return true;
940
        }
941
        $alreadyCalled = true;
942
943
        $AvailableImageOutputFormats   = [];
944
        $AvailableImageOutputFormats[] = 'text';
945
        if (@is_readable(__DIR__ . '/phpthumb.ico.php')) {
946
            $AvailableImageOutputFormats[] = 'ico';
947
        }
948
        if (@is_readable(__DIR__ . '/phpthumb.bmp.php')) {
949
            $AvailableImageOutputFormats[] = 'bmp';
950
        }
951
952
        $this->thumbnailFormat = 'ico';
953
954
        // Set default output format based on what image types are available
955
        if (function_exists('imagetypes')) {
956
            $imagetypes = imagetypes();
957
            if ($imagetypes & IMG_WBMP) {
958
                $this->thumbnailFormat         = 'wbmp';
959
                $AvailableImageOutputFormats[] = 'wbmp';
960
            }
961
            if ($imagetypes & IMG_GIF) {
962
                $this->thumbnailFormat         = 'gif';
963
                $AvailableImageOutputFormats[] = 'gif';
964
            }
965
            if ($imagetypes & IMG_WEBP) {
966
                $this->thumbnailFormat         = 'webp';
967
                $AvailableImageOutputFormats[] = 'webp';
968
            }
969
            if ($imagetypes & IMG_PNG) {
970
                $this->thumbnailFormat         = 'png';
971
                $AvailableImageOutputFormats[] = 'png';
972
            }
973
            if ($imagetypes & IMG_JPG) {
974
                $this->thumbnailFormat         = 'jpeg';
975
                $AvailableImageOutputFormats[] = 'jpeg';
976
            }
977
        } else {
978
            $this->DebugMessage('imagetypes() does not exist - GD support might not be enabled?', __FILE__, __LINE__);
979
        }
980
        if ($this->ImageMagickVersion()) {
981
            $IMformats = ['jpeg', 'png', 'gif', 'bmp', 'ico', 'wbmp', 'webp'];
982
            $this->DebugMessage('Addding ImageMagick formats to $AvailableImageOutputFormats (' . implode(';', $AvailableImageOutputFormats) . ')', __FILE__, __LINE__);
983
            foreach ($IMformats as $key => $format) {
984
                $AvailableImageOutputFormats[] = $format;
985
            }
986
        }
987
        $AvailableImageOutputFormats = array_unique($AvailableImageOutputFormats);
988
        $this->DebugMessage('$AvailableImageOutputFormats = array(' . implode(';', $AvailableImageOutputFormats) . ')', __FILE__, __LINE__);
989
990
        $this->f = preg_replace('#[^a-z]#', '', strtolower($this->f));
991
        if (strtolower($this->config_output_format) == 'jpg') {
992
            $this->config_output_format = 'jpeg';
993
        }
994
        if (strtolower($this->f) == 'jpg') {
995
            $this->f = 'jpeg';
996
        }
997
        if (phpthumb_functions::CaseInsensitiveInArray($this->config_output_format, $AvailableImageOutputFormats)) {
998
            // set output format to config default if that format is available
999
            $this->DebugMessage('$this->thumbnailFormat set to $this->config_output_format "' . strtolower($this->config_output_format) . '"', __FILE__, __LINE__);
1000
            $this->thumbnailFormat = strtolower($this->config_output_format);
1001
        } elseif ($this->config_output_format) {
1002
            $this->DebugMessage('$this->thumbnailFormat staying as "' . $this->thumbnailFormat . '" because $this->config_output_format (' . strtolower($this->config_output_format) . ') is not in $AvailableImageOutputFormats', __FILE__, __LINE__);
1003
        }
1004
        if ($this->f && phpthumb_functions::CaseInsensitiveInArray($this->f, $AvailableImageOutputFormats)) {
1005
            // override output format if $this->f is set and that format is available
1006
            $this->DebugMessage('$this->thumbnailFormat set to $this->f "' . strtolower($this->f) . '"', __FILE__, __LINE__);
1007
            $this->thumbnailFormat = strtolower($this->f);
1008
        } elseif ($this->f) {
1009
            $this->DebugMessage('$this->thumbnailFormat staying as "' . $this->thumbnailFormat . '" because $this->f (' . strtolower($this->f) . ') is not in $AvailableImageOutputFormats', __FILE__, __LINE__);
1010
        }
1011
1012
        // for JPEG images, quality 1 (worst) to 99 (best)
1013
        // quality < 25 is nasty, with not much size savings - not recommended
1014
        // problems with 100 - invalid JPEG?
1015
        $this->thumbnailQuality = max(1, min(99, ($this->q ? (int)$this->q : 75)));
1016
        $this->DebugMessage('$this->thumbnailQuality set to "' . $this->thumbnailQuality . '"', __FILE__, __LINE__);
1017
1018
        return true;
1019
    }
1020
1021
    public function setCacheDirectory()
1022
    {
1023
        // resolve cache directory to absolute pathname
1024
        $this->DebugMessage('setCacheDirectory() starting with config_cache_directory = "' . $this->config_cache_directory . '"', __FILE__, __LINE__);
1025
        if ($this->config_cache_directory && ($this->config_cache_directory[0] == '.')) {
1026
            if (preg_match('#^(f|ht)tps?\://#i', $this->src)) {
1027
                if (!$this->config_cache_disable_warning) {
1028
                    $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');
1029
                }
1030
            } elseif ($this->src) {
1031
                // resolve relative cache directory to source image
1032
                $this->config_cache_directory = dirname($this->ResolveFilenameToAbsolute($this->src)) . DIRECTORY_SEPARATOR . $this->config_cache_directory;
0 ignored issues
show
It seems like $this->ResolveFilenameToAbsolute($this->src) can also be of type false and null; 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

1032
                $this->config_cache_directory = dirname(/** @scrutinizer ignore-type */ $this->ResolveFilenameToAbsolute($this->src)) . DIRECTORY_SEPARATOR . $this->config_cache_directory;
Loading history...
1033
            } else {
1034
                // $this->new is probably set
1035
            }
1036
        }
1037
        if (substr($this->config_cache_directory, -1) == '/') {
1038
            $this->config_cache_directory = substr($this->config_cache_directory, 0, -1);
1039
        }
1040
        if ($this->iswindows) {
1041
            $this->config_cache_directory = str_replace('/', DIRECTORY_SEPARATOR, $this->config_cache_directory);
1042
        }
1043
        if ($this->config_cache_directory) {
1044
            $real_cache_path = $this->realPathSafe($this->config_cache_directory);
1045
            if (!$real_cache_path) {
1046
                $this->DebugMessage('$this->realPathSafe($this->config_cache_directory) failed for "' . $this->config_cache_directory . '"', __FILE__, __LINE__);
1047
                if (!is_dir($this->config_cache_directory)) {
1048
                    $this->DebugMessage('!is_dir(' . $this->config_cache_directory . ')', __FILE__, __LINE__);
1049
                }
1050
            }
1051
            if ($real_cache_path) {
1052
                $this->DebugMessage('setting config_cache_directory to $this->realPathSafe(' . $this->config_cache_directory . ') = "' . $real_cache_path . '"', __FILE__, __LINE__);
1053
                $this->config_cache_directory = $real_cache_path;
1054
            }
1055
        }
1056
        if (!is_dir($this->config_cache_directory)) {
1057
            if (!$this->config_cache_disable_warning) {
1058
                $this->ErrorImage('$this->config_cache_directory (' . $this->config_cache_directory . ') does not exist. Adjust "cache_directory" or "cache_disable_warning" in phpThumb.config.php');
1059
            }
1060
            $this->DebugMessage('$this->config_cache_directory (' . $this->config_cache_directory . ') is not a directory', __FILE__, __LINE__);
1061
            $this->config_cache_directory = null;
1062
        } elseif (!@is_writable($this->config_cache_directory)) {
1063
            $this->DebugMessage('$this->config_cache_directory is not writable (' . $this->config_cache_directory . ')', __FILE__, __LINE__);
1064
        }
1065
1066
        $this->InitializeTempDirSetting();
1067
        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)) {
1068
            $this->DebugMessage('setting $this->config_temp_directory = $this->config_cache_directory (' . $this->config_cache_directory . ')', __FILE__, __LINE__);
1069
            $this->config_temp_directory = $this->config_cache_directory;
1070
        }
1071
        return true;
1072
    }
1073
1074
    /* Takes the array of path segments up to now, and the next segment (maybe a modifier: empty, . or ..)
1075
	   Applies it, adding or removing from $segments as a result. Returns nothing. */
1076
    // http://support.silisoftware.com/phpBB3/viewtopic.php?t=961
1077
    public function applyPathSegment(&$segments, $segment)
1078
    {
1079
        if ($segment == '.') {
1080
            return; // always remove
1081
        }
1082
        if ($segment == '') {
1083
            $test = array_pop($segments);
1084
            if (null === $test) {
1085
                $segments[] = $segment; // keep the first empty block
1086
            } elseif ($test == '') {
1087
                $test = array_pop($segments);
1088
                if (null === $test) {
1089
                    $segments[] = $test;
1090
                    $segments[] = $segment; // keep the second one too
1091
                } else { // put both back and ignore segment
1092
                    $segments[] = $test;
1093
                    $segments[] = $test;
1094
                }
1095
            } else {
1096
                $segments[] = $test; // ignore empty blocks
1097
            }
1098
        } else {
1099
            if ($segment == '..') {
1100
                $test = array_pop($segments);
1101
                if (null === $test) {
1102
                    $segments[] = $segment;
1103
                } elseif ($test == '..') {
1104
                    $segments[] = $test;
1105
                    $segments[] = $segment;
1106
                } else {
1107
                    if ($test == '') {
1108
                        $segments[] = $test;
1109
                    } // else nothing, remove both
1110
                }
1111
            } else {
1112
                $segments[] = $segment;
1113
            }
1114
        }
1115
    }
1116
1117
    /* Takes array of path components, normalizes it: removes empty slots and '.', collapses '..' and folder names.  Returns array. */
1118
    // http://support.silisoftware.com/phpBB3/viewtopic.php?t=961
1119
    public function normalizePath($segments)
1120
    {
1121
        $parts = [];
1122
        foreach ($segments as $segment) {
1123
            $this->applyPathSegment($parts, $segment);
1124
        }
1125
        return $parts;
1126
    }
1127
1128
    /* True if the provided path points (without resolving symbolic links) into one of the allowed directories. */
1129
    // http://support.silisoftware.com/phpBB3/viewtopic.php?t=961
1130
    public function matchPath($path, $allowed_dirs)
1131
    {
1132
        if (!empty($allowed_dirs)) {
1133
            foreach ($allowed_dirs as $one_dir) {
1134
                if (preg_match('#^' . preg_quote(str_replace(DIRECTORY_SEPARATOR, '/', $this->realPathSafe($one_dir))) . '#', $path)) {
1135
                    return true;
1136
                }
1137
            }
1138
        }
1139
        return false;
1140
    }
1141
1142
    /* True if the provided path points inside one of open_basedirs (or if open_basedirs are disabled) */
1143
    // http://support.silisoftware.com/phpBB3/viewtopic.php?t=961
1144
    public function isInOpenBasedir($path)
1145
    {
1146
        static $open_basedirs = null;
1147
        if (null === $open_basedirs) {
1148
            $ini_text = ini_get('open_basedir');
1149
            $this->DebugMessage('open_basedir: "' . $ini_text . '"', __FILE__, __LINE__);
1150
            $open_basedirs = [];
1151
            if (strlen($ini_text) > 0) {
1152
                foreach (preg_split('#[;:]#', $ini_text) as $key => $value) {
1153
                    $open_basedirs[$key] = $this->realPathSafe($value);
1154
                }
1155
            }
1156
        }
1157
        return (empty($open_basedirs) || $this->matchPath($path, $open_basedirs));
1158
    }
1159
1160
    /* 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. */
1161
    // http://support.silisoftware.com/phpBB3/viewtopic.php?t=961
1162
    public function resolvePath($path, $allowed_dirs)
1163
    {
1164
        $this->DebugMessage('resolvePath: ' . $path . ' (allowed_dirs: ' . print_r($allowed_dirs, true) . ')', __FILE__, __LINE__);
0 ignored issues
show
Are you sure print_r($allowed_dirs, true) of type string|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

1164
        $this->DebugMessage('resolvePath: ' . $path . ' (allowed_dirs: ' . /** @scrutinizer ignore-type */ print_r($allowed_dirs, true) . ')', __FILE__, __LINE__);
Loading history...
1165
1166
        // add base path to the top of the list
1167
        if (!$this->config_allow_src_above_docroot) {
1168
            array_unshift($allowed_dirs, $this->realPathSafe($this->config_document_root));
1169
        } else {
1170
            if (!$this->config_allow_src_above_phpthumb) {
1171
                array_unshift($allowed_dirs, $this->realPathSafe(__DIR__));
1172
            } else {
1173
                // no checks are needed, offload the work to realpath and forget about it
1174
                $this->DebugMessage('resolvePath: checks disabled, returning ' . $this->realPathSafe($path), __FILE__, __LINE__);
1175
                return $this->realPathSafe($path);
1176
            }
1177
        }
1178
        if ($path == '') {
1179
            return null; // save us trouble
1180
        }
1181
1182
        do {
1183
            $this->DebugMessage('resolvePath: iteration, path=' . $path . ', base path = ' . $allowed_dirs[0], __FILE__, __LINE__);
1184
1185
            $parts = [];
1186
            // do not use "cleaner" foreach version of this loop as later code relies on both $segments and $i
1187
            // http://support.silisoftware.com/phpBB3/viewtopic.php?t=964
1188
            $segments = explode(DIRECTORY_SEPARATOR, $path);
1189
            for ($i = 0, $iMax = count($segments); $i < $iMax; $i++) {
1190
                $this->applyPathSegment($parts, $segments[$i]);
1191
                $thispart = implode(DIRECTORY_SEPARATOR, $parts);
1192
                if ($this->isInOpenBasedir($thispart)) {
1193
                    if (is_link($thispart)) {
1194
                        break;
1195
                    }
1196
                }
1197
            }
1198
1199
            $this->DebugMessage('resolvePath: stop at component ' . $i, __FILE__, __LINE__);
1200
            // test the part up to here
1201
            $path = implode(DIRECTORY_SEPARATOR, $parts);
1202
            $this->DebugMessage('resolvePath: stop at path=' . $path, __FILE__, __LINE__);
1203
            if (!$this->matchPath($path, $allowed_dirs)) {
1204
                $this->DebugMessage('resolvePath: no match, returning null', __FILE__, __LINE__);
1205
                return null;
1206
            }
1207
            if ($i >= count($segments)) { // reached end
1208
                $this->DebugMessage('resolvePath: path parsed, over', __FILE__, __LINE__);
1209
                break;
1210
            }
1211
            // else it's symlink, rewrite path
1212
            $path = readlink($path);
1213
            $this->DebugMessage('resolvePath: symlink matched, target=' . $path, __FILE__, __LINE__);
1214
1215
            /*
1216
			Replace base path with symlink target.
1217
			Assuming:
1218
			  /www/img/external -> /external
1219
			This is allowed:
1220
			  GET /www/img/external/../external/test/pic.jpg
1221
			This isn't:
1222
			  GET /www/img/external/../www/img/pic.jpg
1223
			So there's only one base path which is the last symlink target, but any number of stable whitelisted paths.
1224
			*/
1225
            if ($this->config_auto_allow_symlinks) {
1226
                $allowed_dirs[0] = $path;
1227
            }
1228
            $path = $path . DIRECTORY_SEPARATOR . implode(DIRECTORY_SEPARATOR, array_slice($segments, $i + 1));
1229
        } while (true);
1230
        return $path;
1231
    }
1232
1233
    public function realPathSafe($filename)
1234
    {
1235
        // 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"
1236
        // realPathSafe() provides a reasonable facsimile of realpath() but does not resolve symbolic links, nor does it check that the file/path actually exists
1237
        if (!$this->config_disable_realpath) {
1238
            return realpath($filename);
1239
        }
1240
1241
        // http://stackoverflow.com/questions/21421569
1242
        $newfilename = preg_replace('#[\\/]+#', DIRECTORY_SEPARATOR, $filename);
1243
1244
        if (phpthumb_functions::is_windows()) {
1245
            $isAlreadyAbsoluteFilename = preg_match('#^[A-Z]\\:#i', $newfilename);  // C:\path\filename.ext
1246
        } else {
1247
            $isAlreadyAbsoluteFilename = ($newfilename[0] == DIRECTORY_SEPARATOR);  // /path/filename.ext
1248
        }
1249
        if (!$isAlreadyAbsoluteFilename) {
1250
            // not already an absolute filename, prepend current directory
1251
            $newfilename = __DIR__ . DIRECTORY_SEPARATOR . $newfilename;
1252
        }
1253
        do {
1254
            $beforeloop = $newfilename;
1255
1256
            // 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.]]
1257
            $newfilename = preg_replace('#' . preg_quote(DIRECTORY_SEPARATOR) . '+#', DIRECTORY_SEPARATOR, $newfilename);
1258
1259
            // Replace all occurrences of /./ with /
1260
            $newfilename = preg_replace('#' . preg_quote(DIRECTORY_SEPARATOR) . '\\.' . preg_quote(DIRECTORY_SEPARATOR) . '#', DIRECTORY_SEPARATOR, $newfilename);
1261
1262
            // Remove ./ if at the start
1263
            $newfilename = preg_replace('#^\\.' . preg_quote(DIRECTORY_SEPARATOR) . '#', '', $newfilename);
1264
1265
            // Remove /. if at the end
1266
            $newfilename = preg_replace('#' . preg_quote(DIRECTORY_SEPARATOR) . '\\.$#', '', $newfilename);
1267
1268
            // Replace /anything/../ with /
1269
            $newfilename = preg_replace('#' . preg_quote(DIRECTORY_SEPARATOR) . '[^' . preg_quote(DIRECTORY_SEPARATOR) . ']+' . preg_quote(DIRECTORY_SEPARATOR) . '\\.\\.' . preg_quote(DIRECTORY_SEPARATOR) . '#', DIRECTORY_SEPARATOR, $newfilename);
1270
1271
            // Remove /anything/.. if at the end
1272
            $newfilename = preg_replace('#' . preg_quote(DIRECTORY_SEPARATOR) . '[^' . preg_quote(DIRECTORY_SEPARATOR) . ']+' . preg_quote(DIRECTORY_SEPARATOR) . '\\.\\.$#', '', $newfilename);
1273
        } while ($newfilename != $beforeloop);
1274
        return $newfilename;
1275
    }
1276
1277
    public function ResolveFilenameToAbsolute($filename)
1278
    {
1279
        if (empty($filename)) {
1280
            return false;
1281
        }
1282
1283
        if (preg_match('#^[a-z0-9]+\\:/{1,2}#i', $filename)) {
1284
            // eg: http://host/path/file.jpg (HTTP URL)
1285
            // eg: ftp://host/path/file.jpg  (FTP URL)
1286
            // eg: data1:/path/file.jpg      (Netware path)
1287
1288
            //$AbsoluteFilename = $filename;
1289
            return $filename;
1290
        } elseif ($this->iswindows && isset($filename[1]) && ($filename[1] == ':')) {
1291
            // absolute pathname (Windows)
1292
            $AbsoluteFilename = $filename;
1293
        } elseif ($this->iswindows && ((substr($filename, 0, 2) == '//') || (substr($filename, 0, 2) == '\\\\'))) {
1294
            // absolute pathname (Windows)
1295
            $AbsoluteFilename = $filename;
1296
        } elseif ($filename[0] == '/') {
1297
            if (@is_readable($filename) && !@is_readable($this->config_document_root . $filename)) {
0 ignored issues
show
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

1297
            if (@is_readable($filename) && !@is_readable(/** @scrutinizer ignore-type */ $this->config_document_root . $filename)) {
Loading history...
1298
                // absolute filename (*nix)
1299
                $AbsoluteFilename = $filename;
1300
            } elseif (isset($filename[1]) && ($filename[1] == '~')) {
1301
                // /~user/path
1302
                if ($ApacheLookupURIarray = phpthumb_functions::ApacheLookupURIarray($filename)) {
1303
                    $AbsoluteFilename = $ApacheLookupURIarray['filename'];
1304
                } else {
1305
                    $AbsoluteFilename = $this->realPathSafe($filename);
1306
                    if (@is_readable($AbsoluteFilename)) {
1307
                        $this->DebugMessage('phpthumb_functions::ApacheLookupURIarray() failed for "' . $filename . '", but the correct filename (' . $AbsoluteFilename . ') seems to have been resolved with $this->realPathSafe($filename)', __FILE__, __LINE__);
1308
                    } elseif (is_dir(dirname($AbsoluteFilename))) {
1309
                        $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__);
1310
                    } else {
1311
                        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")');
1312
                    }
1313
                }
1314
            } else {
1315
                // relative filename (any OS)
1316
                if (preg_match('#^' . preg_quote($this->config_document_root) . '#', $filename)) {
0 ignored issues
show
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

1316
                if (preg_match('#^' . preg_quote(/** @scrutinizer ignore-type */ $this->config_document_root) . '#', $filename)) {
Loading history...
1317
                    $AbsoluteFilename = $filename;
1318
                    $this->DebugMessage('ResolveFilenameToAbsolute() NOT prepending $this->config_document_root (' . $this->config_document_root . ') to $filename (' . $filename . ') resulting in ($AbsoluteFilename = "' . $AbsoluteFilename . '")', __FILE__, __LINE__);
1319
                } else {
1320
                    $AbsoluteFilename = $this->config_document_root . $filename;
1321
                    $this->DebugMessage('ResolveFilenameToAbsolute() prepending $this->config_document_root (' . $this->config_document_root . ') to $filename (' . $filename . ') resulting in ($AbsoluteFilename = "' . $AbsoluteFilename . '")', __FILE__, __LINE__);
1322
                }
1323
            }
1324
        } else {
1325
            // relative to current directory (any OS)
1326
            $AbsoluteFilename = __DIR__ . DIRECTORY_SEPARATOR . preg_replace('#[/\\\\]#', DIRECTORY_SEPARATOR, $filename);
1327
1328
            if (substr(dirname(@$_SERVER['PHP_SELF']), 0, 2) == '/~') {
1329
                if ($ApacheLookupURIarray = phpthumb_functions::ApacheLookupURIarray(dirname(@$_SERVER['PHP_SELF']))) {
1330
                    $AbsoluteFilename = $ApacheLookupURIarray['filename'] . DIRECTORY_SEPARATOR . $filename;
1331
                } else {
1332
                    $AbsoluteFilename = $this->realPathSafe('.') . DIRECTORY_SEPARATOR . $filename;
1333
                    if (@is_readable($AbsoluteFilename)) {
1334
                        $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__);
1335
                    } elseif (is_dir(dirname($AbsoluteFilename))) {
1336
                        $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__);
1337
                    } else {
1338
                        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');
1339
                    }
1340
                }
1341
            }
1342
        }
1343
        /*
1344
		// removed 2014-May-30: http://support.silisoftware.com/phpBB3/viewtopic.php?t=961
1345
		if (is_link($AbsoluteFilename)) {
1346
			$this->DebugMessage('is_link()==true, changing "'.$AbsoluteFilename.'" to "'.readlink($AbsoluteFilename).'"', __FILE__, __LINE__);
1347
			$AbsoluteFilename = readlink($AbsoluteFilename);
1348
		}
1349
		if ($this->realPathSafe($AbsoluteFilename)) {
1350
			$AbsoluteFilename = $this->realPathSafe($AbsoluteFilename);
1351
		}
1352
		*/
1353
        if ($this->iswindows) {
1354
            $AbsoluteFilename = preg_replace('#^' . preg_quote($this->realPathSafe($this->config_document_root)) . '#i', str_replace('\\', '\\\\', $this->realPathSafe($this->config_document_root)), $AbsoluteFilename);
1355
            $AbsoluteFilename = str_replace(DIRECTORY_SEPARATOR, '/', $AbsoluteFilename);
1356
        }
1357
        $resolvedAbsoluteFilename = $this->resolvePath($AbsoluteFilename, $this->config_additional_allowed_dirs);
1358
        if (!$this->config_allow_src_above_docroot && !preg_match('#^' . preg_quote(str_replace(DIRECTORY_SEPARATOR, '/', $this->realPathSafe($this->config_document_root))) . '#', $resolvedAbsoluteFilename)) {
0 ignored issues
show
It seems like $resolvedAbsoluteFilename can also be of type null; 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

1358
        if (!$this->config_allow_src_above_docroot && !preg_match('#^' . preg_quote(str_replace(DIRECTORY_SEPARATOR, '/', $this->realPathSafe($this->config_document_root))) . '#', /** @scrutinizer ignore-type */ $resolvedAbsoluteFilename)) {
Loading history...
1359
            $this->DebugMessage('!$this->config_allow_src_above_docroot therefore setting "' . $AbsoluteFilename . '" (outside "' . $this->realPathSafe($this->config_document_root) . '") to null', __FILE__, __LINE__);
1360
            return false;
1361
        }
1362
        if (!$this->config_allow_src_above_phpthumb && !preg_match('#^' . preg_quote(str_replace(DIRECTORY_SEPARATOR, '/', __DIR__)) . '#', $resolvedAbsoluteFilename)) {
1363
            $this->DebugMessage('!$this->config_allow_src_above_phpthumb therefore setting "' . $AbsoluteFilename . '" (outside "' . __DIR__ . '") to null', __FILE__, __LINE__);
1364
            return false;
1365
        }
1366
        return $resolvedAbsoluteFilename;
1367
    }
1368
1369
    public function file_exists_ignoreopenbasedir($filename, $cached = true)
1370
    {
1371
        static $open_basedirs = null;
1372
        static $file_exists_cache = [];
1373
        if (!$cached || !isset($file_exists_cache[$filename])) {
1374
            if (null === $open_basedirs) {
1375
                $open_basedirs = preg_split('#[;:]#', ini_get('open_basedir'));
1376
            }
1377
            if (empty($open_basedirs) || in_array(dirname($filename), $open_basedirs)) {
1378
                $file_exists_cache[$filename] = file_exists($filename);
1379
            } elseif ($this->iswindows) {
1380
                $ls_filename                  = trim(phpthumb_functions::SafeExec('dir /b ' . phpthumb_functions::escapeshellarg_replacement($filename)));
0 ignored issues
show
It seems like phpthumb_functions::Safe...replacement($filename)) can also be of type false; however, parameter $string 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

1380
                $ls_filename                  = trim(/** @scrutinizer ignore-type */ phpthumb_functions::SafeExec('dir /b ' . phpthumb_functions::escapeshellarg_replacement($filename)));
Loading history...
1381
                $file_exists_cache[$filename] = ($ls_filename == basename($filename));  // command dir /b return only filename without path
1382
            } else {
1383
                $ls_filename                  = trim(phpthumb_functions::SafeExec('ls ' . phpthumb_functions::escapeshellarg_replacement($filename)));
1384
                $file_exists_cache[$filename] = ($ls_filename == $filename);
1385
            }
1386
        }
1387
        return $file_exists_cache[$filename];
1388
    }
1389
1390
    public function ImageMagickWhichConvert()
1391
    {
1392
        static $WhichConvert = null;
1393
        if (null === $WhichConvert) {
1394
            if ($this->iswindows) {
1395
                $WhichConvert = false;
1396
            } else {
1397
                $IMwhichConvertCacheFilename = $this->config_cache_directory . DIRECTORY_SEPARATOR . 'phpThumbCacheIMwhichConvert.txt';
1398
                if (($cachedwhichconvertstring = @file_get_contents($IMwhichConvertCacheFilename)) !== false) {
1399
                    $WhichConvert = $cachedwhichconvertstring;
1400
                } else {
1401
                    $WhichConvert = trim(phpthumb_functions::SafeExec('which convert'));
0 ignored issues
show
It seems like phpthumb_functions::SafeExec('which convert') can also be of type false; however, parameter $string 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

1401
                    $WhichConvert = trim(/** @scrutinizer ignore-type */ phpthumb_functions::SafeExec('which convert'));
Loading history...
1402
                    @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

1402
                    /** @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...
1403
                    @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

1403
                    /** @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...
1404
                }
1405
            }
1406
        }
1407
        return $WhichConvert;
1408
    }
1409
1410
    public function ImageMagickCommandlineBase()
1411
    {
1412
        static $commandline = null;
1413
        if (null === $commandline) {
1414
            if ($this->issafemode) {
1415
                $commandline = '';
1416
                return $commandline;
1417
            }
1418
1419
            $IMcommandlineBaseCacheFilename = $this->config_cache_directory . DIRECTORY_SEPARATOR . 'phpThumbCacheIMcommandlineBase.txt';
1420
            if (($commandline = @file_get_contents($IMcommandlineBaseCacheFilename)) !== false) {
1421
                return $commandline;
1422
            }
1423
1424
            $commandline = (null !== $this->config_imagemagick_path ? $this->config_imagemagick_path : '');
0 ignored issues
show
The assignment to $commandline is dead and can be removed.
Loading history...
1425
1426
            if ($this->config_imagemagick_path && ($this->config_imagemagick_path != $this->realPathSafe($this->config_imagemagick_path))) {
1427
                if (@is_executable($this->realPathSafe($this->config_imagemagick_path))) {
1428
                    $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__);
1429
                    $this->config_imagemagick_path = $this->realPathSafe($this->config_imagemagick_path);
1430
                } else {
1431
                    $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__);
1432
                }
1433
            }
1434
            $this->DebugMessage('                  file_exists(' . $this->config_imagemagick_path . ') = ' . (int)(@file_exists($this->config_imagemagick_path)), __FILE__, __LINE__);
1435
            $this->DebugMessage('file_exists_ignoreopenbasedir(' . $this->config_imagemagick_path . ') = ' . (int)$this->file_exists_ignoreopenbasedir($this->config_imagemagick_path), __FILE__, __LINE__);
1436
            $this->DebugMessage('                      is_file(' . $this->config_imagemagick_path . ') = ' . (int)(@is_file($this->config_imagemagick_path)), __FILE__, __LINE__);
1437
            $this->DebugMessage('                is_executable(' . $this->config_imagemagick_path . ') = ' . (int)(@is_executable($this->config_imagemagick_path)), __FILE__, __LINE__);
1438
1439
            if ($this->file_exists_ignoreopenbasedir($this->config_imagemagick_path)) {
1440
                $this->DebugMessage('using ImageMagick path from $this->config_imagemagick_path (' . $this->config_imagemagick_path . ')', __FILE__, __LINE__);
1441
                if ($this->iswindows) {
1442
                    $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(
1443
                            basename($this->config_imagemagick_path)
1444
                        );
1445
                } else {
1446
                    $commandline = phpthumb_functions::escapeshellarg_replacement($this->config_imagemagick_path);
1447
                }
1448
            } else {
1449
                $which_convert = $this->ImageMagickWhichConvert();
1450
                $IMversion     = $this->ImageMagickVersion();
1451
1452
                if ($which_convert && ($which_convert[0] == '/') && $this->file_exists_ignoreopenbasedir($which_convert)) {
1453
                    // `which convert` *should* return the path if "convert" exist, or nothing if it doesn't
1454
                    // other things *may* get returned, like "sh: convert: not found" or "no convert in /usr/local/bin /usr/sbin /usr/bin /usr/ccs/bin"
1455
                    // so only do this if the value returned exists as a file
1456
                    $this->DebugMessage('using ImageMagick path from `which convert` (' . $which_convert . ')', __FILE__, __LINE__);
1457
                    $commandline = 'convert';
1458
                } elseif ($IMversion) {
1459
                    $this->DebugMessage('setting ImageMagick path to $this->config_imagemagick_path (' . $this->config_imagemagick_path . ') [' . $IMversion . ']', __FILE__, __LINE__);
1460
                    $commandline = $this->config_imagemagick_path;
1461
                } else {
1462
                    $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__);
1463
                    $commandline = '';
1464
                }
1465
            }
1466
1467
            @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

1467
            /** @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...
1468
            @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

1468
            /** @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...
1469
        }
1470
        return $commandline;
1471
    }
1472
1473
    public function ImageMagickVersion($returnRAW = false)
1474
    {
1475
        static $versionstring = null;
1476
        if (null === $versionstring) {
1477
            $versionstring = [0 => false, 1 => false];
1478
1479
            $IMversionCacheFilename = $this->config_cache_directory . DIRECTORY_SEPARATOR . 'phpThumbCacheIMversion.txt';
1480
            if ($cachedversionstring = @file_get_contents($IMversionCacheFilename)) {
1481
                $versionstring    = explode("\n", $cachedversionstring, 2);
1482
                $versionstring[0] = ($versionstring[0] ? $versionstring[0] : false); // "false" is stored as an empty string in the cache file
1483
                $versionstring[1] = ($versionstring[1] ? $versionstring[1] : false); // "false" is stored as an empty string in the cache file
1484
1485
            } else {
1486
                $commandline = $this->ImageMagickCommandlineBase();
1487
                $commandline = (null !== $commandline ? $commandline : '');
1488
                if ($commandline) {
1489
                    $commandline .= ' --version';
1490
                    $this->DebugMessage('ImageMagick version checked with "' . $commandline . '"', __FILE__, __LINE__);
1491
                    $versionstring[1] = trim(phpthumb_functions::SafeExec($commandline));
0 ignored issues
show
It seems like phpthumb_functions::SafeExec($commandline) can also be of type false; however, parameter $string 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

1491
                    $versionstring[1] = trim(/** @scrutinizer ignore-type */ phpthumb_functions::SafeExec($commandline));
Loading history...
1492
                    if (preg_match('#^Version: [^\d]*([ 0-9\\.\\:Q/\\-]+)#i', $versionstring[1], $matches)) {
1493
                        $versionstring[0] = trim($matches[1]);
1494
                    } else {
1495
                        $versionstring[0] = false;
1496
                        $this->DebugMessage('ImageMagick did not return recognized version string (' . $versionstring[1] . ')', __FILE__, __LINE__);
1497
                    }
1498
                    $this->DebugMessage('ImageMagick convert --version says "' . @$matches[0] . '"', __FILE__, __LINE__);
1499
                }
1500
1501
                @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

1501
                /** @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...
1502
                @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

1502
                /** @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...
1503
            }
1504
        }
1505
        return $versionstring[(int)$returnRAW];
1506
    }
1507
1508
    public function ImageMagickSwitchAvailable($switchname)
1509
    {
1510
        static $IMoptions = null;
1511
        if (null === $IMoptions) {
1512
            $IMoptions   = [];
1513
            $commandline = $this->ImageMagickCommandlineBase();
1514
            if (null !== $commandline) {
1515
                $commandline  .= ' -help';
1516
                $IMhelp_lines = explode("\n", phpthumb_functions::SafeExec($commandline));
0 ignored issues
show
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

1516
                $IMhelp_lines = explode("\n", /** @scrutinizer ignore-type */ phpthumb_functions::SafeExec($commandline));
Loading history...
1517
                foreach ($IMhelp_lines as $line) {
1518
                    if (preg_match('#^[\\+\\-]([a-z\\-]+) #', trim($line), $matches)) {
1519
                        $IMoptions[$matches[1]] = true;
1520
                    }
1521
                }
1522
            }
1523
        }
1524
        if (is_array($switchname)) {
1525
            $allOK = true;
1526
            foreach ($switchname as $key => $value) {
1527
                if (!isset($IMoptions[$value])) {
1528
                    $allOK = false;
1529
                    break;
1530
                }
1531
            }
1532
            $this->DebugMessage('ImageMagickSwitchAvailable(' . implode(';', $switchname) . ') = ' . (int)$allOK . '', __FILE__, __LINE__);
1533
        } else {
1534
            $allOK = isset($IMoptions[$switchname]);
1535
            $this->DebugMessage('ImageMagickSwitchAvailable(' . $switchname . ') = ' . (int)$allOK . '', __FILE__, __LINE__);
1536
        }
1537
        return $allOK;
1538
    }
1539
1540
    public function ImageMagickFormatsList()
1541
    {
1542
        static $IMformatsList = null;
1543
        if (null === $IMformatsList) {
1544
            $IMformatsList = '';
1545
            $commandline   = $this->ImageMagickCommandlineBase();
1546
            if (null !== $commandline) {
1547
                $commandline   = dirname($commandline) . DIRECTORY_SEPARATOR . str_replace('convert', 'identify', basename($commandline));
1548
                $commandline   .= ' -list format';
1549
                $IMformatsList = phpthumb_functions::SafeExec($commandline);
1550
            }
1551
        }
1552
        return $IMformatsList;
1553
    }
1554
1555
    public function SourceDataToTempFile()
1556
    {
1557
        if ($IMtempSourceFilename = $this->phpThumb_tempnam()) {
1558
            $IMtempSourceFilename = $this->realPathSafe($IMtempSourceFilename);
1559
            ob_start();
1560
            $fp_tempfile         = fopen($IMtempSourceFilename, 'wb');
1561
            $tempfile_open_error = ob_get_contents();
1562
            ob_end_clean();
1563
            if ($fp_tempfile) {
0 ignored issues
show
$fp_tempfile is of type resource, thus it always evaluated to false.
Loading history...
1564
                fwrite($fp_tempfile, $this->rawImageData);
1565
                fclose($fp_tempfile);
1566
                @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

1566
                /** @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...
1567
                $this->sourceFilename = $IMtempSourceFilename;
1568
                $this->DebugMessage('ImageMagickThumbnailToGD() setting $this->sourceFilename to "' . $IMtempSourceFilename . '" from $this->rawImageData (' . strlen($this->rawImageData) . ' bytes)', __FILE__, __LINE__);
1569
            } else {
1570
                $this->DebugMessage('ImageMagickThumbnailToGD() FAILED setting $this->sourceFilename to "' . $IMtempSourceFilename . '" (failed to open for writing: "' . $tempfile_open_error . '")', __FILE__, __LINE__);
1571
            }
1572
            unset($tempfile_open_error, $IMtempSourceFilename);
1573
            return true;
1574
        }
1575
        $this->DebugMessage('SourceDataToTempFile() FAILED because $this->phpThumb_tempnam() failed', __FILE__, __LINE__);
1576
        return false;
1577
    }
1578
1579
    public function ImageMagickThumbnailToGD()
1580
    {
1581
        // http://www.imagemagick.org/script/command-line-options.php
1582
1583
        $this->useRawIMoutput = true;
1584
        if (phpthumb_functions::gd_version()) {
1585
            // if GD is not available, must use whatever ImageMagick can output
1586
1587
            // $CannotMagickParameters contains options that cannot be used with ImageMagick
1588
            $CannotMagickParameters = ['ica'];
1589
            foreach ($CannotMagickParameters as $parameter) {
1590
                if (isset($this->$parameter)) {
1591
                    $this->DebugMessage('cannot process with ImageMagick because "' . $parameter . '" is set', __FILE__, __LINE__);
1592
                    $this->useRawIMoutput = false;
1593
                    return false;
1594
                }
1595
            }
1596
1597
            // $UnAllowedParameters contains options that can only be processed in GD, not ImageMagick
1598
            // note: 'fltr' *may* need to be processed by GD, but we'll check that in more detail below
1599
            $UnAllowedParameters = ['xto', 'ar', 'bg', 'bc'];
1600
            // 'ra' may be part of this list, if not a multiple of 90 degrees
1601
            foreach ($UnAllowedParameters as $parameter) {
1602
                if (isset($this->$parameter)) {
1603
                    $this->DebugMessage('$this->useRawIMoutput=false because "' . $parameter . '" is set', __FILE__, __LINE__);
1604
                    $this->useRawIMoutput = false;
1605
                    break;
1606
                }
1607
            }
1608
        }
1609
        $this->DebugMessage('$this->useRawIMoutput=' . ($this->useRawIMoutput ? 'true' : 'false') . ' after checking $UnAllowedParameters', __FILE__, __LINE__);
1610
        $ImageCreateFunction = '';
1611
        $outputFormat        = $this->thumbnailFormat;
1612
        if (phpthumb_functions::gd_version()) {
1613
            if ($this->useRawIMoutput) {
1614
                switch ($this->thumbnailFormat) {
1615
                    case 'gif':
1616
                        $ImageCreateFunction = 'imagecreatefromgif';
1617
                        $this->is_alpha      = true;
1618
                        break;
1619
                    case 'png':
1620
                        $ImageCreateFunction = 'imagecreatefrompng';
1621
                        $this->is_alpha      = true;
1622
                        break;
1623
                    case 'jpg':
1624
                    case 'jpeg':
1625
                        $ImageCreateFunction = 'imagecreatefromjpeg';
1626
                        break;
1627
                    case 'webp':
1628
                        $ImageCreateFunction = 'imagecreatefromwebp';
1629
                        $this->is_alpha      = true;
1630
                        break;
1631
                    default:
1632
                        $this->DebugMessage('Forcing output to PNG because $this->thumbnailFormat (' . $this->thumbnailFormat . ' is not a GD-supported format)', __FILE__, __LINE__);
1633
                        $outputFormat         = 'png';
1634
                        $ImageCreateFunction  = 'imagecreatefrompng';
1635
                        $this->is_alpha       = true;
1636
                        $this->useRawIMoutput = false;
1637
                        break;
1638
                }
1639
                if (!function_exists($ImageCreateFunction)) {
1640
                    // ImageMagickThumbnailToGD() depends on imagecreatefrompng/imagecreatefromgif
1641
                    //$this->DebugMessage('ImageMagickThumbnailToGD() aborting because '.@$ImageCreateFunction.'() is not available', __FILE__, __LINE__);
1642
                    $this->useRawIMoutput = true;
1643
                    //return false;
1644
                }
1645
            } else {
1646
                $outputFormat         = 'png';
1647
                $ImageCreateFunction  = 'imagecreatefrompng';
1648
                $this->is_alpha       = true;
1649
                $this->useRawIMoutput = false;
1650
            }
1651
        }
1652
1653
        // http://freealter.org/doc_distrib/ImageMagick-5.1.1/www/convert.html
1654
        if (!$this->sourceFilename && $this->rawImageData) {
1655
            $this->SourceDataToTempFile();
1656
        }
1657
        if (!$this->sourceFilename) {
1658
            $this->DebugMessage('ImageMagickThumbnailToGD() aborting because $this->sourceFilename is empty', __FILE__, __LINE__);
1659
            $this->useRawIMoutput = false;
1660
            return false;
1661
        }
1662
        if ($this->issafemode) {
1663
            $this->DebugMessage('ImageMagickThumbnailToGD() aborting because safe_mode is enabled', __FILE__, __LINE__);
1664
            $this->useRawIMoutput = false;
1665
            return false;
1666
        }
1667
        // TO BE FIXED
1668
        //if (true) {
1669
        //	$this->DebugMessage('ImageMagickThumbnailToGD() aborting it is broken right now', __FILE__, __LINE__);
1670
        //	$this->useRawIMoutput = false;
1671
        //	return false;
1672
        //}
1673
1674
        $commandline = $this->ImageMagickCommandlineBase();
1675
        if ($commandline) {
1676
            $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
1677
            if ($IMtempfilename = $this->phpThumb_tempnam()) {
1678
                $IMtempfilename = $this->realPathSafe($IMtempfilename);
1679
1680
                $IMuseExplicitImageOutputDimensions = false;
1681
                if ($this->ImageMagickSwitchAvailable('thumbnail') && $this->config_imagemagick_use_thumbnail) {
1682
                    $IMresizeParameter = 'thumbnail';
1683
                } else {
1684
                    $IMresizeParameter = 'resize';
1685
1686
                    // some (older? around 2002) versions of IM won't accept "-resize 100x" but require "-resize 100x100"
1687
                    $commandline_test                   = $this->ImageMagickCommandlineBase() . ' logo: -resize 1x ' . phpthumb_functions::escapeshellarg_replacement($IMtempfilename) . ' 2>&1';
1688
                    $IMresult_test                      = phpthumb_functions::SafeExec($commandline_test);
1689
                    $IMuseExplicitImageOutputDimensions = preg_match('#image dimensions are zero#i', $IMresult_test);
0 ignored issues
show
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

1689
                    $IMuseExplicitImageOutputDimensions = preg_match('#image dimensions are zero#i', /** @scrutinizer ignore-type */ $IMresult_test);
Loading history...
1690
                    $this->DebugMessage('IMuseExplicitImageOutputDimensions = ' . (int)$IMuseExplicitImageOutputDimensions, __FILE__, __LINE__);
1691
                    if ($fp_im_temp = @fopen($IMtempfilename, 'wb')) {
1692
                        // erase temp image so ImageMagick logo doesn't get output if other processing fails
1693
                        fclose($fp_im_temp);
1694
                        @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

1694
                        /** @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...
1695
                    }
1696
                }
1697
1698
                ob_start();
1699
                $getimagesize      = getimagesize($this->sourceFilename);
1700
                $GetImageSizeError = ob_get_contents();
1701
                ob_end_clean();
1702
                if (is_array($getimagesize)) {
0 ignored issues
show
The condition is_array($getimagesize) is always true.
Loading history...
1703
                    $this->DebugMessage('getimagesize(' . $this->sourceFilename . ') SUCCEEDED: ' . print_r($getimagesize, true), __FILE__, __LINE__);
0 ignored issues
show
Are you sure print_r($getimagesize, true) of type string|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

1703
                    $this->DebugMessage('getimagesize(' . $this->sourceFilename . ') SUCCEEDED: ' . /** @scrutinizer ignore-type */ print_r($getimagesize, true), __FILE__, __LINE__);
Loading history...
1704
                } else {
1705
                    $this->DebugMessage('getimagesize(' . $this->sourceFilename . ') FAILED with error "' . $GetImageSizeError . '"', __FILE__, __LINE__);
1706
                }
1707
                if (null !== $this->dpi && $this->ImageMagickSwitchAvailable('density')) {
1708
                    // for vector source formats only (WMF, PDF, etc)
1709
                    if (is_array($getimagesize) && isset($getimagesize[2]) && ($getimagesize[2] == IMAGETYPE_PNG)) {
1710
                        // explicitly exclude PNG from "-flatten" to make sure transparency is preserved
1711
                        // https://github.com/JamesHeinrich/phpThumb/issues/65
1712
                    } else {
1713
                        $commandline .= ' -flatten';
1714
                        $commandline .= ' -density ' . phpthumb_functions::escapeshellarg_replacement($this->dpi);
1715
                    }
1716
                }
1717
                if (is_array($getimagesize)) {
1718
                    $this->DebugMessage('getimagesize(' . $this->sourceFilename . ') returned [w=' . $getimagesize[0] . ';h=' . $getimagesize[1] . ';f=' . $getimagesize[2] . ']', __FILE__, __LINE__);
1719
                    $this->source_width  = $getimagesize[0];
1720
                    $this->source_height = $getimagesize[1];
1721
                    $this->DebugMessage('source dimensions set to ' . $this->source_width . 'x' . $this->source_height, __FILE__, __LINE__);
1722
                    $this->SetOrientationDependantWidthHeight();
1723
1724
                    if (!preg_match('#(' . implode('|', $this->AlphaCapableFormats) . ')#i', $outputFormat)) {
1725
                        // not a transparency-capable format
1726
                        $commandline .= ' -background ' . phpthumb_functions::escapeshellarg_replacement('#' . ($this->bg ? $this->bg : 'FFFFFF'));
1727
                        if (!stristr($commandline, ' -flatten')) {
1728
                            $commandline .= ' -flatten';
1729
                        }
1730
                    } else {
1731
                        if ($getimagesize[2] == IMAGETYPE_PNG && !$this->bg) {
1732
                            $commandline .= ' -background none';
1733
                        }
1734
                    }
1735
                    if ($getimagesize[2] == IMAGETYPE_GIF) {
1736
                        $commandline .= ' -coalesce'; // may be needed for animated GIFs
1737
                    }
1738
                    if ($this->source_width || $this->source_height) {
1739
                        if ($this->zc) {
1740
                            $borderThickness = 0;
1741
                            if (!empty($this->fltr)) {
1742
                                foreach ($this->fltr as $key => $value) {
1743
                                    if (preg_match('#^bord\|([\d]+)#', $value, $matches)) {
1744
                                        $borderThickness = $matches[1];
1745
                                        break;
1746
                                    }
1747
                                }
1748
                            }
1749
                            $wAll  = (int)max($this->w, $this->wp, $this->wl, $this->ws) - (2 * $borderThickness);
1750
                            $hAll  = (int)max($this->h, $this->hp, $this->hl, $this->hs) - (2 * $borderThickness);
1751
                            $imAR  = $this->source_width / $this->source_height;
1752
                            $zcAR  = (($wAll && $hAll) ? $wAll / $hAll : 1);
1753
                            $side  = phpthumb_functions::nonempty_min($this->source_width, $this->source_height, max($wAll, $hAll));
1754
                            $sideX = phpthumb_functions::nonempty_min($this->source_width, $wAll, round($hAll * $zcAR));
0 ignored issues
show
The assignment to $sideX is dead and can be removed.
Loading history...
1755
                            $sideY = phpthumb_functions::nonempty_min($this->source_height, $hAll, round($wAll / $zcAR));
1756
1757
                            $thumbnailH = round(max($sideY, ($sideY * $zcAR) / $imAR));
1758
                            if ($this->aoe == 1) {
1759
                                $commandline .= ' -' . $IMresizeParameter . ' "' . $wAll . 'x' . $hAll . '^"';
1760
                            } else {
1761
                                $commandline .= ' -' . $IMresizeParameter . ' ' . phpthumb_functions::escapeshellarg_replacement(($IMuseExplicitImageOutputDimensions ? $thumbnailH : '') . 'x' . $thumbnailH);
1762
                            }
1763
1764
                            switch (strtoupper($this->zc)) {
1765
                                case 'T':
1766
                                    $commandline .= ' -gravity north';
1767
                                    break;
1768
                                case 'B':
1769
                                    $commandline .= ' -gravity south';
1770
                                    break;
1771
                                case 'L':
1772
                                    $commandline .= ' -gravity west';
1773
                                    break;
1774
                                case 'R':
1775
                                    $commandline .= ' -gravity east';
1776
                                    break;
1777
                                case 'TL':
1778
                                    $commandline .= ' -gravity northwest';
1779
                                    break;
1780
                                case 'TR':
1781
                                    $commandline .= ' -gravity northeast';
1782
                                    break;
1783
                                case 'BL':
1784
                                    $commandline .= ' -gravity southwest';
1785
                                    break;
1786
                                case 'BR':
1787
                                    $commandline .= ' -gravity southeast';
1788
                                    break;
1789
                                case '1':
1790
                                case 'C':
1791
                                default:
1792
                                    $commandline .= ' -gravity center';
1793
                                    break;
1794
                            }
1795
1796
                            if (($wAll > 0) && ($hAll > 0)) {
1797
                                $commandline .= ' -crop ' . phpthumb_functions::escapeshellarg_replacement($wAll . 'x' . $hAll . '+0+0');
1798
                            } else {
1799
                                $commandline .= ' -crop ' . phpthumb_functions::escapeshellarg_replacement($side . 'x' . $side . '+0+0');
1800
                            }
1801
                            if ($this->ImageMagickSwitchAvailable('repage')) {
1802
                                $commandline .= ' +repage';
1803
                            } else {
1804
                                $this->DebugMessage('Skipping "+repage" because ImageMagick (v' . $this->ImageMagickVersion() . ') does not support it', __FILE__, __LINE__);
1805
                            }
1806
                        } elseif ($this->sw || $this->sh || $this->sx || $this->sy) {
1807
                            $crop_param = '';
1808
                            $crop_param .= ($this->sw ? (($this->sw < 2) ? round($this->sw * $this->source_width) : $this->sw) : $this->source_width);
1809
                            $crop_param .= 'x' . ($this->sh ? (($this->sh < 2) ? round($this->sh * $this->source_height) : $this->sh) : $this->source_height);
1810
                            $crop_param .= '+' . (($this->sx < 2) ? round($this->sx * $this->source_width) : $this->sx);
1811
                            $crop_param .= '+' . (($this->sy < 2) ? round($this->sy * $this->source_height) : $this->sy);
1812
                            // TO BE FIXED
1813
                            // makes 1x1 output
1814
                            // 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
1815
                            // '/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'
1816
                            $commandline .= ' -crop ' . phpthumb_functions::escapeshellarg_replacement($crop_param);
1817
1818
                            // this is broken for aoe=1, but unsure how to fix. Send advice to [email protected]
1819
                            if ($this->w || $this->h) {
1820
                                //if ($this->ImageMagickSwitchAvailable('repage')) {
1821
                                if (false) {
1822
                                    // TO BE FIXED
1823
                                    // newer versions of ImageMagick require -repage <geometry>
1824
                                    $commandline .= ' -repage';
1825
                                } else {
1826
                                    $this->DebugMessage('Skipping "-repage" because ImageMagick (v' . $this->ImageMagickVersion() . ') does not support it', __FILE__, __LINE__);
1827
                                }
1828
                                if ($IMuseExplicitImageOutputDimensions) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $IMuseExplicitImageOutputDimensions of type false|integer 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...
1829
                                    if ($this->w && !$this->h) {
1830
                                        $this->h = ceil($this->w / ($this->source_width / $this->source_height));
1831
                                    } elseif ($this->h && !$this->w) {
1832
                                        $this->w = ceil($this->h * ($this->source_width / $this->source_height));
1833
                                    }
1834
                                }
1835
                                $commandline .= ' -' . $IMresizeParameter . ' ' . phpthumb_functions::escapeshellarg_replacement($this->w . 'x' . $this->h);
1836
                            }
1837
                        } else {
1838
                            if ($this->iar && ((int)$this->w > 0) && ((int)$this->h > 0)) {
1839
                                [$nw, $nh] = phpthumb_functions::TranslateWHbyAngle($this->w, $this->h, $this->ra);
1840
                                $nw          = ((round($nw) != 0) ? round($nw) : '');
1841
                                $nh          = ((round($nh) != 0) ? round($nh) : '');
1842
                                $commandline .= ' -' . $IMresizeParameter . ' ' . phpthumb_functions::escapeshellarg_replacement($nw . 'x' . $nh . '!');
1843
                            } elseif ($this->far && ((int)$this->w > 0) && ((int)$this->h > 0)) {
1844
                                $commandline .= ' -' . $IMresizeParameter . ' ' . phpthumb_functions::escapeshellarg_replacement(phpthumb_functions::nonempty_min($this->w, $getimagesize[0]) . 'x' . phpthumb_functions::nonempty_min($this->h, $getimagesize[1]));
1845
                                $commandline .= ' -gravity center';
1846
                                if ($this->bg) {
1847
                                    $commandline .= ' -background ' . phpthumb_functions::escapeshellarg_replacement('#' . $this->bg);
1848
                                } else {
1849
                                    $commandline .= ' -background none';
1850
                                }
1851
                                $commandline .= ' -extent ' . phpthumb_functions::escapeshellarg_replacement($this->w . 'x' . $this->h);
0 ignored issues
show
Are you sure $this->h of type false|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

1851
                                $commandline .= ' -extent ' . phpthumb_functions::escapeshellarg_replacement($this->w . 'x' . /** @scrutinizer ignore-type */ $this->h);
Loading history...
Are you sure $this->w of type false|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

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

2281
                    $this->FatalError('ImageMagick failed with message (' . trim(/** @scrutinizer ignore-type */ $IMresult) . ')');
Loading history...
2282
                    $this->DebugMessage('ImageMagick failed with message (' . trim($IMresult) . ')', __FILE__, __LINE__);
2283
                    if ($this->iswindows && !$IMresult) {
2284
                        $this->DebugMessage('Check to make sure that PHP has read+write permissions to "' . dirname($IMtempfilename) . '"', __FILE__, __LINE__);
2285
                    }
2286
                } else {
2287
                    foreach ($successfullyProcessedFilters as $dummy => $filterkey) {
2288
                        unset($this->fltr[$filterkey]);
2289
                    }
2290
                    $this->IMresizedData    = file_get_contents($IMtempfilename);
2291
                    $getimagesize_imresized = @getimagesize($IMtempfilename);
2292
                    $this->DebugMessage('getimagesize(' . $IMtempfilename . ') returned [w=' . $getimagesize_imresized[0] . ';h=' . $getimagesize_imresized[1] . ';f=' . $getimagesize_imresized[2] . ']', __FILE__, __LINE__);
2293
                    if (($this->config_max_source_pixels > 0) && (($getimagesize_imresized[0] * $getimagesize_imresized[1]) > $this->config_max_source_pixels)) {
2294
                        $this->DebugMessage(
2295
                            'skipping ImageMagickThumbnailToGD::'
2296
                            . $ImageCreateFunction
2297
                            . '() because IM output is too large ('
2298
                            . $getimagesize_imresized[0]
2299
                            . 'x'
2300
                            . $getimagesize_imresized[0]
2301
                            . ' = '
2302
                            . ($getimagesize_imresized[0] * $getimagesize_imresized[1])
2303
                            . ' > '
2304
                            . $this->config_max_source_pixels
2305
                            . ')',
2306
                            __FILE__,
2307
                            __LINE__
2308
                        );
2309
                    } elseif (function_exists(@$ImageCreateFunction) && ($this->gdimg_source = @$ImageCreateFunction($IMtempfilename))) {
2310
                        $this->source_width  = imagesx($this->gdimg_source);
2311
                        $this->source_height = imagesy($this->gdimg_source);
2312
                        $this->DebugMessage('ImageMagickThumbnailToGD::' . $ImageCreateFunction . '() succeeded, $this->gdimg_source is now (' . $this->source_width . 'x' . $this->source_height . ')', __FILE__, __LINE__);
2313
                        $this->DebugMessage('ImageMagickThumbnailToGD() returning $this->IMresizedData (' . strlen($this->IMresizedData) . ' bytes)', __FILE__, __LINE__);
2314
                    } else {
2315
                        $this->useRawIMoutput = true;
2316
                        $this->DebugMessage('$this->useRawIMoutput set to TRUE because ' . @$ImageCreateFunction . '(' . $IMtempfilename . ') failed', __FILE__, __LINE__);
2317
                    }
2318
                    if (file_exists($IMtempfilename)) {
2319
                        $this->DebugMessage('deleting "' . $IMtempfilename . '"', __FILE__, __LINE__);
2320
                        @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

2320
                        /** @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...
2321
                    }
2322
                    return true;
2323
                }
2324
                if (file_exists($IMtempfilename)) {
2325
                    $this->DebugMessage('deleting "' . $IMtempfilename . '"', __FILE__, __LINE__);
2326
                    @unlink($IMtempfilename);
2327
                }
2328
            } elseif ($this->issafemode) {
2329
                $this->DebugMessage('ImageMagickThumbnailToGD() aborting because PHP safe_mode is enabled and phpThumb_tempnam() failed', __FILE__, __LINE__);
2330
                $this->useRawIMoutput = false;
2331
            } else {
2332
                if (file_exists($IMtempfilename)) {
2333
                    $this->DebugMessage('deleting "' . $IMtempfilename . '"', __FILE__, __LINE__);
2334
                    @unlink($IMtempfilename);
2335
                }
2336
                $this->DebugMessage('ImageMagickThumbnailToGD() aborting, phpThumb_tempnam() failed', __FILE__, __LINE__);
2337
            }
2338
        } else {
2339
            $this->DebugMessage('ImageMagickThumbnailToGD() aborting because ImageMagickCommandlineBase() failed', __FILE__, __LINE__);
2340
        }
2341
        $this->useRawIMoutput = false;
2342
        return false;
2343
    }
2344
2345
    public function Rotate()
2346
    {
2347
        if ($this->ra || $this->ar) {
2348
            if (!function_exists('imagerotate')) {
2349
                $this->DebugMessage('!function_exists(imagerotate)', __FILE__, __LINE__);
2350
                return false;
2351
            }
2352
            if (!include_once __DIR__ . '/phpthumb.filters.php') {
2353
                $this->DebugMessage('Error including "' . __DIR__ . '/phpthumb.filters.php" which is required for applying filters (' . implode(';', $this->fltr) . ')', __FILE__, __LINE__);
2354
                return false;
2355
            }
2356
2357
            $this->config_background_hexcolor = ($this->bg ? $this->bg : $this->config_background_hexcolor);
2358
            if (!phpthumb_functions::IsHexColor($this->config_background_hexcolor)) {
2359
                return $this->ErrorImage('Invalid hex color string "' . $this->config_background_hexcolor . '" for parameter "bg"');
2360
            }
2361
2362
            $rotate_angle = 0;
2363
            if ($this->ra) {
2364
                $rotate_angle = (float)$this->ra;
2365
            } else {
2366
                if ($this->ar == 'x') {
2367
                    if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '4.2.0', '>=')) {
2368
                        if ($this->sourceFilename) {
2369
                            if (function_exists('exif_read_data')) {
2370
                                if ($exif_data = @exif_read_data($this->sourceFilename, 'IFD0')) {
2371
                                    // http://sylvana.net/jpegcrop/exif_orientation.html
2372
                                    switch (@$exif_data['Orientation']) {
2373
                                        case 1:
2374
                                            $rotate_angle = 0;
2375
                                            break;
2376
                                        case 3:
2377
                                            $rotate_angle = 180;
2378
                                            break;
2379
                                        case 6:
2380
                                            $rotate_angle = 270;
2381
                                            break;
2382
                                        case 8:
2383
                                            $rotate_angle = 90;
2384
                                            break;
2385
2386
                                        default:
2387
                                            $this->DebugMessage('EXIF auto-rotate failed because unknown $exif_data[Orientation] "' . @$exif_data['Orientation'] . '"', __FILE__, __LINE__);
2388
                                            return false;
2389
                                            break;
0 ignored issues
show
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...
2390
                                    }
2391
                                    $this->DebugMessage('EXIF auto-rotate set to ' . $rotate_angle . ' degrees ($exif_data[Orientation] = "' . @$exif_data['Orientation'] . '")', __FILE__, __LINE__);
2392
                                } else {
2393
                                    $this->DebugMessage('failed: exif_read_data(' . $this->sourceFilename . ')', __FILE__, __LINE__);
2394
                                    return false;
2395
                                }
2396
                            } else {
2397
                                $this->DebugMessage('!function_exists(exif_read_data)', __FILE__, __LINE__);
2398
                                return false;
2399
                            }
2400
                        } else {
2401
                            $this->DebugMessage('Cannot auto-rotate from EXIF data because $this->sourceFilename is empty', __FILE__, __LINE__);
2402
                            return false;
2403
                        }
2404
                    } else {
2405
                        $this->DebugMessage('Cannot auto-rotate from EXIF data because PHP is less than v4.2.0 (' . PHP_VERSION . ')', __FILE__, __LINE__);
2406
                        return false;
2407
                    }
2408
                } elseif (($this->ar == 'l') && ($this->source_height > $this->source_width)) {
2409
                    $rotate_angle = 270;
2410
                } elseif (($this->ar == 'L') && ($this->source_height > $this->source_width)) {
2411
                    $rotate_angle = 90;
2412
                } elseif (($this->ar == 'p') && ($this->source_width > $this->source_height)) {
2413
                    $rotate_angle = 90;
2414
                } elseif (($this->ar == 'P') && ($this->source_width > $this->source_height)) {
2415
                    $rotate_angle = 270;
2416
                }
2417
            }
2418
            if ($rotate_angle % 90) {
2419
                $this->is_alpha = true;
2420
            }
2421
            phpthumb_filters::ImprovedImageRotate($this->gdimg_source, $rotate_angle, $this->config_background_hexcolor, $this->bg, $this);
2422
            $this->source_width  = imagesx($this->gdimg_source);
2423
            $this->source_height = imagesy($this->gdimg_source);
2424
        }
2425
        return true;
2426
    }
2427
2428
    public function FixedAspectRatio()
2429
    {
2430
        // optional fixed-dimension images (regardless of aspect ratio)
2431
2432
        if (!$this->far) {
2433
            // do nothing
2434
            return true;
2435
        }
2436
2437
        if (!$this->w || !$this->h) {
2438
            return false;
2439
        }
2440
        $this->thumbnail_width  = $this->w;
2441
        $this->thumbnail_height = $this->h;
2442
        $this->is_alpha         = true;
2443
        if ($this->thumbnail_image_width >= $this->thumbnail_width) {
2444
            $aspectratio = $this->thumbnail_image_height / $this->thumbnail_image_width;
2445
            if ($this->w) {
2446
                $this->thumbnail_image_height = round($this->thumbnail_image_width * $aspectratio);
2447
                $this->thumbnail_height       = ($this->h ? $this->h : $this->thumbnail_image_height);
2448
            } elseif ($this->thumbnail_image_height < $this->thumbnail_height) {
2449
                $this->thumbnail_image_height = $this->thumbnail_height;
2450
                $this->thumbnail_image_width  = round($this->thumbnail_image_height / $aspectratio);
2451
            }
2452
        } else {
2453
            $aspectratio = $this->thumbnail_image_width / $this->thumbnail_image_height;
2454
            if ($this->h) {
2455
                $this->thumbnail_image_width = round($this->thumbnail_image_height * $aspectratio);
2456
            } elseif ($this->thumbnail_image_width < $this->thumbnail_width) {
2457
                $this->thumbnail_image_width  = $this->thumbnail_width;
2458
                $this->thumbnail_image_height = round($this->thumbnail_image_width / $aspectratio);
2459
            }
2460
        }
2461
        return true;
2462
    }
2463
2464
    public function OffsiteDomainIsAllowed($hostname, $allowed_domains)
2465
    {
2466
        static $domain_is_allowed = [];
2467
        $hostname = strtolower($hostname);
2468
        if (!isset($domain_is_allowed[$hostname])) {
2469
            $domain_is_allowed[$hostname] = false;
2470
            foreach ($allowed_domains as $valid_domain) {
2471
                $starpos = strpos($valid_domain, '*');
2472
                if ($starpos !== false) {
2473
                    $valid_domain = substr($valid_domain, $starpos + 1);
2474
                    if (preg_match('#' . preg_quote($valid_domain) . '$#', $hostname)) {
2475
                        $domain_is_allowed[$hostname] = true;
2476
                        break;
2477
                    }
2478
                } else {
2479
                    if (strtolower($valid_domain) === $hostname) {
2480
                        $domain_is_allowed[$hostname] = true;
2481
                        break;
2482
                    }
2483
                }
2484
            }
2485
        }
2486
        return $domain_is_allowed[$hostname];
2487
    }
2488
2489
    public function AntiOffsiteLinking()
2490
    {
2491
        // Optional anti-offsite hijacking of the thumbnail script
2492
        $allow = true;
2493
        if ($allow && $this->config_nooffsitelink_enabled && (@$_SERVER['HTTP_REFERER'] || $this->config_nooffsitelink_require_refer)) {
2494
            $this->DebugMessage('AntiOffsiteLinking() checking $_SERVER[HTTP_REFERER] "' . @$_SERVER['HTTP_REFERER'] . '"', __FILE__, __LINE__);
2495
            foreach ($this->config_nooffsitelink_valid_domains as $key => $valid_domain) {
2496
                // $_SERVER['HTTP_HOST'] contains the port number, so strip it out here to make default configuration work
2497
                [$clean_domain] = explode(':', $valid_domain);
2498
                $this->config_nooffsitelink_valid_domains[$key] = $clean_domain;
2499
            }
2500
            $parsed_url = phpthumb_functions::ParseURLbetter(@$_SERVER['HTTP_REFERER']);
2501
            if (!$this->OffsiteDomainIsAllowed(@$parsed_url['host'], $this->config_nooffsitelink_valid_domains)) {
2502
                $allow = false;
2503
                //$this->DebugMessage('AntiOffsiteLinking() - "'.@$parsed_url['host'].'" is NOT in $this->config_nooffsitelink_valid_domains ('.implode(';', $this->config_nooffsitelink_valid_domains).')', __FILE__, __LINE__);
2504
                $this->ErrorImage('AntiOffsiteLinking() - "' . @$parsed_url['host'] . '" is NOT in $this->config_nooffsitelink_valid_domains (' . implode(';', $this->config_nooffsitelink_valid_domains) . ')');
2505
            } else {
2506
                $this->DebugMessage('AntiOffsiteLinking() - "' . @$parsed_url['host'] . '" is in $this->config_nooffsitelink_valid_domains (' . implode(';', $this->config_nooffsitelink_valid_domains) . ')', __FILE__, __LINE__);
2507
            }
2508
        }
2509
2510
        if ($allow && $this->config_nohotlink_enabled && preg_match('#^(f|ht)tps?\://#i', $this->src)) {
2511
            $parsed_url = phpthumb_functions::ParseURLbetter($this->src);
2512
            //if (!phpthumb_functions::CaseInsensitiveInArray(@$parsed_url['host'], $this->config_nohotlink_valid_domains)) {
2513
            if (!$this->OffsiteDomainIsAllowed(@$parsed_url['host'], $this->config_nohotlink_valid_domains)) {
2514
                // This domain is not allowed
2515
                $allow = false;
2516
                $this->DebugMessage('AntiOffsiteLinking() - "' . $parsed_url['host'] . '" is NOT in $this->config_nohotlink_valid_domains (' . implode(';', $this->config_nohotlink_valid_domains) . ')', __FILE__, __LINE__);
2517
            } else {
2518
                $this->DebugMessage('AntiOffsiteLinking() - "' . $parsed_url['host'] . '" is in $this->config_nohotlink_valid_domains (' . implode(';', $this->config_nohotlink_valid_domains) . ')', __FILE__, __LINE__);
2519
            }
2520
        }
2521
2522
        if ($allow) {
2523
            $this->DebugMessage('AntiOffsiteLinking() says this is allowed', __FILE__, __LINE__);
2524
            return true;
2525
        }
2526
2527
        if (!phpthumb_functions::IsHexColor($this->config_error_bgcolor)) {
2528
            return $this->ErrorImage('Invalid hex color string "' . $this->config_error_bgcolor . '" for $this->config_error_bgcolor');
2529
        }
2530
        if (!phpthumb_functions::IsHexColor($this->config_error_textcolor)) {
2531
            return $this->ErrorImage('Invalid hex color string "' . $this->config_error_textcolor . '" for $this->config_error_textcolor');
2532
        }
2533
        if ($this->config_nooffsitelink_erase_image) {
2534
            return $this->ErrorImage($this->config_nooffsitelink_text_message, $this->thumbnail_width, $this->thumbnail_height);
2535
        } else {
2536
            $this->config_nooffsitelink_watermark_src = $this->ResolveFilenameToAbsolute($this->config_nooffsitelink_watermark_src);
2537
            if (is_file($this->config_nooffsitelink_watermark_src)) {
0 ignored issues
show
It seems like $this->config_nooffsitelink_watermark_src can also be of type false and null; 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

2537
            if (is_file(/** @scrutinizer ignore-type */ $this->config_nooffsitelink_watermark_src)) {
Loading history...
2538
                if (!include_once __DIR__ . '/phpthumb.filters.php') {
2539
                    $this->DebugMessage('Error including "' . __DIR__ . '/phpthumb.filters.php" which is required for applying watermark', __FILE__, __LINE__);
2540
                    return false;
2541
                }
2542
                $watermark_img                   = $this->ImageCreateFromStringReplacement(file_get_contents($this->config_nooffsitelink_watermark_src));
0 ignored issues
show
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

2542
                $watermark_img                   = $this->ImageCreateFromStringReplacement(/** @scrutinizer ignore-type */ file_get_contents($this->config_nooffsitelink_watermark_src));
Loading history...
It seems like $this->config_nooffsitelink_watermark_src can also be of type false and null; 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

2542
                $watermark_img                   = $this->ImageCreateFromStringReplacement(file_get_contents(/** @scrutinizer ignore-type */ $this->config_nooffsitelink_watermark_src));
Loading history...
2543
                $phpthumbFilters                 = new phpthumb_filters();
2544
                $phpthumbFilters->phpThumbObject = &$this;
2545
                $opacity                         = 50;
2546
                $margin                          = 5;
2547
                $phpthumbFilters->WatermarkOverlay($this->gdimg_output, $watermark_img, '*', $opacity, $margin);
2548
                imagedestroy($watermark_img);
2549
                unset($phpthumbFilters);
2550
            } else {
2551
                $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
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

2551
                $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...
2552
                $nohotlink_text_color = phpthumb_functions::ImageHexColorAllocate($this->gdimg_output, $this->config_error_textcolor);
2553
2554
                $topoffset = round(($this->thumbnail_height - (count($nohotlink_text_array) * imagefontheight($this->config_error_fontsize))) / 2);
2555
2556
                $rowcounter = 0;
2557
                $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__);
2558
                foreach ($nohotlink_text_array as $textline) {
2559
                    $leftoffset = max(0, round(($this->thumbnail_width - (strlen($textline) * imagefontwidth($this->config_error_fontsize))) / 2));
2560
                    imagestring($this->gdimg_output, $this->config_error_fontsize, $leftoffset, $topoffset + ($rowcounter++ * imagefontheight($this->config_error_fontsize)), $textline, $nohotlink_text_color);
2561
                }
2562
            }
2563
        }
2564
        return true;
2565
    }
2566
2567
    public function AlphaChannelFlatten()
2568
    {
2569
        if (!$this->is_alpha) {
2570
            // image doesn't have alpha transparency, no need to flatten
2571
            $this->DebugMessage('skipping AlphaChannelFlatten() because !$this->is_alpha', __FILE__, __LINE__);
2572
            return false;
2573
        }
2574
        switch ($this->thumbnailFormat) {
2575
            case 'png':
2576
            case 'webp':
2577
            case 'ico':
2578
                // image has alpha transparency, but output as PNG, WEBP or ICO which can handle it
2579
                $this->DebugMessage('skipping AlphaChannelFlatten() because ($this->thumbnailFormat == "' . $this->thumbnailFormat . '")', __FILE__, __LINE__);
2580
                return false;
2581
                break;
0 ignored issues
show
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...
2582
2583
            case 'gif':
2584
                // image has alpha transparency, but output as GIF which can handle only single-color transparency
2585
                $CurrentImageColorTransparent = imagecolortransparent($this->gdimg_output);
2586
                if ($CurrentImageColorTransparent == -1) {
2587
                    // no transparent color defined
2588
2589
                    if (phpthumb_functions::gd_version() < 2.0) {
2590
                        $this->DebugMessage('AlphaChannelFlatten() failed because GD version is "' . phpthumb_functions::gd_version() . '"', __FILE__, __LINE__);
2591
                        return false;
2592
                    }
2593
2594
                    if ($img_alpha_mixdown_dither = @imagecreatetruecolor(imagesx($this->gdimg_output), imagesy($this->gdimg_output))) {
2595
                        $dither_color = [];
2596
                        for ($i = 0; $i <= 255; $i++) {
2597
                            $dither_color[$i] = imagecolorallocate($img_alpha_mixdown_dither, $i, $i, $i);
2598
                        }
2599
2600
                        // scan through current truecolor image copy alpha channel to temp image as grayscale
2601
                        for ($x = 0; $x < $this->thumbnail_width; $x++) {
2602
                            for ($y = 0; $y < $this->thumbnail_height; $y++) {
2603
                                $PixelColor = phpthumb_functions::GetPixelColor($this->gdimg_output, $x, $y);
2604
                                imagesetpixel($img_alpha_mixdown_dither, $x, $y, $dither_color[$PixelColor['alpha'] * 2]);
2605
                            }
2606
                        }
2607
2608
                        // dither alpha channel grayscale version down to 2 colors
2609
                        imagetruecolortopalette($img_alpha_mixdown_dither, true, 2);
2610
2611
                        // reduce color palette to 256-1 colors (leave one palette position for transparent color)
2612
                        imagetruecolortopalette($this->gdimg_output, true, 255);
2613
2614
                        // allocate a new color for transparent color index
2615
                        $TransparentColor = imagecolorallocate($this->gdimg_output, 1, 254, 253);
2616
                        imagecolortransparent($this->gdimg_output, $TransparentColor);
2617
2618
                        // scan through alpha channel image and note pixels with >50% transparency
2619
                        for ($x = 0; $x < $this->thumbnail_width; $x++) {
2620
                            for ($y = 0; $y < $this->thumbnail_height; $y++) {
2621
                                $AlphaChannelPixel = phpthumb_functions::GetPixelColor($img_alpha_mixdown_dither, $x, $y);
2622
                                if ($AlphaChannelPixel['red'] > 127) {
2623
                                    imagesetpixel($this->gdimg_output, $x, $y, $TransparentColor);
2624
                                }
2625
                            }
2626
                        }
2627
                        imagedestroy($img_alpha_mixdown_dither);
2628
2629
                        $this->DebugMessage('AlphaChannelFlatten() set image to 255+1 colors with transparency for GIF output', __FILE__, __LINE__);
2630
                        return true;
2631
                    } else {
2632
                        $this->DebugMessage('AlphaChannelFlatten() failed imagecreate(' . imagesx($this->gdimg_output) . ', ' . imagesy($this->gdimg_output) . ')', __FILE__, __LINE__);
2633
                        return false;
2634
                    }
2635
                } else {
2636
                    // a single transparent color already defined, leave as-is
2637
                    $this->DebugMessage('skipping AlphaChannelFlatten() because ($this->thumbnailFormat == "' . $this->thumbnailFormat . '") and imagecolortransparent() returned "' . $CurrentImageColorTransparent . '"', __FILE__, __LINE__);
2638
                    return true;
2639
                }
2640
                break;
2641
        }
2642
        $this->DebugMessage('continuing AlphaChannelFlatten() for output format "' . $this->thumbnailFormat . '"', __FILE__, __LINE__);
2643
        // image has alpha transparency, and is being output in a format that doesn't support it -- flatten
2644
        if ($gdimg_flatten_temp = phpthumb_functions::ImageCreateFunction($this->thumbnail_width, $this->thumbnail_height)) {
2645
            $this->config_background_hexcolor = ($this->bg ? $this->bg : $this->config_background_hexcolor);
2646
            if (!phpthumb_functions::IsHexColor($this->config_background_hexcolor)) {
2647
                return $this->ErrorImage('Invalid hex color string "' . $this->config_background_hexcolor . '" for parameter "bg"');
2648
            }
2649
            $background_color = phpthumb_functions::ImageHexColorAllocate($this->gdimg_output, $this->config_background_hexcolor);
2650
            imagefilledrectangle($gdimg_flatten_temp, 0, 0, $this->thumbnail_width, $this->thumbnail_height, $background_color);
2651
            imagecopy($gdimg_flatten_temp, $this->gdimg_output, 0, 0, 0, 0, $this->thumbnail_width, $this->thumbnail_height);
2652
2653
            imagealphablending($this->gdimg_output, true);
2654
            imagesavealpha($this->gdimg_output, false);
2655
            imagecolortransparent($this->gdimg_output, -1);
2656
            imagecopy($this->gdimg_output, $gdimg_flatten_temp, 0, 0, 0, 0, $this->thumbnail_width, $this->thumbnail_height);
2657
2658
            imagedestroy($gdimg_flatten_temp);
2659
            return true;
2660
        } else {
2661
            $this->DebugMessage('ImageCreateFunction() failed', __FILE__, __LINE__);
2662
        }
2663
        return false;
2664
    }
2665
2666
    public function ApplyFilters()
2667
    {
2668
        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...
2669
            if (!include_once __DIR__ . '/phpthumb.filters.php') {
2670
                $this->DebugMessage('Error including "' . __DIR__ . '/phpthumb.filters.php" which is required for applying filters (' . implode(';', $this->fltr) . ')', __FILE__, __LINE__);
2671
                return false;
2672
            }
2673
            $phpthumbFilters                 = new phpthumb_filters();
2674
            $phpthumbFilters->phpThumbObject = &$this;
2675
            foreach ($this->fltr as $filtercommand) {
2676
                @list($command, $parameter) = explode('|', $filtercommand, 2);
2677
                $this->DebugMessage('Attempting to process filter command "' . $command . '(' . $parameter . ')"', __FILE__, __LINE__);
2678
                switch ($command) {
2679
                    case 'brit': // Brightness
2680
                        $phpthumbFilters->Brightness($this->gdimg_output, $parameter);
2681
                        break;
2682
2683
                    case 'cont': // Contrast
2684
                        $phpthumbFilters->Contrast($this->gdimg_output, $parameter);
2685
                        break;
2686
2687
                    case 'ds': // Desaturation
2688
                        $phpthumbFilters->Desaturate($this->gdimg_output, $parameter, '');
2689
                        break;
2690
2691
                    case 'sat': // Saturation
2692
                        $phpthumbFilters->Saturation($this->gdimg_output, $parameter, '');
2693
                        break;
2694
2695
                    case 'gray': // Grayscale
2696
                        $phpthumbFilters->Grayscale($this->gdimg_output);
2697
                        break;
2698
2699
                    case 'clr': // Colorize
2700
                        if (phpthumb_functions::gd_version() < 2) {
2701
                            $this->DebugMessage('Skipping Colorize() because gd_version is "' . phpthumb_functions::gd_version() . '"', __FILE__, __LINE__);
2702
                            break;
2703
                        }
2704
                        @list($amount, $color) = explode('|', $parameter, 2);
2705
                        $phpthumbFilters->Colorize($this->gdimg_output, $amount, $color);
2706
                        break;
2707
2708
                    case 'sep': // Sepia
2709
                        if (phpthumb_functions::gd_version() < 2) {
2710
                            $this->DebugMessage('Skipping Sepia() because gd_version is "' . phpthumb_functions::gd_version() . '"', __FILE__, __LINE__);
2711
                            break;
2712
                        }
2713
                        @list($amount, $color) = explode('|', $parameter, 2);
2714
                        $phpthumbFilters->Sepia($this->gdimg_output, $amount, $color);
2715
                        break;
2716
2717
                    case 'gam': // Gamma correction
2718
                        $phpthumbFilters->Gamma($this->gdimg_output, $parameter);
2719
                        break;
2720
2721
                    case 'neg': // Negative colors
2722
                        $phpthumbFilters->Negative($this->gdimg_output);
2723
                        break;
2724
2725
                    case 'th': // Threshold
2726
                        $phpthumbFilters->Threshold($this->gdimg_output, $parameter);
2727
                        break;
2728
2729
                    case 'rcd': // ReduceColorDepth
2730
                        if (phpthumb_functions::gd_version() < 2) {
2731
                            $this->DebugMessage('Skipping ReduceColorDepth() because gd_version is "' . phpthumb_functions::gd_version() . '"', __FILE__, __LINE__);
2732
                            break;
2733
                        }
2734
                        @list($colors, $dither) = explode('|', $parameter, 2);
2735
                        $colors = ($colors ? (int)$colors : 256);
2736
                        $dither = ((strlen($dither) > 0) ? (bool)$dither : true);
2737
                        $phpthumbFilters->ReduceColorDepth($this->gdimg_output, $colors, $dither);
2738
                        break;
2739
2740
                    case 'flip': // Flip
2741
                        $phpthumbFilters->Flip($this->gdimg_output, strpos(strtolower($parameter), 'x') !== false, strpos(strtolower($parameter), 'y') !== false);
2742
                        break;
2743
2744
                    case 'edge': // EdgeDetect
2745
                        $phpthumbFilters->EdgeDetect($this->gdimg_output);
2746
                        break;
2747
2748
                    case 'emb': // Emboss
2749
                        $phpthumbFilters->Emboss($this->gdimg_output);
2750
                        break;
2751
2752
                    case 'bvl': // Bevel
2753
                        @list($width, $color1, $color2) = explode('|', $parameter, 3);
2754
                        $phpthumbFilters->Bevel($this->gdimg_output, $width, $color1, $color2);
2755
                        break;
2756
2757
                    case 'lvl': // autoLevels
2758
                        @list($band, $method, $threshold) = explode('|', $parameter, 3);
2759
                        $band      = ($band ? preg_replace('#[^RGBA\\*]#', '', strtoupper($band)) : '*');
2760
                        $method    = ((strlen($method) > 0) ? (int)$method : 2);
2761
                        $threshold = ((strlen($threshold) > 0) ? (float)$threshold : 0.1);
2762
2763
                        $phpthumbFilters->HistogramStretch($this->gdimg_output, $band, $method, $threshold);
2764
                        break;
2765
2766
                    case 'wb': // WhiteBalance
2767
                        $phpthumbFilters->WhiteBalance($this->gdimg_output, $parameter);
2768
                        break;
2769
2770
                    case 'hist': // Histogram overlay
2771
                        if (phpthumb_functions::gd_version() < 2) {
2772
                            $this->DebugMessage('Skipping HistogramOverlay() because gd_version is "' . phpthumb_functions::gd_version() . '"', __FILE__, __LINE__);
2773
                            break;
2774
                        }
2775
                        @list($bands, $colors, $width, $height, $alignment, $opacity, $margin_x, $margin_y) = explode('|', $parameter, 8);
2776
                        $bands     = ($bands ? $bands : '*');
2777
                        $colors    = ($colors ? $colors : '');
2778
                        $width     = ($width ? $width : 0.25);
2779
                        $height    = ($height ? $height : 0.25);
2780
                        $alignment = ($alignment ? $alignment : 'BR');
2781
                        $opacity   = ($opacity ? $opacity : 50);
2782
                        $margin_x  = ($margin_x ? $margin_x : 5);
2783
                        // $margin_y -- it wasn't forgotten, let the value always pass unchanged
2784
                        $phpthumbFilters->HistogramOverlay($this->gdimg_output, $bands, $colors, $width, $height, $alignment, $opacity, $margin_x, $margin_y);
2785
                        break;
2786
2787
                    case 'fram': // Frame
2788
                        @list($frame_width, $edge_width, $color_frame, $color1, $color2) = explode('|', $parameter, 5);
2789
                        $phpthumbFilters->Frame($this->gdimg_output, $frame_width, $edge_width, $color_frame, $color1, $color2);
2790
                        break;
2791
2792
                    case 'drop': // DropShadow
2793
                        if (phpthumb_functions::gd_version() < 2) {
2794
                            $this->DebugMessage('Skipping DropShadow() because gd_version is "' . phpthumb_functions::gd_version() . '"', __FILE__, __LINE__);
2795
                            return false;
2796
                        }
2797
                        $this->is_alpha = true;
2798
                        @list($distance, $width, $color, $angle, $fade) = explode('|', $parameter, 5);
2799
                        $phpthumbFilters->DropShadow($this->gdimg_output, $distance, $width, $color, $angle, $fade);
2800
                        break;
2801
2802
                    case 'mask': // Mask cropping
2803
                        if (phpthumb_functions::gd_version() < 2) {
2804
                            $this->DebugMessage('Skipping Mask() because gd_version is "' . phpthumb_functions::gd_version() . '"', __FILE__, __LINE__);
2805
                            return false;
2806
                        }
2807
                        @list($mask_filename, $invert) = explode('|', $parameter, 2);
2808
                        $mask_filename = $this->ResolveFilenameToAbsolute($mask_filename);
2809
                        if (@is_readable($mask_filename) && ($fp_mask = @fopen($mask_filename, 'rb'))) {
0 ignored issues
show
It seems like $mask_filename can also be of type false and null; 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

2809
                        if (@is_readable($mask_filename) && ($fp_mask = @fopen(/** @scrutinizer ignore-type */ $mask_filename, 'rb'))) {
Loading history...
It seems like $mask_filename can also be of type false and null; 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

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

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

3164
                            imagejpeg($this->gdimg_output, null, /** @scrutinizer ignore-type */ $q);
Loading history...
3165
                            $imgdata = ob_get_contents();
3166
                            ob_end_clean();
3167
3168
                            $this->thumbnailQuality = $q;
3169
                            if (strlen($imgdata) <= $this->maxb) {
3170
                                break;
3171
                            }
3172
                        }
3173
                    }
3174
                    if (strlen($imgdata) > $this->maxb) {
3175
                        return false;
3176
                    }
3177
                    break;
3178
3179
                default:
3180
                    return false;
3181
            }
3182
        }
3183
        return true;
3184
    }
3185
3186
    public function CalculateThumbnailDimensions()
3187
    {
3188
        $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__);
3189
        //echo $this->source_width.'x'.$this->source_height.'<hr>';
3190
        $this->thumbnailCropX = ($this->sx ? (($this->sx >= 2) ? $this->sx : round($this->sx * $this->source_width)) : 0);
3191
        //echo $this->thumbnailCropX.'<br>';
3192
        $this->thumbnailCropY = ($this->sy ? (($this->sy >= 2) ? $this->sy : round($this->sy * $this->source_height)) : 0);
3193
        //echo $this->thumbnailCropY.'<br>';
3194
        $this->thumbnailCropW = ($this->sw ? (($this->sw >= 2) ? $this->sw : round($this->sw * $this->source_width)) : $this->source_width);
3195
        //echo $this->thumbnailCropW.'<br>';
3196
        $this->thumbnailCropH = ($this->sh ? (($this->sh >= 2) ? $this->sh : round($this->sh * $this->source_height)) : $this->source_height);
3197
        //echo $this->thumbnailCropH.'<hr>';
3198
3199
        // limit source area to original image area
3200
        $this->thumbnailCropW = max(1, min($this->thumbnailCropW, $this->source_width - $this->thumbnailCropX));
3201
        $this->thumbnailCropH = max(1, min($this->thumbnailCropH, $this->source_height - $this->thumbnailCropY));
3202
3203
        $this->DebugMessage('CalculateThumbnailDimensions() starting with [x,y,w,h] initially set to [' . $this->thumbnailCropX . ',' . $this->thumbnailCropY . ',' . $this->thumbnailCropW . ',' . $this->thumbnailCropH . ']', __FILE__, __LINE__);
3204
3205
        if ($this->zc && $this->w && $this->h) {
3206
            // Zoom Crop
3207
            // retain proportional resizing we did above, but crop off larger dimension so smaller
3208
            // dimension fully fits available space
3209
3210
            $scaling_X = $this->source_width / $this->w;
3211
            $scaling_Y = $this->source_height / $this->h;
3212
            if ($scaling_X > $scaling_Y) {
3213
                // some of the width will need to be cropped
3214
                $allowable_width      = $this->source_width / $scaling_X * $scaling_Y;
3215
                $this->thumbnailCropW = round($allowable_width);
3216
                $this->thumbnailCropX = round(($this->source_width - $allowable_width) / 2);
3217
            } elseif ($scaling_Y > $scaling_X) {
3218
                // some of the height will need to be cropped
3219
                $allowable_height     = $this->source_height / $scaling_Y * $scaling_X;
3220
                $this->thumbnailCropH = round($allowable_height);
3221
                $this->thumbnailCropY = round(($this->source_height - $allowable_height) / 2);
3222
            } else {
3223
                // image fits perfectly, no cropping needed
3224
            }
3225
            $this->thumbnail_width        = $this->w;
3226
            $this->thumbnail_height       = $this->h;
3227
            $this->thumbnail_image_width  = $this->thumbnail_width;
3228
            $this->thumbnail_image_height = $this->thumbnail_height;
3229
        } elseif ($this->iar && $this->w && $this->h) {
3230
            // Ignore Aspect Ratio
3231
            // stretch image to fit exactly 'w' x 'h'
3232
            $this->thumbnail_width        = $this->w;
3233
            $this->thumbnail_height       = $this->h;
3234
            $this->thumbnail_image_width  = $this->thumbnail_width;
3235
            $this->thumbnail_image_height = $this->thumbnail_height;
3236
        } else {
3237
            $original_aspect_ratio = $this->thumbnailCropW / $this->thumbnailCropH;
3238
            if ($this->aoe) {
3239
                if ($this->w && $this->h) {
3240
                    $maxwidth  = min($this->w, $this->h * $original_aspect_ratio);
3241
                    $maxheight = min($this->h, $this->w / $original_aspect_ratio);
3242
                } elseif ($this->w) {
3243
                    $maxwidth  = $this->w;
3244
                    $maxheight = $this->w / $original_aspect_ratio;
3245
                } elseif ($this->h) {
3246
                    $maxwidth  = $this->h * $original_aspect_ratio;
3247
                    $maxheight = $this->h;
3248
                } else {
3249
                    $maxwidth  = $this->thumbnailCropW;
3250
                    $maxheight = $this->thumbnailCropH;
3251
                }
3252
            } else {
3253
                $maxwidth  = phpthumb_functions::nonempty_min($this->w, $this->thumbnailCropW, $this->config_output_maxwidth);
3254
                $maxheight = phpthumb_functions::nonempty_min($this->h, $this->thumbnailCropH, $this->config_output_maxheight);
3255
                //echo $maxwidth.'x'.$maxheight.'<br>';
3256
                $maxwidth  = min($maxwidth, $maxheight * $original_aspect_ratio);
3257
                $maxheight = min($maxheight, $maxwidth / $original_aspect_ratio);
3258
                //echo $maxwidth.'x'.$maxheight.'<hr>';
3259
            }
3260
3261
            $this->thumbnail_image_width  = $maxwidth;
3262
            $this->thumbnail_image_height = $maxheight;
3263
            $this->thumbnail_width        = $maxwidth;
3264
            $this->thumbnail_height       = $maxheight;
3265
3266
            $this->FixedAspectRatio();
3267
        }
3268
3269
        $this->thumbnail_width  = max(1, floor($this->thumbnail_width));
3270
        $this->thumbnail_height = max(1, floor($this->thumbnail_height));
3271
        return true;
3272
    }
3273
3274
    public function CreateGDoutput()
3275
    {
3276
        $this->CalculateThumbnailDimensions();
3277
3278
        // create the GD image (either true-color or 256-color, depending on GD version)
3279
        $this->gdimg_output = phpthumb_functions::ImageCreateFunction($this->thumbnail_width, $this->thumbnail_height);
3280
3281
        // images that have transparency must have the background filled with the configured 'bg' color otherwise the transparent color will appear as black
3282
        imagesavealpha($this->gdimg_output, true);
3283
        if ($this->is_alpha && phpthumb_functions::gd_version() >= 2) {
3284
            imagealphablending($this->gdimg_output, false);
3285
            $output_full_alpha = phpthumb_functions::ImageColorAllocateAlphaSafe($this->gdimg_output, 255, 255, 255, 127);
3286
            imagefilledrectangle($this->gdimg_output, 0, 0, $this->thumbnail_width, $this->thumbnail_height, $output_full_alpha);
3287
        } else {
3288
            $current_transparent_color = imagecolortransparent($this->gdimg_source);
3289
            if ($this->bg || (@$current_transparent_color >= 0)) {
3290
                $this->config_background_hexcolor = ($this->bg ? $this->bg : $this->config_background_hexcolor);
3291
                if (!phpthumb_functions::IsHexColor($this->config_background_hexcolor)) {
3292
                    return $this->ErrorImage('Invalid hex color string "' . $this->config_background_hexcolor . '" for parameter "bg"');
3293
                }
3294
                $background_color = phpthumb_functions::ImageHexColorAllocate($this->gdimg_output, $this->config_background_hexcolor);
3295
                imagefilledrectangle($this->gdimg_output, 0, 0, $this->thumbnail_width, $this->thumbnail_height, $background_color);
3296
            }
3297
        }
3298
        $this->DebugMessage('CreateGDoutput() returning canvas "' . $this->thumbnail_width . 'x' . $this->thumbnail_height . '"', __FILE__, __LINE__);
3299
        return true;
3300
    }
3301
3302
    public function SetOrientationDependantWidthHeight()
3303
    {
3304
        $this->DebugMessage('SetOrientationDependantWidthHeight() starting with "' . $this->source_width . '"x"' . $this->source_height . '"', __FILE__, __LINE__);
3305
        if ($this->source_height > $this->source_width) {
3306
            // portrait
3307
            $this->w = phpthumb_functions::OneOfThese($this->wp, $this->w, $this->ws, $this->wl);
3308
            $this->h = phpthumb_functions::OneOfThese($this->hp, $this->h, $this->hs, $this->hl);
3309
        } elseif ($this->source_height < $this->source_width) {
3310
            // landscape
3311
            $this->w = phpthumb_functions::OneOfThese($this->wl, $this->w, $this->ws, $this->wp);
3312
            $this->h = phpthumb_functions::OneOfThese($this->hl, $this->h, $this->hs, $this->hp);
3313
        } else {
3314
            // square
3315
            $this->w = phpthumb_functions::OneOfThese($this->ws, $this->w, $this->wl, $this->wp);
3316
            $this->h = phpthumb_functions::OneOfThese($this->hs, $this->h, $this->hl, $this->hp);
3317
        }
3318
        //$this->w = round($this->w ? $this->w : (($this->h && $this->source_height) ? $this->h * $this->source_width  / $this->source_height : $this->w));
3319
        //$this->h = round($this->h ? $this->h : (($this->w && $this->source_width)  ? $this->w * $this->source_height / $this->source_width  : $this->h));
3320
        $this->DebugMessage('SetOrientationDependantWidthHeight() setting w="' . (int)$this->w . '", h="' . (int)$this->h . '"', __FILE__, __LINE__);
3321
        return true;
3322
    }
3323
3324
    public function ExtractEXIFgetImageSize()
3325
    {
3326
        $this->DebugMessage('starting ExtractEXIFgetImageSize()', __FILE__, __LINE__);
3327
3328
        if (preg_match('#^http:#i', $this->src) && !$this->sourceFilename && $this->rawImageData) {
3329
            $this->SourceDataToTempFile();
3330
        }
3331
        if (null === $this->getimagesizeinfo) {
3332
            if ($this->sourceFilename) {
3333
                if ($this->getimagesizeinfo = @getimagesize($this->sourceFilename)) {
3334
                    $this->source_width  = $this->getimagesizeinfo[0];
3335
                    $this->source_height = $this->getimagesizeinfo[1];
3336
                    $this->DebugMessage('getimagesize(' . $this->sourceFilename . ') says image is ' . $this->source_width . 'x' . $this->source_height, __FILE__, __LINE__);
3337
                } else {
3338
                    $this->DebugMessage('getimagesize(' . $this->sourceFilename . ') failed', __FILE__, __LINE__);
3339
                }
3340
            } else {
3341
                $this->DebugMessage('skipping getimagesize() because $this->sourceFilename is empty', __FILE__, __LINE__);
3342
            }
3343
        } else {
3344
            $this->DebugMessage('skipping getimagesize() because !is_null($this->getimagesizeinfo)', __FILE__, __LINE__);
3345
        }
3346
3347
        if (is_resource($this->gdimg_source) || (is_object($this->gdimg_source) && $this->gdimg_source instanceof \GdImage)) {
3348
            $this->source_width  = imagesx($this->gdimg_source);
3349
            $this->source_height = imagesy($this->gdimg_source);
3350
3351
            $this->SetOrientationDependantWidthHeight();
3352
        } elseif ($this->rawImageData && !$this->sourceFilename) {
3353
            if ($this->SourceImageIsTooLarge($this->source_width, $this->source_height)) {
3354
                $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__);
3355
            } else {
3356
                $this->DebugMessage(
3357
                    '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)',
3358
                    __FILE__,
3359
                    __LINE__
3360
                );
3361
            }
3362
        }
3363
3364
        if (!empty($this->getimagesizeinfo)) {
3365
            // great
3366
            $this->getimagesizeinfo['filesize'] = @filesize($this->sourceFilename);
3367
        } elseif (!$this->rawImageData) {
3368
            $this->DebugMessage('getimagesize("' . $this->sourceFilename . '") failed', __FILE__, __LINE__);
3369
        }
3370
3371
        if ($this->config_prefer_imagemagick) {
3372
            if ($this->ImageMagickThumbnailToGD()) {
3373
                return true;
3374
            }
3375
            $this->DebugMessage('ImageMagickThumbnailToGD() failed', __FILE__, __LINE__);
3376
        }
3377
3378
        if (isset($this->getimagesizeinfo[1])) {
3379
            $this->source_width  = $this->getimagesizeinfo[0];
3380
            $this->source_height = $this->getimagesizeinfo[1];
3381
        }
3382
3383
        $this->SetOrientationDependantWidthHeight();
3384
3385
        if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '4.2.0', '>=') && function_exists('exif_read_data')) {
3386
            switch (@$this->getimagesizeinfo[2]) {
3387
                case IMAGETYPE_JPEG:
3388
                case IMAGETYPE_TIFF_II:
3389
                case IMAGETYPE_TIFF_MM:
3390
                    $this->exif_raw_data = @exif_read_data($this->sourceFilename, 0, true);
3391
                    break;
3392
            }
3393
        }
3394
        if (function_exists('exif_thumbnail') && (@$this->getimagesizeinfo[2] == IMAGETYPE_JPEG)) {
3395
            // Extract EXIF info from JPEGs
3396
3397
            $this->exif_thumbnail_width  = '';
3398
            $this->exif_thumbnail_height = '';
3399
            $this->exif_thumbnail_type   = '';
3400
3401
            // The parameters width, height and imagetype are available since PHP v4.3.0
3402
            if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '4.3.0', '>=')) {
3403
                $this->exif_thumbnail_data = @exif_thumbnail($this->sourceFilename, $this->exif_thumbnail_width, $this->exif_thumbnail_height, $this->exif_thumbnail_type);
0 ignored issues
show
$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

3403
                $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...
$this->exif_thumbnail_type of type string is incompatible with the type integer expected by parameter $image_type 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

3403
                $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...
$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

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

3499
            if (strpos(/** @scrutinizer ignore-type */ $this->config_cache_default_only_suffix, '*') === false) {
Loading history...
3500
                $this->DebugMessage('aborting simplified caching filename because no * in "' . $this->config_cache_default_only_suffix . '"', __FILE__, __LINE__);
0 ignored issues
show
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

3500
                $this->DebugMessage('aborting simplified caching filename because no * in "' . /** @scrutinizer ignore-type */ $this->config_cache_default_only_suffix . '"', __FILE__, __LINE__);
Loading history...
3501
            } else {
3502
                preg_match('#(.+)(\\.[a-z0-9]+)?$#i', basename($this->sourceFilename), $matches);
3503
                $this->cache_filename = $this->config_cache_directory . DIRECTORY_SEPARATOR . rawurlencode(str_replace('*', @$matches[1], $this->config_cache_default_only_suffix)) . '.' . strtolower($this->thumbnailFormat);
3504
                return true;
3505
            }
3506
        }
3507
3508
        $this->cache_filename = '';
3509
        if ($this->new) {
3510
            $broad_directory_name = strtolower(md5($this->new));
3511
            $this->cache_filename .= '_new' . $broad_directory_name;
3512
        } elseif ($this->md5s) {
3513
            // source image MD5 hash provided
3514
            $this->DebugMessage('SetCacheFilename() _raw set from $this->md5s = "' . $this->md5s . '"', __FILE__, __LINE__);
3515
            $broad_directory_name = $this->md5s;
3516
            $this->cache_filename .= '_raw' . $this->md5s;
3517
        } elseif (!$this->src && $this->rawImageData) {
3518
            $this->DebugMessage('SetCacheFilename() _raw set from md5($this->rawImageData) = "' . md5($this->rawImageData) . '"', __FILE__, __LINE__);
3519
            $broad_directory_name = strtolower(md5($this->rawImageData));
3520
            $this->cache_filename .= '_raw' . $broad_directory_name;
3521
        } else {
3522
            $this->DebugMessage('SetCacheFilename() _src set from md5($this->sourceFilename) "' . $this->sourceFilename . '" = "' . md5($this->sourceFilename) . '"', __FILE__, __LINE__);
3523
            $broad_directory_name = strtolower(md5($this->sourceFilename));
3524
            $this->cache_filename .= '_src' . $broad_directory_name;
3525
        }
3526
        if (!empty($_SERVER['HTTP_REFERER']) && $this->config_nooffsitelink_enabled) {
3527
            $parsed_url1 = @phpthumb_functions::ParseURLbetter(@$_SERVER['HTTP_REFERER']);
3528
            $parsed_url2 = @phpthumb_functions::ParseURLbetter('http://' . @$_SERVER['HTTP_HOST']);
3529
            if (@$parsed_url1['host'] && @$parsed_url2['host'] && ($parsed_url1['host'] != $parsed_url2['host'])) {
3530
                // include "_offsite" only if nooffsitelink_enabled and if referrer doesn't match the domain of the current server
3531
                $this->cache_filename .= '_offsite';
3532
            }
3533
        }
3534
3535
        $ParametersString = '';
3536
        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...
3537
            $ParametersString .= '_fltr' . implode('_fltr', $this->fltr);
3538
        }
3539
        $FilenameParameters1 = ['ar', 'bg', 'bc', 'far', 'sx', 'sy', 'sw', 'sh', 'zc'];
3540
        foreach ($FilenameParameters1 as $key) {
3541
            if ($this->$key) {
3542
                $ParametersString .= '_' . $key . $this->$key;
3543
            }
3544
        }
3545
        $FilenameParameters2 = ['h', 'w', 'wl', 'wp', 'ws', 'hp', 'hs', 'xto', 'ra', 'iar', 'aoe', 'maxb', 'sfn', 'dpi'];
3546
        foreach ($FilenameParameters2 as $key) {
3547
            if ($this->$key) {
3548
                $ParametersString .= '_' . $key . (int)$this->$key;
3549
            }
3550
        }
3551
        $FilenameParameters3 = ['ica'];
3552
        foreach ($FilenameParameters3 as $key) {
3553
            if ($this->$key) {
3554
                $ParametersString .= '_' . $key . substr(md5($this->$key), 0, 4);
3555
            }
3556
        }
3557
        if ($this->thumbnailFormat == 'jpeg') {
3558
            // only JPEG output has variable quality option
3559
            $ParametersString .= '_q' . (int)$this->thumbnailQuality;
3560
        }
3561
        $this->DebugMessage('SetCacheFilename() _par set from md5(' . $ParametersString . ')', __FILE__, __LINE__);
3562
        $this->cache_filename .= '_par' . strtolower(md5($ParametersString));
3563
3564
        if ($this->md5s) {
3565
            // source image MD5 hash provided
3566
            // do not source image modification date --
3567
            // cached image will be used even if file was modified or removed
3568
        } elseif (!$this->config_cache_source_filemtime_ignore_remote && preg_match('#^(f|ht)tps?\://#i', $this->src)) {
3569
            $this->cache_filename .= '_dat' . (int)phpthumb_functions::filedate_remote($this->src);
3570
        } elseif (!$this->config_cache_source_filemtime_ignore_local && $this->src && !$this->rawImageData) {
3571
            $this->cache_filename .= '_dat' . (int)(@filemtime($this->sourceFilename));
3572
        }
3573
3574
        $this->cache_filename .= '.' . strtolower($this->thumbnailFormat);
3575
        $broad_directories    = '';
3576
        for ($i = 0; $i < $this->config_cache_directory_depth; $i++) {
3577
            $broad_directories .= DIRECTORY_SEPARATOR . substr($broad_directory_name, 0, $i + 1);
3578
        }
3579
3580
        $this->cache_filename = $this->config_cache_directory . $broad_directories . DIRECTORY_SEPARATOR . $this->config_cache_prefix . rawurlencode($this->cache_filename);
3581
        return true;
3582
    }
3583
3584
    public function SourceImageIsTooLarge($width, $height)
3585
    {
3586
        if (!$this->config_max_source_pixels) {
3587
            return false;
3588
        }
3589
        if ($this->php_memory_limit && function_exists('memory_get_usage')) {
3590
            $available_memory = $this->php_memory_limit - memory_get_usage();
3591
            return (bool)(($width * $height * 5) > $available_memory);
3592
        }
3593
        return (bool)(($width * $height) > $this->config_max_source_pixels);
3594
    }
3595
3596
    public function ImageCreateFromFilename($filename)
3597
    {
3598
        // try to create GD image source directly via GD, if possible,
3599
        // rather than buffering to memory and creating with imagecreatefromstring
3600
        $ImageCreateWasAttempted = false;
3601
        $gd_image                = false;
3602
3603
        $this->DebugMessage('starting ImageCreateFromFilename(' . $filename . ')', __FILE__, __LINE__);
3604
        if ($filename && ($getimagesizeinfo = @getimagesize($filename))) {
3605
            if (!$this->SourceImageIsTooLarge($getimagesizeinfo[0], $getimagesizeinfo[1])) {
3606
                $ImageCreateFromFunction = [
3607
                    1  => 'imagecreatefromgif',
3608
                    2  => 'imagecreatefromjpeg',
3609
                    3  => 'imagecreatefrompng',
3610
                    15 => 'imagecreatefromwbmp',
3611
                ];
3612
                $this->DebugMessage('ImageCreateFromFilename found ($getimagesizeinfo[2]==' . @$getimagesizeinfo[2] . ')', __FILE__, __LINE__);
3613
                switch (@$getimagesizeinfo[2]) {
3614
                    case 1:  // GIF
3615
                    case 2:  // JPEG
3616
                    case 3:  // PNG
3617
                    case 15: // WBMP
3618
                        $ImageCreateFromFunctionName = $ImageCreateFromFunction[$getimagesizeinfo[2]];
3619
                        if (function_exists($ImageCreateFromFunctionName)) {
3620
                            $this->DebugMessage('Calling ' . $ImageCreateFromFunctionName . '(' . $filename . ')', __FILE__, __LINE__);
3621
                            $ImageCreateWasAttempted = true;
3622
                            $gd_image                = $ImageCreateFromFunctionName($filename);
3623
                        } else {
3624
                            $this->DebugMessage('NOT calling ' . $ImageCreateFromFunctionName . '(' . $filename . ') because !function_exists(' . $ImageCreateFromFunctionName . ')', __FILE__, __LINE__);
3625
                        }
3626
                        break;
3627
3628
                    case 4:  // SWF
3629
                    case 5:  // PSD
3630
                    case 6:  // BMP
3631
                    case 7:  // TIFF (LE)
3632
                    case 8:  // TIFF (BE)
3633
                    case 9:  // JPC
3634
                    case 10: // JP2
3635
                    case 11: // JPX
3636
                    case 12: // JB2
3637
                    case 13: // SWC
3638
                    case 14: // IFF
3639
                    case 16: // XBM
3640
                        $this->DebugMessage('No built-in image creation function for image type "' . @$getimagesizeinfo[2] . '" ($getimagesizeinfo[2])', __FILE__, __LINE__);
3641
                        break;
3642
3643
                    default:
3644
                        $this->DebugMessage('Unknown value for $getimagesizeinfo[2]: "' . @$getimagesizeinfo[2] . '"', __FILE__, __LINE__);
3645
                        break;
3646
                }
3647
            } else {
3648
                $this->DebugMessage(
3649
                    '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 . ')',
3650
                    __FILE__,
3651
                    __LINE__
3652
                );
3653
                return false;
3654
            }
3655
        } else {
3656
            $this->DebugMessage('empty $filename or getimagesize(' . $filename . ') failed', __FILE__, __LINE__);
3657
        }
3658
3659
        if (!$gd_image) {
3660
            // cannot create from filename, attempt to create source image with imagecreatefromstring, if possible
3661
            if ($ImageCreateWasAttempted) {
3662
                $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...
3663
            }
3664
            $this->DebugMessage('Populating $rawimagedata', __FILE__, __LINE__);
3665
            $rawimagedata = '';
3666
            if ($fp = @fopen($filename, 'rb')) {
3667
                $filesize   = filesize($filename);
3668
                $blocksize  = 8192;
3669
                $blockreads = ceil($filesize / $blocksize);
3670
                for ($i = 0; $i < $blockreads; $i++) {
3671
                    $rawimagedata .= fread($fp, $blocksize);
3672
                }
3673
                fclose($fp);
3674
            } else {
3675
                $this->DebugMessage('cannot fopen(' . $filename . ')', __FILE__, __LINE__);
3676
            }
3677
            if ($rawimagedata) {
3678
                $this->DebugMessage('attempting ImageCreateFromStringReplacement($rawimagedata (' . strlen($rawimagedata) . ' bytes), true)', __FILE__, __LINE__);
3679
                $gd_image = $this->ImageCreateFromStringReplacement($rawimagedata, true);
3680
            }
3681
        }
3682
        return $gd_image;
3683
    }
3684
3685
    public function SourceImageToGD()
3686
    {
3687
        if (is_resource($this->gdimg_source) || (is_object($this->gdimg_source) && $this->gdimg_source instanceof \GdImage)) {
3688
            $this->source_width  = imagesx($this->gdimg_source);
3689
            $this->source_height = imagesy($this->gdimg_source);
3690
            $this->DebugMessage('skipping SourceImageToGD() because $this->gdimg_source is already a resource (' . $this->source_width . 'x' . $this->source_height . ')', __FILE__, __LINE__);
3691
            return true;
3692
        }
3693
        $this->DebugMessage('starting SourceImageToGD()', __FILE__, __LINE__);
3694
3695
        if ($this->config_prefer_imagemagick) {
3696
            if (empty($this->sourceFilename) && !empty($this->rawImageData)) {
3697
                $this->DebugMessage('Copying raw image data to temp file and trying again with ImageMagick', __FILE__, __LINE__);
3698
                if ($tempnam = $this->phpThumb_tempnam()) {
3699
                    if (file_put_contents($tempnam, $this->rawImageData)) {
3700
                        $this->sourceFilename = $tempnam;
3701
                        if ($this->ImageMagickThumbnailToGD()) {
3702
                            // excellent, we have a thumbnailed source image
3703
                            $this->DebugMessage('ImageMagickThumbnailToGD() succeeded', __FILE__, __LINE__);
3704
                        } else {
3705
                            $this->DebugMessage('ImageMagickThumbnailToGD() failed', __FILE__, __LINE__);
3706
                        }
3707
                        @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

3707
                        /** @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...
3708
                    } else {
3709
                        $this->DebugMessage('failed to put $this->rawImageData into temp file "' . $tempnam . '"', __FILE__, __LINE__);
3710
                    }
3711
                } else {
3712
                    $this->DebugMessage('failed to generate temp file name', __FILE__, __LINE__);
3713
                }
3714
            }
3715
        }
3716
        if (!$this->gdimg_source && $this->rawImageData) {
3717
            if ($this->SourceImageIsTooLarge($this->source_width, $this->source_height)) {
3718
                $memory_get_usage = (function_exists('memory_get_usage') ? memory_get_usage() : 0);
3719
                return $this->ErrorImage(
3720
                    'Source image is too large ('
3721
                    . $this->source_width
3722
                    . 'x'
3723
                    . $this->source_height
3724
                    . ' = '
3725
                    . number_format($this->source_width * $this->source_height / 1000000, 1)
3726
                    . 'Mpx, max='
3727
                    . number_format($this->config_max_source_pixels / 1000000, 1)
3728
                    . 'Mpx) for GD creation (either install ImageMagick or increase PHP memory_limit to at least '
3729
                    . ceil(($memory_get_usage + (5 * $this->source_width * $this->source_height)) / 1048576)
3730
                    . 'M).'
3731
                );
3732
            }
3733
            if ($this->md5s && ($this->md5s != md5($this->rawImageData))) {
3734
                return $this->ErrorImage('$this->md5s != md5($this->rawImageData)' . "\n" . '"' . $this->md5s . '" != ' . "\n" . '"' . md5($this->rawImageData) . '"');
3735
            }
3736
            //if ($this->issafemode) {
3737
            //	return $this->ErrorImage('Cannot generate thumbnails from raw image data when PHP SAFE_MODE enabled');
3738
            //}
3739
            $this->gdimg_source = $this->ImageCreateFromStringReplacement($this->rawImageData);
3740
            if (!$this->gdimg_source) {
3741
                if (substr($this->rawImageData, 0, 2) === 'BM') {
3742
                    $this->getimagesizeinfo[2] = 6; // BMP
3743
                } elseif (substr($this->rawImageData, 0, 4) === 'II' . "\x2A\x00") {
3744
                    $this->getimagesizeinfo[2] = 7; // TIFF (littlendian)
3745
                } elseif (substr($this->rawImageData, 0, 4) === 'MM' . "\x00\x2A") {
3746
                    $this->getimagesizeinfo[2] = 8; // TIFF (bigendian)
3747
                }
3748
                $this->DebugMessage('SourceImageToGD.ImageCreateFromStringReplacement() failed with unknown image type "' . substr($this->rawImageData, 0, 4) . '" (' . phpthumb_functions::HexCharDisplay(substr($this->rawImageData, 0, 4)) . ')', __FILE__, __LINE__);
3749
                //				return $this->ErrorImage('Unknown image type identified by "'.substr($this->rawImageData, 0, 4).'" ('.phpthumb_functions::HexCharDisplay(substr($this->rawImageData, 0, 4)).') in SourceImageToGD()['.__LINE__.']');
3750
            }
3751
        } elseif (!$this->gdimg_source && $this->sourceFilename) {
3752
            if ($this->md5s && ($this->md5s != phpthumb_functions::md5_file_safe($this->sourceFilename))) {
3753
                return $this->ErrorImage('$this->md5s != md5(sourceFilename)' . "\n" . '"' . $this->md5s . '" != ' . "\n" . '"' . phpthumb_functions::md5_file_safe($this->sourceFilename) . '"');
0 ignored issues
show
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

3753
                return $this->ErrorImage('$this->md5s != md5(sourceFilename)' . "\n" . '"' . $this->md5s . '" != ' . "\n" . '"' . /** @scrutinizer ignore-type */ phpthumb_functions::md5_file_safe($this->sourceFilename) . '"');
Loading history...
3754
            }
3755
            switch (@$this->getimagesizeinfo[2]) {
3756
                case 1:
3757
                case 3:
3758
                    // GIF or PNG input file may have transparency
3759
                    $this->is_alpha = true;
3760
                    break;
3761
            }
3762
            if (!$this->SourceImageIsTooLarge($this->source_width, $this->source_height)) {
3763
                $this->gdimg_source = $this->ImageCreateFromFilename($this->sourceFilename);
3764
            }
3765
        }
3766
3767
        while (true) {
3768
            if ($this->gdimg_source) {
3769
                $this->DebugMessage('Not using EXIF thumbnail data because $this->gdimg_source is already set', __FILE__, __LINE__);
3770
                break;
3771
            }
3772
            if (!$this->exif_thumbnail_data) {
3773
                $this->DebugMessage('Not using EXIF thumbnail data because $this->exif_thumbnail_data is empty', __FILE__, __LINE__);
3774
                break;
3775
            }
3776
            if (ini_get('safe_mode')) {
3777
                if (!$this->SourceImageIsTooLarge($this->source_width, $this->source_height)) {
3778
                    $this->DebugMessage('Using EXIF thumbnail data because source image too large and safe_mode enabled', __FILE__, __LINE__);
3779
                    $this->aoe = true;
3780
                } else {
3781
                    break;
3782
                }
3783
            } else {
3784
                if (!$this->config_use_exif_thumbnail_for_speed) {
3785
                    $this->DebugMessage('Not using EXIF thumbnail data because $this->config_use_exif_thumbnail_for_speed is FALSE', __FILE__, __LINE__);
3786
                    break;
3787
                }
3788
                if (($this->thumbnailCropX != 0) || ($this->thumbnailCropY != 0)) {
3789
                    $this->DebugMessage('Not using EXIF thumbnail data because source cropping is enabled (' . $this->thumbnailCropX . ',' . $this->thumbnailCropY . ')', __FILE__, __LINE__);
3790
                    break;
3791
                }
3792
                if (($this->w > $this->exif_thumbnail_width) || ($this->h > $this->exif_thumbnail_height)) {
3793
                    $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__);
3794
                    break;
3795
                }
3796
                $source_ar = $this->source_width / $this->source_height;
3797
                $exif_ar   = $this->exif_thumbnail_width / $this->exif_thumbnail_height;
3798
                if (number_format($source_ar, 2) != number_format($exif_ar, 2)) {
3799
                    $this->DebugMessage('not using EXIF thumbnail because $source_ar != $exif_ar (' . $source_ar . ' != ' . $exif_ar . ')', __FILE__, __LINE__);
3800
                    break;
3801
                }
3802
            }
3803
3804
            // EXIF thumbnail exists, and is equal to or larger than destination thumbnail, and will be use as source image
3805
            $this->DebugMessage('Trying to use EXIF thumbnail as source image', __FILE__, __LINE__);
3806
3807
            if ($gdimg_exif_temp = $this->ImageCreateFromStringReplacement($this->exif_thumbnail_data, false)) {
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
            } else {
3816
                $this->DebugMessage('$this->ImageCreateFromStringReplacement($this->exif_thumbnail_data, false) failed', __FILE__, __LINE__);
3817
            }
3818
3819
            break;
3820
        }
3821
3822
        if (!$this->gdimg_source) {
3823
            $this->DebugMessage('$this->gdimg_source is still empty', __FILE__, __LINE__);
3824
3825
            $this->DebugMessage('ImageMagickThumbnailToGD() failed', __FILE__, __LINE__);
3826
3827
            $imageHeader   = '';
3828
            $gd_info       = gd_info();
3829
            $GDreadSupport = false;
3830
            switch (@$this->getimagesizeinfo[2]) {
3831
                case 1:
3832
                    $imageHeader   = 'Content-Type: image/gif';
3833
                    $GDreadSupport = (bool)@$gd_info['GIF Read Support'];
3834
                    break;
3835
                case 2:
3836
                    $imageHeader   = 'Content-Type: image/jpeg';
3837
                    $GDreadSupport = (bool)@$gd_info['JPG Support'];
3838
                    break;
3839
                case 3:
3840
                    $imageHeader   = 'Content-Type: image/png';
3841
                    $GDreadSupport = (bool)@$gd_info['PNG Support'];
3842
                    break;
3843
            }
3844
            if ($imageHeader) {
3845
                // cannot create image for whatever reason (maybe imagecreatefromjpeg et al are not available?)
3846
                // and ImageMagick is not available either, no choice but to output original (not resized/modified) data and exit
3847
                if ($this->config_error_die_on_source_failure) {
3848
                    $errormessages   = [];
3849
                    $errormessages[] = 'All attempts to create GD image source failed.';
3850
                    if ($this->fatalerror) {
3851
                        $errormessages[] = $this->fatalerror;
3852
                    }
3853
                    if ($this->issafemode) {
3854
                        $errormessages[] = 'Safe Mode enabled, therefore ImageMagick is unavailable. (disable Safe Mode if possible)';
3855
                    } elseif (!$this->ImageMagickVersion()) {
3856
                        $errormessages[] = 'ImageMagick is not installed (it is highly recommended that you install it).';
3857
                    }
3858
                    if ($this->SourceImageIsTooLarge($this->getimagesizeinfo[0], $this->getimagesizeinfo[1])) {
3859
                        $memory_get_usage = (function_exists('memory_get_usage') ? memory_get_usage() : 0);
3860
                        $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(
3861
                                $this->config_max_source_pixels / 1000000,
3862
                                1
3863
                            ) . '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).';
3864
                    } elseif (!$GDreadSupport) {
3865
                        $errormessages[] = 'GD does not have read support for "' . $imageHeader . '".';
3866
                    } else {
3867
                        $errormessages[] = 'Source image probably corrupt.';
3868
                    }
3869
                    $this->ErrorImage(implode("\n", $errormessages));
3870
                } else {
3871
                    $this->DebugMessage(
3872
                        '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 "'
3873
                                                                                                                                                                                                                                                  . $imageHeader
3874
                                                                                                                                                                                                                                                  . '"')) . '), cannot generate thumbnail'
3875
                    );
3876
                    //$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__);
3877
                    //if (!$this->phpThumbDebug) {
3878
                    //	header($imageHeader);
3879
                    //	echo $this->rawImageData;
3880
                    //	exit;
3881
                    //}
3882
                    return false;
3883
                }
3884
            }
3885
3886
            //switch (substr($this->rawImageData, 0, 2)) {
3887
            //	case 'BM':
3888
            switch (@$this->getimagesizeinfo[2]) {
3889
                case 6:
3890
                    ob_start();
3891
                    if (!@include_once __DIR__ . '/phpthumb.bmp.php') {
3892
                        ob_end_clean();
3893
                        return $this->ErrorImage('include_once(' . __DIR__ . '/phpthumb.bmp.php) failed');
3894
                    }
3895
                    ob_end_clean();
3896
                    if ($fp = @fopen($this->sourceFilename, 'rb')) {
3897
                        $this->rawImageData = '';
3898
                        while (!feof($fp)) {
3899
                            $this->rawImageData .= fread($fp, 32768);
3900
                        }
3901
                        fclose($fp);
3902
                    }
3903
                    $phpthumb_bmp       = new phpthumb_bmp();
3904
                    $this->gdimg_source = $phpthumb_bmp->phpthumb_bmp2gd($this->rawImageData, phpthumb_functions::gd_version() >= 2.0);
3905
                    unset($phpthumb_bmp);
3906
                    if ($this->gdimg_source) {
3907
                        $this->DebugMessage('$phpthumb_bmp->phpthumb_bmp2gd() succeeded', __FILE__, __LINE__);
3908
                    } else {
3909
                        return $this->ErrorImage($this->ImageMagickVersion() ? 'ImageMagick failed on BMP source conversion' : 'phpthumb_bmp2gd() failed');
3910
                    }
3911
                    break;
3912
                //}
3913
                //switch (substr($this->rawImageData, 0, 4)) {
3914
                //	case 'II'."\x2A\x00":
3915
                //	case 'MM'."\x00\x2A":
3916
                case 7:
3917
                case 8:
3918
                    return $this->ErrorImage($this->ImageMagickVersion() ? 'ImageMagick failed on TIFF source conversion' : 'ImageMagick is unavailable and phpThumb() does not support TIFF source images without it');
3919
                    break;
0 ignored issues
show
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...
3920
3921
                //case "\xD7\xCD\xC6\x9A":
3922
                //	return $this->ErrorImage($this->ImageMagickVersion() ? 'ImageMagick failed on WMF source conversion' : 'ImageMagick is unavailable and phpThumb() does not support WMF source images without it');
3923
                //	break;
3924
            }
3925
3926
            if (!$this->gdimg_source) {
3927
                if ($this->rawImageData) {
3928
                    $HeaderFourBytes = substr($this->rawImageData, 0, 4);
3929
                } elseif ($this->sourceFilename) {
3930
                    if ($fp = @fopen($this->sourceFilename, 'rb')) {
3931
                        $HeaderFourBytes = fread($fp, 4);
3932
                        fclose($fp);
3933
                    } else {
3934
                        return $this->ErrorImage('failed to open "' . $this->sourceFilename . '" SourceImageToGD() [' . __LINE__ . ']');
3935
                    }
3936
                } else {
3937
                    return $this->ErrorImage('Unable to create image, neither filename nor image data suppplied in SourceImageToGD() [' . __LINE__ . ']');
3938
                }
3939
                if (!$this->ImageMagickVersion() && !phpthumb_functions::gd_version()) {
3940
                    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.');
3941
                } elseif ($HeaderFourBytes == "\xD7\xCD\xC6\x9A") { // WMF
3942
                    return $this->ErrorImage($this->ImageMagickVersion() ? 'ImageMagick failed on WMF source conversion' : 'ImageMagick is unavailable and phpThumb() does not support WMF source images without it');
3943
                } elseif ($HeaderFourBytes == '%PDF') { // "%PDF"
3944
                    return $this->ErrorImage(
3945
                        $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'
3946
                    );
3947
                } elseif (substr($HeaderFourBytes, 0, 3) == "\xFF\xD8\xFF") { // JPEG
3948
                    return $this->ErrorImage('Image (JPEG) is too large for PHP-GD memory_limit, please install ImageMagick or increase php.ini memory_limit setting');
3949
                } elseif ($HeaderFourBytes == '%PNG') { // "%PNG"
3950
                    return $this->ErrorImage('Image (PNG) is too large for PHP-GD memory_limit, please install ImageMagick or increase php.ini memory_limit setting');
3951
                } elseif (substr($HeaderFourBytes, 0, 3) == 'GIF') { // GIF
3952
                    return $this->ErrorImage('Image (GIF) is too large for PHP-GD memory_limit, please install ImageMagick or increase php.ini memory_limit setting');
3953
                }
3954
                return $this->ErrorImage('Unknown image type identified by "' . $HeaderFourBytes . '" (' . phpthumb_functions::HexCharDisplay($HeaderFourBytes) . ') in SourceImageToGD() [' . __LINE__ . ']');
3955
            }
3956
        }
3957
3958
        if (!$this->gdimg_source) {
3959
            if ($gdimg_exif_temp = $this->ImageCreateFromStringReplacement($this->exif_thumbnail_data, false)) {
3960
                $this->DebugMessage('All other attempts failed, but successfully using EXIF thumbnail as source image', __FILE__, __LINE__);
3961
                $this->gdimg_source = $gdimg_exif_temp;
3962
                // override allow-enlarging setting if EXIF thumbnail is the only source available
3963
                // otherwise thumbnails larger than the EXIF thumbnail will be created at EXIF size
3964
                $this->aoe = true;
3965
                return true;
3966
            }
3967
            return false;
3968
        }
3969
3970
        $this->source_width  = imagesx($this->gdimg_source);
3971
        $this->source_height = imagesy($this->gdimg_source);
3972
        return true;
3973
    }
3974
3975
    private function ImageCropAuto()
3976
    {
3977
        // ImageCropAuto
3978
        if (!is_null($this->ica)) {
3979
            $this->DebugMessage('ImageCropAuto(' . $this->ica . ') starting', __FILE__, __LINE__);
3980
            if (function_exists('imagecropauto')) { // (PHP 5 >= 5.5.0, PHP 7)
3981
                // https://www.php.net/manual/en/function.imagecropauto.php
3982
                // 0 = IMG_CROP_DEFAULT
3983
                // 1 = IMG_CROP_TRANSPARENT
3984
                // 2 = IMG_CROP_BLACK
3985
                // 3 = IMG_CROP_WHITE
3986
                // 4 = IMG_CROP_SIDES
3987
                // 5 = IMG_CROP_THRESHOLD
3988
                if (preg_match('#^(([0-4])|(5)\\|(0?\\.?[0-9]+)\\|([0-9A-F]{6}))$#i', $this->ica, $matches)) {
3989
                    @list($dummy, $dummy, $ica_mode1, $ica_mode2, $ica_threshold, $ica_color) = $matches;
3990
                    if ($ica_mode2) {
3991
                        $param_color = hexdec($ica_color);
3992
                        if (!imageistruecolor($this->gdimg_source)) {
3993
                            $param_color = imagecolorclosest($this->gdimg_source, hexdec(substr($ica_color, 0, 2)), hexdec(substr($ica_color, 2, 2)), hexdec(substr($ica_color, 4, 2)));
0 ignored issues
show
It seems like hexdec(substr($ica_color, 2, 2)) can also be of type double; however, parameter $green of imagecolorclosest() does only seem to accept integer, 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

3993
                            $param_color = imagecolorclosest($this->gdimg_source, hexdec(substr($ica_color, 0, 2)), /** @scrutinizer ignore-type */ hexdec(substr($ica_color, 2, 2)), hexdec(substr($ica_color, 4, 2)));
Loading history...
It seems like hexdec(substr($ica_color, 0, 2)) can also be of type double; however, parameter $red of imagecolorclosest() does only seem to accept integer, 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

3993
                            $param_color = imagecolorclosest($this->gdimg_source, /** @scrutinizer ignore-type */ hexdec(substr($ica_color, 0, 2)), hexdec(substr($ica_color, 2, 2)), hexdec(substr($ica_color, 4, 2)));
Loading history...
It seems like hexdec(substr($ica_color, 4, 2)) can also be of type double; however, parameter $blue of imagecolorclosest() does only seem to accept integer, 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

3993
                            $param_color = imagecolorclosest($this->gdimg_source, hexdec(substr($ica_color, 0, 2)), hexdec(substr($ica_color, 2, 2)), /** @scrutinizer ignore-type */ hexdec(substr($ica_color, 4, 2)));
Loading history...
3994
                        }
3995
                        $cropped = imagecropauto($this->gdimg_source, intval($ica_mode2), floatval($ica_threshold), $param_color);
0 ignored issues
show
It seems like $param_color can also be of type double; however, parameter $color of imagecropauto() does only seem to accept integer, 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

3995
                        $cropped = imagecropauto($this->gdimg_source, intval($ica_mode2), floatval($ica_threshold), /** @scrutinizer ignore-type */ $param_color);
Loading history...
3996
                    } else {
3997
                        $cropped = imagecropauto($this->gdimg_source, intval($ica_mode1));
3998
                    }
3999
                    if ($cropped !== false) {                 // in case a new image resource was returned
4000
                        $this->DebugMessage('ImageCropAuto changing source image size from ' . imagesx($this->gdimg_source) . 'x' . imagesy($this->gdimg_source) . ' to ' . imagesx($cropped) . 'x' . imagesy($cropped), __FILE__, __LINE__);
0 ignored issues
show
It seems like $cropped can also be of type true; however, parameter $image of imagesx() does only seem to accept GdImage|resource, 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

4000
                        $this->DebugMessage('ImageCropAuto changing source image size from ' . imagesx($this->gdimg_source) . 'x' . imagesy($this->gdimg_source) . ' to ' . imagesx(/** @scrutinizer ignore-type */ $cropped) . 'x' . imagesy($cropped), __FILE__, __LINE__);
Loading history...
It seems like $cropped can also be of type true; however, parameter $image of imagesy() does only seem to accept GdImage|resource, 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

4000
                        $this->DebugMessage('ImageCropAuto changing source image size from ' . imagesx($this->gdimg_source) . 'x' . imagesy($this->gdimg_source) . ' to ' . imagesx($cropped) . 'x' . imagesy(/** @scrutinizer ignore-type */ $cropped), __FILE__, __LINE__);
Loading history...
4001
                        imagedestroy($this->gdimg_source);    // we destroy the original image
4002
                        $this->gdimg_source  = $cropped;       // and assign the cropped image to $im
4003
                        $this->source_width  = imagesx($this->gdimg_source);
4004
                        $this->source_height = imagesy($this->gdimg_source);
4005
                    } else {
4006
                        $this->DebugMessage('imagecropauto failed', __FILE__, __LINE__);
4007
                    }
4008
                } else {
4009
                    $this->DebugMessage('invalid "ica" parameter syntax, ignoring', __FILE__, __LINE__);
4010
                }
4011
            } else {
4012
                $this->DebugMessage('!function_exists(imagecropauto), ignoring "ica" parameter', __FILE__, __LINE__);
4013
            }
4014
        }
4015
        return true;
4016
    }
4017
4018
    public function phpThumbDebugVarDump($var)
4019
    {
4020
        if (null === $var) {
4021
            return 'NULL';
4022
        } elseif (is_bool($var)) {
4023
            return ($var ? 'TRUE' : 'FALSE');
4024
        } elseif (is_string($var)) {
4025
            return 'string(' . strlen($var) . ')' . str_repeat(' ', max(0, 3 - strlen(strlen($var)))) . ' "' . $var . '"';
4026
        } elseif (is_int($var)) {
4027
            return 'integer     ' . $var;
4028
        } elseif (is_float($var)) {
4029
            return 'float       ' . $var;
4030
        } elseif (is_array($var)) {
4031
            ob_start();
4032
            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...
4033
            $vardumpoutput = ob_get_contents();
4034
            ob_end_clean();
4035
            return strtr($vardumpoutput, "\n\r\t", '   ');
4036
        }
4037
        return gettype($var);
4038
    }
4039
4040
    public function phpThumbDebug($level = '')
4041
    {
4042
        if ($level && ($this->phpThumbDebug !== $level)) {
4043
            return true;
4044
        }
4045
        if ($this->config_disable_debug) {
4046
            return $this->ErrorImage('phpThumbDebug disabled');
4047
        }
4048
4049
        $FunctionsExistance  = [
4050
            'exif_thumbnail',
4051
            'gd_info',
4052
            'image_type_to_mime_type',
4053
            'getimagesize',
4054
            'imagecopyresampled',
4055
            'imagecopyresized',
4056
            'imagecreate',
4057
            'imagecreatefromstring',
4058
            'imagecreatetruecolor',
4059
            'imageistruecolor',
4060
            'imagerotate',
4061
            'imagetypes',
4062
            'version_compare',
4063
            'imagecreatefromgif',
4064
            'imagecreatefromjpeg',
4065
            'imagecreatefrompng',
4066
            'imagecreatefromwbmp',
4067
            'imagecreatefromxbm',
4068
            'imagecreatefromxpm',
4069
            'imagecreatefromstring',
4070
            'imagecreatefromgd',
4071
            'imagecreatefromgd2',
4072
            'imagecreatefromgd2part',
4073
            'imagejpeg',
4074
            'imagegif',
4075
            'imagepng',
4076
            'imagewbmp',
4077
        ];
4078
        $ParameterNames      = ['src', 'new', 'w', 'h', 'f', 'q', 'sx', 'sy', 'sw', 'sh', 'far', 'bg', 'bc', 'zc', 'ica', 'file', 'goto', 'err', 'xto', 'ra', 'ar', 'aoe', 'iar', 'maxb'];
4079
        $ConfigVariableNames = [
4080
            'document_root',
4081
            'temp_directory',
4082
            'output_format',
4083
            'output_maxwidth',
4084
            'output_maxheight',
4085
            'error_message_image_default',
4086
            'error_bgcolor',
4087
            'error_textcolor',
4088
            'error_fontsize',
4089
            'error_die_on_error',
4090
            'error_silent_die_on_error',
4091
            'error_die_on_source_failure',
4092
            'nohotlink_enabled',
4093
            'nohotlink_valid_domains',
4094
            'nohotlink_erase_image',
4095
            'nohotlink_text_message',
4096
            'nooffsitelink_enabled',
4097
            'nooffsitelink_valid_domains',
4098
            'nooffsitelink_require_refer',
4099
            'nooffsitelink_erase_image',
4100
            'nooffsitelink_text_message',
4101
            'high_security_enabled',
4102
            'allow_src_above_docroot',
4103
            'allow_src_above_phpthumb',
4104
            'max_source_pixels',
4105
            'use_exif_thumbnail_for_speed',
4106
            'border_hexcolor',
4107
            'background_hexcolor',
4108
            'ttf_directory',
4109
            'disable_pathinfo_parsing',
4110
            'disable_imagecopyresampled',
4111
        ];
4112
        $OtherVariableNames  = [
4113
            'phpThumbDebug',
4114
            'thumbnailQuality',
4115
            'thumbnailFormat',
4116
            'gdimg_output',
4117
            'gdimg_source',
4118
            'sourceFilename',
4119
            'source_width',
4120
            'source_height',
4121
            'thumbnailCropX',
4122
            'thumbnailCropY',
4123
            'thumbnailCropW',
4124
            'thumbnailCropH',
4125
            'exif_thumbnail_width',
4126
            'exif_thumbnail_height',
4127
            'exif_thumbnail_type',
4128
            'thumbnail_width',
4129
            'thumbnail_height',
4130
            'thumbnail_image_width',
4131
            'thumbnail_image_height',
4132
        ];
4133
4134
        $DebugOutput   = [];
4135
        $DebugOutput[] = 'phpThumb() version          = ' . $this->phpthumb_version;
4136
        $DebugOutput[] = 'phpversion()                = ' . @PHP_VERSION;
4137
        $DebugOutput[] = 'PHP_OS                      = ' . PHP_OS;
4138
        $DebugOutput[] = '$_SERVER[SERVER_SOFTWARE]   = ' . @$_SERVER['SERVER_SOFTWARE'];
4139
        $DebugOutput[] = '__FILE__                    = ' . __FILE__;
4140
        $DebugOutput[] = 'realpath(.)                 = ' . @realpath('.');
0 ignored issues
show
Are you sure @realpath('.') 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

4140
        $DebugOutput[] = 'realpath(.)                 = ' . /** @scrutinizer ignore-type */ @realpath('.');
Loading history...
4141
        $DebugOutput[] = '$_SERVER[PHP_SELF]          = ' . @$_SERVER['PHP_SELF'];
4142
        $DebugOutput[] = '$_SERVER[HOST_NAME]         = ' . @$_SERVER['HOST_NAME'];
4143
        $DebugOutput[] = '$_SERVER[HTTP_REFERER]      = ' . @$_SERVER['HTTP_REFERER'];
4144
        $DebugOutput[] = '$_SERVER[QUERY_STRING]      = ' . @$_SERVER['QUERY_STRING'];
4145
        $DebugOutput[] = '$_SERVER[PATH_INFO]         = ' . @$_SERVER['PATH_INFO'];
4146
        $DebugOutput[] = '$_SERVER[DOCUMENT_ROOT]     = ' . @$_SERVER['DOCUMENT_ROOT'];
4147
        $DebugOutput[] = 'getenv(DOCUMENT_ROOT)       = ' . @getenv('DOCUMENT_ROOT');
4148
        $DebugOutput[] = '';
4149
4150
        $DebugOutput[] = 'get_magic_quotes_gpc()         = ' . $this->phpThumbDebugVarDump(@get_magic_quotes_gpc());
4151
        $DebugOutput[] = 'get_magic_quotes_runtime()     = ' . $this->phpThumbDebugVarDump(@get_magic_quotes_runtime());
4152
        $DebugOutput[] = 'error_reporting()              = ' . $this->phpThumbDebugVarDump(error_reporting());
4153
        $DebugOutput[] = 'ini_get(error_reporting)       = ' . $this->phpThumbDebugVarDump(@ini_get('error_reporting'));
4154
        $DebugOutput[] = 'ini_get(display_errors)        = ' . $this->phpThumbDebugVarDump(@ini_get('display_errors'));
4155
        $DebugOutput[] = 'ini_get(allow_url_fopen)       = ' . $this->phpThumbDebugVarDump(@ini_get('allow_url_fopen'));
4156
        $DebugOutput[] = 'ini_get(disable_functions)     = ' . $this->phpThumbDebugVarDump(@ini_get('disable_functions'));
4157
        $DebugOutput[] = 'get_cfg_var(disable_functions) = ' . $this->phpThumbDebugVarDump(@get_cfg_var('disable_functions'));
4158
        $DebugOutput[] = 'ini_get(safe_mode)             = ' . $this->phpThumbDebugVarDump(@ini_get('safe_mode'));
4159
        $DebugOutput[] = 'ini_get(open_basedir)          = ' . $this->phpThumbDebugVarDump(@ini_get('open_basedir'));
4160
        $DebugOutput[] = 'ini_get(max_execution_time)    = ' . $this->phpThumbDebugVarDump(@ini_get('max_execution_time'));
4161
        $DebugOutput[] = 'ini_get(memory_limit)          = ' . $this->phpThumbDebugVarDump(@ini_get('memory_limit'));
4162
        $DebugOutput[] = 'get_cfg_var(memory_limit)      = ' . $this->phpThumbDebugVarDump(@get_cfg_var('memory_limit'));
4163
        $DebugOutput[] = 'memory_get_usage()             = ' . (function_exists('memory_get_usage') ? $this->phpThumbDebugVarDump(@memory_get_usage()) : 'n/a');
4164
        $DebugOutput[] = '';
4165
4166
        $DebugOutput[] = '$this->config_prefer_imagemagick            = ' . $this->phpThumbDebugVarDump($this->config_prefer_imagemagick);
4167
        $DebugOutput[] = '$this->config_imagemagick_path              = ' . $this->phpThumbDebugVarDump($this->config_imagemagick_path);
4168
        $DebugOutput[] = '$this->ImageMagickWhichConvert()            = ' . $this->ImageMagickWhichConvert();
4169
        $IMpathUsed    = ($this->config_imagemagick_path ? $this->config_imagemagick_path : $this->ImageMagickWhichConvert());
4170
        $DebugOutput[] = '[actual ImageMagick path used]              = ' . $this->phpThumbDebugVarDump($IMpathUsed);
4171
        $DebugOutput[] = 'file_exists([actual ImageMagick path used]) = ' . $this->phpThumbDebugVarDump(@file_exists($IMpathUsed));
4172
        $DebugOutput[] = 'ImageMagickVersion(false)                   = ' . $this->ImageMagickVersion(false);
4173
        $DebugOutput[] = 'ImageMagickVersion(true)                    = ' . $this->ImageMagickVersion(true);
4174
        $DebugOutput[] = '';
4175
4176
        $DebugOutput[] = '$this->config_cache_directory               = ' . $this->phpThumbDebugVarDump($this->config_cache_directory);
4177
        $DebugOutput[] = '$this->config_cache_directory_depth         = ' . $this->phpThumbDebugVarDump($this->config_cache_directory_depth);
4178
        $DebugOutput[] = '$this->config_cache_disable_warning         = ' . $this->phpThumbDebugVarDump($this->config_cache_disable_warning);
4179
        $DebugOutput[] = '$this->config_cache_maxage                  = ' . $this->phpThumbDebugVarDump($this->config_cache_maxage);
4180
        $DebugOutput[] = '$this->config_cache_maxsize                 = ' . $this->phpThumbDebugVarDump($this->config_cache_maxsize);
4181
        $DebugOutput[] = '$this->config_cache_maxfiles                = ' . $this->phpThumbDebugVarDump($this->config_cache_maxfiles);
4182
        $DebugOutput[] = '$this->config_cache_force_passthru          = ' . $this->phpThumbDebugVarDump($this->config_cache_force_passthru);
4183
        $DebugOutput[] = '$this->cache_filename                       = ' . $this->phpThumbDebugVarDump($this->cache_filename);
4184
        $DebugOutput[] = 'is_readable($this->config_cache_directory)  = ' . $this->phpThumbDebugVarDump(@is_readable($this->config_cache_directory));
4185
        $DebugOutput[] = 'is_writable($this->config_cache_directory)  = ' . $this->phpThumbDebugVarDump(@is_writable($this->config_cache_directory));
4186
        $DebugOutput[] = 'is_readable($this->cache_filename)          = ' . $this->phpThumbDebugVarDump(@is_readable($this->cache_filename));
4187
        $DebugOutput[] = 'is_writable($this->cache_filename)          = ' . (@file_exists($this->cache_filename) ? $this->phpThumbDebugVarDump(@is_writable($this->cache_filename)) : 'n/a');
4188
        $DebugOutput[] = '';
4189
4190
        foreach ($ConfigVariableNames as $varname) {
4191
            $varname       = 'config_' . $varname;
4192
            $value         = $this->$varname;
4193
            $DebugOutput[] = '$this->' . str_pad($varname, 37, ' ', STR_PAD_RIGHT) . ' = ' . $this->phpThumbDebugVarDump($value);
4194
        }
4195
        $DebugOutput[] = '';
4196
        foreach ($OtherVariableNames as $varname) {
4197
            $value         = $this->$varname;
4198
            $DebugOutput[] = '$this->' . str_pad($varname, 27, ' ', STR_PAD_RIGHT) . ' = ' . $this->phpThumbDebugVarDump($value);
4199
        }
4200
        $DebugOutput[] = 'strlen($this->rawImageData)        = ' . strlen(@$this->rawImageData);
4201
        $DebugOutput[] = 'strlen($this->exif_thumbnail_data) = ' . strlen(@$this->exif_thumbnail_data);
4202
        $DebugOutput[] = '';
4203
4204
        foreach ($ParameterNames as $varname) {
4205
            $value         = $this->$varname;
4206
            $DebugOutput[] = '$this->' . str_pad($varname, 4, ' ', STR_PAD_RIGHT) . ' = ' . $this->phpThumbDebugVarDump($value);
4207
        }
4208
        $DebugOutput[] = '';
4209
4210
        foreach ($FunctionsExistance as $functionname) {
4211
            $DebugOutput[] = 'builtin_function_exists(' . $functionname . ')' . str_repeat(' ', 23 - strlen($functionname)) . ' = ' . $this->phpThumbDebugVarDump(phpthumb_functions::builtin_function_exists($functionname));
4212
        }
4213
        $DebugOutput[] = '';
4214
4215
        $gd_info = gd_info();
4216
        foreach ($gd_info as $key => $value) {
4217
            $DebugOutput[] = 'gd_info.' . str_pad($key, 34, ' ', STR_PAD_RIGHT) . ' = ' . $this->phpThumbDebugVarDump($value);
4218
        }
4219
        $DebugOutput[] = '';
4220
4221
        $exif_info = phpthumb_functions::exif_info();
4222
        foreach ($exif_info as $key => $value) {
4223
            $DebugOutput[] = 'exif_info.' . str_pad($key, 26, ' ', STR_PAD_RIGHT) . ' = ' . $this->phpThumbDebugVarDump($value);
4224
        }
4225
        $DebugOutput[] = '';
4226
4227
        if ($ApacheLookupURIarray = phpthumb_functions::ApacheLookupURIarray(dirname(@$_SERVER['PHP_SELF']))) {
4228
            foreach ($ApacheLookupURIarray as $key => $value) {
4229
                $DebugOutput[] = 'ApacheLookupURIarray.' . str_pad($key, 15, ' ', STR_PAD_RIGHT) . ' = ' . $this->phpThumbDebugVarDump($value);
4230
            }
4231
        } else {
4232
            $DebugOutput[] = 'ApacheLookupURIarray() -- FAILED';
4233
        }
4234
        $DebugOutput[] = '';
4235
4236
        if (isset($_GET) && is_array($_GET)) {
4237
            foreach ($_GET as $key => $value) {
4238
                $DebugOutput[] = '$_GET[' . $key . ']' . str_repeat(' ', 30 - strlen($key)) . '= ' . $this->phpThumbDebugVarDump($value);
4239
            }
4240
        }
4241
        if (isset($_POST) && is_array($_POST)) {
4242
            foreach ($_POST as $key => $value) {
4243
                $DebugOutput[] = '$_POST[' . $key . ']' . str_repeat(' ', 29 - strlen($key)) . '= ' . $this->phpThumbDebugVarDump($value);
4244
            }
4245
        }
4246
        $DebugOutput[] = '';
4247
4248
        $DebugOutput[] = '$this->debugmessages:';
4249
        foreach ($this->debugmessages as $errorstring) {
4250
            $DebugOutput[] = '  * ' . $errorstring;
4251
        }
4252
        $DebugOutput[] = '';
4253
4254
        $DebugOutput[] = '$this->debugtiming:';
4255
        foreach ($this->debugtiming as $timestamp => $timingstring) {
4256
            $DebugOutput[] = '  * ' . $timestamp . ' ' . $timingstring;
4257
        }
4258
        $DebugOutput[] = '  * Total processing time: ' . number_format(max(array_keys($this->debugtiming)) - min(array_keys($this->debugtiming)), 6);
4259
4260
        $this->f = (isset($_GET['f']) ? $_GET['f'] : $this->f); // debug modes 0-2 don't recognize text mode otherwise
4261
        return $this->ErrorImage(implode("\n", $DebugOutput), 700, 500, true);
0 ignored issues
show
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...
4262
    }
4263
4264
    public function FatalError($text)
4265
    {
4266
        if (null === $this->fatalerror) {
4267
            $this->fatalerror = $text;
4268
        }
4269
        return true;
4270
    }
4271
4272
    public function ErrorImage($text, $width = 0, $height = 0, $forcedisplay = false)
4273
    {
4274
        $width  = ($width ? $width : $this->config_error_image_width);
4275
        $height = ($height ? $height : $this->config_error_image_height);
4276
4277
        $text = 'phpThumb() v' . $this->phpthumb_version . "\n" . 'http://phpthumb.sourceforge.net' . "\n\n" . ($this->config_disable_debug ? 'Error messages disabled.'
4278
                                                                                                                                              . "\n\n"
4279
                                                                                                                                              . 'edit phpThumb.config.php and (temporarily) set'
4280
                                                                                                                                              . "\n"
4281
                                                                                                                                              . '$PHPTHUMB_CONFIG[\'disable_debug\'] = false;'
4282
                                                                                                                                              . "\n"
4283
                                                                                                                                              . 'to view the details of this error' : $text);
4284
4285
        $this->FatalError($text);
4286
        $this->DebugMessage($text, __FILE__, __LINE__);
4287
        $this->purgeTempFiles();
4288
        if ($this->config_error_silent_die_on_error) {
4289
            exit;
0 ignored issues
show
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...
4290
        }
4291
        if ($this->phpThumbDebug && !$forcedisplay) {
4292
            return false;
4293
        }
4294
        if (!$this->config_error_die_on_error && !$forcedisplay) {
4295
            return false;
4296
        }
4297
        if ($this->err || $this->config_error_message_image_default) {
4298
            // Show generic custom error image instead of error message
4299
            // for use on production sites where you don't want debug messages
4300
            if (($this->err == 'showerror') || $this->phpThumbDebug) {
4301
                // fall through and actually show error message even if default error image is set
4302
            } else {
4303
                header('Location: ' . ($this->err ? $this->err : $this->config_error_message_image_default));
4304
                exit;
4305
            }
4306
        }
4307
        $this->setOutputFormat();
4308
        if (!$this->thumbnailFormat || !$this->config_disable_debug || (phpthumb_functions::gd_version() < 1)) {
4309
            $this->thumbnailFormat = 'text';
4310
        }
4311
        if (@$this->thumbnailFormat == 'text') {
4312
            // bypass all GD functions and output text error message
4313
            if (!headers_sent()) {
4314
                header('Content-type: text/plain');
4315
                echo $text;
4316
            } else {
4317
                echo '<pre>' . htmlspecialchars($text) . '</pre>';
4318
            }
4319
            exit;
0 ignored issues
show
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...
4320
        }
4321
4322
        $FontWidth  = imagefontwidth($this->config_error_fontsize);
4323
        $FontHeight = imagefontheight($this->config_error_fontsize);
4324
4325
        $LinesOfText = explode("\n", @wordwrap($text, floor($width / $FontWidth), "\n", true));
0 ignored issues
show
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

4325
        $LinesOfText = explode("\n", @wordwrap($text, /** @scrutinizer ignore-type */ floor($width / $FontWidth), "\n", true));
Loading history...
4326
        $height      = max($height, count($LinesOfText) * $FontHeight);
4327
4328
        $headers_file = '';
4329
        $headers_line = '';
4330
        if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '4.3.0', '>=') && headers_sent($headers_file, $headers_line)) {
0 ignored issues
show
$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

4330
        if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '4.3.0', '>=') && headers_sent($headers_file, /** @scrutinizer ignore-type */ $headers_line)) {
Loading history...
4331
            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>';
4332
        } elseif (headers_sent()) {
4333
            echo "\n" . '**Headers already sent, dumping error message as text:**<br><pre>' . "\n\n" . $text . "\n" . '</pre>';
4334
        } elseif ($gdimg_error = imagecreate($width, $height)) {
4335
            $background_color = phpthumb_functions::ImageHexColorAllocate($gdimg_error, $this->config_error_bgcolor, true);
4336
            $text_color       = phpthumb_functions::ImageHexColorAllocate($gdimg_error, $this->config_error_textcolor, true);
4337
            imagefilledrectangle($gdimg_error, 0, 0, $width, $height, $background_color);
4338
            $lineYoffset = 0;
4339
            foreach ($LinesOfText as $line) {
4340
                imagestring($gdimg_error, $this->config_error_fontsize, 2, $lineYoffset, $line, $text_color);
4341
                $lineYoffset += $FontHeight;
4342
            }
4343
            if (function_exists('imagetypes')) {
4344
                $imagetypes = imagetypes();
4345
                if ($imagetypes & IMG_PNG) {
4346
                    header('Content-Type: image/png');
4347
                    imagepng($gdimg_error);
4348
                } elseif ($imagetypes & IMG_GIF) {
4349
                    header('Content-Type: image/gif');
4350
                    imagegif($gdimg_error);
4351
                } elseif ($imagetypes & IMG_JPG) {
4352
                    header('Content-Type: image/jpeg');
4353
                    imagejpeg($gdimg_error);
4354
                } elseif ($imagetypes & IMG_WBMP) {
4355
                    header('Content-Type: image/vnd.wap.wbmp');
4356
                    imagewbmp($gdimg_error);
4357
                }
4358
            }
4359
            imagedestroy($gdimg_error);
4360
        }
4361
        if (!headers_sent()) {
4362
            echo "\n" . '**Failed to send graphical error image, dumping error message as text:**<br>' . "\n\n" . $text;
4363
        }
4364
        exit;
0 ignored issues
show
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...
4365
    }
4366
4367
    public function ImageCreateFromStringReplacement(&$RawImageData, $DieOnErrors = false)
4368
    {
4369
        // there are serious bugs in the non-bundled versions of GD which may cause
4370
        // PHP to segfault when calling imagecreatefromstring() - avoid if at all possible
4371
        // when not using a bundled version of GD2
4372
        if (!phpthumb_functions::gd_version()) {
4373
            if ($DieOnErrors) {
4374
                if (!headers_sent()) {
4375
                    // base64-encoded error image in GIF format
4376
                    $ERROR_NOGD = 'R0lGODlhIAAgALMAAAAAABQUFCQkJDY2NkZGRldXV2ZmZnJycoaGhpSUlKWlpbe3t8XFxdXV1eTk5P7+/iwAAAAAIAAgAAAE/vDJSau9WILtTAACUinDNijZtAHfCojS4W5H+qxD8xibIDE9h0OwWaRWDIljJSkUJYsN4bihMB8th3IToAKs1VtYM75cyV8sZ8vygtOE5yMKmGbO4jRdICQCjHdlZzwzNW4qZSQmKDaNjhUMBX4BBAlmMywFSRWEmAI6b5gAlhNxokGhooAIK5o/pi9vEw4Lfj4OLTAUpj6IabMtCwlSFw0DCKBoFqwAB04AjI54PyZ+yY3TD0ss2YcVmN/gvpcu4TOyFivWqYJlbAHPpOntvxNAACcmGHjZzAZqzSzcq5fNjxFmAFw9iFRunD1epU6tsIPmFCAJnWYE0FURk7wJDA0MTKpEzoWAAskiAAA7';
4377
                    header('Content-Type: image/gif');
4378
                    echo base64_decode($ERROR_NOGD);
4379
                } else {
4380
                    echo '*** ERROR: No PHP-GD support available ***';
4381
                }
4382
                exit;
0 ignored issues
show
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...
4383
            } else {
4384
                $this->DebugMessage('ImageCreateFromStringReplacement() failed: gd_version says "' . phpthumb_functions::gd_version() . '"', __FILE__, __LINE__);
4385
                return false;
4386
            }
4387
        }
4388
        if (phpthumb_functions::gd_is_bundled()) {
4389
            $this->DebugMessage('ImageCreateFromStringReplacement() calling built-in imagecreatefromstring()', __FILE__, __LINE__);
4390
            return @imagecreatefromstring($RawImageData);
4391
        }
4392
        if ($this->issafemode) {
4393
            $this->DebugMessage('ImageCreateFromStringReplacement() failed: cannot create temp file in SAFE_MODE', __FILE__, __LINE__);
4394
            return false;
4395
        }
4396
4397
        switch (substr($RawImageData, 0, 3)) {
4398
            case 'GIF':
4399
                $ICFSreplacementFunctionName = 'imagecreatefromgif';
4400
                break;
4401
            case "\xFF\xD8\xFF":
4402
                $ICFSreplacementFunctionName = 'imagecreatefromjpeg';
4403
                break;
4404
            case "\x89" . 'PN':
4405
                $ICFSreplacementFunctionName = 'imagecreatefrompng';
4406
                break;
4407
            default:
4408
                $this->DebugMessage('ImageCreateFromStringReplacement() failed: unknown fileformat signature "' . phpthumb_functions::HexCharDisplay(substr($RawImageData, 0, 3)) . '"', __FILE__, __LINE__);
4409
                return false;
4410
                break;
0 ignored issues
show
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...
4411
        }
4412
        $ErrorMessage = '';
4413
        if ($tempnam = $this->phpThumb_tempnam()) {
4414
            if ($fp_tempnam = @fopen($tempnam, 'wb')) {
4415
                fwrite($fp_tempnam, $RawImageData);
4416
                fclose($fp_tempnam);
4417
                @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

4417
                /** @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...
4418
                if (($ICFSreplacementFunctionName == 'imagecreatefromgif') && !function_exists($ICFSreplacementFunctionName)) {
4419
                    // Need to create from GIF file, but imagecreatefromgif does not exist
4420
                    ob_start();
4421
                    if (!@include_once __DIR__ . '/phpthumb.gif.php') {
4422
                        $ErrorMessage = 'Failed to include required file "' . __DIR__ . '/phpthumb.gif.php" in ' . __FILE__ . ' on line ' . __LINE__;
4423
                        $this->DebugMessage($ErrorMessage, __FILE__, __LINE__);
4424
                    }
4425
                    ob_end_clean();
4426
                    // gif_loadFileToGDimageResource() cannot read from raw data, write to file first
4427
                    if ($tempfilename = $this->phpThumb_tempnam()) {
4428
                        if ($fp_tempfile = @fopen($tempfilename, 'wb')) {
4429
                            fwrite($fp_tempfile, $RawImageData);
4430
                            fclose($fp_tempfile);
4431
                            $gdimg_source = gif_loadFileToGDimageResource($tempfilename);
4432
                            $this->DebugMessage('gif_loadFileToGDimageResource(' . $tempfilename . ') completed', __FILE__, __LINE__);
4433
                            $this->DebugMessage('deleting "' . $tempfilename . '"', __FILE__, __LINE__);
4434
                            unlink($tempfilename);
4435
                            return $gdimg_source;
4436
                        } else {
4437
                            $ErrorMessage = 'Failed to open tempfile in ' . __FILE__ . ' on line ' . __LINE__;
4438
                            $this->DebugMessage($ErrorMessage, __FILE__, __LINE__);
4439
                        }
4440
                    } else {
4441
                        $ErrorMessage = 'Failed to open generate tempfile name in ' . __FILE__ . ' on line ' . __LINE__;
4442
                        $this->DebugMessage($ErrorMessage, __FILE__, __LINE__);
4443
                    }
4444
                } elseif (function_exists($ICFSreplacementFunctionName) && ($gdimg_source = @$ICFSreplacementFunctionName($tempnam))) {
4445
                    // great
4446
                    $this->DebugMessage($ICFSreplacementFunctionName . '(' . $tempnam . ') succeeded', __FILE__, __LINE__);
4447
                    $this->DebugMessage('deleting "' . $tempnam . '"', __FILE__, __LINE__);
4448
                    unlink($tempnam);
4449
                    return $gdimg_source;
4450
                } else {
4451
                    // GD functions not available, or failed to create image
4452
                    $this->DebugMessage($ICFSreplacementFunctionName . '(' . $tempnam . ') ' . (function_exists($ICFSreplacementFunctionName) ? 'failed' : 'does not exist'), __FILE__, __LINE__);
4453
                    if (isset($_GET['phpThumbDebug'])) {
4454
                        $this->phpThumbDebug();
4455
                    }
4456
                }
4457
            } else {
4458
                $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';
4459
                if ($this->issafemode) {
4460
                    $ErrorMessage = 'ImageCreateFromStringReplacement() failed in ' . __FILE__ . ' on line ' . __LINE__ . ': cannot create temp file in SAFE_MODE';
4461
                }
4462
                $this->DebugMessage($ErrorMessage, __FILE__, __LINE__);
4463
            }
4464
            $this->DebugMessage('deleting "' . $tempnam . '"', __FILE__, __LINE__);
4465
            @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

4465
            /** @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...
4466
        } else {
4467
            $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';
4468
            if ($this->issafemode) {
4469
                $ErrorMessage = 'ImageCreateFromStringReplacement() failed in ' . __FILE__ . ' on line ' . __LINE__ . ': cannot create temp file in SAFE_MODE';
4470
            }
4471
        }
4472
        if ($DieOnErrors && $ErrorMessage) {
4473
            return $this->ErrorImage($ErrorMessage);
4474
        }
4475
        return false;
4476
    }
4477
4478
    public function ImageResizeFunction(&$dst_im, &$src_im, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH)
4479
    {
4480
        $this->DebugMessage('ImageResizeFunction($o, $s, ' . $dstX . ', ' . $dstY . ', ' . $srcX . ', ' . $srcY . ', ' . $dstW . ', ' . $dstH . ', ' . $srcW . ', ' . $srcH . ')', __FILE__, __LINE__);
4481
        if (($dstW == $srcW) && ($dstH == $srcH)) {
4482
            return imagecopy($dst_im, $src_im, $dstX, $dstY, $srcX, $srcY, $srcW, $srcH);
4483
        }
4484
        if (phpthumb_functions::gd_version() >= 2.0) {
4485
            if ($this->config_disable_imagecopyresampled) {
4486
                return phpthumb_functions::ImageCopyResampleBicubic($dst_im, $src_im, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH);
4487
            }
4488
            return imagecopyresampled($dst_im, $src_im, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH);
4489
        }
4490
        return imagecopyresized($dst_im, $src_im, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH);
4491
    }
4492
4493
    public function InitializeTempDirSetting()
4494
    {
4495
        $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
4496
        $this->config_temp_directory = ($this->config_temp_directory ? $this->config_temp_directory : $this->realPathSafe(ini_get('upload_tmp_dir')));
4497
        $this->config_temp_directory = ($this->config_temp_directory ? $this->config_temp_directory : $this->realPathSafe(getenv('TMPDIR')));
4498
        $this->config_temp_directory = ($this->config_temp_directory ? $this->config_temp_directory : $this->realPathSafe(getenv('TMP')));
4499
        return true;
4500
    }
4501
4502
    public function phpThumb_tempnam()
4503
    {
4504
        $this->InitializeTempDirSetting();
4505
        $tempnam                           = $this->realPathSafe(tempnam($this->config_temp_directory, 'pThumb'));
4506
        $this->tempFilesToDelete[$tempnam] = $tempnam;
4507
        $this->DebugMessage('phpThumb_tempnam() returning "' . $tempnam . '"', __FILE__, __LINE__);
4508
        return $tempnam;
4509
    }
4510
4511
    public function DebugMessage($message, $file = '', $line = '')
4512
    {
4513
        $this->debugmessages[] = $message . ($file ? ' in file "' . (basename($file) ? basename($file) : $file) . '"' : '') . ($line ? ' on line ' . $line : '');
4514
        return true;
4515
    }
4516
4517
    public function DebugTimingMessage($message, $file = '', $line = '', $timestamp = 0)
4518
    {
4519
        if (!$timestamp) {
4520
            $timestamp = array_sum(explode(' ', microtime()));
4521
        }
4522
        $this->debugtiming[number_format($timestamp, 6, '.', '')] = ': ' . $message . ($file ? ' in file "' . (basename($file) ? basename($file) : $file) . '"' : '') . ($line ? ' on line ' . $line : '');
4523
        return true;
4524
    }
4525
}
4526