Passed
Push — master ( 48d769...5ccf6e )
by Michael
07:14
created

phpthumb::applyPathSegment()   D

Complexity

Conditions 10
Paths 10

Size

Total Lines 36
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 10
eloc 29
c 2
b 0
f 0
nc 10
nop 2
dl 0
loc 36
rs 4.8196

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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

279
                /** @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...
280
            }
281
        }
282
        $this->tempFilesToDelete = [];
283
284
        return true;
285
    }
286
287
    // public:
288
289
    /**
290
     * @param $sourceFilename
291
     * @return bool
292
     */
293
    public function setSourceFilename($sourceFilename)
294
    {
295
        //$this->resetObject();
296
        //$this->rawImageData   = null;
297
        $this->sourceFilename = $sourceFilename;
298
        $this->src            = $sourceFilename;
299
        if (null === $this->config_output_format) {
300
            $sourceFileExtension = strtolower(substr(strrchr($sourceFilename, '.'), 1));
301
            if (preg_match('#^[a-z]{3,4}$#', $sourceFileExtension)) {
302
                $this->config_output_format = $sourceFileExtension;
303
                $this->DebugMessage('setSourceFilename(' . $sourceFilename . ') set $this->config_output_format to "' . $sourceFileExtension . '"', __FILE__, __LINE__);
304
            } else {
305
                $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__);
306
            }
307
        }
308
        $this->DebugMessage('setSourceFilename(' . $sourceFilename . ') set $this->sourceFilename to "' . $this->sourceFilename . '"', __FILE__, __LINE__);
309
310
        return true;
311
    }
312
313
    // public:
314
315
    /**
316
     * @param        $rawImageData
317
     * @param string $sourceFilename
318
     * @return bool
319
     */
320
    public function setSourceData($rawImageData, $sourceFilename = '')
321
    {
322
        //$this->resetObject();
323
        //$this->sourceFilename = null;
324
        $this->rawImageData = $rawImageData;
325
        $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__);
326
        if ($this->config_cache_source_enabled) {
327
            $sourceFilename = ($sourceFilename ?: md5($rawImageData));
328
            if (!is_dir($this->config_cache_source_directory)) {
329
                $this->ErrorImage('$this->config_cache_source_directory (' . $this->config_cache_source_directory . ') is not a directory');
330
            } elseif (!@is_writable($this->config_cache_source_directory)) {
331
                $this->ErrorImage('$this->config_cache_source_directory (' . $this->config_cache_source_directory . ') is not writable');
332
            }
333
            $this->DebugMessage('setSourceData() attempting to save source image to "' . $this->config_cache_source_directory . DIRECTORY_SEPARATOR . urlencode($sourceFilename) . '"', __FILE__, __LINE__);
334
            if ($fp = @fopen($this->config_cache_source_directory . DIRECTORY_SEPARATOR . urlencode($sourceFilename), 'wb')) {
335
                fwrite($fp, $rawImageData);
336
                fclose($fp);
337
            } elseif (!$this->phpThumbDebug) {
338
                $this->ErrorImage('setSourceData() failed to write to source cache (' . $this->config_cache_source_directory . DIRECTORY_SEPARATOR . urlencode($sourceFilename) . ')');
339
            }
340
        }
341
342
        return true;
343
    }
344
345
    // public:
346
347
    /**
348
     * @param $gdimg
349
     * @return bool
350
     */
351
    public function setSourceImageResource($gdimg)
352
    {
353
        //$this->resetObject();
354
        $this->gdimg_source = $gdimg;
355
356
        return true;
357
    }
358
359
    // public:
360
361
    /**
362
     * @param $param
363
     * @param $value
364
     * @return bool
365
     */
366
    public function setParameter($param, $value)
367
    {
368
        if ('src' === $param) {
369
            $this->setSourceFilename($this->ResolveFilenameToAbsolute($value));
370
        } elseif (@is_array($this->$param)) {
371
            if (is_array($value)) {
372
                foreach ($value as $arraykey => $arrayvalue) {
373
                    array_push($this->$param, $arrayvalue);
374
                }
375
            } else {
376
                array_push($this->$param, $value);
377
            }
378
        } else {
379
            $this->$param = $value;
380
        }
381
382
        return true;
383
    }
384
385
    // public:
386
387
    /**
388
     * @param $param
389
     * @return mixed
390
     */
391
    public function getParameter($param)
392
    {
393
        //if (property_exists('phpThumb', $param)) {
394
        return $this->$param;
395
        //}
396
        //$this->DebugMessage('setParameter() attempting to get non-existant parameter "'.$param.'"', __FILE__, __LINE__);
397
        //return false;
398
    }
399
400
    // public:
401
402
    /**
403
     * @return bool
404
     */
405
    public function GenerateThumbnail()
406
    {
407
        $this->setOutputFormat();
408
        $this->phpThumbDebug('8a');
409
        $this->ResolveSource();
410
        $this->phpThumbDebug('8b');
411
        $this->SetCacheFilename();
412
        $this->phpThumbDebug('8c');
413
        $this->ExtractEXIFgetImageSize();
414
        $this->phpThumbDebug('8d');
415
        if ($this->useRawIMoutput) {
416
            $this->DebugMessage('Skipping rest of GenerateThumbnail() because ($this->useRawIMoutput === true)', __FILE__, __LINE__);
417
418
            return true;
419
        }
420
        $this->phpThumbDebug('8e');
421
        if (!$this->SourceImageToGD()) {
422
            $this->DebugMessage('SourceImageToGD() failed', __FILE__, __LINE__);
423
424
            return false;
425
        }
426
        $this->phpThumbDebug('8f');
427
        $this->Rotate();
428
        $this->phpThumbDebug('8g');
429
        $this->CreateGDoutput();
430
        $this->phpThumbDebug('8h');
431
432
        // default values, also applicable for far="C"
433
        $destination_offset_x = round(($this->thumbnail_width - $this->thumbnail_image_width) / 2);
434
        $destination_offset_y = round(($this->thumbnail_height - $this->thumbnail_image_height) / 2);
435
        if (('L' === $this->far) || ('TL' === $this->far) || ('BL' === $this->far)) {
436
            $destination_offset_x = 0;
437
        }
438
        if (('R' === $this->far) || ('TR' === $this->far) || ('BR' === $this->far)) {
439
            $destination_offset_x = round($this->thumbnail_width - $this->thumbnail_image_width);
440
        }
441
        if (('T' === $this->far) || ('TL' === $this->far) || ('TR' === $this->far)) {
442
            $destination_offset_y = 0;
443
        }
444
        if (('B' === $this->far) || ('BL' === $this->far) || ('BR' === $this->far)) {
445
            $destination_offset_y = round($this->thumbnail_height - $this->thumbnail_image_height);
446
        }
447
448
        //		// copy/resize image to appropriate dimensions
449
        //		$borderThickness = 0;
450
        //		if (!empty($this->fltr)) {
451
        //			foreach ($this->fltr as $key => $value) {
452
        //				if (preg_match('#^bord\|([0-9]+)#', $value, $matches)) {
453
        //					$borderThickness = $matches[1];
454
        //					break;
455
        //				}
456
        //			}
457
        //		}
458
        //		if ($borderThickness > 0) {
459
        //			//$this->DebugMessage('Skipping ImageResizeFunction() because BorderThickness="'.$borderThickness.'"', __FILE__, __LINE__);
460
        //			$this->thumbnail_image_height /= 2;
461
        //		}
462
        $this->ImageResizeFunction($this->gdimg_output, $this->gdimg_source, $destination_offset_x, $destination_offset_y, $this->thumbnailCropX, $this->thumbnailCropY, $this->thumbnail_image_width, $this->thumbnail_image_height, $this->thumbnailCropW, $this->thumbnailCropH);
463
464
        $this->DebugMessage('memory_get_usage() after copy-resize = ' . (function_exists('memory_get_usage') ? @memory_get_usage() : 'n/a'), __FILE__, __LINE__);
465
        imagedestroy($this->gdimg_source);
466
        $this->DebugMessage('memory_get_usage() after imagedestroy = ' . (function_exists('memory_get_usage') ? @memory_get_usage() : 'n/a'), __FILE__, __LINE__);
467
468
        $this->phpThumbDebug('8i');
469
        $this->AntiOffsiteLinking();
470
        $this->phpThumbDebug('8j');
471
        $this->ApplyFilters();
472
        $this->phpThumbDebug('8k');
473
        $this->AlphaChannelFlatten();
474
        $this->phpThumbDebug('8l');
475
        $this->MaxFileSize();
476
        $this->phpThumbDebug('8m');
477
478
        $this->DebugMessage('GenerateThumbnail() completed successfully', __FILE__, __LINE__);
479
480
        return true;
481
    }
482
483
    // public:
484
485
    /**
486
     * @return bool
487
     */
488
    public function RenderOutput()
489
    {
490
        if (!$this->useRawIMoutput && !is_resource($this->gdimg_output)) {
491
            $this->DebugMessage('RenderOutput() failed because !is_resource($this->gdimg_output)', __FILE__, __LINE__);
492
493
            return false;
494
        }
495
        if (!$this->thumbnailFormat) {
496
            $this->DebugMessage('RenderOutput() failed because $this->thumbnailFormat is empty', __FILE__, __LINE__);
497
498
            return false;
499
        }
500
        if ($this->useRawIMoutput) {
501
            $this->DebugMessage('RenderOutput copying $this->IMresizedData (' . strlen($this->IMresizedData) . ' bytes) to $this->outputImage', __FILE__, __LINE__);
502
            $this->outputImageData = $this->IMresizedData;
503
504
            return true;
505
        }
506
507
        $builtin_formats = [];
508
        if (function_exists('imagetypes')) {
509
            $imagetypes              = imagetypes();
510
            $builtin_formats['wbmp'] = (bool)($imagetypes & IMG_WBMP);
511
            $builtin_formats['jpg']  = (bool)($imagetypes & IMG_JPG);
512
            $builtin_formats['gif']  = (bool)($imagetypes & IMG_GIF);
513
            $builtin_formats['png']  = (bool)($imagetypes & IMG_PNG);
514
        }
515
516
        $this->DebugMessage('imageinterlace($this->gdimg_output, ' . (int)$this->config_output_interlace . ')', __FILE__, __LINE__);
517
        imageinterlace($this->gdimg_output, (int)$this->config_output_interlace);
518
519
        $this->DebugMessage('RenderOutput() attempting image' . strtolower(@$this->thumbnailFormat) . '($this->gdimg_output)', __FILE__, __LINE__);
520
        ob_start();
521
        switch ($this->thumbnailFormat) {
522
            case 'wbmp':
523
                if (empty($builtin_formats['wbmp'])) {
524
                    $this->DebugMessage('GD does not have required built-in support for WBMP output', __FILE__, __LINE__);
525
                    ob_end_clean();
526
527
                    return false;
528
                }
529
                imagejpeg($this->gdimg_output, null, $this->thumbnailQuality);
530
                $this->outputImageData = ob_get_contents();
531
                break;
532
533
            case 'jpeg':
534
            case 'jpg':  // should be "jpeg" not "jpg" but just in case...
535
                if (empty($builtin_formats['jpg'])) {
536
                    $this->DebugMessage('GD does not have required built-in support for JPEG output', __FILE__, __LINE__);
537
                    ob_end_clean();
538
539
                    return false;
540
                }
541
                imagejpeg($this->gdimg_output, null, $this->thumbnailQuality);
542
                $this->outputImageData = ob_get_contents();
543
                break;
544
545
            case 'png':
546
                if (empty($builtin_formats['png'])) {
547
                    $this->DebugMessage('GD does not have required built-in support for PNG output', __FILE__, __LINE__);
548
                    ob_end_clean();
549
550
                    return false;
551
                }
552
                if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.1.2', '>=')) {
553
                    // https://github.com/JamesHeinrich/phpThumb/issues/24
554
555
                    /* http://php.net/manual/en/function.imagepng.php:
556
                    from php source (gd.h):
557
                    2.0.12: Compression level: 0-9 or -1, where 0 is NO COMPRESSION at all,
558
                    :: 1 is FASTEST but produces larger files, 9 provides the best
559
                    :: compression (smallest files) but takes a long time to compress, and
560
                    :: -1 selects the default compiled into the zlib library.
561
                    Conclusion: Based on the Zlib manual (http://www.zlib.net/manual.html) the default compression level is set to 6.
562
                    */
563
                    if (($this->thumbnailQuality >= -1) && ($this->thumbnailQuality <= 9)) {
564
                        $PNGquality = $this->thumbnailQuality;
565
                    } else {
566
                        $this->DebugMessage('Specified thumbnailQuality "' . $this->thumbnailQuality . '" is outside the accepted range (0-9, or -1). Using 6 as default value.', __FILE__, __LINE__);
567
                        $PNGquality = 6;
568
                    }
569
                    imagepng($this->gdimg_output, null, $PNGquality);
570
                } else {
571
                    imagepng($this->gdimg_output);
572
                }
573
                $this->outputImageData = ob_get_contents();
574
                break;
575
576
            case 'gif':
577
                if (empty($builtin_formats['gif'])) {
578
                    $this->DebugMessage('GD does not have required built-in support for GIF output', __FILE__, __LINE__);
579
                    ob_end_clean();
580
581
                    return false;
582
                }
583
                imagegif($this->gdimg_output);
584
                $this->outputImageData = ob_get_contents();
585
                break;
586
587
            case 'bmp':
588
                if (!@require_once __DIR__ . '/phpthumb.bmp.php') {
589
                    $this->DebugMessage('Error including "' . __DIR__ . '/phpthumb.bmp.php" which is required for BMP format output', __FILE__, __LINE__);
590
                    ob_end_clean();
591
592
                    return false;
593
                }
594
                $phpthumb_bmp          = new phpthumb_bmp();
595
                $this->outputImageData = $phpthumb_bmp->GD2BMPstring($this->gdimg_output);
596
                unset($phpthumb_bmp);
597
                break;
598
599
            case 'ico':
600
                if (!@require_once __DIR__ . '/phpthumb.ico.php') {
601
                    $this->DebugMessage('Error including "' . __DIR__ . '/phpthumb.ico.php" which is required for ICO format output', __FILE__, __LINE__);
602
                    ob_end_clean();
603
604
                    return false;
605
                }
606
                $phpthumb_ico          = new phpthumb_ico();
607
                $arrayOfOutputImages   = [$this->gdimg_output];
608
                $this->outputImageData = $phpthumb_ico->GD2ICOstring($arrayOfOutputImages);
609
                unset($phpthumb_ico);
610
                break;
611
612
            default:
613
                $this->DebugMessage('RenderOutput failed because $this->thumbnailFormat "' . $this->thumbnailFormat . '" is not valid', __FILE__, __LINE__);
614
                ob_end_clean();
615
616
                return false;
617
        }
618
        ob_end_clean();
619
        if (!$this->outputImageData) {
620
            $this->DebugMessage('RenderOutput() for "' . $this->thumbnailFormat . '" failed', __FILE__, __LINE__);
621
            ob_end_clean();
622
623
            return false;
624
        }
625
        $this->DebugMessage('RenderOutput() completing with $this->outputImageData = ' . strlen($this->outputImageData) . ' bytes', __FILE__, __LINE__);
626
627
        return true;
628
    }
629
630
    // public:
631
632
    /**
633
     * @param $filename
634
     * @return bool
635
     */
636
    public function RenderToFile($filename)
637
    {
638
        if (preg_match('#^[a-z0-9]+://#i', $filename)) {
639
            $this->DebugMessage('RenderToFile() failed because $filename (' . $filename . ') is a URL', __FILE__, __LINE__);
640
641
            return false;
642
        }
643
        // render thumbnail to this file only, do not cache, do not output to browser
644
        //$renderfilename = $this->ResolveFilenameToAbsolute(dirname($filename)).DIRECTORY_SEPARATOR.basename($filename);
645
        $renderfilename = $filename;
646
        if (('/' !== $filename{0}) && ('\\' !== $filename{0}) && (':' !== $filename{1})) {
647
            $renderfilename = $this->ResolveFilenameToAbsolute($renderfilename);
648
        }
649
        if (!@is_writable(dirname($renderfilename))) {
650
            $this->DebugMessage('RenderToFile() failed because "' . dirname($renderfilename) . '/" is not writable', __FILE__, __LINE__);
651
652
            return false;
653
        }
654
        if (@is_file($renderfilename) && !@is_writable($renderfilename)) {
655
            $this->DebugMessage('RenderToFile() failed because "' . $renderfilename . '" is not writable', __FILE__, __LINE__);
656
657
            return false;
658
        }
659
660
        if ($this->RenderOutput()) {
661
            if (file_put_contents($renderfilename, $this->outputImageData)) {
662
                $this->DebugMessage('RenderToFile(' . $renderfilename . ') succeeded', __FILE__, __LINE__);
663
664
                return true;
665
            }
666
            if (!@file_exists($renderfilename)) {
667
                $this->DebugMessage('RenderOutput [' . $this->thumbnailFormat . '(' . $renderfilename . ')] did not appear to fail, but the output image does not exist either...', __FILE__, __LINE__);
668
            }
669
        } else {
670
            $this->DebugMessage('RenderOutput [' . $this->thumbnailFormat . '(' . $renderfilename . ')] failed', __FILE__, __LINE__);
671
        }
672
673
        return false;
674
    }
675
676
    // public:
677
678
    /**
679
     * @return bool
680
     */
681
    public function OutputThumbnail()
682
    {
683
        $this->purgeTempFiles();
684
685
        if (!$this->useRawIMoutput && !is_resource($this->gdimg_output)) {
686
            $this->DebugMessage('OutputThumbnail() failed because !is_resource($this->gdimg_output)', __FILE__, __LINE__);
687
688
            return false;
689
        }
690
        if (headers_sent()) {
691
            return $this->ErrorImage('OutputThumbnail() failed - headers already sent');
692
        }
693
694
        $downloadfilename = phpthumb_functions::SanitizeFilename(is_string($this->sia) ? $this->sia : ($this->down ?: 'phpThumb_generated_thumbnail' . '.' . $this->thumbnailFormat));
695
        $this->DebugMessage('Content-Disposition header filename set to "' . $downloadfilename . '"', __FILE__, __LINE__);
0 ignored issues
show
Bug introduced by
Are you sure $downloadfilename of type null|string|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

695
        $this->DebugMessage('Content-Disposition header filename set to "' . /** @scrutinizer ignore-type */ $downloadfilename . '"', __FILE__, __LINE__);
Loading history...
696
        if ($downloadfilename) {
697
            header('Content-Disposition: ' . ($this->down ? 'attachment' : 'inline') . '; filename="' . $downloadfilename . '"');
698
        } else {
699
            $this->DebugMessage('failed to send Content-Disposition header because $downloadfilename is empty', __FILE__, __LINE__);
700
        }
701
702
        if ($this->useRawIMoutput) {
703
            header('Content-Type: ' . phpthumb_functions::ImageTypeToMIMEtype($this->thumbnailFormat));
704
            echo $this->IMresizedData;
705
        } else {
706
            $this->DebugMessage('imageinterlace($this->gdimg_output, ' . (int)$this->config_output_interlace . ')', __FILE__, __LINE__);
707
            imageinterlace($this->gdimg_output, (int)$this->config_output_interlace);
708
            switch ($this->thumbnailFormat) {
709
                case 'jpeg':
710
                    header('Content-Type: ' . phpthumb_functions::ImageTypeToMIMEtype($this->thumbnailFormat));
711
                    $ImageOutFunction = 'image' . $this->thumbnailFormat;
712
                    @$ImageOutFunction($this->gdimg_output, null, $this->thumbnailQuality);
713
                    break;
714
715
                case 'png':
716
                case 'gif':
717
                    header('Content-Type: ' . phpthumb_functions::ImageTypeToMIMEtype($this->thumbnailFormat));
718
                    $ImageOutFunction = 'image' . $this->thumbnailFormat;
719
                    @$ImageOutFunction($this->gdimg_output);
720
                    break;
721
722
                case 'bmp':
723
                    if (!@require_once __DIR__ . '/phpthumb.bmp.php') {
724
                        $this->DebugMessage('Error including "' . __DIR__ . '/phpthumb.bmp.php" which is required for BMP format output', __FILE__, __LINE__);
725
726
                        return false;
727
                    }
728
                    $phpthumb_bmp = new phpthumb_bmp();
729
                    if (is_object($phpthumb_bmp)) {
730
                        $bmp_data = $phpthumb_bmp->GD2BMPstring($this->gdimg_output);
731
                        unset($phpthumb_bmp);
732
                        if (!$bmp_data) {
733
                            $this->DebugMessage('$phpthumb_bmp->GD2BMPstring() failed', __FILE__, __LINE__);
734
735
                            return false;
736
                        }
737
                        header('Content-Type: ' . phpthumb_functions::ImageTypeToMIMEtype($this->thumbnailFormat));
738
                        echo $bmp_data;
739
                    } else {
740
                        $this->DebugMessage('new phpthumb_bmp() failed', __FILE__, __LINE__);
741
742
                        return false;
743
                    }
744
                    break;
745
746
                case 'ico':
747
                    if (!@require_once __DIR__ . '/phpthumb.ico.php') {
748
                        $this->DebugMessage('Error including "' . __DIR__ . '/phpthumb.ico.php" which is required for ICO format output', __FILE__, __LINE__);
749
750
                        return false;
751
                    }
752
                    $phpthumb_ico = new phpthumb_ico();
753
                    if (is_object($phpthumb_ico)) {
754
                        $arrayOfOutputImages = [$this->gdimg_output];
755
                        $ico_data            = $phpthumb_ico->GD2ICOstring($arrayOfOutputImages);
756
                        unset($phpthumb_ico);
757
                        if (!$ico_data) {
758
                            $this->DebugMessage('$phpthumb_ico->GD2ICOstring() failed', __FILE__, __LINE__);
759
760
                            return false;
761
                        }
762
                        header('Content-Type: ' . phpthumb_functions::ImageTypeToMIMEtype($this->thumbnailFormat));
763
                        echo $ico_data;
764
                    } else {
765
                        $this->DebugMessage('new phpthumb_ico() failed', __FILE__, __LINE__);
766
767
                        return false;
768
                    }
769
                    break;
770
771
                default:
772
                    $this->DebugMessage('OutputThumbnail failed because $this->thumbnailFormat "' . $this->thumbnailFormat . '" is not valid', __FILE__, __LINE__);
773
774
                    return false;
775
                    break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

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

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

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

Loading history...
776
            }
777
        }
778
779
        return true;
780
    }
781
782
    // public:
783
784
    /**
785
     * @return bool
786
     */
787
    public function CleanUpCacheDirectory()
788
    {
789
        $this->DebugMessage('CleanUpCacheDirectory() set to purge ('
790
                            . (null === $this->config_cache_maxage ? 'NULL' : number_format($this->config_cache_maxage / 86400, 1))
791
                            . ' days; '
792
                            . (null === $this->config_cache_maxsize ? 'NULL' : number_format($this->config_cache_maxsize / 1048576, 2))
793
                            . ' MB; '
794
                            . (null === $this->config_cache_maxfiles ? 'NULL' : number_format($this->config_cache_maxfiles))
795
                            . ' files)', __FILE__, __LINE__);
796
797
        if (!is_writable($this->config_cache_directory)) {
798
            $this->DebugMessage('CleanUpCacheDirectory() skipped because "' . $this->config_cache_directory . '" is not writable', __FILE__, __LINE__);
799
800
            return true;
801
        }
802
803
        // cache status of cache directory for 1 hour to avoid hammering the filesystem functions
804
        $phpThumbCacheStats_filename = $this->config_cache_directory . DIRECTORY_SEPARATOR . 'phpThumbCacheStats.txt';
805
        if (file_exists($phpThumbCacheStats_filename) && is_readable($phpThumbCacheStats_filename)
806
            && (filemtime($phpThumbCacheStats_filename) >= (time() - 3600))) {
807
            $this->DebugMessage('CleanUpCacheDirectory() skipped because "' . $phpThumbCacheStats_filename . '" is recently modified', __FILE__, __LINE__);
808
809
            return true;
810
        }
811
        if (!@touch($phpThumbCacheStats_filename)) {
812
            $this->DebugMessage('touch(' . $phpThumbCacheStats_filename . ') failed', __FILE__, __LINE__);
813
        }
814
815
        $DeletedKeys              = [];
816
        $AllFilesInCacheDirectory = [];
817
        if (($this->config_cache_maxage > 0) || ($this->config_cache_maxsize > 0)
818
            || ($this->config_cache_maxfiles > 0)) {
819
            $CacheDirOldFilesAge      = [];
820
            $CacheDirOldFilesSize     = [];
821
            $AllFilesInCacheDirectory = phpthumb_functions::GetAllFilesInSubfolders($this->config_cache_directory);
822
            foreach ($AllFilesInCacheDirectory as $fullfilename) {
823
                if (preg_match('#' . preg_quote($this->config_cache_prefix) . '#i', $fullfilename)
824
                    && file_exists($fullfilename)) {
825
                    $CacheDirOldFilesAge[$fullfilename] = @fileatime($fullfilename);
826
                    if (0 == $CacheDirOldFilesAge[$fullfilename]) {
827
                        $CacheDirOldFilesAge[$fullfilename] = @filemtime($fullfilename);
828
                    }
829
                    $CacheDirOldFilesSize[$fullfilename] = @filesize($fullfilename);
830
                }
831
            }
832
            if (empty($CacheDirOldFilesSize)) {
833
                $this->DebugMessage('CleanUpCacheDirectory() skipped because $CacheDirOldFilesSize is empty (phpthumb_functions::GetAllFilesInSubfolders(' . $this->config_cache_directory . ') found no files)', __FILE__, __LINE__);
834
835
                return true;
836
            }
837
            $DeletedKeys['zerobyte'] = [];
838
            foreach ($CacheDirOldFilesSize as $fullfilename => $filesize) {
839
                // purge all zero-size files more than an hour old (to prevent trying to delete just-created and/or in-use files)
840
                $cutofftime = time() - 3600;
841
                if ((0 == $filesize) && ($CacheDirOldFilesAge[$fullfilename] < $cutofftime)) {
842
                    $this->DebugMessage('deleting "' . $fullfilename . '"', __FILE__, __LINE__);
843
                    if (@unlink($fullfilename)) {
844
                        $DeletedKeys['zerobyte'][] = $fullfilename;
845
                        unset($CacheDirOldFilesSize[$fullfilename]);
846
                        unset($CacheDirOldFilesAge[$fullfilename]);
847
                    }
848
                }
849
            }
850
            $this->DebugMessage('CleanUpCacheDirectory() purged ' . count($DeletedKeys['zerobyte']) . ' zero-byte files', __FILE__, __LINE__);
851
            asort($CacheDirOldFilesAge);
852
853
            if ($this->config_cache_maxfiles > 0) {
854
                $TotalCachedFiles        = count($CacheDirOldFilesAge);
855
                $DeletedKeys['maxfiles'] = [];
856
                foreach ($CacheDirOldFilesAge as $fullfilename => $filedate) {
857
                    if ($TotalCachedFiles > $this->config_cache_maxfiles) {
858
                        $this->DebugMessage('deleting "' . $fullfilename . '"', __FILE__, __LINE__);
859
                        if (@unlink($fullfilename)) {
860
                            $TotalCachedFiles--;
861
                            $DeletedKeys['maxfiles'][] = $fullfilename;
862
                        }
863
                    } else {
864
                        // there are few enough files to keep the rest
865
                        break;
866
                    }
867
                }
868
                $this->DebugMessage('CleanUpCacheDirectory() purged ' . count($DeletedKeys['maxfiles']) . ' files based on (config_cache_maxfiles=' . $this->config_cache_maxfiles . ')', __FILE__, __LINE__);
869
                foreach ($DeletedKeys['maxfiles'] as $fullfilename) {
870
                    unset($CacheDirOldFilesAge[$fullfilename]);
871
                    unset($CacheDirOldFilesSize[$fullfilename]);
872
                }
873
            }
874
875
            if ($this->config_cache_maxage > 0) {
876
                $mindate               = time() - $this->config_cache_maxage;
877
                $DeletedKeys['maxage'] = [];
878
                foreach ($CacheDirOldFilesAge as $fullfilename => $filedate) {
879
                    if ($filedate > 0) {
880
                        if ($filedate < $mindate) {
881
                            $this->DebugMessage('deleting "' . $fullfilename . '"', __FILE__, __LINE__);
882
                            if (@unlink($fullfilename)) {
883
                                $DeletedKeys['maxage'][] = $fullfilename;
884
                            }
885
                        } else {
886
                            // the rest of the files are new enough to keep
887
                            break;
888
                        }
889
                    }
890
                }
891
                $this->DebugMessage('CleanUpCacheDirectory() purged ' . count($DeletedKeys['maxage']) . ' files based on (config_cache_maxage=' . $this->config_cache_maxage . ')', __FILE__, __LINE__);
892
                foreach ($DeletedKeys['maxage'] as $fullfilename) {
893
                    unset($CacheDirOldFilesAge[$fullfilename]);
894
                    unset($CacheDirOldFilesSize[$fullfilename]);
895
                }
896
            }
897
898
            if ($this->config_cache_maxsize > 0) {
899
                $TotalCachedFileSize    = array_sum($CacheDirOldFilesSize);
900
                $DeletedKeys['maxsize'] = [];
901
                foreach ($CacheDirOldFilesAge as $fullfilename => $filedate) {
902
                    if ($TotalCachedFileSize > $this->config_cache_maxsize) {
903
                        $this->DebugMessage('deleting "' . $fullfilename . '"', __FILE__, __LINE__);
904
                        if (@unlink($fullfilename)) {
905
                            $TotalCachedFileSize      -= $CacheDirOldFilesSize[$fullfilename];
906
                            $DeletedKeys['maxsize'][] = $fullfilename;
907
                        }
908
                    } else {
909
                        // the total filesizes are small enough to keep the rest of the files
910
                        break;
911
                    }
912
                }
913
                $this->DebugMessage('CleanUpCacheDirectory() purged ' . count($DeletedKeys['maxsize']) . ' files based on (config_cache_maxsize=' . $this->config_cache_maxsize . ')', __FILE__, __LINE__);
914
                foreach ($DeletedKeys['maxsize'] as $fullfilename) {
915
                    unset($CacheDirOldFilesAge[$fullfilename]);
916
                    unset($CacheDirOldFilesSize[$fullfilename]);
917
                }
918
            }
919
        } else {
920
            $this->DebugMessage('skipping CleanUpCacheDirectory() because config set to not use it', __FILE__, __LINE__);
921
        }
922
        $totalpurged = 0;
923
        foreach ($DeletedKeys as $key => $value) {
924
            $totalpurged += count($value);
925
        }
926
        $this->DebugMessage('CleanUpCacheDirectory() purged ' . $totalpurged . ' files (from ' . count($AllFilesInCacheDirectory) . ') based on config settings', __FILE__, __LINE__);
927
        if ($totalpurged > 0) {
928
            $empty_dirs = [];
929
            foreach ($AllFilesInCacheDirectory as $fullfilename) {
930
                if (is_dir($fullfilename)) {
931
                    $empty_dirs[$this->realPathSafe($fullfilename)] = 1;
932
                } else {
933
                    unset($empty_dirs[$this->realPathSafe(dirname($fullfilename))]);
934
                }
935
            }
936
            krsort($empty_dirs);
937
            $totalpurgeddirs = 0;
938
            foreach ($empty_dirs as $empty_dir => $dummy) {
939
                if ($empty_dir == $this->config_cache_directory) {
940
                    // shouldn't happen, but just in case, don't let it delete actual cache directory
941
                    continue;
942
                } elseif (@rmdir($empty_dir)) {
943
                    $totalpurgeddirs++;
944
                } else {
945
                    $this->DebugMessage('failed to rmdir(' . $empty_dir . ')', __FILE__, __LINE__);
946
                }
947
            }
948
            $this->DebugMessage('purged ' . $totalpurgeddirs . ' empty directories', __FILE__, __LINE__);
949
        }
950
951
        return true;
952
    }
953
954
    //////////////////////////////////////////////////////////////////////
955
956
    // private: re-initializator (call between rendering multiple images with one object)
957
    /**
958
     * @return bool
959
     */
960
    public function resetObject()
961
    {
962
        $class_vars = get_class_vars(get_class($this));
963
        foreach ($class_vars as $key => $value) {
964
            // do not clobber debug or config info
965
            if (!preg_match('#^(config_|debug|fatalerror)#i', $key)) {
966
                $this->$key = $value;
967
            }
968
        }
969
        $this->phpThumb(); // re-initialize some class variables
970
971
        return true;
972
    }
973
974
    //////////////////////////////////////////////////////////////////////
975
976
    /**
977
     * @return bool
978
     */
979
    public function ResolveSource()
980
    {
981
        if (is_resource($this->gdimg_source)) {
982
            $this->DebugMessage('ResolveSource() exiting because is_resource($this->gdimg_source)', __FILE__, __LINE__);
983
984
            return true;
985
        }
986
        if ($this->rawImageData) {
987
            $this->sourceFilename = null;
988
            $this->DebugMessage('ResolveSource() exiting because $this->rawImageData is set (' . number_format(strlen($this->rawImageData)) . ' bytes)', __FILE__, __LINE__);
989
990
            return true;
991
        }
992
        if ($this->sourceFilename) {
993
            $this->sourceFilename = $this->ResolveFilenameToAbsolute($this->sourceFilename);
994
            $this->DebugMessage('$this->sourceFilename set to "' . $this->sourceFilename . '"', __FILE__, __LINE__);
995
        } elseif ($this->src) {
996
            $this->sourceFilename = $this->ResolveFilenameToAbsolute($this->src);
997
            $this->DebugMessage('$this->sourceFilename set to "' . $this->sourceFilename . '" from $this->src (' . $this->src . ')', __FILE__, __LINE__);
998
        } else {
999
            return $this->ErrorImage('$this->sourceFilename and $this->src are both empty');
1000
        }
1001
        if ($this->iswindows
1002
            && (('//' === substr($this->sourceFilename, 0, 2))
0 ignored issues
show
Bug introduced by
It seems like $this->sourceFilename can also be of type string[]; 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

1002
            && (('//' === substr(/** @scrutinizer ignore-type */ $this->sourceFilename, 0, 2))
Loading history...
1003
                || ('\\\\' === substr($this->sourceFilename, 0, 2)))) {
1004
            // Windows \\share\filename.ext
1005
        } elseif (preg_match('#^[a-z0-9]+://#i', $this->sourceFilename, $protocol_matches)) {
0 ignored issues
show
Bug introduced by
It seems like $this->sourceFilename can also be of type string[]; 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

1005
        } elseif (preg_match('#^[a-z0-9]+://#i', /** @scrutinizer ignore-type */ $this->sourceFilename, $protocol_matches)) {
Loading history...
1006
            if (preg_match('#^(f|ht)tps?\://#i', $this->sourceFilename)) {
1007
                // URL
1008
                if ($this->config_http_user_agent) {
1009
                    ini_set('user_agent', $this->config_http_user_agent);
1010
                }
1011
            } else {
1012
                return $this->ErrorImage('only FTP and HTTP/HTTPS protocols are allowed, "' . $protocol_matches[1] . '" is not');
1013
            }
1014
        } elseif (!@file_exists($this->sourceFilename)) {
0 ignored issues
show
Bug introduced by
It seems like $this->sourceFilename can also be of type string[]; 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

1014
        } elseif (!@file_exists(/** @scrutinizer ignore-type */ $this->sourceFilename)) {
Loading history...
1015
            return $this->ErrorImage('"' . $this->sourceFilename . '" does not exist');
1016
        } elseif (!@is_file($this->sourceFilename)) {
0 ignored issues
show
Bug introduced by
It seems like $this->sourceFilename can also be of type string[]; 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

1016
        } elseif (!@is_file(/** @scrutinizer ignore-type */ $this->sourceFilename)) {
Loading history...
1017
            return $this->ErrorImage('"' . $this->sourceFilename . '" is not a file');
1018
        }
1019
1020
        return true;
1021
    }
1022
1023
    /**
1024
     * @return bool
1025
     */
1026
    public function setOutputFormat()
1027
    {
1028
        static $alreadyCalled = false;
1029
        if ($this->thumbnailFormat && $alreadyCalled) {
1030
            return true;
1031
        }
1032
        $alreadyCalled = true;
1033
1034
        $AvailableImageOutputFormats   = [];
1035
        $AvailableImageOutputFormats[] = 'text';
1036
        if (@is_readable(__DIR__ . '/phpthumb.ico.php')) {
1037
            $AvailableImageOutputFormats[] = 'ico';
1038
        }
1039
        if (@is_readable(__DIR__ . '/phpthumb.bmp.php')) {
1040
            $AvailableImageOutputFormats[] = 'bmp';
1041
        }
1042
1043
        $this->thumbnailFormat = 'ico';
1044
1045
        // Set default output format based on what image types are available
1046
        if (function_exists('imagetypes')) {
1047
            $imagetypes = imagetypes();
1048
            if ($imagetypes & IMG_WBMP) {
1049
                $this->thumbnailFormat         = 'wbmp';
1050
                $AvailableImageOutputFormats[] = 'wbmp';
1051
            }
1052
            if ($imagetypes & IMG_GIF) {
1053
                $this->thumbnailFormat         = 'gif';
1054
                $AvailableImageOutputFormats[] = 'gif';
1055
            }
1056
            if ($imagetypes & IMG_PNG) {
1057
                $this->thumbnailFormat         = 'png';
1058
                $AvailableImageOutputFormats[] = 'png';
1059
            }
1060
            if ($imagetypes & IMG_JPG) {
1061
                $this->thumbnailFormat         = 'jpeg';
1062
                $AvailableImageOutputFormats[] = 'jpeg';
1063
            }
1064
        } else {
1065
            $this->DebugMessage('imagetypes() does not exist - GD support might not be enabled?', __FILE__, __LINE__);
1066
        }
1067
        if ($this->ImageMagickVersion()) {
1068
            $IMformats = ['jpeg', 'png', 'gif', 'bmp', 'ico', 'wbmp'];
1069
            $this->DebugMessage('Addding ImageMagick formats to $AvailableImageOutputFormats (' . implode(';', $AvailableImageOutputFormats) . ')', __FILE__, __LINE__);
1070
            foreach ($IMformats as $key => $format) {
1071
                $AvailableImageOutputFormats[] = $format;
1072
            }
1073
        }
1074
        $AvailableImageOutputFormats = array_unique($AvailableImageOutputFormats);
1075
        $this->DebugMessage('$AvailableImageOutputFormats = array(' . implode(';', $AvailableImageOutputFormats) . ')', __FILE__, __LINE__);
1076
1077
        $this->f = preg_replace('#[^a-z]#', '', strtolower($this->f));
1078
        if ('jpg' === strtolower($this->config_output_format)) {
1079
            $this->config_output_format = 'jpeg';
1080
        }
1081
        if ('jpg' === strtolower($this->f)) {
1082
            $this->f = 'jpeg';
1083
        }
1084
        if (phpthumb_functions::CaseInsensitiveInArray($this->config_output_format, $AvailableImageOutputFormats)) {
1085
            // set output format to config default if that format is available
1086
            $this->DebugMessage('$this->thumbnailFormat set to $this->config_output_format "' . strtolower($this->config_output_format) . '"', __FILE__, __LINE__);
1087
            $this->thumbnailFormat = strtolower($this->config_output_format);
1088
        } elseif ($this->config_output_format) {
1089
            $this->DebugMessage('$this->thumbnailFormat staying as "' . $this->thumbnailFormat . '" because $this->config_output_format (' . strtolower($this->config_output_format) . ') is not in $AvailableImageOutputFormats', __FILE__, __LINE__);
1090
        }
1091
        if ($this->f && phpthumb_functions::CaseInsensitiveInArray($this->f, $AvailableImageOutputFormats)) {
1092
            // override output format if $this->f is set and that format is available
1093
            $this->DebugMessage('$this->thumbnailFormat set to $this->f "' . strtolower($this->f) . '"', __FILE__, __LINE__);
1094
            $this->thumbnailFormat = strtolower($this->f);
1095
        } elseif ($this->f) {
1096
            $this->DebugMessage('$this->thumbnailFormat staying as "' . $this->thumbnailFormat . '" because $this->f (' . strtolower($this->f) . ') is not in $AvailableImageOutputFormats', __FILE__, __LINE__);
1097
        }
1098
1099
        // for JPEG images, quality 1 (worst) to 99 (best)
1100
        // quality < 25 is nasty, with not much size savings - not recommended
1101
        // problems with 100 - invalid JPEG?
1102
        $this->thumbnailQuality = max(1, min(99, ($this->q ? (int)$this->q : 75)));
1103
        $this->DebugMessage('$this->thumbnailQuality set to "' . $this->thumbnailQuality . '"', __FILE__, __LINE__);
1104
1105
        return true;
1106
    }
1107
1108
    /**
1109
     * @return bool
1110
     */
1111
    public function setCacheDirectory()
1112
    {
1113
        // resolve cache directory to absolute pathname
1114
        $this->DebugMessage('setCacheDirectory() starting with config_cache_directory = "' . $this->config_cache_directory . '"', __FILE__, __LINE__);
1115
        if ('.' === substr($this->config_cache_directory, 0, 1)) {
1116
            if (preg_match('#^(f|ht)tps?\://#i', $this->src)) {
1117
                if (!$this->config_cache_disable_warning) {
1118
                    $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');
1119
                }
1120
            } elseif ($this->src) {
1121
                // resolve relative cache directory to source image
1122
                $this->config_cache_directory = dirname($this->ResolveFilenameToAbsolute($this->src)) . DIRECTORY_SEPARATOR . $this->config_cache_directory;
0 ignored issues
show
Bug introduced by
It seems like $this->ResolveFilenameToAbsolute($this->src) can also be of type string[]; 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

1122
                $this->config_cache_directory = dirname(/** @scrutinizer ignore-type */ $this->ResolveFilenameToAbsolute($this->src)) . DIRECTORY_SEPARATOR . $this->config_cache_directory;
Loading history...
1123
            } else {
1124
                // $this->new is probably set
1125
            }
1126
        }
1127
        if ('/' === substr($this->config_cache_directory, -1)) {
1128
            $this->config_cache_directory = substr($this->config_cache_directory, 0, -1);
1129
        }
1130
        if ($this->iswindows) {
1131
            $this->config_cache_directory = str_replace('/', DIRECTORY_SEPARATOR, $this->config_cache_directory);
1132
        }
1133
        if ($this->config_cache_directory) {
1134
            $real_cache_path = $this->realPathSafe($this->config_cache_directory);
1135
            if (!$real_cache_path) {
1136
                $this->DebugMessage('$this->realPathSafe($this->config_cache_directory) failed for "' . $this->config_cache_directory . '"', __FILE__, __LINE__);
1137
                if (!is_dir($this->config_cache_directory)) {
1138
                    $this->DebugMessage('!is_dir(' . $this->config_cache_directory . ')', __FILE__, __LINE__);
1139
                }
1140
            }
1141
            if ($real_cache_path) {
1142
                $this->DebugMessage('setting config_cache_directory to $this->realPathSafe(' . $this->config_cache_directory . ') = "' . $real_cache_path . '"', __FILE__, __LINE__);
0 ignored issues
show
Bug introduced by
Are you sure $real_cache_path of type string|true|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

1142
                $this->DebugMessage('setting config_cache_directory to $this->realPathSafe(' . $this->config_cache_directory . ') = "' . /** @scrutinizer ignore-type */ $real_cache_path . '"', __FILE__, __LINE__);
Loading history...
1143
                $this->config_cache_directory = $real_cache_path;
1144
            }
1145
        }
1146
        if (!is_dir($this->config_cache_directory)) {
1147
            if (!$this->config_cache_disable_warning) {
1148
                $this->ErrorImage('$this->config_cache_directory (' . $this->config_cache_directory . ') does not exist. Adjust "cache_directory" or "cache_disable_warning" in phpThumb.config.php');
1149
            }
1150
            $this->DebugMessage('$this->config_cache_directory (' . $this->config_cache_directory . ') is not a directory', __FILE__, __LINE__);
1151
            $this->config_cache_directory = null;
1152
        } elseif (!@is_writable($this->config_cache_directory)) {
1153
            $this->DebugMessage('$this->config_cache_directory is not writable (' . $this->config_cache_directory . ')', __FILE__, __LINE__);
1154
        }
1155
1156
        $this->InitializeTempDirSetting();
1157
        if (!@is_dir($this->config_temp_directory) && !@is_writable($this->config_temp_directory)
0 ignored issues
show
Bug introduced by
It seems like $this->config_temp_directory can also be of type string[]; however, parameter $filename of is_dir() 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

1157
        if (!@is_dir(/** @scrutinizer ignore-type */ $this->config_temp_directory) && !@is_writable($this->config_temp_directory)
Loading history...
Bug introduced by
It seems like $this->config_temp_directory can also be of type string[]; however, parameter $filename of is_writable() 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

1157
        if (!@is_dir($this->config_temp_directory) && !@is_writable(/** @scrutinizer ignore-type */ $this->config_temp_directory)
Loading history...
1158
            && @is_dir($this->config_cache_directory)
1159
            && @is_writable($this->config_cache_directory)) {
1160
            $this->DebugMessage('setting $this->config_temp_directory = $this->config_cache_directory (' . $this->config_cache_directory . ')', __FILE__, __LINE__);
1161
            $this->config_temp_directory = $this->config_cache_directory;
1162
        }
1163
1164
        return true;
1165
    }
1166
1167
    /* Takes the array of path segments up to now, and the next segment (maybe a modifier: empty, . or ..)
1168
       Applies it, adding or removing from $segments as a result. Returns nothing. */
1169
    // http://support.silisoftware.com/phpBB3/viewtopic.php?t=961
1170
    /**
1171
     * @param $segments
1172
     * @param $segment
1173
     */
1174
    public function applyPathSegment(&$segments, $segment)
1175
    {
1176
        if ('.' === $segment) {
1177
            return; // always remove
1178
        }
1179
        if ('' == $segment) {
1180
            $test = array_pop($segments);
1181
            if (null === $test) {
1182
                $segments[] = $segment; // keep the first empty block
1183
            } elseif ('' == $test) {
1184
                $test = array_pop($segments);
1185
                if (null === $test) {
1186
                    $segments[] = $test;
1187
                    $segments[] = $segment; // keep the second one too
1188
                } else { // put both back and ignore segment
1189
                    $segments[] = $test;
1190
                    $segments[] = $test;
1191
                }
1192
            } else {
1193
                $segments[] = $test; // ignore empty blocks
1194
            }
1195
        } else {
1196
            if ('..' === $segment) {
1197
                $test = array_pop($segments);
1198
                if (null === $test) {
1199
                    $segments[] = $segment;
1200
                } elseif ('..' === $test) {
1201
                    $segments[] = $test;
1202
                    $segments[] = $segment;
1203
                } else {
1204
                    if ('' == $test) {
1205
                        $segments[] = $test;
1206
                    } // else nothing, remove both
1207
                }
1208
            } else {
1209
                $segments[] = $segment;
1210
            }
1211
        }
1212
    }
1213
1214
    /* Takes array of path components, normalizes it: removes empty slots and '.', collapses '..' and folder names.  Returns array. */
1215
    // http://support.silisoftware.com/phpBB3/viewtopic.php?t=961
1216
    /**
1217
     * @param $segments
1218
     * @return array
1219
     */
1220
    public function normalizePath($segments)
1221
    {
1222
        $parts = [];
1223
        foreach ($segments as $segment) {
1224
            $this->applyPathSegment($parts, $segment);
1225
        }
1226
1227
        return $parts;
1228
    }
1229
1230
    /* True if the provided path points (without resolving symbolic links) into one of the allowed directories. */
1231
    // http://support.silisoftware.com/phpBB3/viewtopic.php?t=961
1232
    /**
1233
     * @param $path
1234
     * @param $allowed_dirs
1235
     * @return bool
1236
     */
1237
    public function matchPath($path, $allowed_dirs)
1238
    {
1239
        if (!empty($allowed_dirs)) {
1240
            foreach ($allowed_dirs as $one_dir) {
1241
                if (preg_match('#^' . preg_quote(str_replace(DIRECTORY_SEPARATOR, '/', $this->realPathSafe($one_dir))) . '#', $path)) {
1242
                    return true;
1243
                }
1244
            }
1245
        }
1246
1247
        return false;
1248
    }
1249
1250
    /* True if the provided path points inside one of open_basedirs (or if open_basedirs are disabled) */
1251
    // http://support.silisoftware.com/phpBB3/viewtopic.php?t=961
1252
    /**
1253
     * @param $path
1254
     * @return bool
1255
     */
1256
    public function isInOpenBasedir($path)
1257
    {
1258
        static $open_basedirs = null;
1259
        if (null === $open_basedirs) {
1260
            $ini_text = ini_get('open_basedir');
1261
            $this->DebugMessage('open_basedir: "' . $ini_text . '"', __FILE__, __LINE__);
1262
            $open_basedirs = [];
1263
            if (strlen($ini_text) > 0) {
1264
                foreach (preg_split('#[;:]#', $ini_text) as $key => $value) {
1265
                    $open_basedirs[$key] = $this->realPathSafe($value);
1266
                }
1267
            }
1268
        }
1269
1270
        return (empty($open_basedirs) || $this->matchPath($path, $open_basedirs));
1271
    }
1272
1273
    /* 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. */
1274
    // http://support.silisoftware.com/phpBB3/viewtopic.php?t=961
1275
    /**
1276
     * @param $path
1277
     * @param $allowed_dirs
1278
     * @return null|string
1279
     */
1280
    public function resolvePath($path, $allowed_dirs)
1281
    {
1282
        $this->DebugMessage('resolvePath: ' . $path . ' (allowed_dirs: ' . print_r($allowed_dirs, true) . ')', __FILE__, __LINE__);
1283
1284
        // add base path to the top of the list
1285
        if (!$this->config_allow_src_above_docroot) {
1286
            array_unshift($allowed_dirs, $this->realPathSafe($this->config_document_root));
1287
        } else {
1288
            if (!$this->config_allow_src_above_phpthumb) {
1289
                array_unshift($allowed_dirs, $this->realPathSafe(__DIR__));
1290
            } else {
1291
                // no checks are needed, offload the work to realpath and forget about it
1292
                $this->DebugMessage('resolvePath: checks disabled, returning ' . $this->realPathSafe($path), __FILE__, __LINE__);
1293
1294
                return $this->realPathSafe($path);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->realPathSafe($path) also could return the type boolean|string[] which is incompatible with the documented return type null|string.
Loading history...
1295
            }
1296
        }
1297
        if ('' == $path) {
1298
            return null; // save us trouble
1299
        }
1300
1301
        do {
1302
            $this->DebugMessage('resolvePath: iteration, path=' . $path . ', base path = ' . $allowed_dirs[0], __FILE__, __LINE__);
1303
1304
            $parts = [];
1305
            // do not use "cleaner" foreach version of this loop as later code relies on both $segments and $i
1306
            // http://support.silisoftware.com/phpBB3/viewtopic.php?t=964
1307
            $segments = explode(DIRECTORY_SEPARATOR, $path);
1308
            for ($i = 0; $i < count($segments); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
1309
                $this->applyPathSegment($parts, $segments[$i]);
1310
                $thispart = implode(DIRECTORY_SEPARATOR, $parts);
1311
                if ($this->isInOpenBasedir($thispart)) {
1312
                    if (is_link($thispart)) {
1313
                        break;
1314
                    }
1315
                }
1316
            }
1317
1318
            $this->DebugMessage('resolvePath: stop at component ' . $i, __FILE__, __LINE__);
1319
            // test the part up to here
1320
            $path = implode(DIRECTORY_SEPARATOR, $parts);
1321
            $this->DebugMessage('resolvePath: stop at path=' . $path, __FILE__, __LINE__);
1322
            if (!$this->matchPath($path, $allowed_dirs)) {
1323
                $this->DebugMessage('resolvePath: no match, returning null', __FILE__, __LINE__);
1324
1325
                return null;
1326
            }
1327
            if ($i >= count($segments)) { // reached end
1328
                $this->DebugMessage('resolvePath: path parsed, over', __FILE__, __LINE__);
1329
                break;
1330
            }
1331
            // else it's symlink, rewrite path
1332
            $path = readlink($path);
1333
            $this->DebugMessage('resolvePath: symlink matched, target=' . $path, __FILE__, __LINE__);
1334
1335
            /*
1336
            Replace base path with symlink target.
1337
            Assuming:
1338
              /www/img/external -> /external
1339
            This is allowed:
1340
              GET /www/img/external/../external/test/pic.jpg
1341
            This isn't:
1342
              GET /www/img/external/../www/img/pic.jpg
1343
            So there's only one base path which is the last symlink target, but any number of stable whitelisted paths.
1344
            */
1345
            if ($this->config_auto_allow_symlinks) {
1346
                $allowed_dirs[0] = $path;
1347
            }
1348
            $path = $path . DIRECTORY_SEPARATOR . implode(DIRECTORY_SEPARATOR, array_slice($segments, $i + 1));
1349
        } while (true);
1350
1351
        return $path;
1352
    }
1353
1354
    /**
1355
     * @param $filename
1356
     * @return bool|null|string|string[]
1357
     */
1358
    public function realPathSafe($filename)
1359
    {
1360
        // 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"
1361
        // realPathSafe() provides a reasonable facsimile of realpath() but does not resolve symbolic links, nor does it check that the file/path actually exists
1362
        if (!$this->config_disable_realpath) {
1363
            return realpath($filename);
1364
        }
1365
1366
        // http://stackoverflow.com/questions/21421569
1367
        $newfilename = preg_replace('#[\\/]+#', DIRECTORY_SEPARATOR, $filename);
1368
        if (!preg_match('#^' . DIRECTORY_SEPARATOR . '#', $newfilename)) {
1369
            $newfilename = __DIR__ . DIRECTORY_SEPARATOR . $newfilename;
1370
        }
1371
        do {
1372
            $beforeloop = $newfilename;
1373
1374
            // 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.]]
1375
            $newfilename = preg_replace('#' . DIRECTORY_SEPARATOR . '+#', DIRECTORY_SEPARATOR, $newfilename);
1376
1377
            // Replace all occurrences of /./ with /
1378
            $newfilename = preg_replace('#' . DIRECTORY_SEPARATOR . '\\.' . DIRECTORY_SEPARATOR . '#', DIRECTORY_SEPARATOR, $newfilename);
1379
1380
            // Remove ./ if at the start
1381
            $newfilename = preg_replace('#^\\.' . DIRECTORY_SEPARATOR . '#', '', $newfilename);
1382
1383
            // Remove /. if at the end
1384
            $newfilename = preg_replace('#' . DIRECTORY_SEPARATOR . '\\.$#', '', $newfilename);
1385
1386
            // Replace /anything/../ with /
1387
            $newfilename = preg_replace('#' . DIRECTORY_SEPARATOR . '[^' . DIRECTORY_SEPARATOR . ']+' . DIRECTORY_SEPARATOR . '\\.\\.' . DIRECTORY_SEPARATOR . '#', DIRECTORY_SEPARATOR, $newfilename);
1388
1389
            // Remove /anything/.. if at the end
1390
            $newfilename = preg_replace('#' . DIRECTORY_SEPARATOR . '[^' . DIRECTORY_SEPARATOR . ']+' . DIRECTORY_SEPARATOR . '\\.\\.$#', '', $newfilename);
1391
        } while ($newfilename != $beforeloop);
1392
1393
        return $newfilename;
1394
    }
1395
1396
    /**
1397
     * @param $filename
1398
     * @return bool|null|string|string[]
1399
     */
1400
    public function ResolveFilenameToAbsolute($filename)
1401
    {
1402
        if (empty($filename)) {
1403
            return false;
1404
        }
1405
1406
        if (preg_match('#^[a-z0-9]+\:/{1,2}#i', $filename)) {
1407
            // eg: http://host/path/file.jpg (HTTP URL)
1408
            // eg: ftp://host/path/file.jpg  (FTP URL)
1409
            // eg: data1:/path/file.jpg      (Netware path)
1410
1411
            //$AbsoluteFilename = $filename;
1412
            return $filename;
1413
        } elseif ($this->iswindows && isset($filename{1}) && (':' === $filename{1})) {
1414
1415
            // absolute pathname (Windows)
1416
            $AbsoluteFilename = $filename;
1417
        } elseif ($this->iswindows && (('//' === substr($filename, 0, 2)) || ('\\\\' === substr($filename, 0, 2)))) {
1418
1419
            // absolute pathname (Windows)
1420
            $AbsoluteFilename = $filename;
1421
        } elseif ('/' === $filename{0}) {
1422
            if (@is_readable($filename) && !@is_readable($this->config_document_root . $filename)) {
0 ignored issues
show
Bug introduced by
Are you sure $this->config_document_root of type mixed can be used in concatenation? ( Ignorable by Annotation )

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

1422
            if (@is_readable($filename) && !@is_readable(/** @scrutinizer ignore-type */ $this->config_document_root . $filename)) {
Loading history...
1423
1424
                // absolute filename (*nix)
1425
                $AbsoluteFilename = $filename;
1426
            } elseif (isset($filename{1}) && ('~' === $filename{1})) {
1427
1428
                // /~user/path
1429
                if ($ApacheLookupURIarray = phpthumb_functions::ApacheLookupURIarray($filename)) {
1430
                    $AbsoluteFilename = $ApacheLookupURIarray['filename'];
1431
                } else {
1432
                    $AbsoluteFilename = $this->realPathSafe($filename);
1433
                    if (@is_readable($AbsoluteFilename)) {
0 ignored issues
show
Bug introduced by
It seems like $AbsoluteFilename can also be of type string[]; 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

1433
                    if (@is_readable(/** @scrutinizer ignore-type */ $AbsoluteFilename)) {
Loading history...
1434
                        $this->DebugMessage('phpthumb_functions::ApacheLookupURIarray() failed for "' . $filename . '", but the correct filename (' . $AbsoluteFilename . ') seems to have been resolved with $this->realPathSafe($filename)', __FILE__, __LINE__);
1435
                    } elseif (is_dir(dirname($AbsoluteFilename))) {
0 ignored issues
show
Bug introduced by
It seems like $AbsoluteFilename can also be of type string[]; 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

1435
                    } elseif (is_dir(dirname(/** @scrutinizer ignore-type */ $AbsoluteFilename))) {
Loading history...
1436
                        $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__);
1437
                    } else {
1438
                        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")');
1439
                    }
1440
                }
1441
            } else {
1442
1443
                // relative filename (any OS)
1444
                if (preg_match('#^' . preg_quote($this->config_document_root) . '#', $filename)) {
0 ignored issues
show
Bug introduced by
It seems like $this->config_document_root can also be of type mixed; however, parameter $str of preg_quote() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

1444
                if (preg_match('#^' . preg_quote(/** @scrutinizer ignore-type */ $this->config_document_root) . '#', $filename)) {
Loading history...
1445
                    $AbsoluteFilename = $filename;
1446
                    $this->DebugMessage('ResolveFilenameToAbsolute() NOT prepending $this->config_document_root (' . $this->config_document_root . ') to $filename (' . $filename . ') resulting in ($AbsoluteFilename = "' . $AbsoluteFilename . '")', __FILE__, __LINE__);
1447
                } else {
1448
                    $AbsoluteFilename = $this->config_document_root . $filename;
1449
                    $this->DebugMessage('ResolveFilenameToAbsolute() prepending $this->config_document_root (' . $this->config_document_root . ') to $filename (' . $filename . ') resulting in ($AbsoluteFilename = "' . $AbsoluteFilename . '")', __FILE__, __LINE__);
1450
                }
1451
            }
1452
        } else {
1453
1454
            // relative to current directory (any OS)
1455
            $AbsoluteFilename = __DIR__ . DIRECTORY_SEPARATOR . preg_replace('#[/\\\\]#', DIRECTORY_SEPARATOR, $filename);
1456
1457
            if ('/~' === substr(dirname(@$_SERVER['PHP_SELF']), 0, 2)) {
1458
                if ($ApacheLookupURIarray = phpthumb_functions::ApacheLookupURIarray(dirname(@$_SERVER['PHP_SELF']))) {
1459
                    $AbsoluteFilename = $ApacheLookupURIarray['filename'] . DIRECTORY_SEPARATOR . $filename;
1460
                } else {
1461
                    $AbsoluteFilename = $this->realPathSafe('.') . DIRECTORY_SEPARATOR . $filename;
1462
                    if (@is_readable($AbsoluteFilename)) {
1463
                        $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__);
1464
                    } elseif (is_dir(dirname($AbsoluteFilename))) {
1465
                        $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__);
1466
                    } else {
1467
                        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');
1468
                    }
1469
                }
1470
            }
1471
        }
1472
        /*
1473
        // removed 2014-May-30: http://support.silisoftware.com/phpBB3/viewtopic.php?t=961
1474
        if (is_link($AbsoluteFilename)) {
1475
            $this->DebugMessage('is_link()==true, changing "'.$AbsoluteFilename.'" to "'.readlink($AbsoluteFilename).'"', __FILE__, __LINE__);
1476
            $AbsoluteFilename = readlink($AbsoluteFilename);
1477
        }
1478
        if ($this->realPathSafe($AbsoluteFilename)) {
1479
            $AbsoluteFilename = $this->realPathSafe($AbsoluteFilename);
1480
        }
1481
        */
1482
        if ($this->iswindows) {
1483
            $AbsoluteFilename = preg_replace('#^' . preg_quote($this->realPathSafe($this->config_document_root)) . '#i', str_replace('\\', '\\\\', $this->realPathSafe($this->config_document_root)), $AbsoluteFilename);
0 ignored issues
show
Bug introduced by
It seems like $this->realPathSafe($this->config_document_root) can also be of type string[]; 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

1483
            $AbsoluteFilename = preg_replace('#^' . preg_quote(/** @scrutinizer ignore-type */ $this->realPathSafe($this->config_document_root)) . '#i', str_replace('\\', '\\\\', $this->realPathSafe($this->config_document_root)), $AbsoluteFilename);
Loading history...
1484
            $AbsoluteFilename = str_replace(DIRECTORY_SEPARATOR, '/', $AbsoluteFilename);
1485
        }
1486
        $AbsoluteFilename = $this->resolvePath($AbsoluteFilename, $this->config_additional_allowed_dirs);
1487
        if (!$this->config_allow_src_above_docroot
1488
            && !preg_match('#^' . preg_quote(str_replace(DIRECTORY_SEPARATOR, '/', $this->realPathSafe($this->config_document_root))) . '#', $AbsoluteFilename)) {
1489
            $this->DebugMessage('!$this->config_allow_src_above_docroot therefore setting "' . $AbsoluteFilename . '" (outside "' . $this->realPathSafe($this->config_document_root) . '") to null', __FILE__, __LINE__);
1490
1491
            return false;
1492
        }
1493
        if (!$this->config_allow_src_above_phpthumb
1494
            && !preg_match('#^' . preg_quote(str_replace(DIRECTORY_SEPARATOR, '/', __DIR__)) . '#', $AbsoluteFilename)) {
1495
            $this->DebugMessage('!$this->config_allow_src_above_phpthumb therefore setting "' . $AbsoluteFilename . '" (outside "' . __DIR__ . '") to null', __FILE__, __LINE__);
1496
1497
            return false;
1498
        }
1499
1500
        return $AbsoluteFilename;
1501
    }
1502
1503
    /**
1504
     * @param      $filename
1505
     * @param bool $cached
1506
     * @return mixed
1507
     */
1508
    public function file_exists_ignoreopenbasedir($filename, $cached = true)
1509
    {
1510
        static $open_basedirs = null;
1511
        static $file_exists_cache = [];
1512
        if (!$cached || !isset($file_exists_cache[$filename])) {
1513
            if (null === $open_basedirs) {
1514
                $open_basedirs = preg_split('#[;:]#', ini_get('open_basedir'));
1515
            }
1516
            if (empty($open_basedirs) || in_array(dirname($filename), $open_basedirs)) {
1517
                $file_exists_cache[$filename] = file_exists($filename);
1518
            } elseif ($this->iswindows) {
1519
                $ls_filename                  = trim(phpthumb_functions::SafeExec('dir /b ' . phpthumb_functions::escapeshellarg_replacement($filename)));
1520
                $file_exists_cache[$filename] = ($ls_filename == basename($filename));  // command dir /b return only filename without path
1521
            } else {
1522
                $ls_filename                  = trim(phpthumb_functions::SafeExec('ls ' . phpthumb_functions::escapeshellarg_replacement($filename)));
1523
                $file_exists_cache[$filename] = ($ls_filename == $filename);
1524
            }
1525
        }
1526
1527
        return $file_exists_cache[$filename];
1528
    }
1529
1530
    /**
1531
     * @return bool|null|string
1532
     */
1533
    public function ImageMagickWhichConvert()
1534
    {
1535
        static $WhichConvert = null;
1536
        if (null === $WhichConvert) {
1537
            if ($this->iswindows) {
1538
                $WhichConvert = false;
1539
            } else {
1540
                $IMwhichConvertCacheFilename = $this->config_cache_directory . DIRECTORY_SEPARATOR . 'phpThumbCacheIMwhichConvert.txt';
1541
                if (false !== ($cachedwhichconvertstring = @file_get_contents($IMwhichConvertCacheFilename))) {
1542
                    $WhichConvert = $cachedwhichconvertstring;
1543
                } else {
1544
                    $WhichConvert = trim(phpthumb_functions::SafeExec('which convert'));
1545
                    @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

1545
                    /** @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...
1546
                }
1547
            }
1548
        }
1549
1550
        return $WhichConvert;
1551
    }
1552
1553
    /**
1554
     * @return bool|null|string
1555
     */
1556
    public function ImageMagickCommandlineBase()
1557
    {
1558
        static $commandline = null;
1559
        if (null === $commandline) {
1560
            if ($this->issafemode) {
1561
                $commandline = '';
1562
1563
                return $commandline;
1564
            }
1565
1566
            $IMcommandlineBaseCacheFilename = $this->config_cache_directory . DIRECTORY_SEPARATOR . 'phpThumbCacheIMcommandlineBase.txt';
1567
            if (false !== ($commandline = @file_get_contents($IMcommandlineBaseCacheFilename))) {
1568
                return $commandline;
1569
            }
1570
1571
            $commandline = (null !== $this->config_imagemagick_path ? $this->config_imagemagick_path : '');
0 ignored issues
show
Unused Code introduced by
The assignment to $commandline is dead and can be removed.
Loading history...
1572
1573
            if ($this->config_imagemagick_path
1574
                && ($this->config_imagemagick_path != $this->realPathSafe($this->config_imagemagick_path))) {
1575
                if (@is_executable($this->realPathSafe($this->config_imagemagick_path))) {
0 ignored issues
show
Bug introduced by
It seems like $this->realPathSafe($thi...onfig_imagemagick_path) can also be of type string[]; however, parameter $filename of is_executable() 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

1575
                if (@is_executable(/** @scrutinizer ignore-type */ $this->realPathSafe($this->config_imagemagick_path))) {
Loading history...
1576
                    $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__);
1577
                    $this->config_imagemagick_path = $this->realPathSafe($this->config_imagemagick_path);
1578
                } else {
1579
                    $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__);
1580
                }
1581
            }
1582
            $this->DebugMessage('                  file_exists(' . $this->config_imagemagick_path . ') = ' . (int)(@file_exists($this->config_imagemagick_path)), __FILE__, __LINE__);
1583
            $this->DebugMessage('file_exists_ignoreopenbasedir(' . $this->config_imagemagick_path . ') = ' . (int)$this->file_exists_ignoreopenbasedir($this->config_imagemagick_path), __FILE__, __LINE__);
1584
            $this->DebugMessage('                      is_file(' . $this->config_imagemagick_path . ') = ' . (int)(@is_file($this->config_imagemagick_path)), __FILE__, __LINE__);
1585
            $this->DebugMessage('                is_executable(' . $this->config_imagemagick_path . ') = ' . (int)(@is_executable($this->config_imagemagick_path)), __FILE__, __LINE__);
1586
1587
            if ($this->file_exists_ignoreopenbasedir($this->config_imagemagick_path)) {
1588
                $this->DebugMessage('using ImageMagick path from $this->config_imagemagick_path (' . $this->config_imagemagick_path . ')', __FILE__, __LINE__);
1589
                if ($this->iswindows) {
1590
                    $commandline = substr($this->config_imagemagick_path, 0, 2)
1591
                                   . ' && cd '
1592
                                   . phpthumb_functions::escapeshellarg_replacement(str_replace('/', DIRECTORY_SEPARATOR, substr(dirname($this->config_imagemagick_path), 2)))
1593
                                   . ' && '
1594
                                   . phpthumb_functions::escapeshellarg_replacement(basename($this->config_imagemagick_path));
1595
                } else {
1596
                    $commandline = phpthumb_functions::escapeshellarg_replacement($this->config_imagemagick_path);
1597
                }
1598
            } else {
1599
                $which_convert = $this->ImageMagickWhichConvert();
1600
                $IMversion     = $this->ImageMagickVersion();
1601
1602
                if ($which_convert && ('/' === $which_convert{0})
1603
                    && $this->file_exists_ignoreopenbasedir($which_convert)) {
1604
1605
                    // `which convert` *should* return the path if "convert" exist, or nothing if it doesn't
1606
                    // other things *may* get returned, like "sh: convert: not found" or "no convert in /usr/local/bin /usr/sbin /usr/bin /usr/ccs/bin"
1607
                    // so only do this if the value returned exists as a file
1608
                    $this->DebugMessage('using ImageMagick path from `which convert` (' . $which_convert . ')', __FILE__, __LINE__);
0 ignored issues
show
Bug introduced by
Are you sure $which_convert 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

1608
                    $this->DebugMessage('using ImageMagick path from `which convert` (' . /** @scrutinizer ignore-type */ $which_convert . ')', __FILE__, __LINE__);
Loading history...
1609
                    $commandline = 'convert';
1610
                } elseif ($IMversion) {
1611
                    $this->DebugMessage('setting ImageMagick path to $this->config_imagemagick_path (' . $this->config_imagemagick_path . ') [' . $IMversion . ']', __FILE__, __LINE__);
1612
                    $commandline = $this->config_imagemagick_path;
1613
                } else {
1614
                    $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__);
1615
                    $commandline = '';
1616
                }
1617
            }
1618
1619
            @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

1619
            /** @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...
1620
        }
1621
1622
        return $commandline;
1623
    }
1624
1625
    /**
1626
     * @param bool $returnRAW
1627
     * @return mixed
1628
     */
1629
    public function ImageMagickVersion($returnRAW = false)
1630
    {
1631
        static $versionstring = null;
1632
        if (null === $versionstring) {
1633
            $versionstring = [0 => false, 1 => false];
1634
1635
            $IMversionCacheFilename = $this->config_cache_directory . DIRECTORY_SEPARATOR . 'phpThumbCacheIMversion.txt';
1636
            if ($cachedversionstring = @file_get_contents($IMversionCacheFilename)) {
1637
                $versionstring    = explode("\n", $cachedversionstring, 2);
1638
                $versionstring[0] = ($versionstring[0] ?: false); // "false" is stored as an empty string in the cache file
1639
                $versionstring[1] = ($versionstring[1] ?: false); // "false" is stored as an empty string in the cache file
1640
            } else {
1641
                $commandline = $this->ImageMagickCommandlineBase();
1642
                $commandline = (null !== $commandline ? $commandline : '');
1643
                if ($commandline) {
1644
                    $commandline .= ' --version';
1645
                    $this->DebugMessage('ImageMagick version checked with "' . $commandline . '"', __FILE__, __LINE__);
1646
                    $versionstring[1] = trim(phpthumb_functions::SafeExec($commandline));
1647
                    if (preg_match('#^Version: [^0-9]*([ 0-9\\.\\:Q/\\-]+)#i', $versionstring[1], $matches)) {
1648
                        $versionstring[0] = trim($matches[1]);
1649
                    } else {
1650
                        $versionstring[0] = false;
1651
                        $this->DebugMessage('ImageMagick did not return recognized version string (' . $versionstring[1] . ')', __FILE__, __LINE__);
1652
                    }
1653
                    $this->DebugMessage('ImageMagick convert --version says "' . @$matches[0] . '"', __FILE__, __LINE__);
1654
                }
1655
1656
                @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

1656
                /** @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...
1657
            }
1658
        }
1659
1660
        return $versionstring[(int)$returnRAW];
1661
    }
1662
1663
    /**
1664
     * @param $switchname
1665
     * @return bool
1666
     */
1667
    public function ImageMagickSwitchAvailable($switchname)
1668
    {
1669
        static $IMoptions = null;
1670
        if (null === $IMoptions) {
1671
            $IMoptions   = [];
1672
            $commandline = $this->ImageMagickCommandlineBase();
1673
            if (null !== $commandline) {
1674
                $commandline  .= ' -help';
1675
                $IMhelp_lines = explode("\n", phpthumb_functions::SafeExec($commandline));
1676
                foreach ($IMhelp_lines as $line) {
1677
                    if (preg_match('#^[\\+\\-]([a-z\\-]+) #', trim($line), $matches)) {
1678
                        $IMoptions[$matches[1]] = true;
1679
                    }
1680
                }
1681
            }
1682
        }
1683
        if (is_array($switchname)) {
1684
            $allOK = true;
1685
            foreach ($switchname as $key => $value) {
1686
                if (!isset($IMoptions[$value])) {
1687
                    $allOK = false;
1688
                    break;
1689
                }
1690
            }
1691
            $this->DebugMessage('ImageMagickSwitchAvailable(' . implode(';', $switchname) . ') = ' . (int)$allOK . '', __FILE__, __LINE__);
1692
        } else {
1693
            $allOK = isset($IMoptions[$switchname]);
1694
            $this->DebugMessage('ImageMagickSwitchAvailable(' . $switchname . ') = ' . (int)$allOK . '', __FILE__, __LINE__);
1695
        }
1696
1697
        return $allOK;
1698
    }
1699
1700
    /**
1701
     * @return bool|null|string
1702
     */
1703
    public function ImageMagickFormatsList()
1704
    {
1705
        static $IMformatsList = null;
1706
        if (null === $IMformatsList) {
1707
            $IMformatsList = '';
1708
            $commandline   = $this->ImageMagickCommandlineBase();
1709
            if (null !== $commandline) {
1710
                $commandline   = dirname($commandline) . DIRECTORY_SEPARATOR . str_replace('convert', 'identify', basename($commandline));
1711
                $commandline   .= ' -list format';
1712
                $IMformatsList = phpthumb_functions::SafeExec($commandline);
1713
            }
1714
        }
1715
1716
        return $IMformatsList;
1717
    }
1718
1719
    /**
1720
     * @return bool
1721
     */
1722
    public function SourceDataToTempFile()
1723
    {
1724
        if ($IMtempSourceFilename = $this->phpThumb_tempnam()) {
1725
            $IMtempSourceFilename = $this->realPathSafe($IMtempSourceFilename);
1726
            ob_start();
1727
            $fp_tempfile         = fopen($IMtempSourceFilename, 'wb');
1728
            $tempfile_open_error = ob_get_contents();
1729
            ob_end_clean();
1730
            if ($fp_tempfile) {
0 ignored issues
show
introduced by
$fp_tempfile is of type resource|false, thus it always evaluated to false.
Loading history...
1731
                fwrite($fp_tempfile, $this->rawImageData);
1732
                fclose($fp_tempfile);
1733
                $this->sourceFilename = $IMtempSourceFilename;
1734
                $this->DebugMessage('ImageMagickThumbnailToGD() setting $this->sourceFilename to "' . $IMtempSourceFilename . '" from $this->rawImageData (' . strlen($this->rawImageData) . ' bytes)', __FILE__, __LINE__);
1735
            } else {
1736
                $this->DebugMessage('ImageMagickThumbnailToGD() FAILED setting $this->sourceFilename to "' . $IMtempSourceFilename . '" (failed to open for writing: "' . $tempfile_open_error . '")', __FILE__, __LINE__);
1737
            }
1738
            unset($tempfile_open_error, $IMtempSourceFilename);
1739
1740
            return true;
1741
        }
1742
        $this->DebugMessage('SourceDataToTempFile() FAILED because $this->phpThumb_tempnam() failed', __FILE__, __LINE__);
1743
1744
        return false;
1745
    }
1746
1747
    /**
1748
     * @return bool
1749
     */
1750
    public function ImageMagickThumbnailToGD()
1751
    {
1752
        // http://www.imagemagick.org/script/command-line-options.php
1753
1754
        $this->useRawIMoutput = true;
1755
        if (phpthumb_functions::gd_version()) {
1756
            // if GD is not available, must use whatever ImageMagick can output
1757
1758
            // $UnAllowedParameters contains options that can only be processed in GD, not ImageMagick
1759
            // note: 'fltr' *may* need to be processed by GD, but we'll check that in more detail below
1760
            $UnAllowedParameters = ['xto', 'ar', 'bg', 'bc'];
1761
            // 'ra' may be part of this list, if not a multiple of 90 degrees
1762
            foreach ($UnAllowedParameters as $parameter) {
1763
                if (isset($this->$parameter)) {
1764
                    $this->DebugMessage('$this->useRawIMoutput=false because "' . $parameter . '" is set', __FILE__, __LINE__);
1765
                    $this->useRawIMoutput = false;
1766
                    break;
1767
                }
1768
            }
1769
        }
1770
        $this->DebugMessage('$this->useRawIMoutput=' . ($this->useRawIMoutput ? 'true' : 'false') . ' after checking $UnAllowedParameters', __FILE__, __LINE__);
1771
        $ImageCreateFunction = '';
1772
        $outputFormat        = $this->thumbnailFormat;
1773
        if (phpthumb_functions::gd_version()) {
1774
            if ($this->useRawIMoutput) {
1775
                switch ($this->thumbnailFormat) {
1776
                    case 'gif':
1777
                        $ImageCreateFunction = 'imagecreatefromgif';
1778
                        $this->is_alpha      = true;
1779
                        break;
1780
                    case 'png':
1781
                        $ImageCreateFunction = 'imagecreatefrompng';
1782
                        $this->is_alpha      = true;
1783
                        break;
1784
                    case 'jpg':
1785
                    case 'jpeg':
1786
                        $ImageCreateFunction = 'imagecreatefromjpeg';
1787
                        break;
1788
                    default:
1789
                        $this->DebugMessage('Forcing output to PNG because $this->thumbnailFormat (' . $this->thumbnailFormat . ' is not a GD-supported format)', __FILE__, __LINE__);
1790
                        $outputFormat         = 'png';
1791
                        $ImageCreateFunction  = 'imagecreatefrompng';
1792
                        $this->is_alpha       = true;
1793
                        $this->useRawIMoutput = false;
1794
                        break;
1795
                }
1796
                if (!function_exists(@$ImageCreateFunction)) {
1797
                    // ImageMagickThumbnailToGD() depends on imagecreatefrompng/imagecreatefromgif
1798
                    //$this->DebugMessage('ImageMagickThumbnailToGD() aborting because '.@$ImageCreateFunction.'() is not available', __FILE__, __LINE__);
1799
                    $this->useRawIMoutput = true;
1800
                    //return false;
1801
                }
1802
            } else {
1803
                $outputFormat         = 'png';
1804
                $ImageCreateFunction  = 'imagecreatefrompng';
1805
                $this->is_alpha       = true;
1806
                $this->useRawIMoutput = false;
1807
            }
1808
        }
1809
1810
        // http://freealter.org/doc_distrib/ImageMagick-5.1.1/www/convert.html
1811
        if (!$this->sourceFilename && $this->rawImageData) {
1812
            $this->SourceDataToTempFile();
1813
        }
1814
        if (!$this->sourceFilename) {
1815
            $this->DebugMessage('ImageMagickThumbnailToGD() aborting because $this->sourceFilename is empty', __FILE__, __LINE__);
1816
            $this->useRawIMoutput = false;
1817
1818
            return false;
1819
        }
1820
        if ($this->issafemode) {
1821
            $this->DebugMessage('ImageMagickThumbnailToGD() aborting because safe_mode is enabled', __FILE__, __LINE__);
1822
            $this->useRawIMoutput = false;
1823
1824
            return false;
1825
        }
1826
        // TO BE FIXED
1827
        //if (true) {
1828
        //	$this->DebugMessage('ImageMagickThumbnailToGD() aborting it is broken right now', __FILE__, __LINE__);
1829
        //	$this->useRawIMoutput = false;
1830
        //	return false;
1831
        //}
1832
1833
        $commandline = $this->ImageMagickCommandlineBase();
1834
        if ($commandline) {
1835
            if ($IMtempfilename = $this->phpThumb_tempnam()) {
1836
                $IMtempfilename = $this->realPathSafe($IMtempfilename);
1837
1838
                $IMuseExplicitImageOutputDimensions = false;
1839
                if ($this->ImageMagickSwitchAvailable('thumbnail') && $this->config_imagemagick_use_thumbnail) {
1840
                    $IMresizeParameter = 'thumbnail';
1841
                } else {
1842
                    $IMresizeParameter = 'resize';
1843
1844
                    // some (older? around 2002) versions of IM won't accept "-resize 100x" but require "-resize 100x100"
1845
                    $commandline_test                   = $this->ImageMagickCommandlineBase() . ' logo: -resize 1x ' . phpthumb_functions::escapeshellarg_replacement($IMtempfilename) . ' 2>&1';
0 ignored issues
show
Bug introduced by
Are you sure $this->ImageMagickCommandlineBase() 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

1845
                    $commandline_test                   = /** @scrutinizer ignore-type */ $this->ImageMagickCommandlineBase() . ' logo: -resize 1x ' . phpthumb_functions::escapeshellarg_replacement($IMtempfilename) . ' 2>&1';
Loading history...
1846
                    $IMresult_test                      = phpthumb_functions::SafeExec($commandline_test);
1847
                    $IMuseExplicitImageOutputDimensions = preg_match('#image dimensions are zero#i', $IMresult_test);
1848
                    $this->DebugMessage('IMuseExplicitImageOutputDimensions = ' . (int)$IMuseExplicitImageOutputDimensions, __FILE__, __LINE__);
1849
                    if ($fp_im_temp = @fopen($IMtempfilename, 'wb')) {
1850
                        // erase temp image so ImageMagick logo doesn't get output if other processing fails
1851
                        fclose($fp_im_temp);
1852
                    }
1853
                }
1854
1855
                if (null !== $this->dpi && $this->ImageMagickSwitchAvailable('density')) {
1856
                    // for vector source formats only (WMF, PDF, etc)
1857
                    $commandline .= ' -flatten -density ' . phpthumb_functions::escapeshellarg_replacement($this->dpi);
1858
                }
1859
                ob_start();
1860
                $getimagesize      = getimagesize($this->sourceFilename);
1861
                $GetImageSizeError = ob_get_contents();
1862
                ob_end_clean();
1863
                if (is_array($getimagesize)) {
1864
                    $this->DebugMessage('getimagesize(' . $this->sourceFilename . ') SUCCEEDED: ' . print_r($getimagesize, true), __FILE__, __LINE__);
1865
                } else {
1866
                    $this->DebugMessage('getimagesize(' . $this->sourceFilename . ') FAILED with error "' . $GetImageSizeError . '"', __FILE__, __LINE__);
1867
                }
1868
                if (is_array($getimagesize)) {
1869
                    $this->DebugMessage('getimagesize(' . $this->sourceFilename . ') returned [w=' . $getimagesize[0] . ';h=' . $getimagesize[1] . ';f=' . $getimagesize[2] . ']', __FILE__, __LINE__);
1870
                    $this->source_width  = $getimagesize[0];
1871
                    $this->source_height = $getimagesize[1];
1872
                    $this->DebugMessage('source dimensions set to ' . $this->source_width . 'x' . $this->source_height, __FILE__, __LINE__);
1873
                    $this->SetOrientationDependantWidthHeight();
1874
1875
                    if (!preg_match('#(' . implode('|', $this->AlphaCapableFormats) . ')#i', $outputFormat)) {
1876
                        // not a transparency-capable format
1877
                        $commandline .= ' -background ' . phpthumb_functions::escapeshellarg_replacement('#' . ($this->bg ?: 'FFFFFF'));
1878
                        if (IMAGETYPE_GIF == $getimagesize[2]) {
1879
                            $commandline .= ' -flatten';
1880
                        }
1881
                    }
1882
                    if (IMAGETYPE_GIF == $getimagesize[2]) {
1883
                        $commandline .= ' -coalesce'; // may be needed for animated GIFs
1884
                    }
1885
                    if ($this->source_width || $this->source_height) {
1886
                        if ($this->zc) {
1887
                            $borderThickness = 0;
1888
                            if (!empty($this->fltr)) {
1889
                                foreach ($this->fltr as $key => $value) {
1890
                                    if (preg_match('#^bord\|([0-9]+)#', $value, $matches)) {
1891
                                        $borderThickness = $matches[1];
1892
                                        break;
1893
                                    }
1894
                                }
1895
                            }
1896
                            $wAll  = (int)max($this->w, $this->wp, $this->wl, $this->ws) - (2 * $borderThickness);
1897
                            $hAll  = (int)max($this->h, $this->hp, $this->hl, $this->hs) - (2 * $borderThickness);
1898
                            $imAR  = $this->source_width / $this->source_height;
1899
                            $zcAR  = (($wAll && $hAll) ? $wAll / $hAll : 1);
1900
                            $side  = phpthumb_functions::nonempty_min($this->source_width, $this->source_height, max($wAll, $hAll));
1901
                            $sideX = phpthumb_functions::nonempty_min($this->source_width, $wAll, round($hAll * $zcAR));
0 ignored issues
show
Unused Code introduced by
The assignment to $sideX is dead and can be removed.
Loading history...
1902
                            $sideY = phpthumb_functions::nonempty_min($this->source_height, $hAll, round($wAll / $zcAR));
1903
1904
                            $thumbnailH  = round(max($sideY, ($sideY * $zcAR) / $imAR));
1905
                            $commandline .= ' -' . $IMresizeParameter . ' ' . phpthumb_functions::escapeshellarg_replacement(($IMuseExplicitImageOutputDimensions ? $thumbnailH : '') . 'x' . $thumbnailH);
1906
1907
                            switch (strtoupper($this->zc)) {
1908
                                case 'T':
1909
                                    $commandline .= ' -gravity north';
1910
                                    break;
1911
                                case 'B':
1912
                                    $commandline .= ' -gravity south';
1913
                                    break;
1914
                                case 'L':
1915
                                    $commandline .= ' -gravity west';
1916
                                    break;
1917
                                case 'R':
1918
                                    $commandline .= ' -gravity east';
1919
                                    break;
1920
                                case 'TL':
1921
                                    $commandline .= ' -gravity northwest';
1922
                                    break;
1923
                                case 'TR':
1924
                                    $commandline .= ' -gravity northeast';
1925
                                    break;
1926
                                case 'BL':
1927
                                    $commandline .= ' -gravity southwest';
1928
                                    break;
1929
                                case 'BR':
1930
                                    $commandline .= ' -gravity southeast';
1931
                                    break;
1932
                                case '1':
1933
                                case 'C':
1934
                                default:
1935
                                    $commandline .= ' -gravity center';
1936
                                    break;
1937
                            }
1938
1939
                            if (($wAll > 0) && ($hAll > 0)) {
1940
                                $commandline .= ' -crop ' . phpthumb_functions::escapeshellarg_replacement($wAll . 'x' . $hAll . '+0+0');
1941
                            } else {
1942
                                $commandline .= ' -crop ' . phpthumb_functions::escapeshellarg_replacement($side . 'x' . $side . '+0+0');
1943
                            }
1944
                            if ($this->ImageMagickSwitchAvailable('repage')) {
1945
                                $commandline .= ' +repage';
1946
                            } else {
1947
                                $this->DebugMessage('Skipping "+repage" because ImageMagick (v' . $this->ImageMagickVersion() . ') does not support it', __FILE__, __LINE__);
1948
                            }
1949
                        } elseif ($this->sw || $this->sh || $this->sx || $this->sy) {
1950
                            $crop_param = '';
1951
                            $crop_param .= ($this->sw ? (($this->sw < 2) ? round($this->sw * $this->source_width) : $this->sw) : $this->source_width);
1952
                            $crop_param .= 'x' . ($this->sh ? (($this->sh < 2) ? round($this->sh * $this->source_height) : $this->sh) : $this->source_height);
1953
                            $crop_param .= '+' . (($this->sx < 2) ? round($this->sx * $this->source_width) : $this->sx);
1954
                            $crop_param .= '+' . (($this->sy < 2) ? round($this->sy * $this->source_height) : $this->sy);
1955
                            // TO BE FIXED
1956
                            // makes 1x1 output
1957
                            // 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
1958
                            // '/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'
1959
                            $commandline .= ' -crop ' . phpthumb_functions::escapeshellarg_replacement($crop_param);
1960
1961
                            // this is broken for aoe=1, but unsure how to fix. Send advice to [email protected]
1962
                            if ($this->w || $this->h) {
1963
                                //if ($this->ImageMagickSwitchAvailable('repage')) {
1964
                                if (false) {
1965
                                    // TO BE FIXED
1966
                                    // newer versions of ImageMagick require -repage <geometry>
1967
                                    $commandline .= ' -repage';
1968
                                } else {
1969
                                    $this->DebugMessage('Skipping "-repage" because ImageMagick (v' . $this->ImageMagickVersion() . ') does not support it', __FILE__, __LINE__);
1970
                                }
1971
                                if ($IMuseExplicitImageOutputDimensions) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $IMuseExplicitImageOutputDimensions of type integer|false is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

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

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

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

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
1972
                                    if ($this->w && !$this->h) {
1973
                                        $this->h = ceil($this->w / ($this->source_width / $this->source_height));
1974
                                    } elseif ($this->h && !$this->w) {
1975
                                        $this->w = ceil($this->h * ($this->source_width / $this->source_height));
1976
                                    }
1977
                                }
1978
                                $commandline .= ' -' . $IMresizeParameter . ' ' . phpthumb_functions::escapeshellarg_replacement($this->w . 'x' . $this->h);
1979
                            }
1980
                        } else {
1981
                            if ($this->iar && ((int)$this->w > 0) && ((int)$this->h > 0)) {
1982
                                list($nw, $nh) = phpthumb_functions::TranslateWHbyAngle($this->w, $this->h, $this->ra);
1983
                                $nw          = ((0 != round($nw)) ? round($nw) : '');
1984
                                $nh          = ((0 != round($nh)) ? round($nh) : '');
1985
                                $commandline .= ' -' . $IMresizeParameter . ' ' . phpthumb_functions::escapeshellarg_replacement($nw . 'x' . $nh . '!');
1986
                            } else {
1987
                                $this->w = ((($this->aoe || $this->far)
1988
                                             && $this->w) ? $this->w : ($this->w ? phpthumb_functions::nonempty_min($this->w, $getimagesize[0]) : ''));
1989
                                $this->h = ((($this->aoe || $this->far)
1990
                                             && $this->h) ? $this->h : ($this->h ? phpthumb_functions::nonempty_min($this->h, $getimagesize[1]) : ''));
1991
                                if ($this->w || $this->h) {
1992
                                    if ($IMuseExplicitImageOutputDimensions) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $IMuseExplicitImageOutputDimensions of type integer|false is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

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

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

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

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
1993
                                        if ($this->w && !$this->h) {
1994
                                            $this->h = ceil($this->w / ($this->source_width / $this->source_height));
1995
                                        } elseif ($this->h && !$this->w) {
1996
                                            $this->w = ceil($this->h * ($this->source_width / $this->source_height));
1997
                                        }
1998
                                    }
1999
                                    list($nw, $nh) = phpthumb_functions::TranslateWHbyAngle($this->w, $this->h, $this->ra);
2000
                                    $nw          = ((0 != round($nw)) ? round($nw) : '');
2001
                                    $nh          = ((0 != round($nh)) ? round($nh) : '');
2002
                                    $commandline .= ' -' . $IMresizeParameter . ' ' . phpthumb_functions::escapeshellarg_replacement($nw . 'x' . $nh);
2003
                                }
2004
                            }
2005
                        }
2006
                    }
2007
                } else {
2008
                    $this->DebugMessage('getimagesize(' . $this->sourceFilename . ') failed', __FILE__, __LINE__);
2009
                    if ($this->w || $this->h) {
2010
                        $exactDimensionsBang = (($this->iar && ((int)$this->w > 0)
2011
                                                 && ((int)$this->h > 0)) ? '!' : '');
2012
                        if ($IMuseExplicitImageOutputDimensions) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $IMuseExplicitImageOutputDimensions of type integer|false is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

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

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

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

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
2013
                            // unknown source aspect ratio, just put large number and hope IM figures it out
2014
                            $commandline .= ' -' . $IMresizeParameter . ' ' . phpthumb_functions::escapeshellarg_replacement(($this->w ?: '9999') . 'x' . ($this->h ?: '9999') . $exactDimensionsBang);
2015
                        } else {
2016
                            $commandline .= ' -' . $IMresizeParameter . ' ' . phpthumb_functions::escapeshellarg_replacement($this->w . 'x' . $this->h . $exactDimensionsBang);
2017
                        }
2018
                    }
2019
                }
2020
2021
                if ($this->ra) {
2022
                    $this->ra = (int)$this->ra;
2023
                    if ($this->ImageMagickSwitchAvailable('rotate')) {
2024
                        if (!preg_match('#(' . implode('|', $this->AlphaCapableFormats) . ')#i', $outputFormat)
2025
                            || phpthumb_functions::version_compare_replacement($this->ImageMagickVersion(), '6.3.7', '>=')) {
2026
                            $this->DebugMessage('Using ImageMagick rotate', __FILE__, __LINE__);
2027
                            $commandline .= ' -rotate ' . phpthumb_functions::escapeshellarg_replacement($this->ra);
2028
                            if (0 != ($this->ra % 90)) {
2029
                                if (preg_match('#(' . implode('|', $this->AlphaCapableFormats) . ')#i', $outputFormat)) {
2030
                                    // alpha-capable format
2031
                                    $commandline .= ' -background rgba(255,255,255,0)';
2032
                                } else {
2033
                                    $commandline .= ' -background ' . phpthumb_functions::escapeshellarg_replacement('#' . ($this->bg ?: 'FFFFFF'));
2034
                                }
2035
                            }
2036
                            $this->ra = 0;
2037
                        } else {
2038
                            $this->DebugMessage('Not using ImageMagick rotate because alpha background buggy before v6.3.7', __FILE__, __LINE__);
2039
                        }
2040
                    } else {
2041
                        $this->DebugMessage('Not using ImageMagick rotate because not supported', __FILE__, __LINE__);
2042
                    }
2043
                }
2044
2045
                $successfullyProcessedFilters = [];
2046
                foreach ($this->fltr as $filterkey => $filtercommand) {
2047
                    @list($command, $parameter) = explode('|', $filtercommand, 2);
2048
                    switch ($command) {
2049
                        case 'brit':
2050
                            if ($this->ImageMagickSwitchAvailable('modulate')) {
2051
                                $commandline                    .= ' -modulate ' . phpthumb_functions::escapeshellarg_replacement((100 + (int)$parameter) . ',100,100');
2052
                                $successfullyProcessedFilters[] = $filterkey;
2053
                            }
2054
                            break;
2055
2056
                        case 'cont':
2057
                            if ($this->ImageMagickSwitchAvailable('contrast')) {
2058
                                $contDiv10 = round((int)$parameter / 10);
2059
                                if ($contDiv10 > 0) {
2060
                                    $contDiv10 = min($contDiv10, 100);
2061
                                    for ($i = 0; $i < $contDiv10; $i++) {
2062
                                        $commandline .= ' -contrast'; // increase contrast by 10%
2063
                                    }
2064
                                } elseif ($contDiv10 < 0) {
2065
                                    $contDiv10 = max($contDiv10, -100);
2066
                                    for ($i = $contDiv10; $i < 0; $i++) {
2067
                                        $commandline .= ' +contrast'; // decrease contrast by 10%
2068
                                    }
2069
                                } else {
2070
                                    // do nothing
2071
                                }
2072
                                $successfullyProcessedFilters[] = $filterkey;
2073
                            }
2074
                            break;
2075
2076
                        case 'ds':
2077
                            if ($this->ImageMagickSwitchAvailable(['colorspace', 'modulate'])) {
2078
                                if (100 == $parameter) {
2079
                                    $commandline .= ' -colorspace GRAY';
2080
                                    $commandline .= ' -modulate 100,0,100';
2081
                                } else {
2082
                                    $commandline .= ' -modulate ' . phpthumb_functions::escapeshellarg_replacement('100,' . (100 - (int)$parameter) . ',100');
2083
                                }
2084
                                $successfullyProcessedFilters[] = $filterkey;
2085
                            }
2086
                            break;
2087
2088
                        case 'sat':
2089
                            if ($this->ImageMagickSwitchAvailable(['colorspace', 'modulate'])) {
2090
                                if (-100 == $parameter) {
2091
                                    $commandline .= ' -colorspace GRAY';
2092
                                    $commandline .= ' -modulate 100,0,100';
2093
                                } else {
2094
                                    $commandline .= ' -modulate ' . phpthumb_functions::escapeshellarg_replacement('100,' . (100 + (int)$parameter) . ',100');
2095
                                }
2096
                                $successfullyProcessedFilters[] = $filterkey;
2097
                            }
2098
                            break;
2099
2100
                        case 'gray':
2101
                            if ($this->ImageMagickSwitchAvailable(['colorspace', 'modulate'])) {
2102
                                $commandline                    .= ' -colorspace GRAY';
2103
                                $commandline                    .= ' -modulate 100,0,100';
2104
                                $successfullyProcessedFilters[] = $filterkey;
2105
                            }
2106
                            break;
2107
2108
                        case 'clr':
2109
                            if ($this->ImageMagickSwitchAvailable(['fill', 'colorize'])) {
2110
                                @list($amount, $color) = explode('|', $parameter);
2111
                                $commandline .= ' -fill ' . phpthumb_functions::escapeshellarg_replacement('#' . preg_replace('#[^0-9A-F]#i', '', $color));
2112
                                $commandline .= ' -colorize ' . phpthumb_functions::escapeshellarg_replacement(min(max((int)$amount, 0), 100));
2113
                            }
2114
                            break;
2115
2116
                        case 'sep':
2117
                            if ($this->ImageMagickSwitchAvailable('sepia-tone')) {
2118
                                @list($amount, $color) = explode('|', $parameter);
2119
                                $amount = ($amount ?: 80);
2120
                                if (!$color) {
2121
                                    $commandline                    .= ' -sepia-tone ' . phpthumb_functions::escapeshellarg_replacement(min(max($amount, 0), 100) . '%');
2122
                                    $successfullyProcessedFilters[] = $filterkey;
2123
                                }
2124
                            }
2125
                            break;
2126
2127
                        case 'gam':
2128
                            @list($amount) = explode('|', $parameter);
2129
                            $amount = min(max((float)$amount, 0.001), 10);
2130
                            if ('1.000' !== number_format($amount, 3)) {
2131
                                if ($this->ImageMagickSwitchAvailable('gamma')) {
2132
                                    $commandline                    .= ' -gamma ' . phpthumb_functions::escapeshellarg_replacement($amount);
2133
                                    $successfullyProcessedFilters[] = $filterkey;
2134
                                }
2135
                            }
2136
                            break;
2137
2138
                        case 'neg':
2139
                            if ($this->ImageMagickSwitchAvailable('negate')) {
2140
                                $commandline                    .= ' -negate';
2141
                                $successfullyProcessedFilters[] = $filterkey;
2142
                            }
2143
                            break;
2144
2145
                        case 'th':
2146
                            @list($amount) = explode('|', $parameter);
2147
                            if ($this->ImageMagickSwitchAvailable(['threshold', 'dither', 'monochrome'])) {
2148
                                $commandline                    .= ' -threshold ' . phpthumb_functions::escapeshellarg_replacement(round(min(max((int)$amount, 0), 255) / 2.55) . '%');
2149
                                $commandline                    .= ' -dither';
2150
                                $commandline                    .= ' -monochrome';
2151
                                $successfullyProcessedFilters[] = $filterkey;
2152
                            }
2153
                            break;
2154
2155
                        case 'rcd':
2156
                            if ($this->ImageMagickSwitchAvailable(['colors', 'dither'])) {
2157
                                @list($colors, $dither) = explode('|', $parameter);
2158
                                $colors                         = ($colors ? (int)$colors : 256);
2159
                                $dither                         = ((strlen($dither) > 0) ? (bool)$dither : true);
2160
                                $commandline                    .= ' -colors ' . phpthumb_functions::escapeshellarg_replacement(max($colors, 8)); // ImageMagick will otherwise fail with "cannot quantize to fewer than 8 colors"
2161
                                $commandline                    .= ($dither ? ' -dither' : ' +dither');
2162
                                $successfullyProcessedFilters[] = $filterkey;
2163
                            }
2164
                            break;
2165
2166
                        case 'flip':
2167
                            if ($this->ImageMagickSwitchAvailable(['flip', 'flop'])) {
2168
                                if (false !== strpos(strtolower($parameter), 'x')) {
2169
                                    $commandline .= ' -flop';
2170
                                }
2171
                                if (false !== strpos(strtolower($parameter), 'y')) {
2172
                                    $commandline .= ' -flip';
2173
                                }
2174
                                $successfullyProcessedFilters[] = $filterkey;
2175
                            }
2176
                            break;
2177
2178
                        case 'edge':
2179
                            if ($this->ImageMagickSwitchAvailable('edge')) {
2180
                                $parameter                      = (!empty($parameter) ? $parameter : 2);
2181
                                $commandline                    .= ' -edge ' . phpthumb_functions::escapeshellarg_replacement(!empty($parameter) ? $parameter : 1);
2182
                                $successfullyProcessedFilters[] = $filterkey;
2183
                            }
2184
                            break;
2185
2186
                        case 'emb':
2187
                            if ($this->ImageMagickSwitchAvailable(['emboss', 'negate'])) {
2188
                                $parameter   = (!empty($parameter) ? $parameter : 2);
2189
                                $commandline .= ' -emboss ' . phpthumb_functions::escapeshellarg_replacement($parameter);
2190
                                if ($parameter < 2) {
2191
                                    $commandline .= ' -negate'; // ImageMagick negates the image for some reason with '-emboss 1';
2192
                                }
2193
                                $successfullyProcessedFilters[] = $filterkey;
2194
                            }
2195
                            break;
2196
2197
                        case 'lvl':
2198
                            @list($band, $method, $threshold) = explode('|', $parameter);
2199
                            $band      = ($band ? preg_replace('#[^RGBA\\*]#', '', strtoupper($band)) : '*');
2200
                            $method    = ((strlen($method) > 0) ? (int)$method : 2);
2201
                            $threshold = ((strlen($threshold) > 0) ? min(max((float)$threshold, 0), 100) : 0.1);
2202
2203
                            $band = preg_replace('#[^RGBA\\*]#', '', strtoupper($band));
2204
2205
                            if (($method > 1)
2206
                                && !$this->ImageMagickSwitchAvailable([
2207
                                                                          'channel',
2208
                                                                          'contrast-stretch'
2209
                                                                      ])) {
2210
                                // Because ImageMagick processing happens before PHP-GD filters, and because some
2211
                                // clipping is involved in the "lvl" filter, if "lvl" happens before "wb" then the
2212
                                // "wb" filter will have (almost) no effect. Therefore, if "wb" is enabled then
2213
                                // force the "lvl" filter to be processed by GD, not ImageMagick.
2214
                                foreach ($this->fltr as $fltr_key => $fltr_value) {
2215
                                    list($fltr_cmd) = explode('|', $fltr_value);
2216
                                    if ('wb' === $fltr_cmd) {
2217
                                        $this->DebugMessage('Setting "lvl" filter method to "0" (from "' . $method . '") because white-balance filter also enabled', __FILE__, __LINE__);
2218
                                        $method = 0;
2219
                                    }
2220
                                }
2221
                            }
2222
2223
                            switch ($method) {
2224
                                case 0: // internal RGB
2225
                                case 1: // internal grayscale
2226
                                    break;
2227
                                case 2: // ImageMagick "contrast-stretch"
2228
                                    if ($this->ImageMagickSwitchAvailable('contrast-stretch')) {
2229
                                        if ('*' !== $band) {
2230
                                            $commandline .= ' -channel ' . phpthumb_functions::escapeshellarg_replacement(strtoupper($band));
2231
                                        }
2232
                                        $threshold = preg_replace('#[^0-9\\.]#', '', $threshold); // should be unneccesary, but just to be double-sure
2233
                                        //$commandline .= ' -contrast-stretch '.phpthumb_functions::escapeshellarg_replacement($threshold.'%');
2234
                                        $commandline .= ' -contrast-stretch \'' . $threshold . '%\'';
2235
                                        if ('*' !== $band) {
2236
                                            $commandline .= ' +channel';
2237
                                        }
2238
                                        $successfullyProcessedFilters[] = $filterkey;
2239
                                    }
2240
                                    break;
2241
                                case 3: // ImageMagick "normalize"
2242
                                    if ($this->ImageMagickSwitchAvailable('normalize')) {
2243
                                        if ('*' !== $band) {
2244
                                            $commandline .= ' -channel ' . phpthumb_functions::escapeshellarg_replacement(strtoupper($band));
2245
                                        }
2246
                                        $commandline .= ' -normalize';
2247
                                        if ('*' !== $band) {
2248
                                            $commandline .= ' +channel';
2249
                                        }
2250
                                        $successfullyProcessedFilters[] = $filterkey;
2251
                                    }
2252
                                    break;
2253
                                default:
2254
                                    $this->DebugMessage('unsupported method (' . $method . ') for "lvl" filter', __FILE__, __LINE__);
2255
                                    break;
2256
                            }
2257
                            if (isset($this->fltr[$filterkey]) && ($method > 1)) {
2258
                                $this->fltr[$filterkey] = $command . '|' . $band . '|0|' . $threshold;
2259
                                $this->DebugMessage('filter "lvl" remapped from method "' . $method . '" to method "0" because ImageMagick support is missing', __FILE__, __LINE__);
2260
                            }
2261
                            break;
2262
2263
                        case 'wb':
2264
                            if ($this->ImageMagickSwitchAvailable(['channel', 'contrast-stretch'])) {
2265
                                @list($threshold) = explode('|', $parameter);
2266
                                $threshold = (!empty($threshold) ? min(max((float)$threshold, 0), 100) : 0.1);
2267
                                $threshold = preg_replace('#[^0-9\\.]#', '', $threshold); // should be unneccesary, but just to be double-sure
2268
                                //$commandline .= ' -channel R -contrast-stretch '.phpthumb_functions::escapeshellarg_replacement($threshold.'%'); // doesn't work on Windows because most versions of PHP do not properly
2269
                                //$commandline .= ' -channel G -contrast-stretch '.phpthumb_functions::escapeshellarg_replacement($threshold.'%'); // escape special characters (such as %) and just replace them with spaces
2270
                                //$commandline .= ' -channel B -contrast-stretch '.phpthumb_functions::escapeshellarg_replacement($threshold.'%'); // https://bugs.php.net/bug.php?id=43261
2271
                                $commandline                    .= ' -channel R -contrast-stretch \'' . $threshold . '%\'';
2272
                                $commandline                    .= ' -channel G -contrast-stretch \'' . $threshold . '%\'';
2273
                                $commandline                    .= ' -channel B -contrast-stretch \'' . $threshold . '%\'';
2274
                                $commandline                    .= ' +channel';
2275
                                $successfullyProcessedFilters[] = $filterkey;
2276
                            }
2277
                            break;
2278
2279
                        case 'blur':
2280
                            if ($this->ImageMagickSwitchAvailable('blur')) {
2281
                                @list($radius) = explode('|', $parameter);
2282
                                $radius                         = (!empty($radius) ? min(max((int)$radius, 0), 25) : 1);
2283
                                $commandline                    .= ' -blur ' . phpthumb_functions::escapeshellarg_replacement($radius);
2284
                                $successfullyProcessedFilters[] = $filterkey;
2285
                            }
2286
                            break;
2287
2288
                        case 'gblr':
2289
                            @list($radius) = explode('|', $parameter);
2290
                            $radius = (!empty($radius) ? min(max((int)$radius, 0), 25) : 1);
2291
                            // "-gaussian" changed to "-gaussian-blur" sometime around 2009
2292
                            if ($this->ImageMagickSwitchAvailable('gaussian-blur')) {
2293
                                $commandline                    .= ' -gaussian-blur ' . phpthumb_functions::escapeshellarg_replacement($radius);
2294
                                $successfullyProcessedFilters[] = $filterkey;
2295
                            } elseif ($this->ImageMagickSwitchAvailable('gaussian')) {
2296
                                $commandline                    .= ' -gaussian ' . phpthumb_functions::escapeshellarg_replacement($radius);
2297
                                $successfullyProcessedFilters[] = $filterkey;
2298
                            }
2299
                            break;
2300
2301
                        case 'usm':
2302
                            if ($this->ImageMagickSwitchAvailable('unsharp')) {
2303
                                @list($amount, $radius, $threshold) = explode('|', $parameter);
2304
                                $amount                         = ($amount ? min(max((int)$radius, 0), 255) : 80);
2305
                                $radius                         = ($radius ? min(max((int)$radius, 0), 10) : 0.5);
2306
                                $threshold                      = (strlen($threshold) ? min(max((int)$radius, 0), 50) : 3);
2307
                                $commandline                    .= ' -unsharp ' . phpthumb_functions::escapeshellarg_replacement(number_format(($radius * 2) - 1, 2, '.', '') . 'x1+' . number_format($amount / 100, 2, '.', '') . '+' . number_format($threshold / 100, 2, '.', ''));
2308
                                $successfullyProcessedFilters[] = $filterkey;
2309
                            }
2310
                            break;
2311
2312
                        case 'bord':
2313
                            if ($this->ImageMagickSwitchAvailable([
2314
                                                                      'border',
2315
                                                                      'bordercolor',
2316
                                                                      'thumbnail',
2317
                                                                      'crop'
2318
                                                                  ])) {
2319
                                if (!$this->zc) {
2320
                                    @list($width, $rX, $rY, $color) = explode('|', $parameter);
2321
                                    $width = (int)$width;
2322
                                    $rX    = (int)$rX;
2323
                                    $rY    = (int)$rY;
2324
                                    if ($width && !$rX && !$rY) {
2325
                                        if (!phpthumb_functions::IsHexColor($color)) {
2326
                                            $color = ((!empty($this->bc)
2327
                                                       && phpthumb_functions::IsHexColor($this->bc)) ? $this->bc : '000000');
2328
                                        }
2329
                                        $commandline .= ' -border ' . phpthumb_functions::escapeshellarg_replacement($width);
2330
                                        $commandline .= ' -bordercolor ' . phpthumb_functions::escapeshellarg_replacement('#' . $color);
2331
2332
                                        if (preg_match('# \\-crop "([0-9]+)x([0-9]+)\\+0\\+0" #', $commandline, $matches)) {
2333
                                            $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);
2334
                                        } elseif (preg_match('# \\-' . $IMresizeParameter . ' "([0-9]+)x([0-9]+)" #', $commandline, $matches)) {
2335
                                            $commandline = str_replace(
2336
                                                ' -' . $IMresizeParameter . ' "' . $matches[1] . 'x' . $matches[2] . '" ',
2337
                                                ' -' . $IMresizeParameter . ' ' . phpthumb_functions::escapeshellarg_replacement(($matches[1] - (2 * $width)) . 'x' . ($matches[2] - (2 * $width))) . ' ',
2338
                                                                       $commandline
2339
                                            );
2340
                                        }
2341
                                        $successfullyProcessedFilters[] = $filterkey;
2342
                                    }
2343
                                }
2344
                            }
2345
                            break;
2346
2347
                        case 'crop':
2348
                            break;
2349
2350
                        case 'sblr':
2351
                            break;
2352
2353
                        case 'mean':
2354
                            break;
2355
2356
                        case 'smth':
2357
                            break;
2358
2359
                        case 'bvl':
2360
                            break;
2361
2362
                        case 'wmi':
2363
                            break;
2364
2365
                        case 'wmt':
2366
                            break;
2367
2368
                        case 'over':
2369
                            break;
2370
2371
                        case 'hist':
2372
                            break;
2373
2374
                        case 'fram':
2375
                            break;
2376
2377
                        case 'drop':
2378
                            break;
2379
2380
                        case 'mask':
2381
                            break;
2382
2383
                        case 'elip':
2384
                            break;
2385
2386
                        case 'ric':
2387
                            break;
2388
2389
                        case 'stc':
2390
                            break;
2391
2392
                        case 'size':
2393
                            break;
2394
2395
                        default:
2396
                            $this->DebugMessage('Unknown $this->fltr[' . $filterkey . '] (' . $filtercommand . ') -- deleting filter command', __FILE__, __LINE__);
2397
                            $successfullyProcessedFilters[] = $filterkey;
2398
                            break;
2399
                    }
2400
                    if (!isset($this->fltr[$filterkey])) {
2401
                        $this->DebugMessage('Processed $this->fltr[' . $filterkey . '] (' . $filtercommand . ') with ImageMagick', __FILE__, __LINE__);
2402
                    } else {
2403
                        $this->DebugMessage('Skipping $this->fltr[' . $filterkey . '] (' . $filtercommand . ') with ImageMagick', __FILE__, __LINE__);
2404
                    }
2405
                }
2406
                $this->DebugMessage('Remaining $this->fltr after ImageMagick: (' . $this->phpThumbDebugVarDump($this->fltr) . ')', __FILE__, __LINE__);
2407
                if (count($this->fltr) > 0) {
2408
                    $this->useRawIMoutput = false;
2409
                }
2410
2411
                if (preg_match('#jpe?g#i', $outputFormat) && $this->q) {
2412
                    if ($this->ImageMagickSwitchAvailable(['quality', 'interlace'])) {
2413
                        $commandline .= ' -quality ' . phpthumb_functions::escapeshellarg_replacement($this->thumbnailQuality);
2414
                        if ($this->config_output_interlace) {
2415
                            // causes weird things with animated GIF... leave for JPEG only
2416
                            $commandline .= ' -interlace line '; // Use Line or Plane to create an interlaced PNG or GIF or progressive JPEG image
2417
                        }
2418
                    }
2419
                }
2420
                $commandline .= ' ' . phpthumb_functions::escapeshellarg_replacement(preg_replace('#[/\\\\]#', DIRECTORY_SEPARATOR, $this->sourceFilename) . (('gif' === $outputFormat) ? '' : '[' . (int)$this->sfn . ']')); // [0] means first frame of (GIF) animation, can be ignored
2421
                $commandline .= ' ' . $outputFormat . ':' . phpthumb_functions::escapeshellarg_replacement($IMtempfilename);
2422
                if (!$this->iswindows) {
2423
                    $commandline .= ' 2>&1';
2424
                }
2425
                $this->DebugMessage('ImageMagick called as (' . $commandline . ')', __FILE__, __LINE__);
2426
                $IMresult = phpthumb_functions::SafeExec($commandline);
2427
                clearstatcache();
2428
                if (!@file_exists($IMtempfilename) || !@filesize($IMtempfilename)) {
2429
                    $this->FatalError('ImageMagick failed with message (' . trim($IMresult) . ')');
2430
                    $this->DebugMessage('ImageMagick failed with message (' . trim($IMresult) . ')', __FILE__, __LINE__);
2431
                    if ($this->iswindows && !$IMresult) {
2432
                        $this->DebugMessage('Check to make sure that PHP has read+write permissions to "' . dirname($IMtempfilename) . '"', __FILE__, __LINE__);
2433
                    }
2434
                } else {
2435
                    foreach ($successfullyProcessedFilters as $dummy => $filterkey) {
2436
                        unset($this->fltr[$filterkey]);
2437
                    }
2438
                    $this->IMresizedData    = file_get_contents($IMtempfilename);
2439
                    $getimagesize_imresized = @getimagesize($IMtempfilename);
2440
                    $this->DebugMessage('getimagesize(' . $IMtempfilename . ') returned [w=' . $getimagesize_imresized[0] . ';h=' . $getimagesize_imresized[1] . ';f=' . $getimagesize_imresized[2] . ']', __FILE__, __LINE__);
2441
                    if (($this->config_max_source_pixels > 0)
2442
                        && (($getimagesize_imresized[0] * $getimagesize_imresized[1]) > $this->config_max_source_pixels)) {
2443
                        $this->DebugMessage('skipping ImageMagickThumbnailToGD::'
2444
                                            . $ImageCreateFunction
2445
                                            . '() because IM output is too large ('
2446
                                            . $getimagesize_imresized[0]
2447
                                            . 'x'
2448
                                            . $getimagesize_imresized[0]
2449
                                            . ' = '
2450
                                            . ($getimagesize_imresized[0] * $getimagesize_imresized[1])
2451
                                            . ' > '
2452
                                            . $this->config_max_source_pixels
2453
                                            . ')', __FILE__, __LINE__);
2454
                    } elseif (function_exists(@$ImageCreateFunction)
2455
                              && ($this->gdimg_source = @$ImageCreateFunction($IMtempfilename))) {
2456
                        $this->source_width  = imagesx($this->gdimg_source);
2457
                        $this->source_height = imagesy($this->gdimg_source);
2458
                        $this->DebugMessage('ImageMagickThumbnailToGD::' . $ImageCreateFunction . '() succeeded, $this->gdimg_source is now (' . $this->source_width . 'x' . $this->source_height . ')', __FILE__, __LINE__);
2459
                        $this->DebugMessage('ImageMagickThumbnailToGD() returning $this->IMresizedData (' . strlen($this->IMresizedData) . ' bytes)', __FILE__, __LINE__);
2460
                    } else {
2461
                        $this->useRawIMoutput = true;
2462
                        $this->DebugMessage('$this->useRawIMoutput set to TRUE because ' . @$ImageCreateFunction . '(' . $IMtempfilename . ') failed', __FILE__, __LINE__);
2463
                    }
2464
                    if (file_exists($IMtempfilename)) {
2465
                        $this->DebugMessage('deleting "' . $IMtempfilename . '"', __FILE__, __LINE__);
2466
                        @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

2466
                        /** @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...
2467
                    }
2468
2469
                    return true;
2470
                }
2471
                if (file_exists($IMtempfilename)) {
2472
                    $this->DebugMessage('deleting "' . $IMtempfilename . '"', __FILE__, __LINE__);
2473
                    @unlink($IMtempfilename);
2474
                }
2475
            } elseif ($this->issafemode) {
2476
                $this->DebugMessage('ImageMagickThumbnailToGD() aborting because PHP safe_mode is enabled and phpThumb_tempnam() failed', __FILE__, __LINE__);
2477
                $this->useRawIMoutput = false;
2478
            } else {
2479
                if (file_exists($IMtempfilename)) {
2480
                    $this->DebugMessage('deleting "' . $IMtempfilename . '"', __FILE__, __LINE__);
2481
                    @unlink($IMtempfilename);
2482
                }
2483
                $this->DebugMessage('ImageMagickThumbnailToGD() aborting, phpThumb_tempnam() failed', __FILE__, __LINE__);
2484
            }
2485
        } else {
2486
            $this->DebugMessage('ImageMagickThumbnailToGD() aborting because ImageMagickCommandlineBase() failed', __FILE__, __LINE__);
2487
        }
2488
        $this->useRawIMoutput = false;
2489
2490
        return false;
2491
    }
2492
2493
    /**
2494
     * @return bool
2495
     */
2496
    public function Rotate()
2497
    {
2498
        if ($this->ra || $this->ar) {
2499
            if (!function_exists('imagerotate')) {
2500
                $this->DebugMessage('!function_exists(imagerotate)', __FILE__, __LINE__);
2501
2502
                return false;
2503
            }
2504
            if (!require_once __DIR__ . '/phpthumb.filters.php') {
2505
                $this->DebugMessage('Error including "' . __DIR__ . '/phpthumb.filters.php" which is required for applying filters (' . implode(';', $this->fltr) . ')', __FILE__, __LINE__);
2506
2507
                return false;
2508
            }
2509
2510
            $this->config_background_hexcolor = ($this->bg ?: $this->config_background_hexcolor);
2511
            if (!phpthumb_functions::IsHexColor($this->config_background_hexcolor)) {
2512
                return $this->ErrorImage('Invalid hex color string "' . $this->config_background_hexcolor . '" for parameter "bg"');
2513
            }
2514
2515
            $rotate_angle = 0;
2516
            if ($this->ra) {
2517
                $rotate_angle = (float)$this->ra;
2518
            } else {
2519
                if ('x' === $this->ar) {
2520
                    if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '4.2.0', '>=')) {
2521
                        if ($this->sourceFilename) {
2522
                            if (function_exists('exif_read_data')) {
2523
                                if ($exif_data = @exif_read_data($this->sourceFilename, 'IFD0')) {
2524
                                    // http://sylvana.net/jpegcrop/exif_orientation.html
2525
                                    switch (@$exif_data['Orientation']) {
2526
                                        case 1:
2527
                                            $rotate_angle = 0;
2528
                                            break;
2529
                                        case 3:
2530
                                            $rotate_angle = 180;
2531
                                            break;
2532
                                        case 6:
2533
                                            $rotate_angle = 270;
2534
                                            break;
2535
                                        case 8:
2536
                                            $rotate_angle = 90;
2537
                                            break;
2538
2539
                                        default:
2540
                                            $this->DebugMessage('EXIF auto-rotate failed because unknown $exif_data[Orientation] "' . @$exif_data['Orientation'] . '"', __FILE__, __LINE__);
2541
2542
                                            return false;
2543
                                            break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

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

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

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

Loading history...
2544
                                    }
2545
                                    $this->DebugMessage('EXIF auto-rotate set to ' . $rotate_angle . ' degrees ($exif_data[Orientation] = "' . @$exif_data['Orientation'] . '")', __FILE__, __LINE__);
2546
                                } else {
2547
                                    $this->DebugMessage('failed: exif_read_data(' . $this->sourceFilename . ')', __FILE__, __LINE__);
2548
2549
                                    return false;
2550
                                }
2551
                            } else {
2552
                                $this->DebugMessage('!function_exists(exif_read_data)', __FILE__, __LINE__);
2553
2554
                                return false;
2555
                            }
2556
                        } else {
2557
                            $this->DebugMessage('Cannot auto-rotate from EXIF data because $this->sourceFilename is empty', __FILE__, __LINE__);
2558
2559
                            return false;
2560
                        }
2561
                    } else {
2562
                        $this->DebugMessage('Cannot auto-rotate from EXIF data because PHP is less than v4.2.0 (' . PHP_VERSION . ')', __FILE__, __LINE__);
2563
2564
                        return false;
2565
                    }
2566
                } elseif (('l' === $this->ar) && ($this->source_height > $this->source_width)) {
2567
                    $rotate_angle = 270;
2568
                } elseif (('L' === $this->ar) && ($this->source_height > $this->source_width)) {
2569
                    $rotate_angle = 90;
2570
                } elseif (('p' === $this->ar) && ($this->source_width > $this->source_height)) {
2571
                    $rotate_angle = 90;
2572
                } elseif (('P' === $this->ar) && ($this->source_width > $this->source_height)) {
2573
                    $rotate_angle = 270;
2574
                }
2575
            }
2576
            if ($rotate_angle % 90) {
2577
                $this->is_alpha = true;
2578
            }
2579
            phpthumb_filters::ImprovedImageRotate($this->gdimg_source, $rotate_angle, $this->config_background_hexcolor, $this->bg, $this);
0 ignored issues
show
Bug introduced by
It seems like $rotate_angle can also be of type double; however, parameter $rotate_angle of phpthumb_filters::ImprovedImageRotate() 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

2579
            phpthumb_filters::ImprovedImageRotate($this->gdimg_source, /** @scrutinizer ignore-type */ $rotate_angle, $this->config_background_hexcolor, $this->bg, $this);
Loading history...
2580
            $this->source_width  = imagesx($this->gdimg_source);
2581
            $this->source_height = imagesy($this->gdimg_source);
2582
        }
2583
2584
        return true;
2585
    }
2586
2587
    /**
2588
     * @return bool
2589
     */
2590
    public function FixedAspectRatio()
2591
    {
2592
        // optional fixed-dimension images (regardless of aspect ratio)
2593
2594
        if (!$this->far) {
2595
            // do nothing
2596
            return true;
2597
        }
2598
2599
        if (!$this->w || !$this->h) {
2600
            return false;
2601
        }
2602
        $this->thumbnail_width  = $this->w;
2603
        $this->thumbnail_height = $this->h;
2604
        $this->is_alpha         = true;
2605
        if ($this->thumbnail_image_width >= $this->thumbnail_width) {
2606
            $aspectratio = $this->thumbnail_image_height / $this->thumbnail_image_width;
2607
            if ($this->w) {
2608
                $this->thumbnail_image_height = round($this->thumbnail_image_width * $aspectratio);
2609
                $this->thumbnail_height       = ($this->h ?: $this->thumbnail_image_height);
2610
            } elseif ($this->thumbnail_image_height < $this->thumbnail_height) {
2611
                $this->thumbnail_image_height = $this->thumbnail_height;
2612
                $this->thumbnail_image_width  = round($this->thumbnail_image_height / $aspectratio);
2613
            }
2614
        } else {
2615
            $aspectratio = $this->thumbnail_image_width / $this->thumbnail_image_height;
2616
            if ($this->h) {
2617
                $this->thumbnail_image_width = round($this->thumbnail_image_height * $aspectratio);
2618
            } elseif ($this->thumbnail_image_width < $this->thumbnail_width) {
2619
                $this->thumbnail_image_width  = $this->thumbnail_width;
2620
                $this->thumbnail_image_height = round($this->thumbnail_image_width / $aspectratio);
2621
            }
2622
        }
2623
2624
        return true;
2625
    }
2626
2627
    /**
2628
     * @param $hostname
2629
     * @param $allowed_domains
2630
     * @return mixed
2631
     */
2632
    public function OffsiteDomainIsAllowed($hostname, $allowed_domains)
2633
    {
2634
        static $domain_is_allowed = [];
2635
        $hostname = strtolower($hostname);
2636
        if (!isset($domain_is_allowed[$hostname])) {
2637
            $domain_is_allowed[$hostname] = false;
2638
            foreach ($allowed_domains as $valid_domain) {
2639
                $starpos = strpos($valid_domain, '*');
2640
                if (false !== $starpos) {
2641
                    $valid_domain = substr($valid_domain, $starpos + 1);
2642
                    if (preg_match('#' . preg_quote($valid_domain) . '$#', $hostname)) {
2643
                        $domain_is_allowed[$hostname] = true;
2644
                        break;
2645
                    }
2646
                } else {
2647
                    if (strtolower($valid_domain) === $hostname) {
2648
                        $domain_is_allowed[$hostname] = true;
2649
                        break;
2650
                    }
2651
                }
2652
            }
2653
        }
2654
2655
        return $domain_is_allowed[$hostname];
2656
    }
2657
2658
    /**
2659
     * @return bool
2660
     */
2661
    public function AntiOffsiteLinking()
2662
    {
2663
        // Optional anti-offsite hijacking of the thumbnail script
2664
        $allow = true;
2665
        if ($allow && $this->config_nooffsitelink_enabled
2666
            && (@$_SERVER['HTTP_REFERER']
2667
                || $this->config_nooffsitelink_require_refer)) {
2668
            $this->DebugMessage('AntiOffsiteLinking() checking $_SERVER[HTTP_REFERER] "' . @$_SERVER['HTTP_REFERER'] . '"', __FILE__, __LINE__);
2669
            foreach ($this->config_nooffsitelink_valid_domains as $key => $valid_domain) {
2670
                // $_SERVER['HTTP_HOST'] contains the port number, so strip it out here to make default configuration work
2671
                list($clean_domain) = explode(':', $valid_domain);
2672
                $this->config_nooffsitelink_valid_domains[$key] = $clean_domain;
2673
            }
2674
            $parsed_url = phpthumb_functions::ParseURLbetter(@$_SERVER['HTTP_REFERER']);
2675
            if (!$this->OffsiteDomainIsAllowed(@$parsed_url['host'], $this->config_nooffsitelink_valid_domains)) {
2676
                $allow = false;
2677
                //$this->DebugMessage('AntiOffsiteLinking() - "'.@$parsed_url['host'].'" is NOT in $this->config_nooffsitelink_valid_domains ('.implode(';', $this->config_nooffsitelink_valid_domains).')', __FILE__, __LINE__);
2678
                $this->ErrorImage('AntiOffsiteLinking() - "' . @$parsed_url['host'] . '" is NOT in $this->config_nooffsitelink_valid_domains (' . implode(';', $this->config_nooffsitelink_valid_domains) . ')');
2679
            } else {
2680
                $this->DebugMessage('AntiOffsiteLinking() - "' . @$parsed_url['host'] . '" is in $this->config_nooffsitelink_valid_domains (' . implode(';', $this->config_nooffsitelink_valid_domains) . ')', __FILE__, __LINE__);
2681
            }
2682
        }
2683
2684
        if ($allow && $this->config_nohotlink_enabled && preg_match('#^(f|ht)tps?\://#i', $this->src)) {
2685
            $parsed_url = phpthumb_functions::ParseURLbetter($this->src);
2686
            //if (!phpthumb_functions::CaseInsensitiveInArray(@$parsed_url['host'], $this->config_nohotlink_valid_domains)) {
2687
            if (!$this->OffsiteDomainIsAllowed(@$parsed_url['host'], $this->config_nohotlink_valid_domains)) {
2688
                // This domain is not allowed
2689
                $allow = false;
2690
                $this->DebugMessage('AntiOffsiteLinking() - "' . $parsed_url['host'] . '" is NOT in $this->config_nohotlink_valid_domains (' . implode(';', $this->config_nohotlink_valid_domains) . ')', __FILE__, __LINE__);
2691
            } else {
2692
                $this->DebugMessage('AntiOffsiteLinking() - "' . $parsed_url['host'] . '" is in $this->config_nohotlink_valid_domains (' . implode(';', $this->config_nohotlink_valid_domains) . ')', __FILE__, __LINE__);
2693
            }
2694
        }
2695
2696
        if ($allow) {
2697
            $this->DebugMessage('AntiOffsiteLinking() says this is allowed', __FILE__, __LINE__);
2698
2699
            return true;
2700
        }
2701
2702
        if (!phpthumb_functions::IsHexColor($this->config_error_bgcolor)) {
2703
            return $this->ErrorImage('Invalid hex color string "' . $this->config_error_bgcolor . '" for $this->config_error_bgcolor');
2704
        }
2705
        if (!phpthumb_functions::IsHexColor($this->config_error_textcolor)) {
2706
            return $this->ErrorImage('Invalid hex color string "' . $this->config_error_textcolor . '" for $this->config_error_textcolor');
2707
        }
2708
        if ($this->config_nooffsitelink_erase_image) {
2709
            return $this->ErrorImage($this->config_nooffsitelink_text_message, $this->thumbnail_width, $this->thumbnail_height);
2710
        } else {
2711
            $this->config_nooffsitelink_watermark_src = $this->ResolveFilenameToAbsolute($this->config_nooffsitelink_watermark_src);
2712
            if (is_file($this->config_nooffsitelink_watermark_src)) {
0 ignored issues
show
Bug introduced by
It seems like $this->config_nooffsitelink_watermark_src can also be of type false; however, parameter $filename of is_file() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

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

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

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

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

2718
                $watermark_img                   = $this->ImageCreateFromStringReplacement(/** @scrutinizer ignore-type */ file_get_contents($this->config_nooffsitelink_watermark_src));
Loading history...
2719
                $phpthumbFilters                 = new phpthumb_filters();
2720
                $phpthumbFilters->phpThumbObject =& $this;
2721
                $opacity                         = 50;
2722
                $margin                          = 5;
2723
                $phpthumbFilters->WatermarkOverlay($this->gdimg_output, $watermark_img, '*', $opacity, $margin);
2724
                imagedestroy($watermark_img);
2725
                unset($phpthumbFilters);
2726
            } else {
2727
                $nohotlink_text_array = explode("\n", wordwrap($this->config_nooffsitelink_text_message, floor($this->thumbnail_width / imagefontwidth($this->config_error_fontsize)), "\n"));
0 ignored issues
show
Bug introduced by
floor($this->thumbnail_w...config_error_fontsize)) of type double is incompatible with the type integer expected by parameter $width of wordwrap(). ( Ignorable by Annotation )

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

2727
                $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...
2728
                $nohotlink_text_color = phpthumb_functions::ImageHexColorAllocate($this->gdimg_output, $this->config_error_textcolor);
2729
2730
                $topoffset = round(($this->thumbnail_height - (count($nohotlink_text_array) * imagefontheight($this->config_error_fontsize))) / 2);
2731
2732
                $rowcounter = 0;
2733
                $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__);
2734
                foreach ($nohotlink_text_array as $textline) {
2735
                    $leftoffset = max(0, round(($this->thumbnail_width - (strlen($textline) * imagefontwidth($this->config_error_fontsize))) / 2));
2736
                    imagestring($this->gdimg_output, $this->config_error_fontsize, $leftoffset, $topoffset + ($rowcounter++ * imagefontheight($this->config_error_fontsize)), $textline, $nohotlink_text_color);
2737
                }
2738
            }
2739
        }
2740
2741
        return true;
2742
    }
2743
2744
    /**
2745
     * @return bool
2746
     */
2747
    public function AlphaChannelFlatten()
2748
    {
2749
        if (!$this->is_alpha) {
2750
            // image doesn't have alpha transparency, no need to flatten
2751
            $this->DebugMessage('skipping AlphaChannelFlatten() because !$this->is_alpha', __FILE__, __LINE__);
2752
2753
            return false;
2754
        }
2755
        switch ($this->thumbnailFormat) {
2756
            case 'png':
2757
            case 'ico':
2758
                // image has alpha transparency, but output as PNG or ICO which can handle it
2759
                $this->DebugMessage('skipping AlphaChannelFlatten() because ($this->thumbnailFormat == "' . $this->thumbnailFormat . '")', __FILE__, __LINE__);
2760
2761
                return false;
2762
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

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

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

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

Loading history...
2763
2764
            case 'gif':
2765
                // image has alpha transparency, but output as GIF which can handle only single-color transparency
2766
                $CurrentImageColorTransparent = imagecolortransparent($this->gdimg_output);
2767
                if (-1 == $CurrentImageColorTransparent) {
2768
                    // no transparent color defined
2769
2770
                    if (phpthumb_functions::gd_version() < 2.0) {
2771
                        $this->DebugMessage('AlphaChannelFlatten() failed because GD version is "' . phpthumb_functions::gd_version() . '"', __FILE__, __LINE__);
2772
2773
                        return false;
2774
                    }
2775
2776
                    if ($img_alpha_mixdown_dither = @imagecreatetruecolor(imagesx($this->gdimg_output), imagesy($this->gdimg_output))) {
2777
                        $dither_color = [];
2778
                        for ($i = 0; $i <= 255; $i++) {
2779
                            $dither_color[$i] = imagecolorallocate($img_alpha_mixdown_dither, $i, $i, $i);
2780
                        }
2781
2782
                        // scan through current truecolor image copy alpha channel to temp image as grayscale
2783
                        for ($x = 0; $x < $this->thumbnail_width; $x++) {
2784
                            for ($y = 0; $y < $this->thumbnail_height; $y++) {
2785
                                $PixelColor = phpthumb_functions::GetPixelColor($this->gdimg_output, $x, $y);
2786
                                imagesetpixel($img_alpha_mixdown_dither, $x, $y, $dither_color[$PixelColor['alpha'] * 2]);
2787
                            }
2788
                        }
2789
2790
                        // dither alpha channel grayscale version down to 2 colors
2791
                        imagetruecolortopalette($img_alpha_mixdown_dither, true, 2);
2792
2793
                        // reduce color palette to 256-1 colors (leave one palette position for transparent color)
2794
                        imagetruecolortopalette($this->gdimg_output, true, 255);
2795
2796
                        // allocate a new color for transparent color index
2797
                        $TransparentColor = imagecolorallocate($this->gdimg_output, 1, 254, 253);
2798
                        imagecolortransparent($this->gdimg_output, $TransparentColor);
2799
2800
                        // scan through alpha channel image and note pixels with >50% transparency
2801
                        for ($x = 0; $x < $this->thumbnail_width; $x++) {
2802
                            for ($y = 0; $y < $this->thumbnail_height; $y++) {
2803
                                $AlphaChannelPixel = phpthumb_functions::GetPixelColor($img_alpha_mixdown_dither, $x, $y);
2804
                                if ($AlphaChannelPixel['red'] > 127) {
2805
                                    imagesetpixel($this->gdimg_output, $x, $y, $TransparentColor);
2806
                                }
2807
                            }
2808
                        }
2809
                        imagedestroy($img_alpha_mixdown_dither);
2810
2811
                        $this->DebugMessage('AlphaChannelFlatten() set image to 255+1 colors with transparency for GIF output', __FILE__, __LINE__);
2812
2813
                        return true;
2814
                    } else {
2815
                        $this->DebugMessage('AlphaChannelFlatten() failed imagecreate(' . imagesx($this->gdimg_output) . ', ' . imagesy($this->gdimg_output) . ')', __FILE__, __LINE__);
2816
2817
                        return false;
2818
                    }
2819
                } else {
2820
                    // a single transparent color already defined, leave as-is
2821
                    $this->DebugMessage('skipping AlphaChannelFlatten() because ($this->thumbnailFormat == "' . $this->thumbnailFormat . '") and imagecolortransparent() returned "' . $CurrentImageColorTransparent . '"', __FILE__, __LINE__);
2822
2823
                    return true;
2824
                }
2825
                break;
2826
        }
2827
        $this->DebugMessage('continuing AlphaChannelFlatten() for output format "' . $this->thumbnailFormat . '"', __FILE__, __LINE__);
2828
        // image has alpha transparency, and is being output in a format that doesn't support it -- flatten
2829
        if ($gdimg_flatten_temp = phpthumb_functions::ImageCreateFunction($this->thumbnail_width, $this->thumbnail_height)) {
2830
            $this->config_background_hexcolor = ($this->bg ?: $this->config_background_hexcolor);
2831
            if (!phpthumb_functions::IsHexColor($this->config_background_hexcolor)) {
2832
                return $this->ErrorImage('Invalid hex color string "' . $this->config_background_hexcolor . '" for parameter "bg"');
2833
            }
2834
            $background_color = phpthumb_functions::ImageHexColorAllocate($this->gdimg_output, $this->config_background_hexcolor);
2835
            imagefilledrectangle($gdimg_flatten_temp, 0, 0, $this->thumbnail_width, $this->thumbnail_height, $background_color);
2836
            imagecopy($gdimg_flatten_temp, $this->gdimg_output, 0, 0, 0, 0, $this->thumbnail_width, $this->thumbnail_height);
2837
2838
            imagealphablending($this->gdimg_output, true);
2839
            imagesavealpha($this->gdimg_output, false);
2840
            imagecolortransparent($this->gdimg_output, -1);
2841
            imagecopy($this->gdimg_output, $gdimg_flatten_temp, 0, 0, 0, 0, $this->thumbnail_width, $this->thumbnail_height);
2842
2843
            imagedestroy($gdimg_flatten_temp);
2844
2845
            return true;
2846
        } else {
2847
            $this->DebugMessage('ImageCreateFunction() failed', __FILE__, __LINE__);
2848
        }
2849
2850
        return false;
2851
    }
2852
2853
    /**
2854
     * @return bool
2855
     */
2856
    public function ApplyFilters()
2857
    {
2858
        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...
2859
            if (!require_once __DIR__ . '/phpthumb.filters.php') {
2860
                $this->DebugMessage('Error including "' . __DIR__ . '/phpthumb.filters.php" which is required for applying filters (' . implode(';', $this->fltr) . ')', __FILE__, __LINE__);
2861
2862
                return false;
2863
            }
2864
            $phpthumbFilters                 = new phpthumb_filters();
2865
            $phpthumbFilters->phpThumbObject =& $this;
2866
            foreach ($this->fltr as $filtercommand) {
2867
                @list($command, $parameter) = explode('|', $filtercommand, 2);
2868
                $this->DebugMessage('Attempting to process filter command "' . $command . '(' . $parameter . ')"', __FILE__, __LINE__);
2869
                switch ($command) {
2870
                    case 'brit': // Brightness
2871
                        $phpthumbFilters->Brightness($this->gdimg_output, $parameter);
0 ignored issues
show
Bug introduced by
$parameter of type string is incompatible with the type integer expected by parameter $amount of phpthumb_filters::Brightness(). ( Ignorable by Annotation )

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

2871
                        $phpthumbFilters->Brightness($this->gdimg_output, /** @scrutinizer ignore-type */ $parameter);
Loading history...
2872
                        break;
2873
2874
                    case 'cont': // Contrast
2875
                        $phpthumbFilters->Contrast($this->gdimg_output, $parameter);
0 ignored issues
show
Bug introduced by
$parameter of type string is incompatible with the type integer expected by parameter $amount of phpthumb_filters::Contrast(). ( Ignorable by Annotation )

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

2875
                        $phpthumbFilters->Contrast($this->gdimg_output, /** @scrutinizer ignore-type */ $parameter);
Loading history...
2876
                        break;
2877
2878
                    case 'ds': // Desaturation
2879
                        $phpthumbFilters->Desaturate($this->gdimg_output, $parameter, '');
2880
                        break;
2881
2882
                    case 'sat': // Saturation
2883
                        $phpthumbFilters->Saturation($this->gdimg_output, $parameter, '');
2884
                        break;
2885
2886
                    case 'gray': // Grayscale
2887
                        $phpthumbFilters->Grayscale($this->gdimg_output);
2888
                        break;
2889
2890
                    case 'clr': // Colorize
2891
                        if (phpthumb_functions::gd_version() < 2) {
2892
                            $this->DebugMessage('Skipping Colorize() because gd_version is "' . phpthumb_functions::gd_version() . '"', __FILE__, __LINE__);
2893
                            break;
2894
                        }
2895
                        @list($amount, $color) = explode('|', $parameter, 2);
2896
                        $phpthumbFilters->Colorize($this->gdimg_output, $amount, $color);
2897
                        break;
2898
2899
                    case 'sep': // Sepia
2900
                        if (phpthumb_functions::gd_version() < 2) {
2901
                            $this->DebugMessage('Skipping Sepia() because gd_version is "' . phpthumb_functions::gd_version() . '"', __FILE__, __LINE__);
2902
                            break;
2903
                        }
2904
                        @list($amount, $color) = explode('|', $parameter, 2);
2905
                        $phpthumbFilters->Sepia($this->gdimg_output, $amount, $color);
2906
                        break;
2907
2908
                    case 'gam': // Gamma correction
2909
                        $phpthumbFilters->Gamma($this->gdimg_output, $parameter);
2910
                        break;
2911
2912
                    case 'neg': // Negative colors
2913
                        $phpthumbFilters->Negative($this->gdimg_output);
2914
                        break;
2915
2916
                    case 'th': // Threshold
2917
                        $phpthumbFilters->Threshold($this->gdimg_output, $parameter);
2918
                        break;
2919
2920
                    case 'rcd': // ReduceColorDepth
2921
                        if (phpthumb_functions::gd_version() < 2) {
2922
                            $this->DebugMessage('Skipping ReduceColorDepth() because gd_version is "' . phpthumb_functions::gd_version() . '"', __FILE__, __LINE__);
2923
                            break;
2924
                        }
2925
                        @list($colors, $dither) = explode('|', $parameter, 2);
2926
                        $colors = ($colors ? (int)$colors : 256);
2927
                        $dither = ((strlen($dither) > 0) ? (bool)$dither : true);
2928
                        $phpthumbFilters->ReduceColorDepth($this->gdimg_output, $colors, $dither);
2929
                        break;
2930
2931
                    case 'flip': // Flip
2932
                        $phpthumbFilters->Flip($this->gdimg_output, false !== strpos(strtolower($parameter), 'x'), false !== strpos(strtolower($parameter), 'y'));
2933
                        break;
2934
2935
                    case 'edge': // EdgeDetect
2936
                        $phpthumbFilters->EdgeDetect($this->gdimg_output);
2937
                        break;
2938
2939
                    case 'emb': // Emboss
2940
                        $phpthumbFilters->Emboss($this->gdimg_output);
2941
                        break;
2942
2943
                    case 'bvl': // Bevel
2944
                        @list($width, $color1, $color2) = explode('|', $parameter, 3);
2945
                        $phpthumbFilters->Bevel($this->gdimg_output, $width, $color1, $color2);
2946
                        break;
2947
2948
                    case 'lvl': // autoLevels
2949
                        @list($band, $method, $threshold) = explode('|', $parameter, 3);
2950
                        $band      = ($band ? preg_replace('#[^RGBA\\*]#', '', strtoupper($band)) : '*');
2951
                        $method    = ((strlen($method) > 0) ? (int)$method : 2);
2952
                        $threshold = ((strlen($threshold) > 0) ? (float)$threshold : 0.1);
2953
2954
                        $phpthumbFilters->HistogramStretch($this->gdimg_output, $band, $method, $threshold);
2955
                        break;
2956
2957
                    case 'wb': // WhiteBalance
2958
                        $phpthumbFilters->WhiteBalance($this->gdimg_output, $parameter);
2959
                        break;
2960
2961
                    case 'hist': // Histogram overlay
2962
                        if (phpthumb_functions::gd_version() < 2) {
2963
                            $this->DebugMessage('Skipping HistogramOverlay() because gd_version is "' . phpthumb_functions::gd_version() . '"', __FILE__, __LINE__);
2964
                            break;
2965
                        }
2966
                        @list($bands, $colors, $width, $height, $alignment, $opacity, $margin_x, $margin_y) = explode('|', $parameter, 8);
2967
                        $bands     = ($bands ?: '*');
2968
                        $colors    = ($colors ?: '');
2969
                        $width     = ($width ?: 0.25);
2970
                        $height    = ($height ?: 0.25);
2971
                        $alignment = ($alignment ?: 'BR');
2972
                        $opacity   = ($opacity ?: 50);
2973
                        $margin_x  = ($margin_x ?: 5);
2974
                        // $margin_y -- it wasn't forgotten, let the value always pass unchanged
2975
                        $phpthumbFilters->HistogramOverlay($this->gdimg_output, $bands, $colors, $width, $height, $alignment, $opacity, $margin_x, $margin_y);
0 ignored issues
show
Bug introduced by
It seems like $height can also be of type string; however, parameter $height of phpthumb_filters::HistogramOverlay() does only seem to accept double, 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

2975
                        $phpthumbFilters->HistogramOverlay($this->gdimg_output, $bands, $colors, $width, /** @scrutinizer ignore-type */ $height, $alignment, $opacity, $margin_x, $margin_y);
Loading history...
Bug introduced by
It seems like $margin_x can also be of type string; however, parameter $margin_x of phpthumb_filters::HistogramOverlay() 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

2975
                        $phpthumbFilters->HistogramOverlay($this->gdimg_output, $bands, $colors, $width, $height, $alignment, $opacity, /** @scrutinizer ignore-type */ $margin_x, $margin_y);
Loading history...
Bug introduced by
It seems like $width can also be of type string; however, parameter $width of phpthumb_filters::HistogramOverlay() does only seem to accept double, 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

2975
                        $phpthumbFilters->HistogramOverlay($this->gdimg_output, $bands, $colors, /** @scrutinizer ignore-type */ $width, $height, $alignment, $opacity, $margin_x, $margin_y);
Loading history...
Bug introduced by
It seems like $opacity can also be of type string; however, parameter $opacity of phpthumb_filters::HistogramOverlay() 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

2975
                        $phpthumbFilters->HistogramOverlay($this->gdimg_output, $bands, $colors, $width, $height, $alignment, /** @scrutinizer ignore-type */ $opacity, $margin_x, $margin_y);
Loading history...
2976
                        break;
2977
2978
                    case 'fram': // Frame
2979
                        @list($frame_width, $edge_width, $color_frame, $color1, $color2) = explode('|', $parameter, 5);
2980
                        $phpthumbFilters->Frame($this->gdimg_output, $frame_width, $edge_width, $color_frame, $color1, $color2);
2981
                        break;
2982
2983
                    case 'drop': // DropShadow
2984
                        if (phpthumb_functions::gd_version() < 2) {
2985
                            $this->DebugMessage('Skipping DropShadow() because gd_version is "' . phpthumb_functions::gd_version() . '"', __FILE__, __LINE__);
2986
2987
                            return false;
2988
                        }
2989
                        $this->is_alpha = true;
2990
                        @list($distance, $width, $color, $angle, $fade) = explode('|', $parameter, 5);
2991
                        $phpthumbFilters->DropShadow($this->gdimg_output, $distance, $width, $color, $angle, $fade);
2992
                        break;
2993
2994
                    case 'mask': // Mask cropping
2995
                        if (phpthumb_functions::gd_version() < 2) {
2996
                            $this->DebugMessage('Skipping Mask() because gd_version is "' . phpthumb_functions::gd_version() . '"', __FILE__, __LINE__);
2997
2998
                            return false;
2999
                        }
3000
                        @list($mask_filename, $invert) = explode('|', $parameter, 2);
3001
                        $mask_filename = $this->ResolveFilenameToAbsolute($mask_filename);
3002
                        if (@is_readable($mask_filename) && ($fp_mask = @fopen($mask_filename, 'rb'))) {
0 ignored issues
show
Bug introduced by
It seems like $mask_filename can also be of type false; however, parameter $filename of fopen() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

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

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

3002
                        if (@is_readable(/** @scrutinizer ignore-type */ $mask_filename) && ($fp_mask = @fopen($mask_filename, 'rb'))) {
Loading history...
3003
                            $MaskImageData = '';
3004
                            do {
3005
                                $buffer        = fread($fp_mask, 8192);
3006
                                $MaskImageData .= $buffer;
3007
                            } while (strlen($buffer) > 0);
3008
                            fclose($fp_mask);
3009
                            if ($gdimg_mask = $this->ImageCreateFromStringReplacement($MaskImageData)) {
3010
                                if ($invert
3011
                                    && phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.0.0', '>=')
3012
                                    && phpthumb_functions::gd_is_bundled()) {
3013
                                    imagefilter($gdimg_mask, IMG_FILTER_NEGATE);
3014
                                }
3015
                                $this->is_alpha = true;
3016
                                $phpthumbFilters->ApplyMask($gdimg_mask, $this->gdimg_output);
3017
                                imagedestroy($gdimg_mask);
3018
                            } else {
3019
                                $this->DebugMessage('ImageCreateFromStringReplacement() failed for "' . $mask_filename . '"', __FILE__, __LINE__);
3020
                            }
3021
                        } else {
3022
                            $this->DebugMessage('Cannot open mask file "' . $mask_filename . '"', __FILE__, __LINE__);
0 ignored issues
show
Bug introduced by
Are you sure $mask_filename of type null|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

3022
                            $this->DebugMessage('Cannot open mask file "' . /** @scrutinizer ignore-type */ $mask_filename . '"', __FILE__, __LINE__);
Loading history...
3023
                        }
3024
                        break;
3025
3026
                    case 'elip': // Ellipse cropping
3027
                        if (phpthumb_functions::gd_version() < 2) {
3028
                            $this->DebugMessage('Skipping Ellipse() because gd_version is "' . phpthumb_functions::gd_version() . '"', __FILE__, __LINE__);
3029
3030
                            return false;
3031
                        }
3032
                        $this->is_alpha = true;
3033
                        $phpthumbFilters->Ellipse($this->gdimg_output);
3034
                        break;
3035
3036
                    case 'ric': // RoundedImageCorners
3037
                        if (phpthumb_functions::gd_version() < 2) {
3038
                            $this->DebugMessage('Skipping RoundedImageCorners() because gd_version is "' . phpthumb_functions::gd_version() . '"', __FILE__, __LINE__);
3039
3040
                            return false;
3041
                        }
3042
                        @list($radius_x, $radius_y) = explode('|', $parameter, 2);
3043
                        if (($radius_x < 1) || ($radius_y < 1)) {
3044
                            $this->DebugMessage('Skipping RoundedImageCorners(' . $radius_x . ', ' . $radius_y . ') because x/y radius is less than 1', __FILE__, __LINE__);
3045
                            break;
3046
                        }
3047
                        $this->is_alpha = true;
3048
                        $phpthumbFilters->RoundedImageCorners($this->gdimg_output, $radius_x, $radius_y);
3049
                        break;
3050
3051
                    case 'crop': // Crop
3052
                        @list($left, $right, $top, $bottom) = explode('|', $parameter, 4);
3053
                        $phpthumbFilters->Crop($this->gdimg_output, $left, $right, $top, $bottom);
0 ignored issues
show
Bug introduced by
$bottom of type string is incompatible with the type integer expected by parameter $bottom of phpthumb_filters::Crop(). ( Ignorable by Annotation )

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

3053
                        $phpthumbFilters->Crop($this->gdimg_output, $left, $right, $top, /** @scrutinizer ignore-type */ $bottom);
Loading history...
Bug introduced by
$left of type string is incompatible with the type integer expected by parameter $left of phpthumb_filters::Crop(). ( Ignorable by Annotation )

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

3053
                        $phpthumbFilters->Crop($this->gdimg_output, /** @scrutinizer ignore-type */ $left, $right, $top, $bottom);
Loading history...
Bug introduced by
$top of type string is incompatible with the type integer expected by parameter $top of phpthumb_filters::Crop(). ( Ignorable by Annotation )

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

3053
                        $phpthumbFilters->Crop($this->gdimg_output, $left, $right, /** @scrutinizer ignore-type */ $top, $bottom);
Loading history...
Bug introduced by
$right of type string is incompatible with the type integer expected by parameter $right of phpthumb_filters::Crop(). ( Ignorable by Annotation )

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

3053
                        $phpthumbFilters->Crop($this->gdimg_output, $left, /** @scrutinizer ignore-type */ $right, $top, $bottom);
Loading history...
3054
                        break;
3055
3056
                    case 'bord': // Border
3057
                        @list($border_width, $radius_x, $radius_y, $hexcolor_border) = explode('|', $parameter, 4);
3058
                        $this->is_alpha = true;
3059
                        $phpthumbFilters->ImageBorder($this->gdimg_output, $border_width, $radius_x, $radius_y, $hexcolor_border);
3060
                        break;
3061
3062
                    case 'over': // Overlay
3063
                        @list($filename, $underlay, $margin, $opacity) = explode('|', $parameter, 4);
3064
                        $underlay = ($underlay ?: false);
3065
                        $margin   = ((strlen($margin) > 0) ? $margin : ($underlay ? 0.1 : 0.0));
3066
                        $opacity  = ((strlen($opacity) > 0) ? $opacity : 100);
3067
                        if (($margin > 0) && ($margin < 1)) {
3068
                            $margin = min(0.499, $margin);
3069
                        } elseif (($margin > -1) && ($margin < 0)) {
3070
                            $margin = max(-0.499, $margin);
3071
                        }
3072
3073
                        $filename = $this->ResolveFilenameToAbsolute($filename);
3074
                        if (@is_readable($filename) && ($fp_watermark = @fopen($filename, 'rb'))) {
3075
                            $WatermarkImageData = '';
3076
                            do {
3077
                                $buffer             = fread($fp_watermark, 8192);
3078
                                $WatermarkImageData .= $buffer;
3079
                            } while (strlen($buffer) > 0);
3080
                            fclose($fp_watermark);
3081
                            if ($img_watermark = $this->ImageCreateFromStringReplacement($WatermarkImageData)) {
3082
                                if (($margin > 0) && ($margin < 1)) {
3083
                                    $resized_x = max(1, imagesx($this->gdimg_output) - round(2 * (imagesx($this->gdimg_output) * $margin)));
3084
                                    $resized_y = max(1, imagesy($this->gdimg_output) - round(2 * (imagesy($this->gdimg_output) * $margin)));
3085
                                } else {
3086
                                    $resized_x = max(1, imagesx($this->gdimg_output) - round(2 * $margin));
3087
                                    $resized_y = max(1, imagesy($this->gdimg_output) - round(2 * $margin));
3088
                                }
3089
3090
                                if ($underlay) {
3091
                                    if ($img_watermark_resized = phpthumb_functions::ImageCreateFunction(imagesx($this->gdimg_output), imagesy($this->gdimg_output))) {
3092
                                        imagealphablending($img_watermark_resized, false);
0 ignored issues
show
Bug introduced by
$img_watermark_resized of type true is incompatible with the type resource expected by parameter $image of imagealphablending(). ( Ignorable by Annotation )

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

3092
                                        imagealphablending(/** @scrutinizer ignore-type */ $img_watermark_resized, false);
Loading history...
3093
                                        imagesavealpha($img_watermark_resized, true);
0 ignored issues
show
Bug introduced by
$img_watermark_resized of type true is incompatible with the type resource expected by parameter $image of imagesavealpha(). ( Ignorable by Annotation )

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

3093
                                        imagesavealpha(/** @scrutinizer ignore-type */ $img_watermark_resized, true);
Loading history...
3094
                                        $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));
0 ignored issues
show
Bug introduced by
$img_watermark_resized of type true is incompatible with the type resource expected by parameter $image of imagesx(). ( Ignorable by Annotation )

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

3094
                                        $this->ImageResizeFunction($img_watermark_resized, $img_watermark, 0, 0, 0, 0, imagesx(/** @scrutinizer ignore-type */ $img_watermark_resized), imagesy($img_watermark_resized), imagesx($img_watermark), imagesy($img_watermark));
Loading history...
Bug introduced by
$img_watermark_resized of type true is incompatible with the type resource expected by parameter $image of imagesy(). ( Ignorable by Annotation )

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

3094
                                        $this->ImageResizeFunction($img_watermark_resized, $img_watermark, 0, 0, 0, 0, imagesx($img_watermark_resized), imagesy(/** @scrutinizer ignore-type */ $img_watermark_resized), imagesx($img_watermark), imagesy($img_watermark));
Loading history...
3095
                                        if ($img_source_resized = phpthumb_functions::ImageCreateFunction($resized_x, $resized_y)) {
3096
                                            imagealphablending($img_source_resized, false);
3097
                                            imagesavealpha($img_source_resized, true);
3098
                                            $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));
3099
                                            $phpthumbFilters->WatermarkOverlay($img_watermark_resized, $img_source_resized, 'C', $opacity, $margin);
0 ignored issues
show
Bug introduced by
It seems like $opacity can also be of type string; however, parameter $opacity of phpthumb_filters::WatermarkOverlay() 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

3099
                                            $phpthumbFilters->WatermarkOverlay($img_watermark_resized, $img_source_resized, 'C', /** @scrutinizer ignore-type */ $opacity, $margin);
Loading history...
Bug introduced by
It seems like $margin can also be of type string and double; however, parameter $margin_x of phpthumb_filters::WatermarkOverlay() 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

3099
                                            $phpthumbFilters->WatermarkOverlay($img_watermark_resized, $img_source_resized, 'C', $opacity, /** @scrutinizer ignore-type */ $margin);
Loading history...
3100
                                            imagecopy($this->gdimg_output, $img_watermark_resized, 0, 0, 0, 0, imagesx($this->gdimg_output), imagesy($this->gdimg_output));
3101
                                        } else {
3102
                                            $this->DebugMessage('phpthumb_functions::ImageCreateFunction(' . $resized_x . ', ' . $resized_y . ')', __FILE__, __LINE__);
3103
                                        }
3104
                                        imagedestroy($img_watermark_resized);
3105
                                    } else {
3106
                                        $this->DebugMessage('phpthumb_functions::ImageCreateFunction(' . imagesx($this->gdimg_output) . ', ' . imagesy($this->gdimg_output) . ')', __FILE__, __LINE__);
3107
                                    }
3108
                                } else { // overlay
3109
3110
                                    if ($img_watermark_resized = phpthumb_functions::ImageCreateFunction($resized_x, $resized_y)) {
3111
                                        imagealphablending($img_watermark_resized, false);
3112
                                        imagesavealpha($img_watermark_resized, true);
3113
                                        $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));
3114
                                        $phpthumbFilters->WatermarkOverlay($this->gdimg_output, $img_watermark_resized, 'C', $opacity, $margin);
3115
                                        imagedestroy($img_watermark_resized);
3116
                                    } else {
3117
                                        $this->DebugMessage('phpthumb_functions::ImageCreateFunction(' . $resized_x . ', ' . $resized_y . ')', __FILE__, __LINE__);
3118
                                    }
3119
                                }
3120
                                imagedestroy($img_watermark);
3121
                            } else {
3122
                                $this->DebugMessage('ImageCreateFromStringReplacement() failed for "' . $filename . '"', __FILE__, __LINE__);
3123
                            }
3124
                        } else {
3125
                            $this->DebugMessage('Cannot open overlay file "' . $filename . '"', __FILE__, __LINE__);
0 ignored issues
show
Bug introduced by
Are you sure $filename of type null|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

3125
                            $this->DebugMessage('Cannot open overlay file "' . /** @scrutinizer ignore-type */ $filename . '"', __FILE__, __LINE__);
Loading history...
3126
                        }
3127
                        break;
3128
3129
                    case 'wmi': // WaterMarkImage
3130
                        @list($filename, $alignment, $opacity, $margin['x'], $margin['y'], $rotate_angle) = explode('|', $parameter, 6);
3131
                        // $margin can be pixel margin or percent margin if $alignment is text, or max width/height if $alignment is position like "50x75"
3132
                        $alignment    = ($alignment ?: 'BR');
3133
                        $opacity      = (strlen($opacity) ? (int)$opacity : 50);
3134
                        $rotate_angle = (strlen($rotate_angle) ? (int)$rotate_angle : 0);
3135
                        if (!preg_match('#^([0-9\\.\\-]*)x([0-9\\.\\-]*)$#i', $alignment, $matches)) {
3136
                            $margins = ['x', 'y'];
3137
                            foreach ($margins as $xy) {
3138
                                $margin[$xy] = (strlen($margin[$xy]) ? $margin[$xy] : 5);
3139
                                if (($margin[$xy] > 0) && ($margin[$xy] < 1)) {
3140
                                    $margin[$xy] = min(0.499, $margin[$xy]);
3141
                                } elseif (($margin[$xy] > -1) && ($margin[$xy] < 0)) {
3142
                                    $margin[$xy] = max(-0.499, $margin[$xy]);
3143
                                }
3144
                            }
3145
                        }
3146
3147
                        $filename = $this->ResolveFilenameToAbsolute($filename);
3148
                        if (@is_readable($filename)) {
3149
                            if ($img_watermark = $this->ImageCreateFromFilename($filename)) {
3150
                                if (0 !== $rotate_angle) {
3151
                                    $phpthumbFilters->ImprovedImageRotate($img_watermark, $rotate_angle, 'FFFFFF', null, $this);
3152
                                }
3153
                                if (preg_match('#^([0-9\\.\\-]*)x([0-9\\.\\-]*)$#i', $alignment, $matches)) {
3154
                                    $watermark_max_width  = ($margin['x'] ?: imagesx($img_watermark));
3155
                                    $watermark_max_height = ($margin['y'] ?: imagesy($img_watermark));
3156
                                    $scale                = phpthumb_functions::ScaleToFitInBox(imagesx($img_watermark), imagesy($img_watermark), $watermark_max_width, $watermark_max_height, true, true);
0 ignored issues
show
Bug introduced by
It seems like $watermark_max_width can also be of type integer; however, parameter $maxwidth of phpthumb_functions::ScaleToFitInBox() does only seem to accept null, 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

3156
                                    $scale                = phpthumb_functions::ScaleToFitInBox(imagesx($img_watermark), imagesy($img_watermark), /** @scrutinizer ignore-type */ $watermark_max_width, $watermark_max_height, true, true);
Loading history...
Bug introduced by
It seems like $watermark_max_height can also be of type integer; however, parameter $maxheight of phpthumb_functions::ScaleToFitInBox() does only seem to accept null, 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

3156
                                    $scale                = phpthumb_functions::ScaleToFitInBox(imagesx($img_watermark), imagesy($img_watermark), $watermark_max_width, /** @scrutinizer ignore-type */ $watermark_max_height, true, true);
Loading history...
3157
                                    $this->DebugMessage('Scaling watermark by a factor of ' . number_format($scale, 4), __FILE__, __LINE__);
3158
                                    if (($scale > 1) || ($scale < 1)) {
3159
                                        if ($img_watermark2 = phpthumb_functions::ImageCreateFunction($scale * imagesx($img_watermark), $scale * imagesy($img_watermark))) {
3160
                                            imagealphablending($img_watermark2, false);
3161
                                            imagesavealpha($img_watermark2, true);
3162
                                            $this->ImageResizeFunction($img_watermark2, $img_watermark, 0, 0, 0, 0, imagesx($img_watermark2), imagesy($img_watermark2), imagesx($img_watermark), imagesy($img_watermark));
3163
                                            $img_watermark = $img_watermark2;
3164
                                        } else {
3165
                                            $this->DebugMessage('ImageCreateFunction(' . ($scale * imagesx($img_watermark)) . ', ' . ($scale * imagesx($img_watermark)) . ') failed', __FILE__, __LINE__);
3166
                                        }
3167
                                    }
3168
                                    $watermark_dest_x = round($matches[1] - (imagesx($img_watermark) / 2));
3169
                                    $watermark_dest_y = round($matches[2] - (imagesy($img_watermark) / 2));
3170
                                    $alignment        = $watermark_dest_x . 'x' . $watermark_dest_y;
3171
                                }
3172
                                $phpthumbFilters->WatermarkOverlay($this->gdimg_output, $img_watermark, $alignment, $opacity, $margin['x'], $margin['y']);
3173
                                imagedestroy($img_watermark);
3174
                                if (isset($img_watermark2) && is_resource($img_watermark2)) {
3175
                                    imagedestroy($img_watermark2);
3176
                                }
3177
                            } else {
3178
                                $this->DebugMessage('ImageCreateFromFilename() failed for "' . $filename . '"', __FILE__, __LINE__);
3179
                            }
3180
                        } else {
3181
                            $this->DebugMessage('!is_readable(' . $filename . ')', __FILE__, __LINE__);
3182
                        }
3183
                        break;
3184
3185
                    case 'wmt': // WaterMarkText
3186
                        @list($text, $size, $alignment, $hex_color, $ttffont, $opacity, $margin, $angle, $bg_color, $bg_opacity, $fillextend) = explode('|', $parameter, 11);
3187
                        $text       = ($text ?: '');
3188
                        $size       = ($size ?: 3);
3189
                        $alignment  = ($alignment ?: 'BR');
3190
                        $hex_color  = ($hex_color ?: '000000');
3191
                        $ttffont    = ($ttffont ?: '');
3192
                        $opacity    = (strlen($opacity) ? $opacity : 50);
3193
                        $margin     = (strlen($margin) ? $margin : 5);
3194
                        $angle      = (strlen($angle) ? $angle : 0);
3195
                        $bg_color   = ($bg_color ?: false);
3196
                        $bg_opacity = ($bg_opacity ?: 0);
3197
                        $fillextend = ($fillextend ?: '');
3198
3199
                        if (basename($ttffont) == $ttffont) {
3200
                            $ttffont = $this->realPathSafe($this->config_ttf_directory . DIRECTORY_SEPARATOR . $ttffont);
3201
                        } else {
3202
                            $ttffont = $this->ResolveFilenameToAbsolute($ttffont);
3203
                        }
3204
                        $phpthumbFilters->WatermarkText($this->gdimg_output, $text, $size, $alignment, $hex_color, $ttffont, $opacity, $margin, $angle, $bg_color, $bg_opacity, $fillextend);
0 ignored issues
show
Bug introduced by
It seems like $angle can also be of type string; however, parameter $angle of phpthumb_filters::WatermarkText() 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

3204
                        $phpthumbFilters->WatermarkText($this->gdimg_output, $text, $size, $alignment, $hex_color, $ttffont, $opacity, $margin, /** @scrutinizer ignore-type */ $angle, $bg_color, $bg_opacity, $fillextend);
Loading history...
Bug introduced by
It seems like $opacity can also be of type string; however, parameter $opacity of phpthumb_filters::WatermarkText() 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

3204
                        $phpthumbFilters->WatermarkText($this->gdimg_output, $text, $size, $alignment, $hex_color, $ttffont, /** @scrutinizer ignore-type */ $opacity, $margin, $angle, $bg_color, $bg_opacity, $fillextend);
Loading history...
Bug introduced by
It seems like $bg_color can also be of type string; however, parameter $bg_color of phpthumb_filters::WatermarkText() does only seem to accept boolean, 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

3204
                        $phpthumbFilters->WatermarkText($this->gdimg_output, $text, $size, $alignment, $hex_color, $ttffont, $opacity, $margin, $angle, /** @scrutinizer ignore-type */ $bg_color, $bg_opacity, $fillextend);
Loading history...
Bug introduced by
It seems like $margin can also be of type string; however, parameter $margin of phpthumb_filters::WatermarkText() 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

3204
                        $phpthumbFilters->WatermarkText($this->gdimg_output, $text, $size, $alignment, $hex_color, $ttffont, $opacity, /** @scrutinizer ignore-type */ $margin, $angle, $bg_color, $bg_opacity, $fillextend);
Loading history...
Bug introduced by
It seems like $bg_opacity can also be of type string; however, parameter $bg_opacity of phpthumb_filters::WatermarkText() 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

3204
                        $phpthumbFilters->WatermarkText($this->gdimg_output, $text, $size, $alignment, $hex_color, $ttffont, $opacity, $margin, $angle, $bg_color, /** @scrutinizer ignore-type */ $bg_opacity, $fillextend);
Loading history...
3205
                        break;
3206
3207
                    case 'blur': // Blur
3208
                        @list($radius) = explode('|', $parameter, 1);
3209
                        $radius = ($radius ?: 1);
3210
                        if (phpthumb_functions::gd_version() >= 2) {
3211
                            $phpthumbFilters->Blur($this->gdimg_output, $radius);
0 ignored issues
show
Bug introduced by
It seems like $radius can also be of type string; however, parameter $radius of phpthumb_filters::Blur() does only seem to accept double, 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

3211
                            $phpthumbFilters->Blur($this->gdimg_output, /** @scrutinizer ignore-type */ $radius);
Loading history...
3212
                        } else {
3213
                            $this->DebugMessage('Skipping Blur() because gd_version is "' . phpthumb_functions::gd_version() . '"', __FILE__, __LINE__);
3214
                        }
3215
                        break;
3216
3217
                    case 'gblr': // Gaussian Blur
3218
                        $phpthumbFilters->BlurGaussian($this->gdimg_output);
3219
                        break;
3220
3221
                    case 'sblr': // Selective Blur
3222
                        $phpthumbFilters->BlurSelective($this->gdimg_output);
3223
                        break;
3224
3225
                    case 'mean': // MeanRemoval blur
3226
                        $phpthumbFilters->MeanRemoval($this->gdimg_output);
3227
                        break;
3228
3229
                    case 'smth': // Smooth blur
3230
                        $phpthumbFilters->Smooth($this->gdimg_output, $parameter);
0 ignored issues
show
Bug introduced by
$parameter of type string is incompatible with the type integer expected by parameter $amount of phpthumb_filters::Smooth(). ( Ignorable by Annotation )

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

3230
                        $phpthumbFilters->Smooth($this->gdimg_output, /** @scrutinizer ignore-type */ $parameter);
Loading history...
3231
                        break;
3232
3233
                    case 'usm': // UnSharpMask sharpening
3234
                        @list($amount, $radius, $threshold) = explode('|', $parameter, 3);
3235
                        $amount    = ($amount ?: 80);
3236
                        $radius    = ($radius ?: 0.5);
3237
                        $threshold = (strlen($threshold) ? $threshold : 3);
3238
                        if (phpthumb_functions::gd_version() >= 2.0) {
3239
                            ob_start();
3240
                            if (!@require_once __DIR__ . '/phpthumb.unsharp.php') {
3241
                                $include_error = ob_get_contents();
3242
                                if ($include_error) {
3243
                                    $this->DebugMessage('include_once("' . __DIR__ . '/phpthumb.unsharp.php") generated message: "' . $include_error . '"', __FILE__, __LINE__);
3244
                                }
3245
                                $this->DebugMessage('Error including "' . __DIR__ . '/phpthumb.unsharp.php" which is required for unsharp masking', __FILE__, __LINE__);
3246
                                ob_end_clean();
3247
3248
                                return false;
3249
                            }
3250
                            ob_end_clean();
3251
                            phpUnsharpMask::applyUnsharpMask($this->gdimg_output, $amount, $radius, $threshold);
3252
                        } else {
3253
                            $this->DebugMessage('Skipping unsharp mask because gd_version is "' . phpthumb_functions::gd_version() . '"', __FILE__, __LINE__);
3254
3255
                            return false;
3256
                        }
3257
                        break;
3258
3259
                    case 'size': // Resize
3260
                        @list($newwidth, $newheight, $stretch) = explode('|', $parameter);
3261
                        $newwidth  = (!$newwidth ? imagesx($this->gdimg_output) : ((($newwidth > 0)
3262
                                                                                    && ($newwidth < 1)) ? round($newwidth * imagesx($this->gdimg_output)) : round($newwidth)));
0 ignored issues
show
Bug introduced by
$newwidth of type string is incompatible with the type double expected by parameter $val of round(). ( Ignorable by Annotation )

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

3262
                                                                                    && ($newwidth < 1)) ? round($newwidth * imagesx($this->gdimg_output)) : round(/** @scrutinizer ignore-type */ $newwidth)));
Loading history...
3263
                        $newheight = (!$newheight ? imagesy($this->gdimg_output) : ((($newheight > 0)
3264
                                                                                     && ($newheight < 1)) ? round($newheight * imagesy($this->gdimg_output)) : round($newheight)));
3265
                        $stretch   = ($stretch ? true : false);
3266
                        if ($stretch) {
3267
                            $scale_x = phpthumb_functions::ScaleToFitInBox(imagesx($this->gdimg_output), imagesx($this->gdimg_output), $newwidth, $newwidth, true, true);
3268
                            $scale_y = phpthumb_functions::ScaleToFitInBox(imagesy($this->gdimg_output), imagesy($this->gdimg_output), $newheight, $newheight, true, true);
3269
                        } else {
3270
                            $scale_x = phpthumb_functions::ScaleToFitInBox(imagesx($this->gdimg_output), imagesy($this->gdimg_output), $newwidth, $newheight, true, true);
3271
                            $scale_y = $scale_x;
3272
                        }
3273
                        $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__);
3274
                        if (($scale_x > 1) || ($scale_x < 1) || ($scale_y > 1) || ($scale_y < 1)) {
3275
                            if ($img_temp = phpthumb_functions::ImageCreateFunction(imagesx($this->gdimg_output), imagesy($this->gdimg_output))) {
3276
                                imagecopy($img_temp, $this->gdimg_output, 0, 0, 0, 0, imagesx($this->gdimg_output), imagesy($this->gdimg_output));
0 ignored issues
show
Bug introduced by
$img_temp of type true is incompatible with the type resource expected by parameter $dst_im of imagecopy(). ( Ignorable by Annotation )

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

3276
                                imagecopy(/** @scrutinizer ignore-type */ $img_temp, $this->gdimg_output, 0, 0, 0, 0, imagesx($this->gdimg_output), imagesy($this->gdimg_output));
Loading history...
3277
                                if ($this->gdimg_output = phpthumb_functions::ImageCreateFunction($scale_x * imagesx($img_temp), $scale_y * imagesy($img_temp))) {
3278
                                    imagealphablending($this->gdimg_output, false);
3279
                                    imagesavealpha($this->gdimg_output, true);
3280
                                    $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));
3281
                                } else {
3282
                                    $this->DebugMessage('ImageCreateFunction(' . ($scale_x * imagesx($img_temp)) . ', ' . ($scale_y * imagesy($img_temp)) . ') failed', __FILE__, __LINE__);
3283
                                }
3284
                                imagedestroy($img_temp);
3285
                            } else {
3286
                                $this->DebugMessage('ImageCreateFunction(' . imagesx($this->gdimg_output) . ', ' . imagesy($this->gdimg_output) . ') failed', __FILE__, __LINE__);
3287
                            }
3288
                        }
3289
                        break;
3290
3291
                    case 'rot': // ROTate
3292
                        @list($angle, $bgcolor) = explode('|', $parameter, 2);
3293
                        $phpthumbFilters->ImprovedImageRotate($this->gdimg_output, $angle, $bgcolor, null, $this);
0 ignored issues
show
Bug introduced by
$angle of type string is incompatible with the type integer expected by parameter $rotate_angle of phpthumb_filters::ImprovedImageRotate(). ( Ignorable by Annotation )

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

3293
                        $phpthumbFilters->ImprovedImageRotate($this->gdimg_output, /** @scrutinizer ignore-type */ $angle, $bgcolor, null, $this);
Loading history...
3294
                        break;
3295
3296
                    case 'stc': // Source Transparent Color
3297
                        @list($hexcolor, $min_limit, $max_limit) = explode('|', $parameter, 3);
3298
                        if (!phpthumb_functions::IsHexColor($hexcolor)) {
3299
                            $this->DebugMessage('Skipping SourceTransparentColor hex color is invalid (' . $hexcolor . ')', __FILE__, __LINE__);
3300
3301
                            return false;
3302
                        }
3303
                        $min_limit = (strlen($min_limit) ? $min_limit : 5);
3304
                        $max_limit = (strlen($max_limit) ? $max_limit : 10);
3305
                        if ($gdimg_mask = $phpthumbFilters->SourceTransparentColorMask($this->gdimg_output, $hexcolor, $min_limit, $max_limit)) {
0 ignored issues
show
Bug introduced by
It seems like $min_limit can also be of type string; however, parameter $min_limit of phpthumb_filters::SourceTransparentColorMask() 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

3305
                        if ($gdimg_mask = $phpthumbFilters->SourceTransparentColorMask($this->gdimg_output, $hexcolor, /** @scrutinizer ignore-type */ $min_limit, $max_limit)) {
Loading history...
Bug introduced by
It seems like $max_limit can also be of type string; however, parameter $max_limit of phpthumb_filters::SourceTransparentColorMask() 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

3305
                        if ($gdimg_mask = $phpthumbFilters->SourceTransparentColorMask($this->gdimg_output, $hexcolor, $min_limit, /** @scrutinizer ignore-type */ $max_limit)) {
Loading history...
3306
                            $this->is_alpha = true;
3307
                            $phpthumbFilters->ApplyMask($gdimg_mask, $this->gdimg_output);
3308
                            imagedestroy($gdimg_mask);
3309
                        } else {
3310
                            $this->DebugMessage('SourceTransparentColorMask() failed for "' . $hexcolor . ',' . $min_limit . ',' . $max_limit . '"', __FILE__, __LINE__);
3311
                        }
3312
                        break;
3313
                }
3314
                $this->DebugMessage('Finished processing filter command "' . $command . '(' . $parameter . ')"', __FILE__, __LINE__);
3315
            }
3316
        }
3317
3318
        return true;
3319
    }
3320
3321
    /**
3322
     * @return bool
3323
     */
3324
    public function MaxFileSize()
3325
    {
3326
        if (phpthumb_functions::gd_version() < 2) {
3327
            $this->DebugMessage('Skipping MaxFileSize() because gd_version is "' . phpthumb_functions::gd_version() . '"', __FILE__, __LINE__);
3328
3329
            return false;
3330
        }
3331
        if ($this->maxb > 0) {
3332
            switch ($this->thumbnailFormat) {
3333
                case 'png':
3334
                case 'gif':
3335
                    $imgRenderFunction = 'image' . $this->thumbnailFormat;
3336
3337
                    ob_start();
3338
                    $imgRenderFunction($this->gdimg_output);
3339
                    $imgdata = ob_get_contents();
3340
                    ob_end_clean();
3341
3342
                    if (strlen($imgdata) > $this->maxb) {
3343
                        for ($i = 8; $i >= 1; $i--) {
3344
                            $tempIMG = imagecreatetruecolor(imagesx($this->gdimg_output), imagesy($this->gdimg_output));
3345
                            imagecopy($tempIMG, $this->gdimg_output, 0, 0, 0, 0, imagesx($this->gdimg_output), imagesy($this->gdimg_output));
3346
                            imagetruecolortopalette($tempIMG, true, 2 ** $i);
3347
                            ob_start();
3348
                            $imgRenderFunction($tempIMG);
3349
                            $imgdata = ob_get_contents();
3350
                            ob_end_clean();
3351
3352
                            if (strlen($imgdata) <= $this->maxb) {
3353
                                imagetruecolortopalette($this->gdimg_output, true, 2 ** $i);
3354
                                break;
3355
                            }
3356
                        }
3357
                    }
3358
                    break;
3359
3360
                case 'jpeg':
3361
                    ob_start();
3362
                    imagejpeg($this->gdimg_output);
3363
                    $imgdata = ob_get_contents();
3364
                    ob_end_clean();
3365
3366
                    if (strlen($imgdata) > $this->maxb) {
3367
                        for ($i = 3; $i < 20; $i++) {
3368
                            $q = round(100 * (1 - log10($i / 2)));
3369
                            ob_start();
3370
                            imagejpeg($this->gdimg_output, null, $q);
0 ignored issues
show
Bug introduced by
$q of type double is incompatible with the type integer expected by parameter $quality of imagejpeg(). ( Ignorable by Annotation )

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

3370
                            imagejpeg($this->gdimg_output, null, /** @scrutinizer ignore-type */ $q);
Loading history...
3371
                            $imgdata = ob_get_contents();
3372
                            ob_end_clean();
3373
3374
                            $this->thumbnailQuality = $q;
3375
                            if (strlen($imgdata) <= $this->maxb) {
3376
                                break;
3377
                            }
3378
                        }
3379
                    }
3380
                    if (strlen($imgdata) > $this->maxb) {
3381
                        return false;
3382
                    }
3383
                    break;
3384
3385
                default:
3386
                    return false;
3387
            }
3388
        }
3389
3390
        return true;
3391
    }
3392
3393
    /**
3394
     * @return bool
3395
     */
3396
    public function CalculateThumbnailDimensions()
3397
    {
3398
        $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__);
3399
        //echo $this->source_width.'x'.$this->source_height.'<hr>';
3400
        $this->thumbnailCropX = ($this->sx ? (($this->sx >= 2) ? $this->sx : round($this->sx * $this->source_width)) : 0);
3401
        //echo $this->thumbnailCropX.'<br>';
3402
        $this->thumbnailCropY = ($this->sy ? (($this->sy >= 2) ? $this->sy : round($this->sy * $this->source_height)) : 0);
3403
        //echo $this->thumbnailCropY.'<br>';
3404
        $this->thumbnailCropW = ($this->sw ? (($this->sw >= 2) ? $this->sw : round($this->sw * $this->source_width)) : $this->source_width);
3405
        //echo $this->thumbnailCropW.'<br>';
3406
        $this->thumbnailCropH = ($this->sh ? (($this->sh >= 2) ? $this->sh : round($this->sh * $this->source_height)) : $this->source_height);
3407
        //echo $this->thumbnailCropH.'<hr>';
3408
3409
        // limit source area to original image area
3410
        $this->thumbnailCropW = max(1, min($this->thumbnailCropW, $this->source_width - $this->thumbnailCropX));
3411
        $this->thumbnailCropH = max(1, min($this->thumbnailCropH, $this->source_height - $this->thumbnailCropY));
3412
3413
        $this->DebugMessage('CalculateThumbnailDimensions() starting with [x,y,w,h] initially set to [' . $this->thumbnailCropX . ',' . $this->thumbnailCropY . ',' . $this->thumbnailCropW . ',' . $this->thumbnailCropH . ']', __FILE__, __LINE__);
3414
3415
        if ($this->zc && $this->w && $this->h) {
3416
            // Zoom Crop
3417
            // retain proportional resizing we did above, but crop off larger dimension so smaller
3418
            // dimension fully fits available space
3419
3420
            $scaling_X = $this->source_width / $this->w;
3421
            $scaling_Y = $this->source_height / $this->h;
3422
            if ($scaling_X > $scaling_Y) {
3423
                // some of the width will need to be cropped
3424
                $allowable_width      = $this->source_width / $scaling_X * $scaling_Y;
3425
                $this->thumbnailCropW = round($allowable_width);
3426
                $this->thumbnailCropX = round(($this->source_width - $allowable_width) / 2);
3427
            } elseif ($scaling_Y > $scaling_X) {
3428
                // some of the height will need to be cropped
3429
                $allowable_height     = $this->source_height / $scaling_Y * $scaling_X;
3430
                $this->thumbnailCropH = round($allowable_height);
3431
                $this->thumbnailCropY = round(($this->source_height - $allowable_height) / 2);
3432
            } else {
3433
                // image fits perfectly, no cropping needed
3434
            }
3435
            $this->thumbnail_width        = $this->w;
3436
            $this->thumbnail_height       = $this->h;
3437
            $this->thumbnail_image_width  = $this->thumbnail_width;
3438
            $this->thumbnail_image_height = $this->thumbnail_height;
3439
        } elseif ($this->iar && $this->w && $this->h) {
3440
3441
            // Ignore Aspect Ratio
3442
            // stretch image to fit exactly 'w' x 'h'
3443
            $this->thumbnail_width        = $this->w;
3444
            $this->thumbnail_height       = $this->h;
3445
            $this->thumbnail_image_width  = $this->thumbnail_width;
3446
            $this->thumbnail_image_height = $this->thumbnail_height;
3447
        } else {
3448
            $original_aspect_ratio = $this->thumbnailCropW / $this->thumbnailCropH;
3449
            if ($this->aoe) {
3450
                if ($this->w && $this->h) {
3451
                    $maxwidth  = min($this->w, $this->h * $original_aspect_ratio);
3452
                    $maxheight = min($this->h, $this->w / $original_aspect_ratio);
3453
                } elseif ($this->w) {
3454
                    $maxwidth  = $this->w;
3455
                    $maxheight = $this->w / $original_aspect_ratio;
3456
                } elseif ($this->h) {
3457
                    $maxwidth  = $this->h * $original_aspect_ratio;
3458
                    $maxheight = $this->h;
3459
                } else {
3460
                    $maxwidth  = $this->thumbnailCropW;
3461
                    $maxheight = $this->thumbnailCropH;
3462
                }
3463
            } else {
3464
                $maxwidth  = phpthumb_functions::nonempty_min($this->w, $this->thumbnailCropW, $this->config_output_maxwidth);
3465
                $maxheight = phpthumb_functions::nonempty_min($this->h, $this->thumbnailCropH, $this->config_output_maxheight);
3466
                //echo $maxwidth.'x'.$maxheight.'<br>';
3467
                $maxwidth  = min($maxwidth, $maxheight * $original_aspect_ratio);
3468
                $maxheight = min($maxheight, $maxwidth / $original_aspect_ratio);
3469
                //echo $maxwidth.'x'.$maxheight.'<hr>';
3470
            }
3471
3472
            $this->thumbnail_image_width  = $maxwidth;
3473
            $this->thumbnail_image_height = $maxheight;
3474
            $this->thumbnail_width        = $maxwidth;
3475
            $this->thumbnail_height       = $maxheight;
3476
3477
            $this->FixedAspectRatio();
3478
        }
3479
3480
        $this->thumbnail_width  = max(1, floor($this->thumbnail_width));
3481
        $this->thumbnail_height = max(1, floor($this->thumbnail_height));
3482
3483
        return true;
3484
    }
3485
3486
    /**
3487
     * @return bool
3488
     */
3489
    public function CreateGDoutput()
3490
    {
3491
        $this->CalculateThumbnailDimensions();
3492
3493
        // create the GD image (either true-color or 256-color, depending on GD version)
3494
        $this->gdimg_output = phpthumb_functions::ImageCreateFunction($this->thumbnail_width, $this->thumbnail_height);
3495
3496
        // images that have transparency must have the background filled with the configured 'bg' color otherwise the transparent color will appear as black
3497
        imagesavealpha($this->gdimg_output, true);
0 ignored issues
show
Bug introduced by
$this->gdimg_output of type boolean is incompatible with the type resource expected by parameter $image of imagesavealpha(). ( Ignorable by Annotation )

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

3497
        imagesavealpha(/** @scrutinizer ignore-type */ $this->gdimg_output, true);
Loading history...
3498
        if ($this->is_alpha && phpthumb_functions::gd_version() >= 2) {
3499
            imagealphablending($this->gdimg_output, false);
0 ignored issues
show
Bug introduced by
$this->gdimg_output of type boolean is incompatible with the type resource expected by parameter $image of imagealphablending(). ( Ignorable by Annotation )

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

3499
            imagealphablending(/** @scrutinizer ignore-type */ $this->gdimg_output, false);
Loading history...
3500
            $output_full_alpha = phpthumb_functions::ImageColorAllocateAlphaSafe($this->gdimg_output, 255, 255, 255, 127);
0 ignored issues
show
Bug introduced by
127 of type integer is incompatible with the type boolean expected by parameter $alpha of phpthumb_functions::ImageColorAllocateAlphaSafe(). ( Ignorable by Annotation )

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

3500
            $output_full_alpha = phpthumb_functions::ImageColorAllocateAlphaSafe($this->gdimg_output, 255, 255, 255, /** @scrutinizer ignore-type */ 127);
Loading history...
3501
            imagefilledrectangle($this->gdimg_output, 0, 0, $this->thumbnail_width, $this->thumbnail_height, $output_full_alpha);
3502
        } else {
3503
            $current_transparent_color = imagecolortransparent($this->gdimg_source);
3504
            if ($this->bg || (@$current_transparent_color >= 0)) {
3505
                $this->config_background_hexcolor = ($this->bg ?: $this->config_background_hexcolor);
3506
                if (!phpthumb_functions::IsHexColor($this->config_background_hexcolor)) {
3507
                    return $this->ErrorImage('Invalid hex color string "' . $this->config_background_hexcolor . '" for parameter "bg"');
3508
                }
3509
                $background_color = phpthumb_functions::ImageHexColorAllocate($this->gdimg_output, $this->config_background_hexcolor);
3510
                imagefilledrectangle($this->gdimg_output, 0, 0, $this->thumbnail_width, $this->thumbnail_height, $background_color);
3511
            }
3512
        }
3513
        $this->DebugMessage('CreateGDoutput() returning canvas "' . $this->thumbnail_width . 'x' . $this->thumbnail_height . '"', __FILE__, __LINE__);
3514
3515
        return true;
3516
    }
3517
3518
    /**
3519
     * @return bool
3520
     */
3521
    public function SetOrientationDependantWidthHeight()
3522
    {
3523
        $this->DebugMessage('SetOrientationDependantWidthHeight() starting with "' . $this->source_width . '"x"' . $this->source_height . '"', __FILE__, __LINE__);
3524
        if ($this->source_height > $this->source_width) {
3525
            // portrait
3526
            $this->w = phpthumb_functions::OneOfThese($this->wp, $this->w, $this->ws, $this->wl);
3527
            $this->h = phpthumb_functions::OneOfThese($this->hp, $this->h, $this->hs, $this->hl);
3528
        } elseif ($this->source_height < $this->source_width) {
3529
            // landscape
3530
            $this->w = phpthumb_functions::OneOfThese($this->wl, $this->w, $this->ws, $this->wp);
3531
            $this->h = phpthumb_functions::OneOfThese($this->hl, $this->h, $this->hs, $this->hp);
3532
        } else {
3533
            // square
3534
            $this->w = phpthumb_functions::OneOfThese($this->ws, $this->w, $this->wl, $this->wp);
3535
            $this->h = phpthumb_functions::OneOfThese($this->hs, $this->h, $this->hl, $this->hp);
3536
        }
3537
        //$this->w = round($this->w ? $this->w : (($this->h && $this->source_height) ? $this->h * $this->source_width  / $this->source_height : $this->w));
3538
        //$this->h = round($this->h ? $this->h : (($this->w && $this->source_width)  ? $this->w * $this->source_height / $this->source_width  : $this->h));
3539
        $this->DebugMessage('SetOrientationDependantWidthHeight() setting w="' . (int)$this->w . '", h="' . (int)$this->h . '"', __FILE__, __LINE__);
3540
3541
        return true;
3542
    }
3543
3544
    /**
3545
     * @return bool
3546
     */
3547
    public function ExtractEXIFgetImageSize()
3548
    {
3549
        $this->DebugMessage('starting ExtractEXIFgetImageSize()', __FILE__, __LINE__);
3550
3551
        if (preg_match('#^http:#i', $this->src) && !$this->sourceFilename && $this->rawImageData) {
3552
            $this->SourceDataToTempFile();
3553
        }
3554
        if (null === $this->getimagesizeinfo) {
3555
            if ($this->sourceFilename) {
3556
                $this->getimagesizeinfo = @getimagesize($this->sourceFilename);
3557
                $this->source_width     = $this->getimagesizeinfo[0];
3558
                $this->source_height    = $this->getimagesizeinfo[1];
3559
                $this->DebugMessage('getimagesize(' . $this->sourceFilename . ') says image is ' . $this->source_width . 'x' . $this->source_height, __FILE__, __LINE__);
3560
            } else {
3561
                $this->DebugMessage('skipping getimagesize() because $this->sourceFilename is empty', __FILE__, __LINE__);
3562
            }
3563
        } else {
3564
            $this->DebugMessage('skipping getimagesize() because !is_null($this->getimagesizeinfo)', __FILE__, __LINE__);
3565
        }
3566
3567
        if (is_resource($this->gdimg_source)) {
3568
            $this->source_width  = imagesx($this->gdimg_source);
3569
            $this->source_height = imagesy($this->gdimg_source);
3570
3571
            $this->SetOrientationDependantWidthHeight();
3572
        } elseif ($this->rawImageData && !$this->sourceFilename) {
3573
            if ($this->SourceImageIsTooLarge($this->source_width, $this->source_height)) {
3574
                $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__);
3575
            } else {
3576
                $this->DebugMessage('bypassing EXIF and getimagesize sections because $this->rawImageData is set, and $this->sourceFilename is not set, and source image is not too large for GD (' . $this->source_width . 'x' . $this->source_width . '=' . ($this->source_width
3577
                                                                                                                                                                                                                                                               * $this->source_height
3578
                                                                                                                                                                                                                                                               * 5) . 'MB)', __FILE__, __LINE__);
3579
            }
3580
        }
3581
3582
        if (null === $this->getimagesizeinfo) {
3583
            $this->getimagesizeinfo = @getimagesize($this->sourceFilename);
3584
        }
3585
3586
        if (!empty($this->getimagesizeinfo)) {
3587
            // great
3588
            $this->getimagesizeinfo['filesize'] = @filesize($this->sourceFilename);
3589
        } elseif (!$this->rawImageData) {
3590
            $this->DebugMessage('getimagesize("' . $this->sourceFilename . '") failed', __FILE__, __LINE__);
3591
        }
3592
3593
        if ($this->config_prefer_imagemagick) {
3594
            if ($this->ImageMagickThumbnailToGD()) {
3595
                return true;
3596
            }
3597
            $this->DebugMessage('ImageMagickThumbnailToGD() failed', __FILE__, __LINE__);
3598
        }
3599
3600
        $this->source_width  = $this->getimagesizeinfo[0];
3601
        $this->source_height = $this->getimagesizeinfo[1];
3602
3603
        $this->SetOrientationDependantWidthHeight();
3604
3605
        if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '4.2.0', '>=')
3606
            && function_exists('exif_read_data')) {
3607
            switch ($this->getimagesizeinfo[2]) {
3608
                case IMAGETYPE_JPEG:
3609
                case IMAGETYPE_TIFF_II:
3610
                case IMAGETYPE_TIFF_MM:
3611
                    $this->exif_raw_data = @exif_read_data($this->sourceFilename, 0, true);
3612
                    break;
3613
            }
3614
        }
3615
        if (function_exists('exif_thumbnail') && (IMAGETYPE_JPEG == $this->getimagesizeinfo[2])) {
3616
            // Extract EXIF info from JPEGs
3617
3618
            $this->exif_thumbnail_width  = '';
3619
            $this->exif_thumbnail_height = '';
3620
            $this->exif_thumbnail_type   = '';
3621
3622
            // The parameters width, height and imagetype are available since PHP v4.3.0
3623
            if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '4.3.0', '>=')) {
3624
                $this->exif_thumbnail_data = @exif_thumbnail($this->sourceFilename, $this->exif_thumbnail_width, $this->exif_thumbnail_height, $this->exif_thumbnail_type);
0 ignored issues
show
Bug introduced by
$this->exif_thumbnail_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

3624
                $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...
Bug introduced by
$this->exif_thumbnail_type of type string is incompatible with the type integer expected by parameter $imagetype of exif_thumbnail(). ( Ignorable by Annotation )

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

3624
                $this->exif_thumbnail_data = @exif_thumbnail($this->sourceFilename, $this->exif_thumbnail_width, $this->exif_thumbnail_height, /** @scrutinizer ignore-type */ $this->exif_thumbnail_type);
Loading history...
Bug introduced by
$this->exif_thumbnail_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

3624
                $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...
3625
            } else {
3626
3627
                // older versions of exif_thumbnail output an error message but NOT return false on failure
3628
                ob_start();
3629
                $this->exif_thumbnail_data = exif_thumbnail($this->sourceFilename);
3630
                $exit_thumbnail_error      = ob_get_contents();
3631
                ob_end_clean();
3632
                if (!$exit_thumbnail_error && $this->exif_thumbnail_data) {
3633
                    if ($gdimg_exif_temp = $this->ImageCreateFromStringReplacement($this->exif_thumbnail_data, false)) {
3634
                        $this->exif_thumbnail_width  = imagesx($gdimg_exif_temp);
3635
                        $this->exif_thumbnail_height = imagesy($gdimg_exif_temp);
3636
                        $this->exif_thumbnail_type   = 2; // (2 == JPEG) before PHP v4.3.0 only JPEG format EXIF thumbnails are returned
3637
                        unset($gdimg_exif_temp);
3638
                    } else {
3639
                        return $this->ErrorImage('Failed - $this->ImageCreateFromStringReplacement($this->exif_thumbnail_data) in ' . __FILE__ . ' on line ' . __LINE__);
3640
                    }
3641
                }
3642
            }
3643
        } elseif (!function_exists('exif_thumbnail')) {
3644
            $this->DebugMessage('exif_thumbnail() does not exist, cannot extract EXIF thumbnail', __FILE__, __LINE__);
3645
        }
3646
3647
        $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__);
3648
3649
        // see if EXIF thumbnail can be used directly with no processing
3650
        if ($this->config_use_exif_thumbnail_for_speed && $this->exif_thumbnail_data) {
3651
            while (true) {
3652
                if (!$this->xto) {
3653
                    $source_ar = $this->source_width / $this->source_height;
3654
                    $exif_ar   = $this->exif_thumbnail_width / $this->exif_thumbnail_height;
3655
                    if (number_format($source_ar, 2) != number_format($exif_ar, 2)) {
3656
                        $this->DebugMessage('not using EXIF thumbnail because $source_ar != $exif_ar (' . $source_ar . ' != ' . $exif_ar . ')', __FILE__, __LINE__);
3657
                        break;
3658
                    }
3659
                    if ($this->w && ($this->w != $this->exif_thumbnail_width)) {
3660
                        $this->DebugMessage('not using EXIF thumbnail because $this->w != $this->exif_thumbnail_width (' . $this->w . ' != ' . $this->exif_thumbnail_width . ')', __FILE__, __LINE__);
0 ignored issues
show
Bug introduced by
Are you sure $this->w 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

3660
                        $this->DebugMessage('not using EXIF thumbnail because $this->w != $this->exif_thumbnail_width (' . /** @scrutinizer ignore-type */ $this->w . ' != ' . $this->exif_thumbnail_width . ')', __FILE__, __LINE__);
Loading history...
3661
                        break;
3662
                    }
3663
                    if ($this->h && ($this->h != $this->exif_thumbnail_height)) {
3664
                        $this->DebugMessage('not using EXIF thumbnail because $this->h != $this->exif_thumbnail_height (' . $this->h . ' != ' . $this->exif_thumbnail_height . ')', __FILE__, __LINE__);
0 ignored issues
show
Bug introduced by
Are you sure $this->h 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

3664
                        $this->DebugMessage('not using EXIF thumbnail because $this->h != $this->exif_thumbnail_height (' . /** @scrutinizer ignore-type */ $this->h . ' != ' . $this->exif_thumbnail_height . ')', __FILE__, __LINE__);
Loading history...
3665
                        break;
3666
                    }
3667
                    $CannotBeSetParameters = ['sx', 'sy', 'sh', 'sw', 'far', 'bg', 'bc', 'fltr', 'phpThumbDebug'];
3668
                    foreach ($CannotBeSetParameters as $parameter) {
3669
                        if ($this->$parameter) {
3670
                            break 2;
3671
                        }
3672
                    }
3673
                }
3674
3675
                $this->DebugMessage('setting $this->gdimg_source = $this->ImageCreateFromStringReplacement($this->exif_thumbnail_data)', __FILE__, __LINE__);
3676
                $this->gdimg_source  = $this->ImageCreateFromStringReplacement($this->exif_thumbnail_data);
3677
                $this->source_width  = imagesx($this->gdimg_source);
3678
                $this->source_height = imagesy($this->gdimg_source);
3679
3680
                return true;
3681
            }
3682
        }
3683
3684
        if (($this->config_max_source_pixels > 0)
3685
            && (($this->source_width * $this->source_height) > $this->config_max_source_pixels)) {
3686
3687
            // Source image is larger than would fit in available PHP memory.
3688
            // If ImageMagick is installed, use it to generate the thumbnail.
3689
            // Else, if an EXIF thumbnail is available, use that as the source image.
3690
            // Otherwise, no choice but to fail with an error message
3691
            $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__);
3692
            if (!$this->config_prefer_imagemagick && $this->ImageMagickThumbnailToGD()) {
3693
                // excellent, we have a thumbnailed source image
3694
                return true;
3695
            }
3696
        }
3697
3698
        return true;
3699
    }
3700
3701
    /**
3702
     * @return bool
3703
     */
3704
    public function SetCacheFilename()
3705
    {
3706
        if (null !== $this->cache_filename) {
3707
            $this->DebugMessage('$this->cache_filename already set, skipping SetCacheFilename()', __FILE__, __LINE__);
3708
3709
            return true;
3710
        }
3711
        if (null === $this->config_cache_directory) {
3712
            $this->setCacheDirectory();
3713
            if (!$this->config_cache_directory) {
3714
                $this->DebugMessage('SetCacheFilename() failed because $this->config_cache_directory is empty', __FILE__, __LINE__);
3715
3716
                return false;
3717
            }
3718
        }
3719
        $this->setOutputFormat();
3720
3721
        if (!$this->sourceFilename && !$this->rawImageData && $this->src) {
3722
            $this->sourceFilename = $this->ResolveFilenameToAbsolute($this->src);
3723
        }
3724
3725
        if ($this->config_cache_default_only_suffix && $this->sourceFilename) {
3726
            // simplified cache filenames:
3727
            // only use default parameters in phpThumb.config.php
3728
            // substitute source filename into * in $this->config_cache_default_only_suffix
3729
            // (eg: '*_thumb' becomes 'picture_thumb.jpg')
3730
            if (false === strpos($this->config_cache_default_only_suffix, '*')) {
0 ignored issues
show
Bug introduced by
$this->config_cache_default_only_suffix of type true is incompatible with the type string expected by parameter $haystack of strpos(). ( Ignorable by Annotation )

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

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

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

3731
                $this->DebugMessage('aborting simplified caching filename because no * in "' . /** @scrutinizer ignore-type */ $this->config_cache_default_only_suffix . '"', __FILE__, __LINE__);
Loading history...
3732
            } else {
3733
                preg_match('#(.+)(\\.[a-z0-9]+)?$#i', basename($this->sourceFilename), $matches);
3734
                $this->cache_filename = $this->config_cache_directory . DIRECTORY_SEPARATOR . rawurlencode(str_replace('*', @$matches[1], $this->config_cache_default_only_suffix)) . '.' . strtolower($this->thumbnailFormat);
3735
3736
                return true;
3737
            }
3738
        }
3739
3740
        $this->cache_filename = '';
3741
        if ($this->new) {
3742
            $broad_directory_name = strtolower(md5($this->new));
3743
            $this->cache_filename .= '_new' . $broad_directory_name;
3744
        } elseif ($this->md5s) {
3745
            // source image MD5 hash provided
3746
            $this->DebugMessage('SetCacheFilename() _raw set from $this->md5s = "' . $this->md5s . '"', __FILE__, __LINE__);
3747
            $broad_directory_name = $this->md5s;
3748
            $this->cache_filename .= '_raw' . $this->md5s;
3749
        } elseif (!$this->src && $this->rawImageData) {
3750
            $this->DebugMessage('SetCacheFilename() _raw set from md5($this->rawImageData) = "' . md5($this->rawImageData) . '"', __FILE__, __LINE__);
3751
            $broad_directory_name = strtolower(md5($this->rawImageData));
3752
            $this->cache_filename .= '_raw' . $broad_directory_name;
3753
        } else {
3754
            $this->DebugMessage('SetCacheFilename() _src set from md5($this->sourceFilename) "' . $this->sourceFilename . '" = "' . md5($this->sourceFilename) . '"', __FILE__, __LINE__);
3755
            $broad_directory_name = strtolower(md5($this->sourceFilename));
3756
            $this->cache_filename .= '_src' . $broad_directory_name;
3757
        }
3758
        if (!empty($_SERVER['HTTP_REFERER']) && $this->config_nooffsitelink_enabled) {
3759
            $parsed_url1 = @phpthumb_functions::ParseURLbetter(@$_SERVER['HTTP_REFERER']);
3760
            $parsed_url2 = @phpthumb_functions::ParseURLbetter('http://' . @$_SERVER['HTTP_HOST']);
3761
            if (@$parsed_url1['host'] && @$parsed_url2['host'] && ($parsed_url1['host'] != $parsed_url2['host'])) {
3762
                // include "_offsite" only if nooffsitelink_enabled and if referrer doesn't match the domain of the current server
3763
                $this->cache_filename .= '_offsite';
3764
            }
3765
        }
3766
3767
        $ParametersString = '';
3768
        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...
3769
            $ParametersString .= '_fltr' . implode('_fltr', $this->fltr);
3770
        }
3771
        $FilenameParameters1 = ['ar', 'bg', 'bc', 'far', 'sx', 'sy', 'sw', 'sh', 'zc'];
3772
        foreach ($FilenameParameters1 as $key) {
3773
            if ($this->$key) {
3774
                $ParametersString .= '_' . $key . $this->$key;
3775
            }
3776
        }
3777
        $FilenameParameters2 = [
3778
            'h',
3779
            'w',
3780
            'wl',
3781
            'wp',
3782
            'ws',
3783
            'hp',
3784
            'hs',
3785
            'xto',
3786
            'ra',
3787
            'iar',
3788
            'aoe',
3789
            'maxb',
3790
            'sfn',
3791
            'dpi'
3792
        ];
3793
        foreach ($FilenameParameters2 as $key) {
3794
            if ($this->$key) {
3795
                $ParametersString .= '_' . $key . (int)$this->$key;
3796
            }
3797
        }
3798
        if ('jpeg' === $this->thumbnailFormat) {
3799
            // only JPEG output has variable quality option
3800
            $ParametersString .= '_q' . (int)$this->thumbnailQuality;
3801
        }
3802
        $this->DebugMessage('SetCacheFilename() _par set from md5(' . $ParametersString . ')', __FILE__, __LINE__);
3803
        $this->cache_filename .= '_par' . strtolower(md5($ParametersString));
3804
3805
        if ($this->md5s) {
3806
            // source image MD5 hash provided
3807
            // do not source image modification date --
3808
            // cached image will be used even if file was modified or removed
3809
        } elseif (!$this->config_cache_source_filemtime_ignore_remote && preg_match('#^(f|ht)tps?\://#i', $this->src)) {
3810
            $this->cache_filename .= '_dat' . (int)phpthumb_functions::filedate_remote($this->src);
3811
        } elseif (!$this->config_cache_source_filemtime_ignore_local && $this->src && !$this->rawImageData) {
3812
            $this->cache_filename .= '_dat' . (int)(@filemtime($this->sourceFilename));
3813
        }
3814
3815
        $this->cache_filename .= '.' . strtolower($this->thumbnailFormat);
3816
        $broad_directories    = '';
3817
        for ($i = 0; $i < $this->config_cache_directory_depth; $i++) {
3818
            $broad_directories .= DIRECTORY_SEPARATOR . substr($broad_directory_name, 0, $i + 1);
3819
        }
3820
3821
        $this->cache_filename = $this->config_cache_directory . $broad_directories . DIRECTORY_SEPARATOR . $this->config_cache_prefix . rawurlencode($this->cache_filename);
3822
3823
        return true;
3824
    }
3825
3826
    /**
3827
     * @param $width
3828
     * @param $height
3829
     * @return bool
3830
     */
3831
    public function SourceImageIsTooLarge($width, $height)
3832
    {
3833
        if (!$this->config_max_source_pixels) {
3834
            return false;
3835
        }
3836
        if ($this->php_memory_limit && function_exists('memory_get_usage')) {
3837
            $available_memory = $this->php_memory_limit - memory_get_usage();
3838
3839
            return (($width * $height * 5) > $available_memory);
3840
        }
3841
3842
        return (($width * $height) > $this->config_max_source_pixels);
3843
    }
3844
3845
    /**
3846
     * @param $filename
3847
     * @return bool|resource
3848
     */
3849
    public function ImageCreateFromFilename($filename)
3850
    {
3851
        // try to create GD image source directly via GD, if possible,
3852
        // rather than buffering to memory and creating with imagecreatefromstring
3853
        $ImageCreateWasAttempted = false;
3854
        $gd_image                = false;
3855
3856
        $this->DebugMessage('starting ImageCreateFromFilename(' . $filename . ')', __FILE__, __LINE__);
3857
        if ($filename && ($getimagesizeinfo = @getimagesize($filename))) {
3858
            if (!$this->SourceImageIsTooLarge($getimagesizeinfo[0], $getimagesizeinfo[1])) {
3859
                $ImageCreateFromFunction = [
3860
                    1  => 'imagecreatefromgif',
3861
                    2  => 'imagecreatefromjpeg',
3862
                    3  => 'imagecreatefrompng',
3863
                    15 => 'imagecreatefromwbmp',
3864
                ];
3865
                $this->DebugMessage('ImageCreateFromFilename found ($getimagesizeinfo[2]==' . @$getimagesizeinfo[2] . ')', __FILE__, __LINE__);
3866
                switch (@$getimagesizeinfo[2]) {
3867
                    case 1:  // GIF
3868
                    case 2:  // JPEG
3869
                    case 3:  // PNG
3870
                    case 15: // WBMP
3871
                        $ImageCreateFromFunctionName = $ImageCreateFromFunction[$getimagesizeinfo[2]];
3872
                        if (function_exists($ImageCreateFromFunctionName)) {
3873
                            $this->DebugMessage('Calling ' . $ImageCreateFromFunctionName . '(' . $filename . ')', __FILE__, __LINE__);
3874
                            $ImageCreateWasAttempted = true;
3875
                            $gd_image                = $ImageCreateFromFunctionName($filename);
3876
                        } else {
3877
                            $this->DebugMessage('NOT calling ' . $ImageCreateFromFunctionName . '(' . $filename . ') because !function_exists(' . $ImageCreateFromFunctionName . ')', __FILE__, __LINE__);
3878
                        }
3879
                        break;
3880
3881
                    case 4:  // SWF
3882
                    case 5:  // PSD
3883
                    case 6:  // BMP
3884
                    case 7:  // TIFF (LE)
3885
                    case 8:  // TIFF (BE)
3886
                    case 9:  // JPC
3887
                    case 10: // JP2
3888
                    case 11: // JPX
3889
                    case 12: // JB2
3890
                    case 13: // SWC
3891
                    case 14: // IFF
3892
                    case 16: // XBM
3893
                        $this->DebugMessage('No built-in image creation function for image type "' . @$getimagesizeinfo[2] . '" ($getimagesizeinfo[2])', __FILE__, __LINE__);
3894
                        break;
3895
3896
                    default:
3897
                        $this->DebugMessage('Unknown value for $getimagesizeinfo[2]: "' . @$getimagesizeinfo[2] . '"', __FILE__, __LINE__);
3898
                        break;
3899
                }
3900
            } else {
3901
                $this->DebugMessage(
3902
                    '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 . ')',
3903
                    __FILE__,
3904
                                    __LINE__
3905
                );
3906
3907
                return false;
3908
            }
3909
        } else {
3910
            $this->DebugMessage('empty $filename or getimagesize(' . $filename . ') failed', __FILE__, __LINE__);
3911
        }
3912
3913
        if (!$gd_image) {
3914
            // cannot create from filename, attempt to create source image with imagecreatefromstring, if possible
3915
            if ($ImageCreateWasAttempted) {
3916
                $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...
3917
            }
3918
            $this->DebugMessage('Populating $rawimagedata', __FILE__, __LINE__);
3919
            $rawimagedata = '';
3920
            if ($fp = @fopen($filename, 'rb')) {
3921
                $filesize   = filesize($filename);
3922
                $blocksize  = 8192;
3923
                $blockreads = ceil($filesize / $blocksize);
3924
                for ($i = 0; $i < $blockreads; $i++) {
3925
                    $rawimagedata .= fread($fp, $blocksize);
3926
                }
3927
                fclose($fp);
3928
            } else {
3929
                $this->DebugMessage('cannot fopen(' . $filename . ')', __FILE__, __LINE__);
3930
            }
3931
            if ($rawimagedata) {
3932
                $this->DebugMessage('attempting ImageCreateFromStringReplacement($rawimagedata (' . strlen($rawimagedata) . ' bytes), true)', __FILE__, __LINE__);
3933
                $gd_image = $this->ImageCreateFromStringReplacement($rawimagedata, true);
3934
            }
3935
        }
3936
3937
        return $gd_image;
3938
    }
3939
3940
    /**
3941
     * @return bool
3942
     */
3943
    public function SourceImageToGD()
3944
    {
3945
        if (is_resource($this->gdimg_source)) {
3946
            $this->source_width  = imagesx($this->gdimg_source);
3947
            $this->source_height = imagesy($this->gdimg_source);
3948
            $this->DebugMessage('skipping SourceImageToGD() because $this->gdimg_source is already a resource (' . $this->source_width . 'x' . $this->source_height . ')', __FILE__, __LINE__);
3949
3950
            return true;
3951
        }
3952
        $this->DebugMessage('starting SourceImageToGD()', __FILE__, __LINE__);
3953
3954
        if ($this->config_prefer_imagemagick) {
3955
            if (empty($this->sourceFilename) && !empty($this->rawImageData)) {
3956
                $this->DebugMessage('Copying raw image data to temp file and trying again with ImageMagick', __FILE__, __LINE__);
3957
                if ($tempnam = $this->phpThumb_tempnam()) {
3958
                    if (file_put_contents($tempnam, $this->rawImageData)) {
3959
                        $this->sourceFilename = $tempnam;
3960
                        if ($this->ImageMagickThumbnailToGD()) {
3961
                            // excellent, we have a thumbnailed source image
3962
                            $this->DebugMessage('ImageMagickThumbnailToGD() succeeded', __FILE__, __LINE__);
3963
                        } else {
3964
                            $this->DebugMessage('ImageMagickThumbnailToGD() failed', __FILE__, __LINE__);
3965
                        }
3966
                    } else {
3967
                        $this->DebugMessage('failed to put $this->rawImageData into temp file "' . $tempnam . '"', __FILE__, __LINE__);
3968
                    }
3969
                } else {
3970
                    $this->DebugMessage('failed to generate temp file name', __FILE__, __LINE__);
3971
                }
3972
            }
3973
        }
3974
        if (!$this->gdimg_source && $this->rawImageData) {
3975
            if ($this->SourceImageIsTooLarge($this->source_width, $this->source_height)) {
3976
                $memory_get_usage = (function_exists('memory_get_usage') ? memory_get_usage() : 0);
3977
3978
                return $this->ErrorImage('Source image is too large ('
3979
                                         . $this->source_width
3980
                                         . 'x'
3981
                                         . $this->source_height
3982
                                         . ' = '
3983
                                         . number_format($this->source_width * $this->source_height / 1000000, 1)
3984
                                         . 'Mpx, max='
3985
                                         . number_format($this->config_max_source_pixels / 1000000, 1)
3986
                                         . 'Mpx) for GD creation (either install ImageMagick or increase PHP memory_limit to at least '
3987
                                         . ceil(($memory_get_usage + (5 * $this->source_width * $this->source_height)) / 1048576)
3988
                                         . 'M).');
3989
            }
3990
            if ($this->md5s && ($this->md5s != md5($this->rawImageData))) {
3991
                return $this->ErrorImage('$this->md5s != md5($this->rawImageData)' . "\n" . '"' . $this->md5s . '" != ' . "\n" . '"' . md5($this->rawImageData) . '"');
3992
            }
3993
            //if ($this->issafemode) {
3994
            //	return $this->ErrorImage('Cannot generate thumbnails from raw image data when PHP SAFE_MODE enabled');
3995
            //}
3996
            $this->gdimg_source = $this->ImageCreateFromStringReplacement($this->rawImageData);
3997
            if (!$this->gdimg_source) {
3998
                if ('BM' === substr($this->rawImageData, 0, 2)) {
3999
                    $this->getimagesizeinfo[2] = 6; // BMP
4000
                } elseif (substr($this->rawImageData, 0, 4) === 'II' . "\x2A\x00") {
4001
                    $this->getimagesizeinfo[2] = 7; // TIFF (littlendian)
4002
                } elseif (substr($this->rawImageData, 0, 4) === 'MM' . "\x00\x2A") {
4003
                    $this->getimagesizeinfo[2] = 8; // TIFF (bigendian)
4004
                }
4005
                $this->DebugMessage('SourceImageToGD.ImageCreateFromStringReplacement() failed with unknown image type "' . substr($this->rawImageData, 0, 4) . '" (' . phpthumb_functions::HexCharDisplay(substr($this->rawImageData, 0, 4)) . ')', __FILE__, __LINE__);
4006
                //				return $this->ErrorImage('Unknown image type identified by "'.substr($this->rawImageData, 0, 4).'" ('.phpthumb_functions::HexCharDisplay(substr($this->rawImageData, 0, 4)).') in SourceImageToGD()['.__LINE__.']');
4007
            }
4008
        } elseif (!$this->gdimg_source && $this->sourceFilename) {
4009
            if ($this->md5s && ($this->md5s != phpthumb_functions::md5_file_safe($this->sourceFilename))) {
4010
                return $this->ErrorImage('$this->md5s != md5(sourceFilename)' . "\n" . '"' . $this->md5s . '" != ' . "\n" . '"' . phpthumb_functions::md5_file_safe($this->sourceFilename) . '"');
0 ignored issues
show
Bug introduced by
Are you sure phpthumb_functions::md5_...($this->sourceFilename) of type false|string can be used in concatenation? ( Ignorable by Annotation )

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

4010
                return $this->ErrorImage('$this->md5s != md5(sourceFilename)' . "\n" . '"' . $this->md5s . '" != ' . "\n" . '"' . /** @scrutinizer ignore-type */ phpthumb_functions::md5_file_safe($this->sourceFilename) . '"');
Loading history...
4011
            }
4012
            switch (@$this->getimagesizeinfo[2]) {
4013
                case 1:
4014
                case 3:
4015
                    // GIF or PNG input file may have transparency
4016
                    $this->is_alpha = true;
4017
                    break;
4018
            }
4019
            if (!$this->SourceImageIsTooLarge($this->source_width, $this->source_height)) {
4020
                $this->gdimg_source = $this->ImageCreateFromFilename($this->sourceFilename);
4021
            }
4022
        }
4023
4024
        while (true) {
4025
            if ($this->gdimg_source) {
4026
                $this->DebugMessage('Not using EXIF thumbnail data because $this->gdimg_source is already set', __FILE__, __LINE__);
4027
                break;
4028
            }
4029
            if (!$this->exif_thumbnail_data) {
4030
                $this->DebugMessage('Not using EXIF thumbnail data because $this->exif_thumbnail_data is empty', __FILE__, __LINE__);
4031
                break;
4032
            }
4033
            if (ini_get('safe_mode')) {
4034
                if (!$this->SourceImageIsTooLarge($this->source_width, $this->source_height)) {
4035
                    $this->DebugMessage('Using EXIF thumbnail data because source image too large and safe_mode enabled', __FILE__, __LINE__);
4036
                    $this->aoe = true;
4037
                } else {
4038
                    break;
4039
                }
4040
            } else {
4041
                if (!$this->config_use_exif_thumbnail_for_speed) {
4042
                    $this->DebugMessage('Not using EXIF thumbnail data because $this->config_use_exif_thumbnail_for_speed is FALSE', __FILE__, __LINE__);
4043
                    break;
4044
                }
4045
                if ((0 != $this->thumbnailCropX) || (0 != $this->thumbnailCropY)) {
4046
                    $this->DebugMessage('Not using EXIF thumbnail data because source cropping is enabled (' . $this->thumbnailCropX . ',' . $this->thumbnailCropY . ')', __FILE__, __LINE__);
4047
                    break;
4048
                }
4049
                if (($this->w > $this->exif_thumbnail_width) || ($this->h > $this->exif_thumbnail_height)) {
4050
                    $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__);
4051
                    break;
4052
                }
4053
                $source_ar = $this->source_width / $this->source_height;
4054
                $exif_ar   = $this->exif_thumbnail_width / $this->exif_thumbnail_height;
4055
                if (number_format($source_ar, 2) != number_format($exif_ar, 2)) {
4056
                    $this->DebugMessage('not using EXIF thumbnail because $source_ar != $exif_ar (' . $source_ar . ' != ' . $exif_ar . ')', __FILE__, __LINE__);
4057
                    break;
4058
                }
4059
            }
4060
4061
            // EXIF thumbnail exists, and is equal to or larger than destination thumbnail, and will be use as source image
4062
            $this->DebugMessage('Trying to use EXIF thumbnail as source image', __FILE__, __LINE__);
4063
4064
            if ($gdimg_exif_temp = $this->ImageCreateFromStringReplacement($this->exif_thumbnail_data, false)) {
4065
                $this->DebugMessage('Successfully using EXIF thumbnail as source image', __FILE__, __LINE__);
4066
                $this->gdimg_source   = $gdimg_exif_temp;
4067
                $this->source_width   = $this->exif_thumbnail_width;
4068
                $this->source_height  = $this->exif_thumbnail_height;
4069
                $this->thumbnailCropW = $this->source_width;
4070
                $this->thumbnailCropH = $this->source_height;
4071
4072
                return true;
4073
            } else {
4074
                $this->DebugMessage('$this->ImageCreateFromStringReplacement($this->exif_thumbnail_data, false) failed', __FILE__, __LINE__);
4075
            }
4076
4077
            break;
4078
        }
4079
4080
        if (!$this->gdimg_source) {
4081
            $this->DebugMessage('$this->gdimg_source is still empty', __FILE__, __LINE__);
4082
4083
            $this->DebugMessage('ImageMagickThumbnailToGD() failed', __FILE__, __LINE__);
4084
4085
            $imageHeader   = '';
4086
            $gd_info       = gd_info();
4087
            $GDreadSupport = false;
4088
            switch (@$this->getimagesizeinfo[2]) {
4089
                case 1:
4090
                    $imageHeader   = 'Content-Type: image/gif';
4091
                    $GDreadSupport = (bool)@$gd_info['GIF Read Support'];
4092
                    break;
4093
                case 2:
4094
                    $imageHeader   = 'Content-Type: image/jpeg';
4095
                    $GDreadSupport = (bool)@$gd_info['JPG Support'];
4096
                    break;
4097
                case 3:
4098
                    $imageHeader   = 'Content-Type: image/png';
4099
                    $GDreadSupport = (bool)@$gd_info['PNG Support'];
4100
                    break;
4101
            }
4102
            if ($imageHeader) {
4103
                // cannot create image for whatever reason (maybe imagecreatefromjpeg et al are not available?)
4104
                // and ImageMagick is not available either, no choice but to output original (not resized/modified) data and exit
4105
                if ($this->config_error_die_on_source_failure) {
4106
                    $errormessages   = [];
4107
                    $errormessages[] = 'All attempts to create GD image source failed.';
4108
                    if ($this->fatalerror) {
4109
                        $errormessages[] = $this->fatalerror;
4110
                    }
4111
                    if ($this->issafemode) {
4112
                        $errormessages[] = 'Safe Mode enabled, therefore ImageMagick is unavailable. (disable Safe Mode if possible)';
4113
                    } elseif (!$this->ImageMagickVersion()) {
4114
                        $errormessages[] = 'ImageMagick is not installed (it is highly recommended that you install it).';
4115
                    }
4116
                    if ($this->SourceImageIsTooLarge($this->getimagesizeinfo[0], $this->getimagesizeinfo[1])) {
4117
                        $memory_get_usage = (function_exists('memory_get_usage') ? memory_get_usage() : 0);
4118
                        $errormessages[]  = 'Source image is too large ('
4119
                                            . $this->getimagesizeinfo[0]
4120
                                            . 'x'
4121
                                            . $this->getimagesizeinfo[1]
4122
                                            . ' = '
4123
                                            . number_format($this->getimagesizeinfo[0] * $this->getimagesizeinfo[1] / 1000000, 1)
4124
                                            . 'Mpx, max='
4125
                                            . number_format($this->config_max_source_pixels
4126
                                                            / 1000000, 1)
4127
                                            . 'Mpx) for GD creation (either install ImageMagick or increase PHP memory_limit to at least '
4128
                                            . ceil(($memory_get_usage + (5 * $this->getimagesizeinfo[0] * $this->getimagesizeinfo[1])) / 1048576)
4129
                                            . 'M).';
4130
                    } elseif (!$GDreadSupport) {
4131
                        $errormessages[] = 'GD does not have read support for "' . $imageHeader . '".';
4132
                    } else {
4133
                        $errormessages[] = 'Source image probably corrupt.';
4134
                    }
4135
                    $this->ErrorImage(implode("\n", $errormessages));
4136
                } else {
4137
                    $this->DebugMessage('All attempts to create GD image source failed (' . (ini_get('safe_mode') ? 'Safe Mode enabled, ImageMagick unavailable and source image probably too large for GD' : ($GDreadSupport ? 'source image probably corrupt' : 'GD does not have read support for "'
4138
                                                                                                                                                                                                                                                                  . $imageHeader
4139
                                                                                                                                                                                                                                                                  . '"')) . '), cannot generate thumbnail');
4140
                    //$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__);
4141
                    //if (!$this->phpThumbDebug) {
4142
                    //	header($imageHeader);
4143
                    //	echo $this->rawImageData;
4144
                    //	exit;
4145
                    //}
4146
                    return false;
4147
                }
4148
            }
4149
4150
            //switch (substr($this->rawImageData, 0, 2)) {
4151
            //	case 'BM':
4152
            switch (@$this->getimagesizeinfo[2]) {
4153
                case 6:
4154
                    ob_start();
4155
                    if (!@require_once __DIR__ . '/phpthumb.bmp.php') {
4156
                        ob_end_clean();
4157
4158
                        return $this->ErrorImage('include_once(' . __DIR__ . '/phpthumb.bmp.php) failed');
4159
                    }
4160
                    ob_end_clean();
4161
                    if ($fp = @fopen($this->sourceFilename, 'rb')) {
4162
                        $this->rawImageData = '';
4163
                        while (!feof($fp)) {
4164
                            $this->rawImageData .= fread($fp, 32768);
4165
                        }
4166
                        fclose($fp);
4167
                    }
4168
                    $phpthumb_bmp       = new phpthumb_bmp();
4169
                    $this->gdimg_source = $phpthumb_bmp->phpthumb_bmp2gd($this->rawImageData, phpthumb_functions::gd_version() >= 2.0);
4170
                    unset($phpthumb_bmp);
4171
                    if ($this->gdimg_source) {
4172
                        $this->DebugMessage('$phpthumb_bmp->phpthumb_bmp2gd() succeeded', __FILE__, __LINE__);
4173
                    } else {
4174
                        return $this->ErrorImage($this->ImageMagickVersion() ? 'ImageMagick failed on BMP source conversion' : 'phpthumb_bmp2gd() failed');
4175
                    }
4176
                    break;
4177
                //}
4178
                //switch (substr($this->rawImageData, 0, 4)) {
4179
                //	case 'II'."\x2A\x00":
4180
                //	case 'MM'."\x00\x2A":
4181
                case 7:
4182
                case 8:
4183
                    return $this->ErrorImage($this->ImageMagickVersion() ? 'ImageMagick failed on TIFF source conversion' : 'ImageMagick is unavailable and phpThumb() does not support TIFF source images without it');
4184
                    break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

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

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

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

Loading history...
4185
4186
                //case "\xD7\xCD\xC6\x9A":
4187
                //	return $this->ErrorImage($this->ImageMagickVersion() ? 'ImageMagick failed on WMF source conversion' : 'ImageMagick is unavailable and phpThumb() does not support WMF source images without it');
4188
                //	break;
4189
            }
4190
4191
            if (!$this->gdimg_source) {
4192
                if ($this->rawImageData) {
4193
                    $HeaderFourBytes = substr($this->rawImageData, 0, 4);
4194
                } elseif ($this->sourceFilename) {
4195
                    if ($fp = @fopen($this->sourceFilename, 'rb')) {
4196
                        $HeaderFourBytes = fread($fp, 4);
4197
                        fclose($fp);
4198
                    } else {
4199
                        return $this->ErrorImage('failed to open "' . $this->sourceFilename . '" SourceImageToGD() [' . __LINE__ . ']');
4200
                    }
4201
                } else {
4202
                    return $this->ErrorImage('Unable to create image, neither filename nor image data suppplied in SourceImageToGD() [' . __LINE__ . ']');
4203
                }
4204
                if (!$this->ImageMagickVersion() && !phpthumb_functions::gd_version()) {
4205
                    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.');
4206
                } elseif ("\xD7\xCD\xC6\x9A" === $HeaderFourBytes) { // WMF
4207
                    return $this->ErrorImage($this->ImageMagickVersion() ? 'ImageMagick failed on WMF source conversion' : 'ImageMagick is unavailable and phpThumb() does not support WMF source images without it');
4208
                } elseif ('%PDF' === $HeaderFourBytes) { // "%PDF"
4209
                    return $this->ErrorImage($this->ImageMagickVersion() ? 'ImageMagick and GhostScript are both required for PDF source images; GhostScript may not be properly configured' : 'ImageMagick and/or GhostScript are unavailable and phpThumb() does not support PDF source images without them');
4210
                } elseif ("\xFF\xD8\xFF" === substr($HeaderFourBytes, 0, 3)) { // JPEG
4211
                    return $this->ErrorImage('Image (JPEG) is too large for PHP-GD memory_limit, please install ImageMagick or increase php.ini memory_limit setting');
4212
                } elseif ('%PNG' === $HeaderFourBytes) { // "%PNG"
4213
                    return $this->ErrorImage('Image (PNG) is too large for PHP-GD memory_limit, please install ImageMagick or increase php.ini memory_limit setting');
4214
                } elseif ('GIF' === substr($HeaderFourBytes, 0, 3)) { // GIF
4215
                    return $this->ErrorImage('Image (GIF) is too large for PHP-GD memory_limit, please install ImageMagick or increase php.ini memory_limit setting');
4216
                }
4217
4218
                return $this->ErrorImage('Unknown image type identified by "' . $HeaderFourBytes . '" (' . phpthumb_functions::HexCharDisplay($HeaderFourBytes) . ') in SourceImageToGD() [' . __LINE__ . ']');
4219
            }
4220
        }
4221
4222
        if (!$this->gdimg_source) {
4223
            if ($gdimg_exif_temp = $this->ImageCreateFromStringReplacement($this->exif_thumbnail_data, false)) {
4224
                $this->DebugMessage('All other attempts failed, but successfully using EXIF thumbnail as source image', __FILE__, __LINE__);
4225
                $this->gdimg_source = $gdimg_exif_temp;
4226
                // override allow-enlarging setting if EXIF thumbnail is the only source available
4227
                // otherwise thumbnails larger than the EXIF thumbnail will be created at EXIF size
4228
                $this->aoe = true;
4229
4230
                return true;
4231
            }
4232
4233
            return false;
4234
        }
4235
4236
        $this->source_width  = imagesx($this->gdimg_source);
4237
        $this->source_height = imagesy($this->gdimg_source);
4238
4239
        return true;
4240
    }
4241
4242
    /**
4243
     * @param $var
4244
     * @return string
4245
     */
4246
    public function phpThumbDebugVarDump($var)
4247
    {
4248
        if (null === $var) {
4249
            return 'NULL';
4250
        } elseif (is_bool($var)) {
4251
            return ($var ? 'TRUE' : 'FALSE');
4252
        } elseif (is_string($var)) {
4253
            return 'string(' . strlen($var) . ')' . str_repeat(' ', max(0, 3 - strlen(strlen($var)))) . ' "' . $var . '"';
4254
        } elseif (is_int($var)) {
4255
            return 'integer     ' . $var;
4256
        } elseif (is_float($var)) {
4257
            return 'float       ' . $var;
4258
        } elseif (is_array($var)) {
4259
            ob_start();
4260
            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...
4261
            $vardumpoutput = ob_get_contents();
4262
            ob_end_clean();
4263
4264
            return strtr($vardumpoutput, "\n\r\t", '   ');
4265
        }
4266
4267
        return gettype($var);
4268
    }
4269
4270
    /**
4271
     * @param string $level
4272
     * @return bool
4273
     */
4274
    public function phpThumbDebug($level = '')
4275
    {
4276
        if ($level && ($this->phpThumbDebug !== $level)) {
4277
            return true;
4278
        }
4279
        if ($this->config_disable_debug) {
4280
            return $this->ErrorImage('phpThumbDebug disabled');
4281
        }
4282
4283
        $FunctionsExistance  = [
4284
            'exif_thumbnail',
4285
            'gd_info',
4286
            'image_type_to_mime_type',
4287
            'getimagesize',
4288
            'imagecopyresampled',
4289
            'imagecopyresized',
4290
            'imagecreate',
4291
            'imagecreatefromstring',
4292
            'imagecreatetruecolor',
4293
            'imageistruecolor',
4294
            'imagerotate',
4295
            'imagetypes',
4296
            'version_compare',
4297
            'imagecreatefromgif',
4298
            'imagecreatefromjpeg',
4299
            'imagecreatefrompng',
4300
            'imagecreatefromwbmp',
4301
            'imagecreatefromxbm',
4302
            'imagecreatefromxpm',
4303
            'imagecreatefromstring',
4304
            'imagecreatefromgd',
4305
            'imagecreatefromgd2',
4306
            'imagecreatefromgd2part',
4307
            'imagejpeg',
4308
            'imagegif',
4309
            'imagepng',
4310
            'imagewbmp'
4311
        ];
4312
        $ParameterNames      = [
4313
            'src',
4314
            'new',
4315
            'w',
4316
            'h',
4317
            'f',
4318
            'q',
4319
            'sx',
4320
            'sy',
4321
            'sw',
4322
            'sh',
4323
            'far',
4324
            'bg',
4325
            'bc',
4326
            'file',
4327
            'goto',
4328
            'err',
4329
            'xto',
4330
            'ra',
4331
            'ar',
4332
            'aoe',
4333
            'iar',
4334
            'maxb'
4335
        ];
4336
        $ConfigVariableNames = [
4337
            'document_root',
4338
            'temp_directory',
4339
            'output_format',
4340
            'output_maxwidth',
4341
            'output_maxheight',
4342
            'error_message_image_default',
4343
            'error_bgcolor',
4344
            'error_textcolor',
4345
            'error_fontsize',
4346
            'error_die_on_error',
4347
            'error_silent_die_on_error',
4348
            'error_die_on_source_failure',
4349
            'nohotlink_enabled',
4350
            'nohotlink_valid_domains',
4351
            'nohotlink_erase_image',
4352
            'nohotlink_text_message',
4353
            'nooffsitelink_enabled',
4354
            'nooffsitelink_valid_domains',
4355
            'nooffsitelink_require_refer',
4356
            'nooffsitelink_erase_image',
4357
            'nooffsitelink_text_message',
4358
            'high_security_enabled',
4359
            'allow_src_above_docroot',
4360
            'allow_src_above_phpthumb',
4361
            'max_source_pixels',
4362
            'use_exif_thumbnail_for_speed',
4363
            'border_hexcolor',
4364
            'background_hexcolor',
4365
            'ttf_directory',
4366
            'disable_pathinfo_parsing',
4367
            'disable_imagecopyresampled'
4368
        ];
4369
        $OtherVariableNames  = [
4370
            'phpThumbDebug',
4371
            'thumbnailQuality',
4372
            'thumbnailFormat',
4373
            'gdimg_output',
4374
            'gdimg_source',
4375
            'sourceFilename',
4376
            'source_width',
4377
            'source_height',
4378
            'thumbnailCropX',
4379
            'thumbnailCropY',
4380
            'thumbnailCropW',
4381
            'thumbnailCropH',
4382
            'exif_thumbnail_width',
4383
            'exif_thumbnail_height',
4384
            'exif_thumbnail_type',
4385
            'thumbnail_width',
4386
            'thumbnail_height',
4387
            'thumbnail_image_width',
4388
            'thumbnail_image_height'
4389
        ];
4390
4391
        $DebugOutput   = [];
4392
        $DebugOutput[] = 'phpThumb() version          = ' . $this->phpthumb_version;
4393
        $DebugOutput[] = 'PHP_VERSION                = ' . @PHP_VERSION;
4394
        $DebugOutput[] = 'PHP_OS                      = ' . PHP_OS;
4395
        $DebugOutput[] = '$_SERVER[SERVER_SOFTWARE]   = ' . @$_SERVER['SERVER_SOFTWARE'];
4396
        $DebugOutput[] = '__FILE__                    = ' . __FILE__;
4397
        $DebugOutput[] = 'realpath(.)                 = ' . @realpath('.');
4398
        $DebugOutput[] = '$_SERVER[PHP_SELF]          = ' . @$_SERVER['PHP_SELF'];
4399
        $DebugOutput[] = '$_SERVER[HOST_NAME]         = ' . @$_SERVER['HOST_NAME'];
4400
        $DebugOutput[] = '$_SERVER[HTTP_REFERER]      = ' . @$_SERVER['HTTP_REFERER'];
4401
        $DebugOutput[] = '$_SERVER[QUERY_STRING]      = ' . @$_SERVER['QUERY_STRING'];
4402
        $DebugOutput[] = '$_SERVER[PATH_INFO]         = ' . @$_SERVER['PATH_INFO'];
4403
        $DebugOutput[] = '$_SERVER[DOCUMENT_ROOT]     = ' . @$_SERVER['DOCUMENT_ROOT'];
4404
        $DebugOutput[] = 'getenv(DOCUMENT_ROOT)       = ' . @getenv('DOCUMENT_ROOT');
4405
        $DebugOutput[] = '';
4406
4407
        $DebugOutput[] = 'get_magic_quotes_gpc()         = ' . $this->phpThumbDebugVarDump(@get_magic_quotes_gpc());
4408
        $DebugOutput[] = 'get_magic_quotes_runtime()     = ' . $this->phpThumbDebugVarDump(@get_magic_quotes_runtime());
4409
        $DebugOutput[] = 'error_reporting()              = ' . $this->phpThumbDebugVarDump(error_reporting());
4410
        $DebugOutput[] = 'ini_get(error_reporting)       = ' . $this->phpThumbDebugVarDump(@ini_get('error_reporting'));
4411
        $DebugOutput[] = 'ini_get(display_errors)        = ' . $this->phpThumbDebugVarDump(@ini_get('display_errors'));
4412
        $DebugOutput[] = 'ini_get(allow_url_fopen)       = ' . $this->phpThumbDebugVarDump(@ini_get('allow_url_fopen'));
4413
        $DebugOutput[] = 'ini_get(disable_functions)     = ' . $this->phpThumbDebugVarDump(@ini_get('disable_functions'));
4414
        $DebugOutput[] = 'get_cfg_var(disable_functions) = ' . $this->phpThumbDebugVarDump(@get_cfg_var('disable_functions'));
4415
        $DebugOutput[] = 'ini_get(safe_mode)             = ' . $this->phpThumbDebugVarDump(@ini_get('safe_mode'));
4416
        $DebugOutput[] = 'ini_get(open_basedir)          = ' . $this->phpThumbDebugVarDump(@ini_get('open_basedir'));
4417
        $DebugOutput[] = 'ini_get(max_execution_time)    = ' . $this->phpThumbDebugVarDump(@ini_get('max_execution_time'));
4418
        $DebugOutput[] = 'ini_get(memory_limit)          = ' . $this->phpThumbDebugVarDump(@ini_get('memory_limit'));
4419
        $DebugOutput[] = 'get_cfg_var(memory_limit)      = ' . $this->phpThumbDebugVarDump(@get_cfg_var('memory_limit'));
4420
        $DebugOutput[] = 'memory_get_usage()             = ' . (function_exists('memory_get_usage') ? $this->phpThumbDebugVarDump(@memory_get_usage()) : 'n/a');
4421
        $DebugOutput[] = '';
4422
4423
        $DebugOutput[] = '$this->config_prefer_imagemagick            = ' . $this->phpThumbDebugVarDump($this->config_prefer_imagemagick);
4424
        $DebugOutput[] = '$this->config_imagemagick_path              = ' . $this->phpThumbDebugVarDump($this->config_imagemagick_path);
4425
        $DebugOutput[] = '$this->ImageMagickWhichConvert()            = ' . $this->ImageMagickWhichConvert();
4426
        $IMpathUsed    = ($this->config_imagemagick_path ?: $this->ImageMagickWhichConvert());
4427
        $DebugOutput[] = '[actual ImageMagick path used]              = ' . $this->phpThumbDebugVarDump($IMpathUsed);
4428
        $DebugOutput[] = 'file_exists([actual ImageMagick path used]) = ' . $this->phpThumbDebugVarDump(@file_exists($IMpathUsed));
4429
        $DebugOutput[] = 'ImageMagickVersion(false)                   = ' . $this->ImageMagickVersion(false);
4430
        $DebugOutput[] = 'ImageMagickVersion(true)                    = ' . $this->ImageMagickVersion(true);
4431
        $DebugOutput[] = '';
4432
4433
        $DebugOutput[] = '$this->config_cache_directory               = ' . $this->phpThumbDebugVarDump($this->config_cache_directory);
4434
        $DebugOutput[] = '$this->config_cache_directory_depth         = ' . $this->phpThumbDebugVarDump($this->config_cache_directory_depth);
4435
        $DebugOutput[] = '$this->config_cache_disable_warning         = ' . $this->phpThumbDebugVarDump($this->config_cache_disable_warning);
4436
        $DebugOutput[] = '$this->config_cache_maxage                  = ' . $this->phpThumbDebugVarDump($this->config_cache_maxage);
4437
        $DebugOutput[] = '$this->config_cache_maxsize                 = ' . $this->phpThumbDebugVarDump($this->config_cache_maxsize);
4438
        $DebugOutput[] = '$this->config_cache_maxfiles                = ' . $this->phpThumbDebugVarDump($this->config_cache_maxfiles);
4439
        $DebugOutput[] = '$this->config_cache_force_passthru          = ' . $this->phpThumbDebugVarDump($this->config_cache_force_passthru);
4440
        $DebugOutput[] = '$this->cache_filename                       = ' . $this->phpThumbDebugVarDump($this->cache_filename);
4441
        $DebugOutput[] = 'is_readable($this->config_cache_directory)  = ' . $this->phpThumbDebugVarDump(@is_readable($this->config_cache_directory));
4442
        $DebugOutput[] = 'is_writable($this->config_cache_directory)  = ' . $this->phpThumbDebugVarDump(@is_writable($this->config_cache_directory));
4443
        $DebugOutput[] = 'is_readable($this->cache_filename)          = ' . $this->phpThumbDebugVarDump(@is_readable($this->cache_filename));
4444
        $DebugOutput[] = 'is_writable($this->cache_filename)          = ' . (@file_exists($this->cache_filename) ? $this->phpThumbDebugVarDump(@is_writable($this->cache_filename)) : 'n/a');
4445
        $DebugOutput[] = '';
4446
4447
        foreach ($ConfigVariableNames as $varname) {
4448
            $varname       = 'config_' . $varname;
4449
            $value         = $this->$varname;
4450
            $DebugOutput[] = '$this->' . str_pad($varname, 37, ' ', STR_PAD_RIGHT) . ' = ' . $this->phpThumbDebugVarDump($value);
4451
        }
4452
        $DebugOutput[] = '';
4453
        foreach ($OtherVariableNames as $varname) {
4454
            $value         = $this->$varname;
4455
            $DebugOutput[] = '$this->' . str_pad($varname, 27, ' ', STR_PAD_RIGHT) . ' = ' . $this->phpThumbDebugVarDump($value);
4456
        }
4457
        $DebugOutput[] = 'strlen($this->rawImageData)        = ' . strlen(@$this->rawImageData);
4458
        $DebugOutput[] = 'strlen($this->exif_thumbnail_data) = ' . strlen(@$this->exif_thumbnail_data);
4459
        $DebugOutput[] = '';
4460
4461
        foreach ($ParameterNames as $varname) {
4462
            $value         = $this->$varname;
4463
            $DebugOutput[] = '$this->' . str_pad($varname, 4, ' ', STR_PAD_RIGHT) . ' = ' . $this->phpThumbDebugVarDump($value);
4464
        }
4465
        $DebugOutput[] = '';
4466
4467
        foreach ($FunctionsExistance as $functionname) {
4468
            $DebugOutput[] = 'builtin_function_exists(' . $functionname . ')' . str_repeat(' ', 23 - strlen($functionname)) . ' = ' . $this->phpThumbDebugVarDump(phpthumb_functions::builtin_function_exists($functionname));
4469
        }
4470
        $DebugOutput[] = '';
4471
4472
        $gd_info = gd_info();
4473
        foreach ($gd_info as $key => $value) {
4474
            $DebugOutput[] = 'gd_info.' . str_pad($key, 34, ' ', STR_PAD_RIGHT) . ' = ' . $this->phpThumbDebugVarDump($value);
4475
        }
4476
        $DebugOutput[] = '';
4477
4478
        $exif_info = phpthumb_functions::exif_info();
4479
        foreach ($exif_info as $key => $value) {
4480
            $DebugOutput[] = 'exif_info.' . str_pad($key, 26, ' ', STR_PAD_RIGHT) . ' = ' . $this->phpThumbDebugVarDump($value);
4481
        }
4482
        $DebugOutput[] = '';
4483
4484
        if ($ApacheLookupURIarray = phpthumb_functions::ApacheLookupURIarray(dirname(@$_SERVER['PHP_SELF']))) {
4485
            foreach ($ApacheLookupURIarray as $key => $value) {
4486
                $DebugOutput[] = 'ApacheLookupURIarray.' . str_pad($key, 15, ' ', STR_PAD_RIGHT) . ' = ' . $this->phpThumbDebugVarDump($value);
4487
            }
4488
        } else {
4489
            $DebugOutput[] = 'ApacheLookupURIarray() -- FAILED';
4490
        }
4491
        $DebugOutput[] = '';
4492
4493
        if (isset($_GET) && is_array($_GET)) {
4494
            foreach ($_GET as $key => $value) {
4495
                $DebugOutput[] = '$_GET[' . $key . ']' . str_repeat(' ', 30 - strlen($key)) . '= ' . $this->phpThumbDebugVarDump($value);
4496
            }
4497
        }
4498
        if (isset($_POST) && is_array($_POST)) {
4499
            foreach ($_POST as $key => $value) {
4500
                $DebugOutput[] = '$_POST[' . $key . ']' . str_repeat(' ', 29 - strlen($key)) . '= ' . $this->phpThumbDebugVarDump($value);
4501
            }
4502
        }
4503
        $DebugOutput[] = '';
4504
4505
        $DebugOutput[] = '$this->debugmessages:';
4506
        foreach ($this->debugmessages as $errorstring) {
4507
            $DebugOutput[] = '  * ' . $errorstring;
4508
        }
4509
        $DebugOutput[] = '';
4510
4511
        $DebugOutput[] = '$this->debugtiming:';
4512
        foreach ($this->debugtiming as $timestamp => $timingstring) {
4513
            $DebugOutput[] = '  * ' . $timestamp . ' ' . $timingstring;
4514
        }
4515
        $DebugOutput[] = '  * Total processing time: ' . number_format(max(array_keys($this->debugtiming)) - min(array_keys($this->debugtiming)), 6);
4516
4517
        $this->f = (isset($_GET['f']) ? $_GET['f'] : $this->f); // debug modes 0-2 don't recognize text mode otherwise
4518
4519
        return $this->ErrorImage(implode("\n", $DebugOutput), 700, 500, true);
4520
    }
4521
4522
    /**
4523
     * @param $text
4524
     * @return bool
4525
     */
4526
    public function FatalError($text)
4527
    {
4528
        if (null === $this->fatalerror) {
4529
            $this->fatalerror = $text;
4530
        }
4531
4532
        return true;
4533
    }
4534
4535
    /**
4536
     * @param      $text
4537
     * @param int  $width
4538
     * @param int  $height
4539
     * @param bool $forcedisplay
4540
     * @return bool
4541
     */
4542
    public function ErrorImage($text, $width = 0, $height = 0, $forcedisplay = false)
4543
    {
4544
        $width  = ($width ?: $this->config_error_image_width);
4545
        $height = ($height ?: $this->config_error_image_height);
4546
4547
        $text = 'phpThumb() v' . $this->phpthumb_version . "\n" . 'http://phpthumb.sourceforge.net' . "\n\n" . ($this->config_disable_debug ? 'Error messages disabled.'
4548
                                                                                                                                              . "\n\n"
4549
                                                                                                                                              . 'edit phpThumb.config.php and (temporarily) set'
4550
                                                                                                                                              . "\n"
4551
                                                                                                                                              . '$PHPTHUMB_CONFIG[\'disable_debug\'] = false;'
4552
                                                                                                                                              . "\n"
4553
                                                                                                                                              . 'to view the details of this error' : $text);
4554
4555
        $this->FatalError($text);
4556
        $this->DebugMessage($text, __FILE__, __LINE__);
4557
        $this->purgeTempFiles();
4558
        if ($this->config_error_silent_die_on_error) {
4559
            exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

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

Loading history...
4560
        }
4561
        if ($this->phpThumbDebug && !$forcedisplay) {
4562
            return false;
4563
        }
4564
        if (!$this->config_error_die_on_error && !$forcedisplay) {
4565
            return false;
4566
        }
4567
        if ($this->err || $this->config_error_message_image_default) {
4568
            // Show generic custom error image instead of error message
4569
            // for use on production sites where you don't want debug messages
4570
            if (('showerror' === $this->err) || $this->phpThumbDebug) {
4571
                // fall through and actually show error message even if default error image is set
4572
            } else {
4573
                header('Location: ' . ($this->err ?: $this->config_error_message_image_default));
4574
                exit;
4575
            }
4576
        }
4577
        $this->setOutputFormat();
4578
        if (!$this->thumbnailFormat || !$this->config_disable_debug || (phpthumb_functions::gd_version() < 1)) {
4579
            $this->thumbnailFormat = 'text';
4580
        }
4581
        if ('text' === @$this->thumbnailFormat) {
4582
            // bypass all GD functions and output text error message
4583
            if (!headers_sent()) {
4584
                header('Content-type: text/plain');
4585
                echo $text;
4586
            } else {
4587
                echo '<pre>' . htmlspecialchars($text, ENT_QUOTES | ENT_HTML5) . '</pre>';
4588
            }
4589
            exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

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

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

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

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

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

4601
            && headers_sent($headers_file, /** @scrutinizer ignore-type */ $headers_line)) {
Loading history...
4602
            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>';
4603
        } elseif (headers_sent()) {
4604
            echo "\n" . '**Headers already sent, dumping error message as text:**<br><pre>' . "\n\n" . $text . "\n" . '</pre>';
4605
        } elseif ($gdimg_error = imagecreate($width, $height)) {
4606
            $background_color = phpthumb_functions::ImageHexColorAllocate($gdimg_error, $this->config_error_bgcolor, true);
4607
            $text_color       = phpthumb_functions::ImageHexColorAllocate($gdimg_error, $this->config_error_textcolor, true);
4608
            imagefilledrectangle($gdimg_error, 0, 0, $width, $height, $background_color);
4609
            $lineYoffset = 0;
4610
            foreach ($LinesOfText as $line) {
4611
                imagestring($gdimg_error, $this->config_error_fontsize, 2, $lineYoffset, $line, $text_color);
4612
                $lineYoffset += $FontHeight;
4613
            }
4614
            if (function_exists('imagetypes')) {
4615
                $imagetypes = imagetypes();
4616
                if ($imagetypes & IMG_PNG) {
4617
                    header('Content-Type: image/png');
4618
                    imagepng($gdimg_error);
4619
                } elseif ($imagetypes & IMG_GIF) {
4620
                    header('Content-Type: image/gif');
4621
                    imagegif($gdimg_error);
4622
                } elseif ($imagetypes & IMG_JPG) {
4623
                    header('Content-Type: image/jpeg');
4624
                    imagejpeg($gdimg_error);
4625
                } elseif ($imagetypes & IMG_WBMP) {
4626
                    header('Content-Type: image/vnd.wap.wbmp');
4627
                    imagewbmp($gdimg_error);
4628
                }
4629
            }
4630
            imagedestroy($gdimg_error);
4631
        }
4632
        if (!headers_sent()) {
4633
            echo "\n" . '**Failed to send graphical error image, dumping error message as text:**<br>' . "\n\n" . $text;
4634
        }
4635
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

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

Loading history...
4636
    }
4637
4638
    /**
4639
     * @param      $RawImageData
4640
     * @param bool $DieOnErrors
4641
     * @return bool|resource
4642
     */
4643
    public function ImageCreateFromStringReplacement(&$RawImageData, $DieOnErrors = false)
4644
    {
4645
        // there are serious bugs in the non-bundled versions of GD which may cause
4646
        // PHP to segfault when calling imagecreatefromstring() - avoid if at all possible
4647
        // when not using a bundled version of GD2
4648
        if (!phpthumb_functions::gd_version()) {
4649
            if ($DieOnErrors) {
4650
                if (!headers_sent()) {
4651
                    // base64-encoded error image in GIF format
4652
                    $ERROR_NOGD = 'R0lGODlhIAAgALMAAAAAABQUFCQkJDY2NkZGRldXV2ZmZnJycoaGhpSUlKWlpbe3t8XFxdXV1eTk5P7+/iwAAAAAIAAgAAAE/vDJSau9WILtTAACUinDNijZtAHfCojS4W5H+qxD8xibIDE9h0OwWaRWDIljJSkUJYsN4bihMB8th3IToAKs1VtYM75cyV8sZ8vygtOE5yMKmGbO4jRdICQCjHdlZzwzNW4qZSQmKDaNjhUMBX4BBAlmMywFSRWEmAI6b5gAlhNxokGhooAIK5o/pi9vEw4Lfj4OLTAUpj6IabMtCwlSFw0DCKBoFqwAB04AjI54PyZ+yY3TD0ss2YcVmN/gvpcu4TOyFivWqYJlbAHPpOntvxNAACcmGHjZzAZqzSzcq5fNjxFmAFw9iFRunD1epU6tsIPmFCAJnWYE0FURk7wJDA0MTKpEzoWAAskiAAA7';
4653
                    header('Content-Type: image/gif');
4654
                    echo base64_decode($ERROR_NOGD);
4655
                } else {
4656
                    echo '*** ERROR: No PHP-GD support available ***';
4657
                }
4658
                exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

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

Loading history...
4659
            } else {
4660
                $this->DebugMessage('ImageCreateFromStringReplacement() failed: gd_version says "' . phpthumb_functions::gd_version() . '"', __FILE__, __LINE__);
4661
4662
                return false;
4663
            }
4664
        }
4665
        if (phpthumb_functions::gd_is_bundled()) {
4666
            $this->DebugMessage('ImageCreateFromStringReplacement() calling built-in imagecreatefromstring()', __FILE__, __LINE__);
4667
4668
            return @imagecreatefromstring($RawImageData);
4669
        }
4670
        if ($this->issafemode) {
4671
            $this->DebugMessage('ImageCreateFromStringReplacement() failed: cannot create temp file in SAFE_MODE', __FILE__, __LINE__);
4672
4673
            return false;
4674
        }
4675
4676
        switch (substr($RawImageData, 0, 3)) {
4677
            case 'GIF':
4678
                $ICFSreplacementFunctionName = 'imagecreatefromgif';
4679
                break;
4680
            case "\xFF\xD8\xFF":
4681
                $ICFSreplacementFunctionName = 'imagecreatefromjpeg';
4682
                break;
4683
            case "\x89" . 'PN':
4684
                $ICFSreplacementFunctionName = 'imagecreatefrompng';
4685
                break;
4686
            default:
4687
                $this->DebugMessage('ImageCreateFromStringReplacement() failed: unknown fileformat signature "' . phpthumb_functions::HexCharDisplay(substr($RawImageData, 0, 3)) . '"', __FILE__, __LINE__);
4688
4689
                return false;
4690
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

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

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

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

Loading history...
4691
        }
4692
        $ErrorMessage = '';
4693
        if ($tempnam = $this->phpThumb_tempnam()) {
4694
            if ($fp_tempnam = @fopen($tempnam, 'wb')) {
4695
                fwrite($fp_tempnam, $RawImageData);
4696
                fclose($fp_tempnam);
4697
                if (('imagecreatefromgif' === $ICFSreplacementFunctionName)
4698
                    && !function_exists($ICFSreplacementFunctionName)) {
4699
4700
                    // Need to create from GIF file, but imagecreatefromgif does not exist
4701
                    ob_start();
4702
                    if (!@require_once __DIR__ . '/phpthumb.gif.php') {
4703
                        $ErrorMessage = 'Failed to include required file "' . __DIR__ . '/phpthumb.gif.php" in ' . __FILE__ . ' on line ' . __LINE__;
4704
                        $this->DebugMessage($ErrorMessage, __FILE__, __LINE__);
4705
                    }
4706
                    ob_end_clean();
4707
                    // gif_loadFileToGDimageResource() cannot read from raw data, write to file first
4708
                    if ($tempfilename = $this->phpThumb_tempnam()) {
4709
                        if ($fp_tempfile = @fopen($tempfilename, 'wb')) {
4710
                            fwrite($fp_tempfile, $RawImageData);
4711
                            fclose($fp_tempfile);
4712
                            $gdimg_source = gif_loadFileToGDimageResource($tempfilename);
4713
                            $this->DebugMessage('gif_loadFileToGDimageResource(' . $tempfilename . ') completed', __FILE__, __LINE__);
4714
                            $this->DebugMessage('deleting "' . $tempfilename . '"', __FILE__, __LINE__);
4715
                            unlink($tempfilename);
4716
4717
                            return $gdimg_source;
4718
                        } else {
4719
                            $ErrorMessage = 'Failed to open tempfile in ' . __FILE__ . ' on line ' . __LINE__;
4720
                            $this->DebugMessage($ErrorMessage, __FILE__, __LINE__);
4721
                        }
4722
                    } else {
4723
                        $ErrorMessage = 'Failed to open generate tempfile name in ' . __FILE__ . ' on line ' . __LINE__;
4724
                        $this->DebugMessage($ErrorMessage, __FILE__, __LINE__);
4725
                    }
4726
                } elseif (function_exists($ICFSreplacementFunctionName)
4727
                          && ($gdimg_source = @$ICFSreplacementFunctionName($tempnam))) {
4728
4729
                    // great
4730
                    $this->DebugMessage($ICFSreplacementFunctionName . '(' . $tempnam . ') succeeded', __FILE__, __LINE__);
4731
                    $this->DebugMessage('deleting "' . $tempnam . '"', __FILE__, __LINE__);
4732
                    unlink($tempnam);
4733
4734
                    return $gdimg_source;
4735
                } else {
4736
4737
                    // GD functions not available, or failed to create image
4738
                    $this->DebugMessage($ICFSreplacementFunctionName . '(' . $tempnam . ') ' . (function_exists($ICFSreplacementFunctionName) ? 'failed' : 'does not exist'), __FILE__, __LINE__);
4739
                    if (isset($_GET['phpThumbDebug'])) {
4740
                        $this->phpThumbDebug();
4741
                    }
4742
                }
4743
            } else {
4744
                $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';
4745
                if ($this->issafemode) {
4746
                    $ErrorMessage = 'ImageCreateFromStringReplacement() failed in ' . __FILE__ . ' on line ' . __LINE__ . ': cannot create temp file in SAFE_MODE';
4747
                }
4748
                $this->DebugMessage($ErrorMessage, __FILE__, __LINE__);
4749
            }
4750
            $this->DebugMessage('deleting "' . $tempnam . '"', __FILE__, __LINE__);
4751
            @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

4751
            /** @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...
4752
        } else {
4753
            $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';
4754
            if ($this->issafemode) {
4755
                $ErrorMessage = 'ImageCreateFromStringReplacement() failed in ' . __FILE__ . ' on line ' . __LINE__ . ': cannot create temp file in SAFE_MODE';
4756
            }
4757
        }
4758
        if ($DieOnErrors && $ErrorMessage) {
4759
            return $this->ErrorImage($ErrorMessage);
4760
        }
4761
4762
        return false;
4763
    }
4764
4765
    /**
4766
     * @param $dst_im
4767
     * @param $src_im
4768
     * @param $dstX
4769
     * @param $dstY
4770
     * @param $srcX
4771
     * @param $srcY
4772
     * @param $dstW
4773
     * @param $dstH
4774
     * @param $srcW
4775
     * @param $srcH
4776
     * @return bool
4777
     */
4778
    public function ImageResizeFunction(&$dst_im, &$src_im, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH)
4779
    {
4780
        $this->DebugMessage('ImageResizeFunction($o, $s, ' . $dstX . ', ' . $dstY . ', ' . $srcX . ', ' . $srcY . ', ' . $dstW . ', ' . $dstH . ', ' . $srcW . ', ' . $srcH . ')', __FILE__, __LINE__);
4781
        if (($dstW == $srcW) && ($dstH == $srcH)) {
4782
            return imagecopy($dst_im, $src_im, $dstX, $dstY, $srcX, $srcY, $srcW, $srcH);
4783
        }
4784
        if (phpthumb_functions::gd_version() >= 2.0) {
4785
            if ($this->config_disable_imagecopyresampled) {
4786
                return phpthumb_functions::ImageCopyResampleBicubic($dst_im, $src_im, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH);
4787
            }
4788
4789
            return imagecopyresampled($dst_im, $src_im, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH);
4790
        }
4791
4792
        return imagecopyresized($dst_im, $src_im, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH);
4793
    }
4794
4795
    /**
4796
     * @return bool
4797
     */
4798
    public function InitializeTempDirSetting()
4799
    {
4800
        $this->config_temp_directory = ($this->config_temp_directory ?: (function_exists('sys_get_temp_dir') ? sys_get_temp_dir() : '')); // sys_get_temp_dir added in PHP v5.2.1
4801
        $this->config_temp_directory = ($this->config_temp_directory ?: getenv('TMPDIR'));
4802
        $this->config_temp_directory = ($this->config_temp_directory ?: getenv('TMP'));
4803
        $this->config_temp_directory = ($this->config_temp_directory ?: ini_get('upload_tmp_dir'));
4804
        $this->config_temp_directory = $this->realPathSafe($this->config_temp_directory);
4805
4806
        return true;
4807
    }
4808
4809
    /**
4810
     * @return bool|null|string|string[]
4811
     */
4812
    public function phpThumb_tempnam()
4813
    {
4814
        $this->InitializeTempDirSetting();
4815
        $tempnam                           = $this->realPathSafe(tempnam($this->config_temp_directory, 'pThumb'));
0 ignored issues
show
Bug introduced by
It seems like $this->config_temp_directory can also be of type string[]; however, parameter $dir of tempnam() 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

4815
        $tempnam                           = $this->realPathSafe(tempnam(/** @scrutinizer ignore-type */ $this->config_temp_directory, 'pThumb'));
Loading history...
4816
        $this->tempFilesToDelete[$tempnam] = $tempnam;
4817
        $this->DebugMessage('phpThumb_tempnam() returning "' . $tempnam . '"', __FILE__, __LINE__);
4818
4819
        return $tempnam;
4820
    }
4821
4822
    /**
4823
     * @param        $message
4824
     * @param string $file
4825
     * @param string $line
4826
     * @return bool
4827
     */
4828
    public function DebugMessage($message, $file = '', $line = '')
4829
    {
4830
        $this->debugmessages[] = $message . ($file ? ' in file "' . (basename($file) ?: $file) . '"' : '') . ($line ? ' on line ' . $line : '');
4831
4832
        return true;
4833
    }
4834
4835
    /**
4836
     * @param        $message
4837
     * @param string $file
4838
     * @param string $line
4839
     * @param int    $timestamp
4840
     * @return bool
4841
     */
4842
    public function DebugTimingMessage($message, $file = '', $line = '', $timestamp = 0)
4843
    {
4844
        if (!$timestamp) {
4845
            $timestamp = array_sum(explode(' ', microtime()));
4846
        }
4847
        $this->debugtiming[number_format($timestamp, 6, '.', '')] = ': ' . $message . ($file ? ' in file "' . (basename($file) ?: $file) . '"' : '') . ($line ? ' on line ' . $line : '');
4848
4849
        return true;
4850
    }
4851
}
4852