Issues (1210)

Security Analysis    not enabled

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

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

thumbs/phpthumb.class.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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 = array();  // 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 = array();
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 = array();
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     = array(); // 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 = array();
169
    public $debugtiming   = array();
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 = array();
208
    public $cache_filename    = null;
209
210
    public $AlphaCapableFormats = array('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-201603240806';
218
219
    //////////////////////////////////////////////////////////////////////
220
221
    // public: constructor
222
    /**
223
     * phpthumb constructor.
224
     */
225
    public function __construct()
226
    {
227
        $this->phpThumb();
228
    }
229
230
    public function phpThumb()
231
    {
232
        $this->DebugTimingMessage('phpThumb() constructor', __FILE__, __LINE__);
233
        $this->DebugMessage('phpThumb() v' . $this->phpthumb_version, __FILE__, __LINE__);
234
235
        foreach (array(ini_get('memory_limit'), get_cfg_var('memory_limit')) as $php_config_memory_limit) {
236
            if (strlen($php_config_memory_limit)) {
237
                if (substr($php_config_memory_limit, -1, 1) == 'G') { // PHP memory limit expressed in Gigabytes
238
                    $php_config_memory_limit = (int)substr($php_config_memory_limit, 0, -1) * 1073741824;
239
                } elseif (substr($php_config_memory_limit, -1, 1) == 'M') { // PHP memory limit expressed in Megabytes
240
                    $php_config_memory_limit = (int)substr($php_config_memory_limit, 0, -1) * 1048576;
241
                }
242
                $this->php_memory_limit = max($this->php_memory_limit, $php_config_memory_limit);
243
            }
244
        }
245
        if ($this->php_memory_limit > 0) { // could be "-1" for "no limit"
246
            $this->config_max_source_pixels = round($this->php_memory_limit * 0.20); // 20% of memory_limit
247
        }
248
249
        $this->iswindows            = (bool)(strtoupper(substr(PHP_OS, 0, 3)) == 'WIN');
250
        $this->issafemode           = (bool)preg_match('#(1|ON)#i', ini_get('safe_mode'));
251
        $this->config_document_root = (!empty($_SERVER['DOCUMENT_ROOT']) ? $_SERVER['DOCUMENT_ROOT'] : $this->config_document_root);
252
        $this->config_cache_prefix  = (isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] . '_' : '');
253
254
        $this->purgeTempFiles(); // purge existing temp files if re-initializing object
255
256
        $php_sapi_name = strtolower(function_exists('php_sapi_name') ? php_sapi_name() : '');
257
        if ($php_sapi_name == 'cli') {
258
            $this->config_allow_src_above_docroot = true;
259
        }
260
261
        if (!$this->config_disable_debug) {
262
            // if debug mode is enabled, force phpThumbDebug output, do not allow normal thumbnails to be generated
263
            $this->phpThumbDebug = (is_null($this->phpThumbDebug) ? 9 : max(1, (int)$this->phpThumbDebug));
264
        }
265
    }
266
267
    public function __destruct()
268
    {
269
        $this->purgeTempFiles();
270
    }
271
272
    // public:
273
274
    /**
275
     * @return bool
276
     */
277
    public function purgeTempFiles()
278
    {
279
        foreach ($this->tempFilesToDelete as $tempFileToDelete) {
280
            if (file_exists($tempFileToDelete)) {
281
                $this->DebugMessage('Deleting temp file "' . $tempFileToDelete . '"', __FILE__, __LINE__);
282
                @unlink($tempFileToDelete);
283
            }
284
        }
285
        $this->tempFilesToDelete = array();
286
287
        return true;
288
    }
289
290
    // public:
291
292
    /**
293
     * @param $sourceFilename
294
     * @return bool
295
     */
296
    public function setSourceFilename($sourceFilename)
297
    {
298
        //$this->resetObject();
299
        //$this->rawImageData   = null;
300
        $this->sourceFilename = $sourceFilename;
301
        $this->src            = $sourceFilename;
302
        if (is_null($this->config_output_format)) {
303
            $sourceFileExtension = strtolower(substr(strrchr($sourceFilename, '.'), 1));
304
            if (preg_match('#^[a-z]{3,4}$#', $sourceFileExtension)) {
305
                $this->config_output_format = $sourceFileExtension;
306
                $this->DebugMessage('setSourceFilename(' . $sourceFilename . ') set $this->config_output_format to "' . $sourceFileExtension . '"', __FILE__, __LINE__);
307
            } else {
308
                $this->DebugMessage('setSourceFilename('
309
                                    . $sourceFilename
310
                                    . ') did NOT set $this->config_output_format to "'
311
                                    . $sourceFileExtension
312
                                    . '" because it did not seem like an appropriate image format', __FILE__, __LINE__);
313
            }
314
        }
315
        $this->DebugMessage('setSourceFilename(' . $sourceFilename . ') set $this->sourceFilename to "' . $this->sourceFilename . '"', __FILE__, __LINE__);
316
317
        return true;
318
    }
319
320
    // public:
321
322
    /**
323
     * @param         $rawImageData
324
     * @param  string $sourceFilename
325
     * @return bool
326
     */
327
    public function setSourceData($rawImageData, $sourceFilename = '')
328
    {
329
        //$this->resetObject();
330
        //$this->sourceFilename = null;
331
        $this->rawImageData = $rawImageData;
332
        $this->DebugMessage('setSourceData() setting $this->rawImageData ('
333
                            . strlen($this->rawImageData)
334
                            . ' bytes; magic="'
335
                            . substr($this->rawImageData, 0, 4)
336
                            . '" ('
337
                            . phpthumb_functions::HexCharDisplay(substr($this->rawImageData, 0, 4))
338
                            . '))', __FILE__, __LINE__);
339
        if ($this->config_cache_source_enabled) {
340
            $sourceFilename = ($sourceFilename ?: md5($rawImageData));
341
            if (!is_dir($this->config_cache_source_directory)) {
342
                $this->ErrorImage('$this->config_cache_source_directory (' . $this->config_cache_source_directory . ') is not a directory');
343
            } elseif (!@is_writable($this->config_cache_source_directory)) {
344
                $this->ErrorImage('$this->config_cache_source_directory (' . $this->config_cache_source_directory . ') is not writable');
345
            }
346
            $this->DebugMessage('setSourceData() attempting to save source image to "' . $this->config_cache_source_directory . DIRECTORY_SEPARATOR . urlencode($sourceFilename) . '"', __FILE__,
347
                                __LINE__);
348
            if ($fp = @fopen($this->config_cache_source_directory . DIRECTORY_SEPARATOR . urlencode($sourceFilename), 'wb')) {
349
                fwrite($fp, $rawImageData);
350
                fclose($fp);
351
            } elseif (!$this->phpThumbDebug) {
352
                $this->ErrorImage('setSourceData() failed to write to source cache (' . $this->config_cache_source_directory . DIRECTORY_SEPARATOR . urlencode($sourceFilename) . ')');
353
            }
354
        }
355
356
        return true;
357
    }
358
359
    // public:
360
361
    /**
362
     * @param $gdimg
363
     * @return bool
364
     */
365
    public function setSourceImageResource($gdimg)
366
    {
367
        //$this->resetObject();
368
        $this->gdimg_source = $gdimg;
369
370
        return true;
371
    }
372
373
    // public:
374
375
    /**
376
     * @param $param
377
     * @param $value
378
     * @return bool
379
     */
380
    public function setParameter($param, $value)
381
    {
382
        if ($param == 'src') {
383
            $this->setSourceFilename($this->ResolveFilenameToAbsolute($value));
384
        } elseif (@is_array($this->$param)) {
385
            if (is_array($value)) {
386
                foreach ($value as $arraykey => $arrayvalue) {
387
                    array_push($this->$param, $arrayvalue);
388
                }
389
            } else {
390
                array_push($this->$param, $value);
391
            }
392
        } else {
393
            $this->$param = $value;
394
        }
395
396
        return true;
397
    }
398
399
    // public:
400
401
    /**
402
     * @param $param
403
     * @return mixed
404
     */
405
    public function getParameter($param)
406
    {
407
        //if (property_exists('phpThumb', $param)) {
408
        return $this->$param;
409
        //}
410
        //$this->DebugMessage('setParameter() attempting to get non-existant parameter "'.$param.'"', __FILE__, __LINE__);
411
        //return false;
412
    }
413
414
    // public:
415
416
    /**
417
     * @return bool
418
     */
419
    public function GenerateThumbnail()
420
    {
421
        $this->setOutputFormat();
422
        $this->phpThumbDebug('8a');
423
        $this->ResolveSource();
424
        $this->phpThumbDebug('8b');
425
        $this->SetCacheFilename();
426
        $this->phpThumbDebug('8c');
427
        $this->ExtractEXIFgetImageSize();
428
        $this->phpThumbDebug('8d');
429
        if ($this->useRawIMoutput) {
430
            $this->DebugMessage('Skipping rest of GenerateThumbnail() because ($this->useRawIMoutput === true)', __FILE__, __LINE__);
431
432
            return true;
433
        }
434
        $this->phpThumbDebug('8e');
435
        if (!$this->SourceImageToGD()) {
436
            $this->DebugMessage('SourceImageToGD() failed', __FILE__, __LINE__);
437
438
            return false;
439
        }
440
        $this->phpThumbDebug('8f');
441
        $this->Rotate();
442
        $this->phpThumbDebug('8g');
443
        $this->CreateGDoutput();
444
        $this->phpThumbDebug('8h');
445
446
        // default values, also applicable for far="C"
447
        $destination_offset_x = round(($this->thumbnail_width - $this->thumbnail_image_width) / 2);
448
        $destination_offset_y = round(($this->thumbnail_height - $this->thumbnail_image_height) / 2);
449
        if (($this->far == 'L') || ($this->far == 'TL') || ($this->far == 'BL')) {
450
            $destination_offset_x = 0;
451
        }
452
        if (($this->far == 'R') || ($this->far == 'TR') || ($this->far == 'BR')) {
453
            $destination_offset_x = round($this->thumbnail_width - $this->thumbnail_image_width);
454
        }
455
        if (($this->far == 'T') || ($this->far == 'TL') || ($this->far == 'TR')) {
456
            $destination_offset_y = 0;
457
        }
458
        if (($this->far == 'B') || ($this->far == 'BL') || ($this->far == 'BR')) {
459
            $destination_offset_y = round($this->thumbnail_height - $this->thumbnail_image_height);
460
        }
461
462
        //      // copy/resize image to appropriate dimensions
463
        //      $borderThickness = 0;
464
        //      if (!empty($this->fltr)) {
465
        //          foreach ($this->fltr as $key => $value) {
466
        //              if (preg_match('#^bord\|([0-9]+)#', $value, $matches)) {
467
        //                  $borderThickness = $matches[1];
468
        //                  break;
469
        //              }
470
        //          }
471
        //      }
472
        //      if ($borderThickness > 0) {
473
        //          //$this->DebugMessage('Skipping ImageResizeFunction() because BorderThickness="'.$borderThickness.'"', __FILE__, __LINE__);
474
        //          $this->thumbnail_image_height /= 2;
475
        //      }
476
        $this->ImageResizeFunction($this->gdimg_output, $this->gdimg_source, $destination_offset_x, $destination_offset_y, $this->thumbnailCropX, $this->thumbnailCropY, $this->thumbnail_image_width,
477
                                   $this->thumbnail_image_height, $this->thumbnailCropW, $this->thumbnailCropH);
478
479
        $this->DebugMessage('memory_get_usage() after copy-resize = ' . (function_exists('memory_get_usage') ? @memory_get_usage() : 'n/a'), __FILE__, __LINE__);
480
        imagedestroy($this->gdimg_source);
481
        $this->DebugMessage('memory_get_usage() after ImageDestroy = ' . (function_exists('memory_get_usage') ? @memory_get_usage() : 'n/a'), __FILE__, __LINE__);
482
483
        $this->phpThumbDebug('8i');
484
        $this->AntiOffsiteLinking();
485
        $this->phpThumbDebug('8j');
486
        $this->ApplyFilters();
487
        $this->phpThumbDebug('8k');
488
        $this->AlphaChannelFlatten();
489
        $this->phpThumbDebug('8l');
490
        $this->MaxFileSize();
491
        $this->phpThumbDebug('8m');
492
493
        $this->DebugMessage('GenerateThumbnail() completed successfully', __FILE__, __LINE__);
494
495
        return true;
496
    }
497
498
    // public:
499
500
    /**
501
     * @return bool
502
     */
503
    public function RenderOutput()
504
    {
505 View Code Duplication
        if (!$this->useRawIMoutput && !is_resource($this->gdimg_output)) {
506
            $this->DebugMessage('RenderOutput() failed because !is_resource($this->gdimg_output)', __FILE__, __LINE__);
507
508
            return false;
509
        }
510
        if (!$this->thumbnailFormat) {
511
            $this->DebugMessage('RenderOutput() failed because $this->thumbnailFormat is empty', __FILE__, __LINE__);
512
513
            return false;
514
        }
515
        if ($this->useRawIMoutput) {
516
            $this->DebugMessage('RenderOutput copying $this->IMresizedData (' . strlen($this->IMresizedData) . ' bytes) to $this->outputImage', __FILE__, __LINE__);
517
            $this->outputImageData = $this->IMresizedData;
518
519
            return true;
520
        }
521
522
        $builtin_formats = array();
523
        if (function_exists('ImageTypes')) {
524
            $imagetypes              = imagetypes();
525
            $builtin_formats['wbmp'] = (bool)($imagetypes & IMG_WBMP);
526
            $builtin_formats['jpg']  = (bool)($imagetypes & IMG_JPG);
527
            $builtin_formats['gif']  = (bool)($imagetypes & IMG_GIF);
528
            $builtin_formats['png']  = (bool)($imagetypes & IMG_PNG);
529
        }
530
531
        $this->DebugMessage('ImageInterlace($this->gdimg_output, ' . (int)$this->config_output_interlace . ')', __FILE__, __LINE__);
532
        imageinterlace($this->gdimg_output, (int)$this->config_output_interlace);
533
534
        $this->DebugMessage('RenderOutput() attempting Image' . strtoupper(@$this->thumbnailFormat) . '($this->gdimg_output)', __FILE__, __LINE__);
535
        ob_start();
536
        switch ($this->thumbnailFormat) {
537 View Code Duplication
            case 'wbmp':
538
                if (empty($builtin_formats['wbmp'])) {
539
                    $this->DebugMessage('GD does not have required built-in support for WBMP output', __FILE__, __LINE__);
540
                    ob_end_clean();
541
542
                    return false;
543
                }
544
                imagejpeg($this->gdimg_output, null, $this->thumbnailQuality);
545
                $this->outputImageData = ob_get_contents();
546
                break;
547
548
            case 'jpeg':
549 View Code Duplication
            case 'jpg':  // should be "jpeg" not "jpg" but just in case...
550
                if (empty($builtin_formats['jpg'])) {
551
                    $this->DebugMessage('GD does not have required built-in support for JPEG output', __FILE__, __LINE__);
552
                    ob_end_clean();
553
554
                    return false;
555
                }
556
                imagejpeg($this->gdimg_output, null, $this->thumbnailQuality);
557
                $this->outputImageData = ob_get_contents();
558
                break;
559
560
            case 'png':
561
                if (empty($builtin_formats['png'])) {
562
                    $this->DebugMessage('GD does not have required built-in support for PNG output', __FILE__, __LINE__);
563
                    ob_end_clean();
564
565
                    return false;
566
                }
567
                if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.1.2', '>=')) {
568
                    // https://github.com/JamesHeinrich/phpThumb/issues/24
569
570
                    /* http://php.net/manual/en/function.imagepng.php:
571
                    from php source (gd.h):
572
                    2.0.12: Compression level: 0-9 or -1, where 0 is NO COMPRESSION at all,
573
                    :: 1 is FASTEST but produces larger files, 9 provides the best
574
                    :: compression (smallest files) but takes a long time to compress, and
575
                    :: -1 selects the default compiled into the zlib library.
576
                    Conclusion: Based on the Zlib manual (http://www.zlib.net/manual.html) the default compression level is set to 6.
577
                    */
578
                    if (($this->thumbnailQuality >= -1) && ($this->thumbnailQuality <= 9)) {
579
                        $PNGquality = $this->thumbnailQuality;
580
                    } else {
581
                        $this->DebugMessage('Specified thumbnailQuality "' . $this->thumbnailQuality . '" is outside the accepted range (0-9, or -1). Using 6 as default value.', __FILE__, __LINE__);
582
                        $PNGquality = 6;
583
                    }
584
                    imagepng($this->gdimg_output, null, $PNGquality);
585
                } else {
586
                    imagepng($this->gdimg_output);
587
                }
588
                $this->outputImageData = ob_get_contents();
589
                break;
590
591
            case 'gif':
592
                if (empty($builtin_formats['gif'])) {
593
                    $this->DebugMessage('GD does not have required built-in support for GIF output', __FILE__, __LINE__);
594
                    ob_end_clean();
595
596
                    return false;
597
                }
598
                imagegif($this->gdimg_output);
599
                $this->outputImageData = ob_get_contents();
600
                break;
601
602 View Code Duplication
            case 'bmp':
603
                $ImageOutFunction = '"builtin BMP output"';
604
                if (!@require_once __DIR__ . '/phpthumb.bmp.php') {
605
                    $this->DebugMessage('Error including "' . __DIR__ . '/phpthumb.bmp.php" which is required for BMP format output', __FILE__, __LINE__);
606
                    ob_end_clean();
607
608
                    return false;
609
                }
610
                $phpthumb_bmp          = new phpthumb_bmp();
611
                $this->outputImageData = $phpthumb_bmp->GD2BMPstring($this->gdimg_output);
612
                unset($phpthumb_bmp);
613
                break;
614
615 View Code Duplication
            case 'ico':
616
                $ImageOutFunction = '"builtin ICO output"';
617
                if (!@require_once __DIR__ . '/phpthumb.ico.php') {
618
                    $this->DebugMessage('Error including "' . __DIR__ . '/phpthumb.ico.php" which is required for ICO format output', __FILE__, __LINE__);
619
                    ob_end_clean();
620
621
                    return false;
622
                }
623
                $phpthumb_ico          = new phpthumb_ico();
624
                $arrayOfOutputImages   = array($this->gdimg_output);
625
                $this->outputImageData = $phpthumb_ico->GD2ICOstring($arrayOfOutputImages);
626
                unset($phpthumb_ico);
627
                break;
628
629 View Code Duplication
            default:
630
                $this->DebugMessage('RenderOutput failed because $this->thumbnailFormat "' . $this->thumbnailFormat . '" is not valid', __FILE__, __LINE__);
631
                ob_end_clean();
632
633
                return false;
634
        }
635
        ob_end_clean();
636
        if (!$this->outputImageData) {
637
            $this->DebugMessage('RenderOutput() for "' . $this->thumbnailFormat . '" failed', __FILE__, __LINE__);
638
            ob_end_clean();
639
640
            return false;
641
        }
642
        $this->DebugMessage('RenderOutput() completing with $this->outputImageData = ' . strlen($this->outputImageData) . ' bytes', __FILE__, __LINE__);
643
644
        return true;
645
    }
646
647
    // public:
648
649
    /**
650
     * @param $filename
651
     * @return bool
652
     */
653
    public function RenderToFile($filename)
654
    {
655
        if (preg_match('#^[a-z0-9]+://#i', $filename)) {
656
            $this->DebugMessage('RenderToFile() failed because $filename (' . $filename . ') is a URL', __FILE__, __LINE__);
657
658
            return false;
659
        }
660
        // render thumbnail to this file only, do not cache, do not output to browser
661
        //$renderfilename = $this->ResolveFilenameToAbsolute(dirname($filename)).DIRECTORY_SEPARATOR.basename($filename);
662
        $renderfilename = $filename;
663
        if (($filename{0} != '/') && ($filename{0} != '\\') && ($filename{1} != ':')) {
664
            $renderfilename = $this->ResolveFilenameToAbsolute($renderfilename);
665
        }
666 View Code Duplication
        if (!@is_writable(dirname($renderfilename))) {
667
            $this->DebugMessage('RenderToFile() failed because "' . dirname($renderfilename) . '/" is not writable', __FILE__, __LINE__);
668
669
            return false;
670
        }
671 View Code Duplication
        if (@is_file($renderfilename) && !@is_writable($renderfilename)) {
672
            $this->DebugMessage('RenderToFile() failed because "' . $renderfilename . '" is not writable', __FILE__, __LINE__);
673
674
            return false;
675
        }
676
677
        if ($this->RenderOutput()) {
678
            if (file_put_contents($renderfilename, $this->outputImageData)) {
679
                $this->DebugMessage('RenderToFile(' . $renderfilename . ') succeeded', __FILE__, __LINE__);
680
681
                return true;
682
            }
683
            if (!@file_exists($renderfilename)) {
684
                $this->DebugMessage('RenderOutput [' . $this->thumbnailFormat . '(' . $renderfilename . ')] did not appear to fail, but the output image does not exist either...', __FILE__, __LINE__);
685
            }
686
        } else {
687
            $this->DebugMessage('RenderOutput [' . $this->thumbnailFormat . '(' . $renderfilename . ')] failed', __FILE__, __LINE__);
688
        }
689
690
        return false;
691
    }
692
693
    // public:
694
695
    /**
696
     * @return bool
697
     */
698
    public function OutputThumbnail()
699
    {
700
        $this->purgeTempFiles();
701
702 View Code Duplication
        if (!$this->useRawIMoutput && !is_resource($this->gdimg_output)) {
703
            $this->DebugMessage('OutputThumbnail() failed because !is_resource($this->gdimg_output)', __FILE__, __LINE__);
704
705
            return false;
706
        }
707
        if (headers_sent()) {
708
            return $this->ErrorImage('OutputThumbnail() failed - headers already sent');
709
            exit;
710
        }
711
712
        $downloadfilename = phpthumb_functions::SanitizeFilename(is_string($this->sia) ? $this->sia : ($this->down ?: 'phpThumb_generated_thumbnail' . '.' . $this->thumbnailFormat));
713
        $this->DebugMessage('Content-Disposition header filename set to "' . $downloadfilename . '"', __FILE__, __LINE__);
714
        if ($downloadfilename) {
715
            header('Content-Disposition: ' . ($this->down ? 'attachment' : 'inline') . '; filename="' . $downloadfilename . '"');
716
        } else {
717
            $this->DebugMessage('failed to send Content-Disposition header because $downloadfilename is empty', __FILE__, __LINE__);
718
        }
719
720
        if ($this->useRawIMoutput) {
721
            header('Content-Type: ' . phpthumb_functions::ImageTypeToMIMEtype($this->thumbnailFormat));
722
            echo $this->IMresizedData;
723
        } else {
724
            $this->DebugMessage('ImageInterlace($this->gdimg_output, ' . (int)$this->config_output_interlace . ')', __FILE__, __LINE__);
725
            imageinterlace($this->gdimg_output, (int)$this->config_output_interlace);
726
            switch ($this->thumbnailFormat) {
727 View Code Duplication
                case 'jpeg':
728
                    header('Content-Type: ' . phpthumb_functions::ImageTypeToMIMEtype($this->thumbnailFormat));
729
                    $ImageOutFunction = 'image' . $this->thumbnailFormat;
730
                    @$ImageOutFunction($this->gdimg_output, null, $this->thumbnailQuality);
731
                    break;
732
733
                case 'png':
734 View Code Duplication
                case 'gif':
735
                    header('Content-Type: ' . phpthumb_functions::ImageTypeToMIMEtype($this->thumbnailFormat));
736
                    $ImageOutFunction = 'image' . $this->thumbnailFormat;
737
                    @$ImageOutFunction($this->gdimg_output);
738
                    break;
739
740 View Code Duplication
                case 'bmp':
741
                    if (!@require_once __DIR__ . '/phpthumb.bmp.php') {
742
                        $this->DebugMessage('Error including "' . __DIR__ . '/phpthumb.bmp.php" which is required for BMP format output', __FILE__, __LINE__);
743
744
                        return false;
745
                    }
746
                    $phpthumb_bmp = new phpthumb_bmp();
747
                    if (is_object($phpthumb_bmp)) {
748
                        $bmp_data = $phpthumb_bmp->GD2BMPstring($this->gdimg_output);
749
                        unset($phpthumb_bmp);
750
                        if (!$bmp_data) {
751
                            $this->DebugMessage('$phpthumb_bmp->GD2BMPstring() failed', __FILE__, __LINE__);
752
753
                            return false;
754
                        }
755
                        header('Content-Type: ' . phpthumb_functions::ImageTypeToMIMEtype($this->thumbnailFormat));
756
                        echo $bmp_data;
757
                    } else {
758
                        $this->DebugMessage('new phpthumb_bmp() failed', __FILE__, __LINE__);
759
760
                        return false;
761
                    }
762
                    break;
763
764 View Code Duplication
                case 'ico':
765
                    if (!@require_once __DIR__ . '/phpthumb.ico.php') {
766
                        $this->DebugMessage('Error including "' . __DIR__ . '/phpthumb.ico.php" which is required for ICO format output', __FILE__, __LINE__);
767
768
                        return false;
769
                    }
770
                    $phpthumb_ico = new phpthumb_ico();
771
                    if (is_object($phpthumb_ico)) {
772
                        $arrayOfOutputImages = array($this->gdimg_output);
773
                        $ico_data            = $phpthumb_ico->GD2ICOstring($arrayOfOutputImages);
774
                        unset($phpthumb_ico);
775
                        if (!$ico_data) {
776
                            $this->DebugMessage('$phpthumb_ico->GD2ICOstring() failed', __FILE__, __LINE__);
777
778
                            return false;
779
                        }
780
                        header('Content-Type: ' . phpthumb_functions::ImageTypeToMIMEtype($this->thumbnailFormat));
781
                        echo $ico_data;
782
                    } else {
783
                        $this->DebugMessage('new phpthumb_ico() failed', __FILE__, __LINE__);
784
785
                        return false;
786
                    }
787
                    break;
788
789
                default:
790
                    $this->DebugMessage('OutputThumbnail failed because $this->thumbnailFormat "' . $this->thumbnailFormat . '" is not valid', __FILE__, __LINE__);
791
792
                    return false;
793
                    break;
794
            }
795
        }
796
797
        return true;
798
    }
799
800
    // public:
801
802
    /**
803
     * @return bool
804
     */
805
    public function CleanUpCacheDirectory()
806
    {
807
        $this->DebugMessage('CleanUpCacheDirectory() set to purge ('
808
                            . (is_null($this->config_cache_maxage) ? 'NULL' : number_format($this->config_cache_maxage / 86400, 1))
809
                            . ' days; '
810
                            . (is_null($this->config_cache_maxsize) ? 'NULL' : number_format($this->config_cache_maxsize / 1048576, 2))
811
                            . ' MB; '
812
                            . (is_null($this->config_cache_maxfiles) ? 'NULL' : number_format($this->config_cache_maxfiles))
813
                            . ' files)', __FILE__, __LINE__);
814
815 View Code Duplication
        if (!is_writable($this->config_cache_directory)) {
816
            $this->DebugMessage('CleanUpCacheDirectory() skipped because "' . $this->config_cache_directory . '" is not writable', __FILE__, __LINE__);
817
818
            return true;
819
        }
820
821
        // cache status of cache directory for 1 hour to avoid hammering the filesystem functions
822
        $phpThumbCacheStats_filename = $this->config_cache_directory . DIRECTORY_SEPARATOR . 'phpThumbCacheStats.txt';
823
        if (file_exists($phpThumbCacheStats_filename) && is_readable($phpThumbCacheStats_filename)
824
            && (filemtime($phpThumbCacheStats_filename) >= (time() - 3600))
825
        ) {
826
            $this->DebugMessage('CleanUpCacheDirectory() skipped because "' . $phpThumbCacheStats_filename . '" is recently modified', __FILE__, __LINE__);
827
828
            return true;
829
        }
830
        if (!@touch($phpThumbCacheStats_filename)) {
831
            $this->DebugMessage('touch(' . $phpThumbCacheStats_filename . ') failed', __FILE__, __LINE__);
832
        }
833
834
        $DeletedKeys              = array();
835
        $AllFilesInCacheDirectory = array();
836
        if (($this->config_cache_maxage > 0) || ($this->config_cache_maxsize > 0)
837
            || ($this->config_cache_maxfiles > 0)
838
        ) {
839
            $CacheDirOldFilesAge      = array();
840
            $CacheDirOldFilesSize     = array();
841
            $AllFilesInCacheDirectory = phpthumb_functions::GetAllFilesInSubfolders($this->config_cache_directory);
842
            foreach ($AllFilesInCacheDirectory as $fullfilename) {
843
                if (preg_match('#' . preg_quote($this->config_cache_prefix) . '#i', $fullfilename)
844
                    && file_exists($fullfilename)
845
                ) {
846
                    $CacheDirOldFilesAge[$fullfilename] = @fileatime($fullfilename);
847
                    if ($CacheDirOldFilesAge[$fullfilename] == 0) {
848
                        $CacheDirOldFilesAge[$fullfilename] = @filemtime($fullfilename);
849
                    }
850
                    $CacheDirOldFilesSize[$fullfilename] = @filesize($fullfilename);
851
                }
852
            }
853
            if (empty($CacheDirOldFilesSize)) {
854
                $this->DebugMessage('CleanUpCacheDirectory() skipped because $CacheDirOldFilesSize is empty (phpthumb_functions::GetAllFilesInSubfolders('
855
                                    . $this->config_cache_directory
856
                                    . ') found no files)', __FILE__, __LINE__);
857
858
                return true;
859
            }
860
            $DeletedKeys['zerobyte'] = array();
861
            foreach ($CacheDirOldFilesSize as $fullfilename => $filesize) {
862
                // purge all zero-size files more than an hour old (to prevent trying to delete just-created and/or in-use files)
863
                $cutofftime = time() - 3600;
864
                if (($filesize == 0) && ($CacheDirOldFilesAge[$fullfilename] < $cutofftime)) {
865
                    $this->DebugMessage('deleting "' . $fullfilename . '"', __FILE__, __LINE__);
866
                    if (@unlink($fullfilename)) {
867
                        $DeletedKeys['zerobyte'][] = $fullfilename;
868
                        unset($CacheDirOldFilesSize[$fullfilename]);
869
                        unset($CacheDirOldFilesAge[$fullfilename]);
870
                    }
871
                }
872
            }
873
            $this->DebugMessage('CleanUpCacheDirectory() purged ' . count($DeletedKeys['zerobyte']) . ' zero-byte files', __FILE__, __LINE__);
874
            asort($CacheDirOldFilesAge);
875
876 View Code Duplication
            if ($this->config_cache_maxfiles > 0) {
877
                $TotalCachedFiles        = count($CacheDirOldFilesAge);
878
                $DeletedKeys['maxfiles'] = array();
879
                foreach ($CacheDirOldFilesAge as $fullfilename => $filedate) {
880
                    if ($TotalCachedFiles > $this->config_cache_maxfiles) {
881
                        $this->DebugMessage('deleting "' . $fullfilename . '"', __FILE__, __LINE__);
882
                        if (@unlink($fullfilename)) {
883
                            $TotalCachedFiles--;
884
                            $DeletedKeys['maxfiles'][] = $fullfilename;
885
                        }
886
                    } else {
887
                        // there are few enough files to keep the rest
888
                        break;
889
                    }
890
                }
891
                $this->DebugMessage('CleanUpCacheDirectory() purged ' . count($DeletedKeys['maxfiles']) . ' files based on (config_cache_maxfiles=' . $this->config_cache_maxfiles . ')', __FILE__,
892
                                    __LINE__);
893
                foreach ($DeletedKeys['maxfiles'] as $fullfilename) {
894
                    unset($CacheDirOldFilesAge[$fullfilename]);
895
                    unset($CacheDirOldFilesSize[$fullfilename]);
896
                }
897
            }
898
899 View Code Duplication
            if ($this->config_cache_maxage > 0) {
900
                $mindate               = time() - $this->config_cache_maxage;
901
                $DeletedKeys['maxage'] = array();
902
                foreach ($CacheDirOldFilesAge as $fullfilename => $filedate) {
903
                    if ($filedate > 0) {
904
                        if ($filedate < $mindate) {
905
                            $this->DebugMessage('deleting "' . $fullfilename . '"', __FILE__, __LINE__);
906
                            if (@unlink($fullfilename)) {
907
                                $DeletedKeys['maxage'][] = $fullfilename;
908
                            }
909
                        } else {
910
                            // the rest of the files are new enough to keep
911
                            break;
912
                        }
913
                    }
914
                }
915
                $this->DebugMessage('CleanUpCacheDirectory() purged ' . count($DeletedKeys['maxage']) . ' files based on (config_cache_maxage=' . $this->config_cache_maxage . ')', __FILE__, __LINE__);
916
                foreach ($DeletedKeys['maxage'] as $fullfilename) {
917
                    unset($CacheDirOldFilesAge[$fullfilename]);
918
                    unset($CacheDirOldFilesSize[$fullfilename]);
919
                }
920
            }
921
922
            if ($this->config_cache_maxsize > 0) {
923
                $TotalCachedFileSize    = array_sum($CacheDirOldFilesSize);
924
                $DeletedKeys['maxsize'] = array();
925
                foreach ($CacheDirOldFilesAge as $fullfilename => $filedate) {
926
                    if ($TotalCachedFileSize > $this->config_cache_maxsize) {
927
                        $this->DebugMessage('deleting "' . $fullfilename . '"', __FILE__, __LINE__);
928
                        if (@unlink($fullfilename)) {
929
                            $TotalCachedFileSize      -= $CacheDirOldFilesSize[$fullfilename];
930
                            $DeletedKeys['maxsize'][] = $fullfilename;
931
                        }
932
                    } else {
933
                        // the total filesizes are small enough to keep the rest of the files
934
                        break;
935
                    }
936
                }
937
                $this->DebugMessage('CleanUpCacheDirectory() purged ' . count($DeletedKeys['maxsize']) . ' files based on (config_cache_maxsize=' . $this->config_cache_maxsize . ')', __FILE__,
938
                                    __LINE__);
939
                foreach ($DeletedKeys['maxsize'] as $fullfilename) {
940
                    unset($CacheDirOldFilesAge[$fullfilename]);
941
                    unset($CacheDirOldFilesSize[$fullfilename]);
942
                }
943
            }
944
        } else {
945
            $this->DebugMessage('skipping CleanUpCacheDirectory() because config set to not use it', __FILE__, __LINE__);
946
        }
947
        $totalpurged = 0;
948
        foreach ($DeletedKeys as $key => $value) {
949
            $totalpurged += count($value);
950
        }
951
        $this->DebugMessage('CleanUpCacheDirectory() purged ' . $totalpurged . ' files (from ' . count($AllFilesInCacheDirectory) . ') based on config settings', __FILE__, __LINE__);
952
        if ($totalpurged > 0) {
953
            $empty_dirs = array();
954
            foreach ($AllFilesInCacheDirectory as $fullfilename) {
955
                if (is_dir($fullfilename)) {
956
                    $empty_dirs[$this->realPathSafe($fullfilename)] = 1;
957
                } else {
958
                    unset($empty_dirs[$this->realPathSafe(dirname($fullfilename))]);
959
                }
960
            }
961
            krsort($empty_dirs);
962
            $totalpurgeddirs = 0;
963
            foreach ($empty_dirs as $empty_dir => $dummy) {
964
                if ($empty_dir == $this->config_cache_directory) {
965
                    // shouldn't happen, but just in case, don't let it delete actual cache directory
966
                    continue;
967
                } elseif (@rmdir($empty_dir)) {
968
                    $totalpurgeddirs++;
969
                } else {
970
                    $this->DebugMessage('failed to rmdir(' . $empty_dir . ')', __FILE__, __LINE__);
971
                }
972
            }
973
            $this->DebugMessage('purged ' . $totalpurgeddirs . ' empty directories', __FILE__, __LINE__);
974
        }
975
976
        return true;
977
    }
978
979
    //////////////////////////////////////////////////////////////////////
980
981
    // private: re-initializator (call between rendering multiple images with one object)
982
    /**
983
     * @return bool
984
     */
985
    public function resetObject()
986
    {
987
        $class_vars = get_class_vars(get_class($this));
988
        foreach ($class_vars as $key => $value) {
989
            // do not clobber debug or config info
990
            if (!preg_match('#^(config_|debug|fatalerror)#i', $key)) {
991
                $this->$key = $value;
992
            }
993
        }
994
        $this->phpThumb(); // re-initialize some class variables
995
        return true;
996
    }
997
998
    //////////////////////////////////////////////////////////////////////
999
1000
    /**
1001
     * @return bool
1002
     */
1003
    public function ResolveSource()
1004
    {
1005
        if (is_resource($this->gdimg_source)) {
1006
            $this->DebugMessage('ResolveSource() exiting because is_resource($this->gdimg_source)', __FILE__, __LINE__);
1007
1008
            return true;
1009
        }
1010
        if ($this->rawImageData) {
1011
            $this->sourceFilename = null;
1012
            $this->DebugMessage('ResolveSource() exiting because $this->rawImageData is set (' . number_format(strlen($this->rawImageData)) . ' bytes)', __FILE__, __LINE__);
1013
1014
            return true;
1015
        }
1016
        if ($this->sourceFilename) {
1017
            $this->sourceFilename = $this->ResolveFilenameToAbsolute($this->sourceFilename);
1018
            $this->DebugMessage('$this->sourceFilename set to "' . $this->sourceFilename . '"', __FILE__, __LINE__);
1019
        } elseif ($this->src) {
1020
            $this->sourceFilename = $this->ResolveFilenameToAbsolute($this->src);
1021
            $this->DebugMessage('$this->sourceFilename set to "' . $this->sourceFilename . '" from $this->src (' . $this->src . ')', __FILE__, __LINE__);
1022
        } else {
1023
            return $this->ErrorImage('$this->sourceFilename and $this->src are both empty');
1024
        }
1025
        if ($this->iswindows
1026
            && ((substr($this->sourceFilename, 0, 2) == '//')
1027
                || (substr($this->sourceFilename, 0, 2) == '\\\\'))
1028
        ) {
1029
            // Windows \\share\filename.ext
1030
        } elseif (preg_match('#^[a-z0-9]+://#i', $this->sourceFilename, $protocol_matches)) {
1031
            if (preg_match('#^(f|ht)tps?\://#i', $this->sourceFilename)) {
1032
                // URL
1033
                if ($this->config_http_user_agent) {
1034
                    ini_set('user_agent', $this->config_http_user_agent);
1035
                }
1036
            } else {
1037
                return $this->ErrorImage('only FTP and HTTP/HTTPS protocols are allowed, "' . $protocol_matches[1] . '" is not');
1038
            }
1039
        } elseif (!@file_exists($this->sourceFilename)) {
1040
            return $this->ErrorImage('"' . $this->sourceFilename . '" does not exist');
1041
        } elseif (!@is_file($this->sourceFilename)) {
1042
            return $this->ErrorImage('"' . $this->sourceFilename . '" is not a file');
1043
        }
1044
1045
        return true;
1046
    }
1047
1048
    /**
1049
     * @return bool
1050
     */
1051
    public function setOutputFormat()
1052
    {
1053
        static $alreadyCalled = false;
1054
        if ($this->thumbnailFormat && $alreadyCalled) {
1055
            return true;
1056
        }
1057
        $alreadyCalled = true;
1058
1059
        $AvailableImageOutputFormats   = array();
1060
        $AvailableImageOutputFormats[] = 'text';
1061
        if (@is_readable(__DIR__ . '/phpthumb.ico.php')) {
1062
            $AvailableImageOutputFormats[] = 'ico';
1063
        }
1064
        if (@is_readable(__DIR__ . '/phpthumb.bmp.php')) {
1065
            $AvailableImageOutputFormats[] = 'bmp';
1066
        }
1067
1068
        $this->thumbnailFormat = 'ico';
1069
1070
        // Set default output format based on what image types are available
1071
        if (function_exists('ImageTypes')) {
1072
            $imagetypes = imagetypes();
1073
            if ($imagetypes & IMG_WBMP) {
1074
                $this->thumbnailFormat         = 'wbmp';
1075
                $AvailableImageOutputFormats[] = 'wbmp';
1076
            }
1077
            if ($imagetypes & IMG_GIF) {
1078
                $this->thumbnailFormat         = 'gif';
1079
                $AvailableImageOutputFormats[] = 'gif';
1080
            }
1081
            if ($imagetypes & IMG_PNG) {
1082
                $this->thumbnailFormat         = 'png';
1083
                $AvailableImageOutputFormats[] = 'png';
1084
            }
1085
            if ($imagetypes & IMG_JPG) {
1086
                $this->thumbnailFormat         = 'jpeg';
1087
                $AvailableImageOutputFormats[] = 'jpeg';
1088
            }
1089
        } else {
1090
            //return $this->ErrorImage('ImageTypes() does not exist - GD support might not be enabled?');
1091
            $this->DebugMessage('ImageTypes() does not exist - GD support might not be enabled?', __FILE__, __LINE__);
1092
        }
1093
        if ($this->ImageMagickVersion()) {
1094
            $IMformats = array('jpeg', 'png', 'gif', 'bmp', 'ico', 'wbmp');
1095
            $this->DebugMessage('Addding ImageMagick formats to $AvailableImageOutputFormats (' . implode(';', $AvailableImageOutputFormats) . ')', __FILE__, __LINE__);
1096
            foreach ($IMformats as $key => $format) {
1097
                $AvailableImageOutputFormats[] = $format;
1098
            }
1099
        }
1100
        $AvailableImageOutputFormats = array_unique($AvailableImageOutputFormats);
1101
        $this->DebugMessage('$AvailableImageOutputFormats = array(' . implode(';', $AvailableImageOutputFormats) . ')', __FILE__, __LINE__);
1102
1103
        $this->f = preg_replace('#[^a-z]#', '', strtolower($this->f));
1104
        if (strtolower($this->config_output_format) == 'jpg') {
1105
            $this->config_output_format = 'jpeg';
1106
        }
1107
        if (strtolower($this->f) == 'jpg') {
1108
            $this->f = 'jpeg';
1109
        }
1110 View Code Duplication
        if (phpthumb_functions::CaseInsensitiveInArray($this->config_output_format, $AvailableImageOutputFormats)) {
1111
            // set output format to config default if that format is available
1112
            $this->DebugMessage('$this->thumbnailFormat set to $this->config_output_format "' . strtolower($this->config_output_format) . '"', __FILE__, __LINE__);
1113
            $this->thumbnailFormat = strtolower($this->config_output_format);
1114
        } elseif ($this->config_output_format) {
1115
            $this->DebugMessage('$this->thumbnailFormat staying as "'
1116
                                . $this->thumbnailFormat
1117
                                . '" because $this->config_output_format ('
1118
                                . strtolower($this->config_output_format)
1119
                                . ') is not in $AvailableImageOutputFormats', __FILE__, __LINE__);
1120
        }
1121 View Code Duplication
        if ($this->f && phpthumb_functions::CaseInsensitiveInArray($this->f, $AvailableImageOutputFormats)) {
1122
            // override output format if $this->f is set and that format is available
1123
            $this->DebugMessage('$this->thumbnailFormat set to $this->f "' . strtolower($this->f) . '"', __FILE__, __LINE__);
1124
            $this->thumbnailFormat = strtolower($this->f);
1125
        } elseif ($this->f) {
1126
            $this->DebugMessage('$this->thumbnailFormat staying as "' . $this->thumbnailFormat . '" because $this->f (' . strtolower($this->f) . ') is not in $AvailableImageOutputFormats', __FILE__,
1127
                                __LINE__);
1128
        }
1129
1130
        // for JPEG images, quality 1 (worst) to 99 (best)
1131
        // quality < 25 is nasty, with not much size savings - not recommended
1132
        // problems with 100 - invalid JPEG?
1133
        $this->thumbnailQuality = max(1, min(99, ($this->q ? (int)$this->q : 75)));
1134
        $this->DebugMessage('$this->thumbnailQuality set to "' . $this->thumbnailQuality . '"', __FILE__, __LINE__);
1135
1136
        return true;
1137
    }
1138
1139
    /**
1140
     * @return bool
1141
     */
1142
    public function setCacheDirectory()
1143
    {
1144
        // resolve cache directory to absolute pathname
1145
        $this->DebugMessage('setCacheDirectory() starting with config_cache_directory = "' . $this->config_cache_directory . '"', __FILE__, __LINE__);
1146
        if (substr($this->config_cache_directory, 0, 1) == '.') {
1147
            if (preg_match('#^(f|ht)tps?\://#i', $this->src)) {
1148
                if (!$this->config_cache_disable_warning) {
1149
                    $this->ErrorImage('$this->config_cache_directory ('
1150
                                      . $this->config_cache_directory
1151
                                      . ') cannot be used for remote images. Adjust "cache_directory" or "cache_disable_warning" in phpThumb.config.php');
1152
                }
1153
            } elseif ($this->src) {
1154
                // resolve relative cache directory to source image
1155
                $this->config_cache_directory = dirname($this->ResolveFilenameToAbsolute($this->src)) . DIRECTORY_SEPARATOR . $this->config_cache_directory;
1156
            } else {
1157
                // $this->new is probably set
1158
            }
1159
        }
1160
        if (substr($this->config_cache_directory, -1) == '/') {
1161
            $this->config_cache_directory = substr($this->config_cache_directory, 0, -1);
1162
        }
1163
        if ($this->iswindows) {
1164
            $this->config_cache_directory = str_replace('/', DIRECTORY_SEPARATOR, $this->config_cache_directory);
1165
        }
1166
        if ($this->config_cache_directory) {
1167
            $real_cache_path = $this->realPathSafe($this->config_cache_directory);
1168
            if (!$real_cache_path) {
1169
                $this->DebugMessage('$this->realPathSafe($this->config_cache_directory) failed for "' . $this->config_cache_directory . '"', __FILE__, __LINE__);
1170
                if (!is_dir($this->config_cache_directory)) {
1171
                    $this->DebugMessage('!is_dir(' . $this->config_cache_directory . ')', __FILE__, __LINE__);
1172
                }
1173
            }
1174
            if ($real_cache_path) {
1175
                $this->DebugMessage('setting config_cache_directory to $this->realPathSafe(' . $this->config_cache_directory . ') = "' . $real_cache_path . '"', __FILE__, __LINE__);
1176
                $this->config_cache_directory = $real_cache_path;
1177
            }
1178
        }
1179
        if (!is_dir($this->config_cache_directory)) {
1180
            if (!$this->config_cache_disable_warning) {
1181
                $this->ErrorImage('$this->config_cache_directory (' . $this->config_cache_directory . ') does not exist. Adjust "cache_directory" or "cache_disable_warning" in phpThumb.config.php');
1182
            }
1183
            $this->DebugMessage('$this->config_cache_directory (' . $this->config_cache_directory . ') is not a directory', __FILE__, __LINE__);
1184
            $this->config_cache_directory = null;
1185 View Code Duplication
        } elseif (!@is_writable($this->config_cache_directory)) {
1186
            $this->DebugMessage('$this->config_cache_directory is not writable (' . $this->config_cache_directory . ')', __FILE__, __LINE__);
1187
        }
1188
1189
        $this->InitializeTempDirSetting();
1190
        if (!@is_dir($this->config_temp_directory) && !@is_writable($this->config_temp_directory)
1191
            && @is_dir($this->config_cache_directory)
1192
            && @is_writable($this->config_cache_directory)
1193
        ) {
1194
            $this->DebugMessage('setting $this->config_temp_directory = $this->config_cache_directory (' . $this->config_cache_directory . ')', __FILE__, __LINE__);
1195
            $this->config_temp_directory = $this->config_cache_directory;
1196
        }
1197
1198
        return true;
1199
    }
1200
1201
    /* Takes the array of path segments up to now, and the next segment (maybe a modifier: empty, . or ..)
1202
       Applies it, adding or removing from $segments as a result. Returns nothing. */
1203
    // http://support.silisoftware.com/phpBB3/viewtopic.php?t=961
1204
    /**
1205
     * @param $segments
1206
     * @param $segment
1207
     */
1208
    public function applyPathSegment(&$segments, $segment)
1209
    {
1210
        if ($segment == '.') {
1211
            return; // always remove
1212
        }
1213
        if ($segment == '') {
1214
            $test = array_pop($segments);
1215
            if (is_null($test)) {
1216
                $segments[] = $segment; // keep the first empty block
1217 View Code Duplication
            } elseif ($test == '') {
1218
                $test = array_pop($segments);
1219
                if (is_null($test)) {
1220
                    $segments[] = $test;
1221
                    $segments[] = $segment; // keep the second one too
1222
                } else { // put both back and ignore segment
1223
                    $segments[] = $test;
1224
                    $segments[] = $test;
1225
                }
1226
            } else {
1227
                $segments[] = $test; // ignore empty blocks
1228
            }
1229
        } else {
1230
            if ($segment == '..') {
1231
                $test = array_pop($segments);
1232 View Code Duplication
                if (is_null($test)) {
1233
                    $segments[] = $segment;
1234
                } elseif ($test == '..') {
1235
                    $segments[] = $test;
1236
                    $segments[] = $segment;
1237
                } else {
1238
                    if ($test == '') {
1239
                        $segments[] = $test;
1240
                    } // else nothing, remove both
1241
                }
1242
            } else {
1243
                $segments[] = $segment;
1244
            }
1245
        }
1246
    }
1247
1248
    /* Takes array of path components, normalizes it: removes empty slots and '.', collapses '..' and folder names.  Returns array. */
1249
    // http://support.silisoftware.com/phpBB3/viewtopic.php?t=961
1250
    /**
1251
     * @param $segments
1252
     * @return array
1253
     */
1254
    public function normalizePath($segments)
1255
    {
1256
        $parts = array();
1257
        foreach ($segments as $segment) {
1258
            $this->applyPathSegment($parts, $segment);
1259
        }
1260
1261
        return $parts;
1262
    }
1263
1264
    /* True if the provided path points (without resolving symbolic links) into one of the allowed directories. */
1265
    // http://support.silisoftware.com/phpBB3/viewtopic.php?t=961
1266
    /**
1267
     * @param $path
1268
     * @param $allowed_dirs
1269
     * @return bool
1270
     */
1271
    public function matchPath($path, $allowed_dirs)
1272
    {
1273
        if (!empty($allowed_dirs)) {
1274
            foreach ($allowed_dirs as $one_dir) {
1275
                if (preg_match('#^' . preg_quote(str_replace(DIRECTORY_SEPARATOR, '/', $this->realPathSafe($one_dir))) . '#', $path)) {
1276
                    return true;
1277
                }
1278
            }
1279
        }
1280
1281
        return false;
1282
    }
1283
1284
    /* True if the provided path points inside one of open_basedirs (or if open_basedirs are disabled) */
1285
    // http://support.silisoftware.com/phpBB3/viewtopic.php?t=961
1286
    /**
1287
     * @param $path
1288
     * @return bool
1289
     */
1290
    public function isInOpenBasedir($path)
1291
    {
1292
        static $open_basedirs = null;
1293
        if (is_null($open_basedirs)) {
1294
            $ini_text = ini_get('open_basedir');
1295
            $this->DebugMessage('open_basedir: "' . $ini_text . '"', __FILE__, __LINE__);
1296
            $open_basedirs = array();
1297
            if (strlen($ini_text) > 0) {
1298
                foreach (preg_split('#[;:]#', $ini_text) as $key => $value) {
1299
                    $open_basedirs[$key] = $this->realPathSafe($value);
1300
                }
1301
            }
1302
        }
1303
1304
        return (empty($open_basedirs) || $this->matchPath($path, $open_basedirs));
1305
    }
1306
1307
    /* 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. */
1308
    // http://support.silisoftware.com/phpBB3/viewtopic.php?t=961
1309
    /**
1310
     * @param $path
1311
     * @param $allowed_dirs
1312
     * @return null|string
1313
     */
1314
    public function resolvePath($path, $allowed_dirs)
1315
    {
1316
        $this->DebugMessage('resolvePath: ' . $path . ' (allowed_dirs: ' . print_r($allowed_dirs, true) . ')', __FILE__, __LINE__);
1317
1318
        // add base path to the top of the list
1319
        if (!$this->config_allow_src_above_docroot) {
1320
            array_unshift($allowed_dirs, $this->realPathSafe($this->config_document_root));
1321
        } else {
1322
            if (!$this->config_allow_src_above_phpthumb) {
1323
                array_unshift($allowed_dirs, $this->realPathSafe(__DIR__));
1324
            } else {
1325
                // no checks are needed, offload the work to realpath and forget about it
1326
                $this->DebugMessage('resolvePath: checks disabled, returning ' . $this->realPathSafe($path), __FILE__, __LINE__);
1327
1328
                return $this->realPathSafe($path);
1329
            }
1330
        }
1331
        if ($path == '') {
1332
            return null; // save us trouble
1333
        }
1334
1335
        do {
1336
            $this->DebugMessage('resolvePath: iteration, path=' . $path . ', base path = ' . $allowed_dirs[0], __FILE__, __LINE__);
1337
1338
            $parts = array();
1339
            // do not use "cleaner" foreach version of this loop as later code relies on both $segments and $i
1340
            // http://support.silisoftware.com/phpBB3/viewtopic.php?t=964
1341
            $segments = explode(DIRECTORY_SEPARATOR, $path);
1342
            for ($i = 0, $iMax = count($segments); $i < $iMax; ++$i) {
1343
                $this->applyPathSegment($parts, $segments[$i]);
1344
                $thispart = implode(DIRECTORY_SEPARATOR, $parts);
1345
                if ($this->isInOpenBasedir($thispart)) {
1346
                    if (is_link($thispart)) {
1347
                        break;
1348
                    }
1349
                }
1350
            }
1351
1352
            $this->DebugMessage('resolvePath: stop at component ' . $i, __FILE__, __LINE__);
1353
            // test the part up to here
1354
            $path = implode(DIRECTORY_SEPARATOR, $parts);
1355
            $this->DebugMessage('resolvePath: stop at path=' . $path, __FILE__, __LINE__);
1356
            if (!$this->matchPath($path, $allowed_dirs)) {
1357
                $this->DebugMessage('resolvePath: no match, returning null', __FILE__, __LINE__);
1358
1359
                return null;
1360
            }
1361
            if ($i >= count($segments)) { // reached end
1362
                $this->DebugMessage('resolvePath: path parsed, over', __FILE__, __LINE__);
1363
                break;
1364
            }
1365
            // else it's symlink, rewrite path
1366
            $path = readlink($path);
1367
            $this->DebugMessage('resolvePath: symlink matched, target=' . $path, __FILE__, __LINE__);
1368
1369
            /*
1370
            Replace base path with symlink target.
1371
            Assuming:
1372
              /www/img/external -> /external
1373
            This is allowed:
1374
              GET /www/img/external/../external/test/pic.jpg
1375
            This isn't:
1376
              GET /www/img/external/../www/img/pic.jpg
1377
            So there's only one base path which is the last symlink target, but any number of stable whitelisted paths.
1378
            */
1379
            if ($this->config_auto_allow_symlinks) {
1380
                $allowed_dirs[0] = $path;
1381
            }
1382
            $path = $path . DIRECTORY_SEPARATOR . implode(DIRECTORY_SEPARATOR, array_slice($segments, $i + 1));
1383
        } while (true);
1384
1385
        return $path;
1386
    }
1387
1388
    /**
1389
     * @param $filename
1390
     * @return mixed|string
1391
     */
1392
    public function realPathSafe($filename)
1393
    {
1394
        // 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"
1395
        // realPathSafe() provides a reasonable facsimile of realpath() but does not resolve symbolic links, nor does it check that the file/path actually exists
1396
        if (!$this->config_disable_realpath) {
1397
            return realpath($filename);
1398
        }
1399
1400
        // http://stackoverflow.com/questions/21421569
1401
        $newfilename = preg_replace('#[\\/]+#', DIRECTORY_SEPARATOR, $filename);
1402
        if (!preg_match('#^' . DIRECTORY_SEPARATOR . '#', $newfilename)) {
1403
            $newfilename = __DIR__ . DIRECTORY_SEPARATOR . $newfilename;
1404
        }
1405
        do {
1406
            $beforeloop = $newfilename;
1407
1408
            // 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.]]
1409
            $newfilename = preg_replace('#' . DIRECTORY_SEPARATOR . '+#', DIRECTORY_SEPARATOR, $newfilename);
1410
1411
            // Replace all occurrences of /./ with /
1412
            $newfilename = preg_replace('#' . DIRECTORY_SEPARATOR . '\\.' . DIRECTORY_SEPARATOR . '#', DIRECTORY_SEPARATOR, $newfilename);
1413
1414
            // Remove ./ if at the start
1415
            $newfilename = preg_replace('#^\\.' . DIRECTORY_SEPARATOR . '#', '', $newfilename);
1416
1417
            // Remove /. if at the end
1418
            $newfilename = preg_replace('#' . DIRECTORY_SEPARATOR . '\\.$#', '', $newfilename);
1419
1420
            // Replace /anything/../ with /
1421
            $newfilename = preg_replace('#' . DIRECTORY_SEPARATOR . '[^' . DIRECTORY_SEPARATOR . ']+' . DIRECTORY_SEPARATOR . '\\.\\.' . DIRECTORY_SEPARATOR . '#', DIRECTORY_SEPARATOR, $newfilename);
1422
1423
            // Remove /anything/.. if at the end
1424
            $newfilename = preg_replace('#' . DIRECTORY_SEPARATOR . '[^' . DIRECTORY_SEPARATOR . ']+' . DIRECTORY_SEPARATOR . '\\.\\.$#', '', $newfilename);
1425
        } while ($newfilename != $beforeloop);
1426
1427
        return $newfilename;
1428
    }
1429
1430
    /**
1431
     * @param $filename
1432
     * @return bool|mixed|string
1433
     */
1434
    public function ResolveFilenameToAbsolute($filename)
1435
    {
1436
        if (empty($filename)) {
1437
            return false;
1438
        }
1439
1440
        if (preg_match('#^[a-z0-9]+\:/{1,2}#i', $filename)) {
1441
            // eg: http://host/path/file.jpg (HTTP URL)
1442
            // eg: ftp://host/path/file.jpg  (FTP URL)
1443
            // eg: data1:/path/file.jpg      (Netware path)
1444
1445
            //$AbsoluteFilename = $filename;
1446
            return $filename;
1447
        } elseif ($this->iswindows && isset($filename{1}) && ($filename{1} == ':')) {
1448
1449
            // absolute pathname (Windows)
1450
            $AbsoluteFilename = $filename;
1451
        } elseif ($this->iswindows && ((substr($filename, 0, 2) == '//') || (substr($filename, 0, 2) == '\\\\'))) {
1452
1453
            // absolute pathname (Windows)
1454
            $AbsoluteFilename = $filename;
1455
        } elseif ($filename{0} == '/') {
1456
            if (@is_readable($filename) && !@is_readable($this->config_document_root . $filename)) {
1457
1458
                // absolute filename (*nix)
1459
                $AbsoluteFilename = $filename;
1460
            } elseif (isset($filename{1}) && ($filename{1} == '~')) {
1461
1462
                // /~user/path
1463
                if ($ApacheLookupURIarray = phpthumb_functions::ApacheLookupURIarray($filename)) {
1464
                    $AbsoluteFilename = $ApacheLookupURIarray['filename'];
1465
                } else {
1466
                    $AbsoluteFilename = $this->realPathSafe($filename);
1467
                    if (@is_readable($AbsoluteFilename)) {
1468
                        $this->DebugMessage('phpthumb_functions::ApacheLookupURIarray() failed for "'
1469
                                            . $filename
1470
                                            . '", but the correct filename ('
1471
                                            . $AbsoluteFilename
1472
                                            . ') seems to have been resolved with $this->realPathSafe($filename)', __FILE__, __LINE__);
1473 View Code Duplication
                    } elseif (is_dir(dirname($AbsoluteFilename))) {
1474
                        $this->DebugMessage('phpthumb_functions::ApacheLookupURIarray() failed for "'
1475
                                            . dirname($filename)
1476
                                            . '", but the correct directory ('
1477
                                            . dirname($AbsoluteFilename)
1478
                                            . ') seems to have been resolved with $this->realPathSafe(.)', __FILE__, __LINE__);
1479
                    } else {
1480
                        return $this->ErrorImage('phpthumb_functions::ApacheLookupURIarray() failed for "'
1481
                                                 . $filename
1482
                                                 . '". 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")');
1483
                    }
1484
                }
1485
            } else {
1486
1487
                // relative filename (any OS)
1488
                if (preg_match('#^' . preg_quote($this->config_document_root) . '#', $filename)) {
1489
                    $AbsoluteFilename = $filename;
1490
                    $this->DebugMessage('ResolveFilenameToAbsolute() NOT prepending $this->config_document_root ('
1491
                                        . $this->config_document_root
1492
                                        . ') to $filename ('
1493
                                        . $filename
1494
                                        . ') resulting in ($AbsoluteFilename = "'
1495
                                        . $AbsoluteFilename
1496
                                        . '")', __FILE__, __LINE__);
1497
                } else {
1498
                    $AbsoluteFilename = $this->config_document_root . $filename;
1499
                    $this->DebugMessage('ResolveFilenameToAbsolute() prepending $this->config_document_root ('
1500
                                        . $this->config_document_root
1501
                                        . ') to $filename ('
1502
                                        . $filename
1503
                                        . ') resulting in ($AbsoluteFilename = "'
1504
                                        . $AbsoluteFilename
1505
                                        . '")', __FILE__, __LINE__);
1506
                }
1507
            }
1508
        } else {
1509
1510
            // relative to current directory (any OS)
1511
            $AbsoluteFilename = __DIR__ . DIRECTORY_SEPARATOR . preg_replace('#[/\\\\]#', DIRECTORY_SEPARATOR, $filename);
1512
1513
            if (substr(dirname(@$_SERVER['PHP_SELF']), 0, 2) == '/~') {
1514
                if ($ApacheLookupURIarray = phpthumb_functions::ApacheLookupURIarray(dirname(@$_SERVER['PHP_SELF']))) {
1515
                    $AbsoluteFilename = $ApacheLookupURIarray['filename'] . DIRECTORY_SEPARATOR . $filename;
1516
                } else {
1517
                    $AbsoluteFilename = $this->realPathSafe('.') . DIRECTORY_SEPARATOR . $filename;
1518
                    if (@is_readable($AbsoluteFilename)) {
1519
                        $this->DebugMessage('phpthumb_functions::ApacheLookupURIarray() failed for "'
1520
                                            . dirname(@$_SERVER['PHP_SELF'])
1521
                                            . '", but the correct filename ('
1522
                                            . $AbsoluteFilename
1523
                                            . ') seems to have been resolved with $this->realPathSafe(.)/$filename', __FILE__, __LINE__);
1524 View Code Duplication
                    } elseif (is_dir(dirname($AbsoluteFilename))) {
1525
                        $this->DebugMessage('phpthumb_functions::ApacheLookupURIarray() failed for "'
1526
                                            . dirname(@$_SERVER['PHP_SELF'])
1527
                                            . '", but the correct directory ('
1528
                                            . dirname($AbsoluteFilename)
1529
                                            . ') seems to have been resolved with $this->realPathSafe(.)', __FILE__, __LINE__);
1530
                    } else {
1531
                        return $this->ErrorImage('phpthumb_functions::ApacheLookupURIarray() failed for "'
1532
                                                 . dirname(@$_SERVER['PHP_SELF'])
1533
                                                 . '". This has been known to fail on Apache2 - try using the absolute filename for the source image');
1534
                    }
1535
                }
1536
            }
1537
        }
1538
        /*
1539
        // removed 2014-May-30: http://support.silisoftware.com/phpBB3/viewtopic.php?t=961
1540
        if (is_link($AbsoluteFilename)) {
1541
            $this->DebugMessage('is_link()==true, changing "'.$AbsoluteFilename.'" to "'.readlink($AbsoluteFilename).'"', __FILE__, __LINE__);
1542
            $AbsoluteFilename = readlink($AbsoluteFilename);
1543
        }
1544
        if ($this->realPathSafe($AbsoluteFilename)) {
1545
            $AbsoluteFilename = $this->realPathSafe($AbsoluteFilename);
1546
        }
1547
        */
1548
        if ($this->iswindows) {
1549
            $AbsoluteFilename = preg_replace('#^' . preg_quote($this->realPathSafe($this->config_document_root)) . '#i', $this->realPathSafe($this->config_document_root), $AbsoluteFilename);
1550
            $AbsoluteFilename = str_replace(DIRECTORY_SEPARATOR, '/', $AbsoluteFilename);
1551
        }
1552
        $AbsoluteFilename = $this->resolvePath($AbsoluteFilename, $this->config_additional_allowed_dirs);
1553
        if (!$this->config_allow_src_above_docroot
1554
            && !preg_match('#^' . preg_quote(str_replace(DIRECTORY_SEPARATOR, '/', $this->realPathSafe($this->config_document_root))) . '#', $AbsoluteFilename)
1555
        ) {
1556
            $this->DebugMessage('!$this->config_allow_src_above_docroot therefore setting "' . $AbsoluteFilename . '" (outside "' . $this->realPathSafe($this->config_document_root) . '") to null',
1557
                                __FILE__, __LINE__);
1558
1559
            return false;
1560
        }
1561
        if (!$this->config_allow_src_above_phpthumb
1562
            && !preg_match('#^' . preg_quote(str_replace(DIRECTORY_SEPARATOR, '/', __DIR__)) . '#', $AbsoluteFilename)
1563
        ) {
1564
            $this->DebugMessage('!$this->config_allow_src_above_phpthumb therefore setting "' . $AbsoluteFilename . '" (outside "' . __DIR__ . '") to null', __FILE__, __LINE__);
1565
1566
            return false;
1567
        }
1568
1569
        return $AbsoluteFilename;
1570
    }
1571
1572
    /**
1573
     * @param        $filename
1574
     * @param  bool  $cached
1575
     * @return mixed
1576
     */
1577
    public function file_exists_ignoreopenbasedir($filename, $cached = true)
1578
    {
1579
        static $open_basedirs = null;
1580
        static $file_exists_cache = array();
1581
        if (!$cached || !isset($file_exists_cache[$filename])) {
1582
            if (is_null($open_basedirs)) {
1583
                $open_basedirs = preg_split('#[;:]#', ini_get('open_basedir'));
1584
            }
1585
            if (empty($open_basedirs) || in_array(dirname($filename), $open_basedirs)) {
1586
                $file_exists_cache[$filename] = file_exists($filename);
1587
            } elseif ($this->iswindows) {
1588
                $ls_filename                  = trim(phpthumb_functions::SafeExec('dir /b ' . phpthumb_functions::escapeshellarg_replacement($filename)));
1589
                $file_exists_cache[$filename] = ($ls_filename == basename($filename));  // command dir /b return only filename without path
1590
            } else {
1591
                $ls_filename                  = trim(phpthumb_functions::SafeExec('ls ' . phpthumb_functions::escapeshellarg_replacement($filename)));
1592
                $file_exists_cache[$filename] = ($ls_filename == $filename);
1593
            }
1594
        }
1595
1596
        return $file_exists_cache[$filename];
1597
    }
1598
1599
    /**
1600
     * @return bool|null|string
1601
     */
1602
    public function ImageMagickWhichConvert()
1603
    {
1604
        static $WhichConvert = null;
1605
        if (is_null($WhichConvert)) {
1606
            if ($this->iswindows) {
1607
                $WhichConvert = false;
1608
            } else {
1609
                $IMwhichConvertCacheFilename = $this->config_cache_directory . DIRECTORY_SEPARATOR . 'phpThumbCacheIMwhichConvert.txt';
1610
                if (($cachedwhichconvertstring = @file_get_contents($IMwhichConvertCacheFilename)) !== false) {
1611
                    $WhichConvert = $cachedwhichconvertstring;
1612
                } else {
1613
                    $WhichConvert = trim(phpthumb_functions::SafeExec('which convert'));
1614
                    @file_put_contents($IMwhichConvertCacheFilename, $WhichConvert);
1615
                }
1616
            }
1617
        }
1618
1619
        return $WhichConvert;
1620
    }
1621
1622
    /**
1623
     * @return bool|null|string
1624
     */
1625
    public function ImageMagickCommandlineBase()
1626
    {
1627
        static $commandline = null;
1628
        if (is_null($commandline)) {
1629
            if ($this->issafemode) {
1630
                $commandline = '';
1631
1632
                return $commandline;
1633
            }
1634
1635
            $IMcommandlineBaseCacheFilename = $this->config_cache_directory . DIRECTORY_SEPARATOR . 'phpThumbCacheIMcommandlineBase.txt';
1636
            if (($commandline = @file_get_contents($IMcommandlineBaseCacheFilename)) !== false) {
1637
                return $commandline;
1638
            }
1639
1640
            $commandline = (!is_null($this->config_imagemagick_path) ? $this->config_imagemagick_path : '');
1641
1642
            if ($this->config_imagemagick_path
1643
                && ($this->config_imagemagick_path != $this->realPathSafe($this->config_imagemagick_path))
1644
            ) {
1645
                if (@is_executable($this->realPathSafe($this->config_imagemagick_path))) {
1646
                    $this->DebugMessage('Changing $this->config_imagemagick_path ('
1647
                                        . $this->config_imagemagick_path
1648
                                        . ') to $this->realPathSafe($this->config_imagemagick_path) ('
1649
                                        . $this->realPathSafe($this->config_imagemagick_path)
1650
                                        . ')', __FILE__, __LINE__);
1651
                    $this->config_imagemagick_path = $this->realPathSafe($this->config_imagemagick_path);
1652
                } else {
1653
                    $this->DebugMessage('Leaving $this->config_imagemagick_path as ('
1654
                                        . $this->config_imagemagick_path
1655
                                        . ') because !is_execuatable($this->realPathSafe($this->config_imagemagick_path)) ('
1656
                                        . $this->realPathSafe($this->config_imagemagick_path)
1657
                                        . ')', __FILE__, __LINE__);
1658
                }
1659
            }
1660
            $this->DebugMessage('                  file_exists(' . $this->config_imagemagick_path . ') = ' . (int)(@file_exists($this->config_imagemagick_path)), __FILE__, __LINE__);
1661
            $this->DebugMessage('file_exists_ignoreopenbasedir(' . $this->config_imagemagick_path . ') = ' . (int)$this->file_exists_ignoreopenbasedir($this->config_imagemagick_path), __FILE__,
1662
                                __LINE__);
1663
            $this->DebugMessage('                      is_file(' . $this->config_imagemagick_path . ') = ' . (int)(@is_file($this->config_imagemagick_path)), __FILE__, __LINE__);
1664
            $this->DebugMessage('                is_executable(' . $this->config_imagemagick_path . ') = ' . (int)(@is_executable($this->config_imagemagick_path)), __FILE__, __LINE__);
1665
1666
            if ($this->file_exists_ignoreopenbasedir($this->config_imagemagick_path)) {
1667
                $this->DebugMessage('using ImageMagick path from $this->config_imagemagick_path (' . $this->config_imagemagick_path . ')', __FILE__, __LINE__);
1668
                if ($this->iswindows) {
1669
                    $commandline = substr($this->config_imagemagick_path, 0, 2)
1670
                                   . ' && cd '
1671
                                   . phpthumb_functions::escapeshellarg_replacement(str_replace('/', DIRECTORY_SEPARATOR, substr(dirname($this->config_imagemagick_path), 2)))
1672
                                   . ' && '
1673
                                   . phpthumb_functions::escapeshellarg_replacement(basename($this->config_imagemagick_path));
1674
                } else {
1675
                    $commandline = phpthumb_functions::escapeshellarg_replacement($this->config_imagemagick_path);
1676
                }
1677
            } else {
1678
                $which_convert = $this->ImageMagickWhichConvert();
1679
                $IMversion     = $this->ImageMagickVersion();
1680
1681
                if ($which_convert && ($which_convert{0} == '/')
1682
                    && $this->file_exists_ignoreopenbasedir($which_convert)
1683
                ) {
1684
1685
                    // `which convert` *should* return the path if "convert" exist, or nothing if it doesn't
1686
                    // other things *may* get returned, like "sh: convert: not found" or "no convert in /usr/local/bin /usr/sbin /usr/bin /usr/ccs/bin"
1687
                    // so only do this if the value returned exists as a file
1688
                    $this->DebugMessage('using ImageMagick path from `which convert` (' . $which_convert . ')', __FILE__, __LINE__);
1689
                    $commandline = 'convert';
1690
                } elseif ($IMversion) {
1691
                    $this->DebugMessage('setting ImageMagick path to $this->config_imagemagick_path (' . $this->config_imagemagick_path . ') [' . $IMversion . ']', __FILE__, __LINE__);
1692
                    $commandline = $this->config_imagemagick_path;
1693
                } else {
1694
                    $this->DebugMessage('ImageMagickThumbnailToGD() aborting because cannot find convert in $this->config_imagemagick_path ('
1695
                                        . $this->config_imagemagick_path
1696
                                        . '), and `which convert` returned ('
1697
                                        . $which_convert
1698
                                        . ')', __FILE__, __LINE__);
1699
                    $commandline = '';
1700
                }
1701
            }
1702
1703
            @file_put_contents($IMcommandlineBaseCacheFilename, $commandline);
1704
        }
1705
1706
        return $commandline;
1707
    }
1708
1709
    /**
1710
     * @param  bool $returnRAW
1711
     * @return mixed
1712
     */
1713
    public function ImageMagickVersion($returnRAW = false)
1714
    {
1715
        static $versionstring = null;
1716
        if (is_null($versionstring)) {
1717
            $versionstring = array(0 => false, 1 => false);
1718
1719
            $IMversionCacheFilename = $this->config_cache_directory . DIRECTORY_SEPARATOR . 'phpThumbCacheIMversion.txt';
1720
            if ($cachedversionstring = @file_get_contents($IMversionCacheFilename)) {
1721
                $versionstring    = explode("\n", $cachedversionstring, 2);
1722
                $versionstring[0] = ($versionstring[0] ?: false); // "false" is stored as an empty string in the cache file
1723
                $versionstring[1] = ($versionstring[1] ?: false); // "false" is stored as an empty string in the cache file
1724
            } else {
1725
                $commandline = $this->ImageMagickCommandlineBase();
1726
                $commandline = (!is_null($commandline) ? $commandline : '');
1727
                if ($commandline) {
1728
                    $commandline .= ' --version';
1729
                    $this->DebugMessage('ImageMagick version checked with "' . $commandline . '"', __FILE__, __LINE__);
1730
                    $versionstring[1] = trim(phpthumb_functions::SafeExec($commandline));
1731
                    if (preg_match('#^Version: [^0-9]*([ 0-9\\.\\:Q/\\-]+)#i', $versionstring[1], $matches)) {
1732
                        $versionstring[0] = trim($matches[1]);
1733
                    } else {
1734
                        $versionstring[0] = false;
1735
                        $this->DebugMessage('ImageMagick did not return recognized version string (' . $versionstring[1] . ')', __FILE__, __LINE__);
1736
                    }
1737
                    $this->DebugMessage('ImageMagick convert --version says "' . @$matches[0] . '"', __FILE__, __LINE__);
1738
                }
1739
1740
                @file_put_contents($IMversionCacheFilename, $versionstring[0] . "\n" . $versionstring[1]);
1741
            }
1742
        }
1743
1744
        return $versionstring[(int)$returnRAW];
1745
    }
1746
1747
    /**
1748
     * @param $switchname
1749
     * @return bool
1750
     */
1751
    public function ImageMagickSwitchAvailable($switchname)
1752
    {
1753
        static $IMoptions = null;
1754
        if (is_null($IMoptions)) {
1755
            $IMoptions   = array();
1756
            $commandline = $this->ImageMagickCommandlineBase();
1757
            if (!is_null($commandline)) {
1758
                $commandline  .= ' -help';
1759
                $IMhelp_lines = explode("\n", phpthumb_functions::SafeExec($commandline));
1760
                foreach ($IMhelp_lines as $line) {
1761
                    if (preg_match('#^[\\+\\-]([a-z\\-]+) #', trim($line), $matches)) {
1762
                        $IMoptions[$matches[1]] = true;
1763
                    }
1764
                }
1765
            }
1766
        }
1767
        if (is_array($switchname)) {
1768
            $allOK = true;
1769
            foreach ($switchname as $key => $value) {
1770
                if (!isset($IMoptions[$value])) {
1771
                    $allOK = false;
1772
                    break;
1773
                }
1774
            }
1775
            $this->DebugMessage('ImageMagickSwitchAvailable(' . implode(';', $switchname) . ') = ' . (int)$allOK . '', __FILE__, __LINE__);
1776
        } else {
1777
            $allOK = isset($IMoptions[$switchname]);
1778
            $this->DebugMessage('ImageMagickSwitchAvailable(' . $switchname . ') = ' . (int)$allOK . '', __FILE__, __LINE__);
1779
        }
1780
1781
        return $allOK;
1782
    }
1783
1784
    /**
1785
     * @return bool|null|string
1786
     */
1787
    public function ImageMagickFormatsList()
1788
    {
1789
        static $IMformatsList = null;
1790
        if (is_null($IMformatsList)) {
1791
            $IMformatsList = '';
1792
            $commandline   = $this->ImageMagickCommandlineBase();
1793
            if (!is_null($commandline)) {
1794
                $commandline   = dirname($commandline) . DIRECTORY_SEPARATOR . str_replace('convert', 'identify', basename($commandline));
1795
                $commandline   .= ' -list format';
1796
                $IMformatsList = phpthumb_functions::SafeExec($commandline);
1797
            }
1798
        }
1799
1800
        return $IMformatsList;
1801
    }
1802
1803
    /**
1804
     * @return bool
1805
     */
1806
    public function SourceDataToTempFile()
1807
    {
1808
        if ($IMtempSourceFilename = $this->phpThumb_tempnam()) {
1809
            $IMtempSourceFilename = $this->realPathSafe($IMtempSourceFilename);
1810
            ob_start();
1811
            $fp_tempfile         = fopen($IMtempSourceFilename, 'wb');
1812
            $tempfile_open_error = ob_get_contents();
1813
            ob_end_clean();
1814
            if ($fp_tempfile) {
1815
                fwrite($fp_tempfile, $this->rawImageData);
1816
                fclose($fp_tempfile);
1817
                $this->sourceFilename = $IMtempSourceFilename;
1818
                $this->DebugMessage('ImageMagickThumbnailToGD() setting $this->sourceFilename to "' . $IMtempSourceFilename . '" from $this->rawImageData (' . strlen($this->rawImageData) . ' bytes)',
1819
                                    __FILE__, __LINE__);
1820
            } else {
1821
                $this->DebugMessage('ImageMagickThumbnailToGD() FAILED setting $this->sourceFilename to "' . $IMtempSourceFilename . '" (failed to open for writing: "' . $tempfile_open_error . '")',
1822
                                    __FILE__, __LINE__);
1823
            }
1824
            unset($tempfile_open_error, $IMtempSourceFilename);
1825
1826
            return true;
1827
        }
1828
        $this->DebugMessage('SourceDataToTempFile() FAILED because $this->phpThumb_tempnam() failed', __FILE__, __LINE__);
1829
1830
        return false;
1831
    }
1832
1833
    /**
1834
     * @return bool
1835
     */
1836
    public function ImageMagickThumbnailToGD()
1837
    {
1838
        // http://www.imagemagick.org/script/command-line-options.php
1839
1840
        $this->useRawIMoutput = true;
1841
        if (phpthumb_functions::gd_version()) {
1842
            // if GD is not available, must use whatever ImageMagick can output
1843
1844
            // $UnAllowedParameters contains options that can only be processed in GD, not ImageMagick
1845
            // note: 'fltr' *may* need to be processed by GD, but we'll check that in more detail below
1846
            $UnAllowedParameters = array('xto', 'ar', 'bg', 'bc');
1847
            // 'ra' may be part of this list, if not a multiple of 90 degrees
1848
            foreach ($UnAllowedParameters as $parameter) {
1849
                if (isset($this->$parameter)) {
1850
                    $this->DebugMessage('$this->useRawIMoutput=false because "' . $parameter . '" is set', __FILE__, __LINE__);
1851
                    $this->useRawIMoutput = false;
1852
                    break;
1853
                }
1854
            }
1855
        }
1856
        $this->DebugMessage('$this->useRawIMoutput=' . ($this->useRawIMoutput ? 'true' : 'false') . ' after checking $UnAllowedParameters', __FILE__, __LINE__);
1857
        $outputFormat = $this->thumbnailFormat;
1858
        if (phpthumb_functions::gd_version()) {
1859
            if ($this->useRawIMoutput) {
1860
                switch ($this->thumbnailFormat) {
1861
                    case 'gif':
1862
                        $ImageCreateFunction = 'ImageCreateFromGIF';
1863
                        $this->is_alpha      = true;
1864
                        break;
1865
                    case 'png':
1866
                        $ImageCreateFunction = 'ImageCreateFromPNG';
1867
                        $this->is_alpha      = true;
1868
                        break;
1869
                    case 'jpg':
1870
                    case 'jpeg':
1871
                        $ImageCreateFunction = 'ImageCreateFromJPEG';
1872
                        break;
1873
                    default:
1874
                        $this->DebugMessage('Forcing output to PNG because $this->thumbnailFormat (' . $this->thumbnailFormat . ' is not a GD-supported format)', __FILE__, __LINE__);
1875
                        $outputFormat         = 'png';
1876
                        $ImageCreateFunction  = 'ImageCreateFromPNG';
1877
                        $this->is_alpha       = true;
1878
                        $this->useRawIMoutput = false;
1879
                        break;
1880
                }
1881
                if (!function_exists(@$ImageCreateFunction)) {
1882
                    // ImageMagickThumbnailToGD() depends on ImageCreateFromPNG/ImageCreateFromGIF
1883
                    //$this->DebugMessage('ImageMagickThumbnailToGD() aborting because '.@$ImageCreateFunction.'() is not available', __FILE__, __LINE__);
1884
                    $this->useRawIMoutput = true;
1885
                    //return false;
1886
                }
1887
            } else {
1888
                $outputFormat         = 'png';
1889
                $ImageCreateFunction  = 'ImageCreateFromPNG';
1890
                $this->is_alpha       = true;
1891
                $this->useRawIMoutput = false;
1892
            }
1893
        }
1894
1895
        // http://freealter.org/doc_distrib/ImageMagick-5.1.1/www/convert.html
1896
        if (!$this->sourceFilename && $this->rawImageData) {
1897
            $this->SourceDataToTempFile();
1898
        }
1899
        if (!$this->sourceFilename) {
1900
            $this->DebugMessage('ImageMagickThumbnailToGD() aborting because $this->sourceFilename is empty', __FILE__, __LINE__);
1901
            $this->useRawIMoutput = false;
1902
1903
            return false;
1904
        }
1905
        if ($this->issafemode) {
1906
            $this->DebugMessage('ImageMagickThumbnailToGD() aborting because safe_mode is enabled', __FILE__, __LINE__);
1907
            $this->useRawIMoutput = false;
1908
1909
            return false;
1910
        }
1911
        // TO BE FIXED
1912
        //if (true) {
1913
        //  $this->DebugMessage('ImageMagickThumbnailToGD() aborting it is broken right now', __FILE__, __LINE__);
1914
        //  $this->useRawIMoutput = false;
1915
        //  return false;
1916
        //}
1917
1918
        $commandline = $this->ImageMagickCommandlineBase();
1919
        if ($commandline) {
1920
            if ($IMtempfilename = $this->phpThumb_tempnam()) {
1921
                $IMtempfilename = $this->realPathSafe($IMtempfilename);
1922
1923
                $IMuseExplicitImageOutputDimensions = false;
1924
                if ($this->ImageMagickSwitchAvailable('thumbnail') && $this->config_imagemagick_use_thumbnail) {
1925
                    $IMresizeParameter = 'thumbnail';
1926
                } else {
1927
                    $IMresizeParameter = 'resize';
1928
1929
                    // some (older? around 2002) versions of IM won't accept "-resize 100x" but require "-resize 100x100"
1930
                    $commandline_test                   = $this->ImageMagickCommandlineBase() . ' logo: -resize 1x ' . phpthumb_functions::escapeshellarg_replacement($IMtempfilename) . ' 2>&1';
1931
                    $IMresult_test                      = phpthumb_functions::SafeExec($commandline_test);
1932
                    $IMuseExplicitImageOutputDimensions = preg_match('#image dimensions are zero#i', $IMresult_test);
1933
                    $this->DebugMessage('IMuseExplicitImageOutputDimensions = ' . (int)$IMuseExplicitImageOutputDimensions, __FILE__, __LINE__);
1934
                    if ($fp_im_temp = @fopen($IMtempfilename, 'wb')) {
1935
                        // erase temp image so ImageMagick logo doesn't get output if other processing fails
1936
                        fclose($fp_im_temp);
1937
                    }
1938
                }
1939
1940
                if (!is_null($this->dpi) && $this->ImageMagickSwitchAvailable('density')) {
1941
                    // for raster source formats only (WMF, PDF, etc)
1942
                    $commandline .= ' -density ' . phpthumb_functions::escapeshellarg_replacement($this->dpi);
1943
                }
1944
                ob_start();
1945
                $getimagesize      = getimagesize($this->sourceFilename);
1946
                $GetImageSizeError = ob_get_contents();
1947
                ob_end_clean();
1948
                if (is_array($getimagesize)) {
1949
                    $this->DebugMessage('GetImageSize(' . $this->sourceFilename . ') SUCCEEDED: ' . print_r($getimagesize, true), __FILE__, __LINE__);
1950
                } else {
1951
                    $this->DebugMessage('GetImageSize(' . $this->sourceFilename . ') FAILED with error "' . $GetImageSizeError . '"', __FILE__, __LINE__);
1952
                }
1953
                if (is_array($getimagesize)) {
1954
                    $this->DebugMessage('GetImageSize(' . $this->sourceFilename . ') returned [w=' . $getimagesize[0] . ';h=' . $getimagesize[1] . ';f=' . $getimagesize[2] . ']', __FILE__, __LINE__);
1955
                    $this->source_width  = $getimagesize[0];
1956
                    $this->source_height = $getimagesize[1];
1957
                    $this->DebugMessage('source dimensions set to ' . $this->source_width . 'x' . $this->source_height, __FILE__, __LINE__);
1958
                    $this->SetOrientationDependantWidthHeight();
1959
1960 View Code Duplication
                    if (!preg_match('#(' . implode('|', $this->AlphaCapableFormats) . ')#i', $outputFormat)) {
1961
                        // not a transparency-capable format
1962
                        $commandline .= ' -background ' . phpthumb_functions::escapeshellarg_replacement('#' . ($this->bg ?: 'FFFFFF'));
1963
                        if ($getimagesize[2] == IMAGETYPE_GIF) {
1964
                            $commandline .= ' -flatten';
1965
                        }
1966
                    }
1967
                    if ($getimagesize[2] == IMAGETYPE_GIF) {
1968
                        $commandline .= ' -coalesce'; // may be needed for animated GIFs
1969
                    }
1970
                    if ($this->source_width || $this->source_height) {
1971
                        if ($this->zc) {
1972
                            $borderThickness = 0;
1973
                            if (!empty($this->fltr)) {
1974
                                foreach ($this->fltr as $key => $value) {
1975
                                    if (preg_match('#^bord\|([0-9]+)#', $value, $matches)) {
1976
                                        $borderThickness = $matches[1];
1977
                                        break;
1978
                                    }
1979
                                }
1980
                            }
1981
                            $wAll  = (int)max($this->w, $this->wp, $this->wl, $this->ws) - (2 * $borderThickness);
1982
                            $hAll  = (int)max($this->h, $this->hp, $this->hl, $this->hs) - (2 * $borderThickness);
1983
                            $imAR  = $this->source_width / $this->source_height;
1984
                            $zcAR  = (($wAll && $hAll) ? $wAll / $hAll : 1);
1985
                            $side  = phpthumb_functions::nonempty_min($this->source_width, $this->source_height, max($wAll, $hAll));
1986
                            $sideX = phpthumb_functions::nonempty_min($this->source_width, $wAll, round($hAll * $zcAR));
1987
                            $sideY = phpthumb_functions::nonempty_min($this->source_height, $hAll, round($wAll / $zcAR));
1988
1989
                            $thumbnailH  = round(max($sideY, ($sideY * $zcAR) / $imAR));
1990
                            $commandline .= ' -' . $IMresizeParameter . ' ' . phpthumb_functions::escapeshellarg_replacement(($IMuseExplicitImageOutputDimensions ? $thumbnailH : '')
1991
                                                                                                                             . 'x'
1992
                                                                                                                             . $thumbnailH);
1993
1994
                            switch (strtoupper($this->zc)) {
1995
                                case 'T':
1996
                                    $commandline .= ' -gravity north';
1997
                                    break;
1998
                                case 'B':
1999
                                    $commandline .= ' -gravity south';
2000
                                    break;
2001
                                case 'L':
2002
                                    $commandline .= ' -gravity west';
2003
                                    break;
2004
                                case 'R':
2005
                                    $commandline .= ' -gravity east';
2006
                                    break;
2007
                                case 'TL':
2008
                                    $commandline .= ' -gravity northwest';
2009
                                    break;
2010
                                case 'TR':
2011
                                    $commandline .= ' -gravity northeast';
2012
                                    break;
2013
                                case 'BL':
2014
                                    $commandline .= ' -gravity southwest';
2015
                                    break;
2016
                                case 'BR':
2017
                                    $commandline .= ' -gravity southeast';
2018
                                    break;
2019
                                case '1':
2020
                                case 'C':
2021
                                default:
2022
                                    $commandline .= ' -gravity center';
2023
                                    break;
2024
                            }
2025
2026
                            if (($wAll > 0) && ($hAll > 0)) {
2027
                                $commandline .= ' -crop ' . phpthumb_functions::escapeshellarg_replacement($wAll . 'x' . $hAll . '+0+0');
2028
                            } else {
2029
                                $commandline .= ' -crop ' . phpthumb_functions::escapeshellarg_replacement($side . 'x' . $side . '+0+0');
2030
                            }
2031
                            if ($this->ImageMagickSwitchAvailable('repage')) {
2032
                                $commandline .= ' +repage';
2033
                            } else {
2034
                                $this->DebugMessage('Skipping "+repage" because ImageMagick (v' . $this->ImageMagickVersion() . ') does not support it', __FILE__, __LINE__);
2035
                            }
2036
                        } elseif ($this->sw || $this->sh || $this->sx || $this->sy) {
2037
                            $crop_param = '';
2038
                            $crop_param .= ($this->sw ? (($this->sw < 2) ? round($this->sw * $this->source_width) : $this->sw) : $this->source_width);
2039
                            $crop_param .= 'x' . ($this->sh ? (($this->sh < 2) ? round($this->sh * $this->source_height) : $this->sh) : $this->source_height);
2040
                            $crop_param .= '+' . (($this->sx < 2) ? round($this->sx * $this->source_width) : $this->sx);
2041
                            $crop_param .= '+' . (($this->sy < 2) ? round($this->sy * $this->source_height) : $this->sy);
2042
                            // TO BE FIXED
2043
                            // makes 1x1 output
2044
                            // 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
2045
                            // '/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'
2046
                            $commandline .= ' -crop ' . phpthumb_functions::escapeshellarg_replacement($crop_param);
2047
2048
                            // this is broken for aoe=1, but unsure how to fix. Send advice to [email protected]
2049
                            if ($this->w || $this->h) {
2050
                                //if ($this->ImageMagickSwitchAvailable('repage')) {
2051
                                if (false) {
2052
                                    // TO BE FIXED
2053
                                    // newer versions of ImageMagick require -repage <geometry>
2054
                                    $commandline .= ' -repage';
2055
                                } else {
2056
                                    $this->DebugMessage('Skipping "-repage" because ImageMagick (v' . $this->ImageMagickVersion() . ') does not support it', __FILE__, __LINE__);
2057
                                }
2058 View Code Duplication
                                if ($IMuseExplicitImageOutputDimensions) {
2059
                                    if ($this->w && !$this->h) {
2060
                                        $this->h = ceil($this->w / ($this->source_width / $this->source_height));
2061
                                    } elseif ($this->h && !$this->w) {
2062
                                        $this->w = ceil($this->h * ($this->source_width / $this->source_height));
2063
                                    }
2064
                                }
2065
                                $commandline .= ' -' . $IMresizeParameter . ' ' . phpthumb_functions::escapeshellarg_replacement($this->w . 'x' . $this->h);
2066
                            }
2067
                        } else {
2068
                            if ($this->iar && ((int)$this->w > 0) && ((int)$this->h > 0)) {
2069
                                list($nw, $nh) = phpthumb_functions::TranslateWHbyAngle($this->w, $this->h, $this->ra);
2070
                                $nw          = ((round($nw) != 0) ? round($nw) : '');
2071
                                $nh          = ((round($nh) != 0) ? round($nh) : '');
2072
                                $commandline .= ' -' . $IMresizeParameter . ' ' . phpthumb_functions::escapeshellarg_replacement($nw . 'x' . $nh . '!');
2073
                            } else {
2074
                                $this->w = ((($this->aoe || $this->far)
2075
                                             && $this->w) ? $this->w : ($this->w ? phpthumb_functions::nonempty_min($this->w, $getimagesize[0]) : ''));
2076
                                $this->h = ((($this->aoe || $this->far)
2077
                                             && $this->h) ? $this->h : ($this->h ? phpthumb_functions::nonempty_min($this->h, $getimagesize[1]) : ''));
2078
                                if ($this->w || $this->h) {
2079 View Code Duplication
                                    if ($IMuseExplicitImageOutputDimensions) {
2080
                                        if ($this->w && !$this->h) {
2081
                                            $this->h = ceil($this->w / ($this->source_width / $this->source_height));
2082
                                        } elseif ($this->h && !$this->w) {
2083
                                            $this->w = ceil($this->h * ($this->source_width / $this->source_height));
2084
                                        }
2085
                                    }
2086
                                    list($nw, $nh) = phpthumb_functions::TranslateWHbyAngle($this->w, $this->h, $this->ra);
2087
                                    $nw          = ((round($nw) != 0) ? round($nw) : '');
2088
                                    $nh          = ((round($nh) != 0) ? round($nh) : '');
2089
                                    $commandline .= ' -' . $IMresizeParameter . ' ' . phpthumb_functions::escapeshellarg_replacement($nw . 'x' . $nh);
2090
                                }
2091
                            }
2092
                        }
2093
                    }
2094
                } else {
2095
                    $this->DebugMessage('GetImageSize(' . $this->sourceFilename . ') failed', __FILE__, __LINE__);
2096
                    if ($this->w || $this->h) {
2097
                        $exactDimensionsBang = (($this->iar && ((int)$this->w > 0)
2098
                                                 && ((int)$this->h > 0)) ? '!' : '');
2099
                        if ($IMuseExplicitImageOutputDimensions) {
2100
                            // unknown source aspect ratio, just put large number and hope IM figures it out
2101
                            $commandline .= ' -' . $IMresizeParameter . ' ' . phpthumb_functions::escapeshellarg_replacement(($this->w ?: '9999')
2102
                                                                                                                             . 'x'
2103
                                                                                                                             . ($this->h ? $this->h : '9999')
2104
                                                                                                                             . $exactDimensionsBang);
2105
                        } else {
2106
                            $commandline .= ' -' . $IMresizeParameter . ' ' . phpthumb_functions::escapeshellarg_replacement($this->w . 'x' . $this->h . $exactDimensionsBang);
2107
                        }
2108
                    }
2109
                }
2110
2111
                if ($this->ra) {
2112
                    $this->ra = (int)$this->ra;
2113
                    if ($this->ImageMagickSwitchAvailable('rotate')) {
2114
                        if (!preg_match('#(' . implode('|', $this->AlphaCapableFormats) . ')#i', $outputFormat)
2115
                            || phpthumb_functions::version_compare_replacement($this->ImageMagickVersion(), '6.3.7', '>=')
2116
                        ) {
2117
                            $this->DebugMessage('Using ImageMagick rotate', __FILE__, __LINE__);
2118
                            $commandline .= ' -rotate ' . phpthumb_functions::escapeshellarg_replacement($this->ra);
2119
                            if (($this->ra % 90) != 0) {
2120 View Code Duplication
                                if (preg_match('#(' . implode('|', $this->AlphaCapableFormats) . ')#i', $outputFormat)) {
2121
                                    // alpha-capable format
2122
                                    $commandline .= ' -background rgba(255,255,255,0)';
2123
                                } else {
2124
                                    $commandline .= ' -background ' . phpthumb_functions::escapeshellarg_replacement('#' . ($this->bg ?: 'FFFFFF'));
2125
                                }
2126
                            }
2127
                            $this->ra = 0;
2128
                        } else {
2129
                            $this->DebugMessage('Not using ImageMagick rotate because alpha background buggy before v6.3.7', __FILE__, __LINE__);
2130
                        }
2131
                    } else {
2132
                        $this->DebugMessage('Not using ImageMagick rotate because not supported', __FILE__, __LINE__);
2133
                    }
2134
                }
2135
2136
                $successfullyProcessedFilters = array();
2137
                foreach ($this->fltr as $filterkey => $filtercommand) {
2138
                    @list($command, $parameter) = explode('|', $filtercommand, 2);
2139
                    switch ($command) {
2140
                        case 'brit':
2141
                            if ($this->ImageMagickSwitchAvailable('modulate')) {
2142
                                $commandline                    .= ' -modulate ' . phpthumb_functions::escapeshellarg_replacement((100 + (int)$parameter) . ',100,100');
2143
                                $successfullyProcessedFilters[] = $filterkey;
2144
                            }
2145
                            break;
2146
2147
                        case 'cont':
2148
                            if ($this->ImageMagickSwitchAvailable('contrast')) {
2149
                                $contDiv10 = round((int)$parameter / 10);
2150
                                if ($contDiv10 > 0) {
2151
                                    $contDiv10 = min($contDiv10, 100);
2152
                                    for ($i = 0; $i < $contDiv10; $i++) {
2153
                                        $commandline .= ' -contrast'; // increase contrast by 10%
2154
                                    }
2155
                                } elseif ($contDiv10 < 0) {
2156
                                    $contDiv10 = max($contDiv10, -100);
2157
                                    for ($i = $contDiv10; $i < 0; $i++) {
2158
                                        $commandline .= ' +contrast'; // decrease contrast by 10%
2159
                                    }
2160
                                } else {
2161
                                    // do nothing
2162
                                }
2163
                                $successfullyProcessedFilters[] = $filterkey;
2164
                            }
2165
                            break;
2166
2167 View Code Duplication
                        case 'ds':
2168
                            if ($this->ImageMagickSwitchAvailable(array('colorspace', 'modulate'))) {
2169
                                if ($parameter == 100) {
2170
                                    $commandline .= ' -colorspace GRAY';
2171
                                    $commandline .= ' -modulate 100,0,100';
2172
                                } else {
2173
                                    $commandline .= ' -modulate ' . phpthumb_functions::escapeshellarg_replacement('100,' . (100 - (int)$parameter) . ',100');
2174
                                }
2175
                                $successfullyProcessedFilters[] = $filterkey;
2176
                            }
2177
                            break;
2178
2179 View Code Duplication
                        case 'sat':
2180
                            if ($this->ImageMagickSwitchAvailable(array('colorspace', 'modulate'))) {
2181
                                if ($parameter == -100) {
2182
                                    $commandline .= ' -colorspace GRAY';
2183
                                    $commandline .= ' -modulate 100,0,100';
2184
                                } else {
2185
                                    $commandline .= ' -modulate ' . phpthumb_functions::escapeshellarg_replacement('100,' . (100 + (int)$parameter) . ',100');
2186
                                }
2187
                                $successfullyProcessedFilters[] = $filterkey;
2188
                            }
2189
                            break;
2190
2191
                        case 'gray':
2192
                            if ($this->ImageMagickSwitchAvailable(array('colorspace', 'modulate'))) {
2193
                                $commandline                    .= ' -colorspace GRAY';
2194
                                $commandline                    .= ' -modulate 100,0,100';
2195
                                $successfullyProcessedFilters[] = $filterkey;
2196
                            }
2197
                            break;
2198
2199
                        case 'clr':
2200
                            if ($this->ImageMagickSwitchAvailable(array('fill', 'colorize'))) {
2201
                                @list($amount, $color) = explode('|', $parameter);
2202
                                $commandline .= ' -fill ' . phpthumb_functions::escapeshellarg_replacement('#' . preg_replace('#[^0-9A-F]#i', '', $color));
2203
                                $commandline .= ' -colorize ' . phpthumb_functions::escapeshellarg_replacement(min(max((int)$amount, 0), 100));
2204
                            }
2205
                            break;
2206
2207 View Code Duplication
                        case 'sep':
2208
                            if ($this->ImageMagickSwitchAvailable('sepia-tone')) {
2209
                                @list($amount, $color) = explode('|', $parameter);
2210
                                $amount = ($amount ?: 80);
2211
                                if (!$color) {
2212
                                    $commandline                    .= ' -sepia-tone ' . phpthumb_functions::escapeshellarg_replacement(min(max((int)$amount, 0), 100) . '%');
2213
                                    $successfullyProcessedFilters[] = $filterkey;
2214
                                }
2215
                            }
2216
                            break;
2217
2218 View Code Duplication
                        case 'gam':
2219
                            @list($amount) = explode('|', $parameter);
2220
                            $amount = min(max((float)$amount, 0.001), 10);
2221
                            if (number_format($amount, 3) != '1.000') {
2222
                                if ($this->ImageMagickSwitchAvailable('gamma')) {
2223
                                    $commandline                    .= ' -gamma ' . phpthumb_functions::escapeshellarg_replacement($amount);
2224
                                    $successfullyProcessedFilters[] = $filterkey;
2225
                                }
2226
                            }
2227
                            break;
2228
2229
                        case 'neg':
2230
                            if ($this->ImageMagickSwitchAvailable('negate')) {
2231
                                $commandline                    .= ' -negate';
2232
                                $successfullyProcessedFilters[] = $filterkey;
2233
                            }
2234
                            break;
2235
2236
                        case 'th':
2237
                            @list($amount) = explode('|', $parameter);
2238
                            if ($this->ImageMagickSwitchAvailable(array('threshold', 'dither', 'monochrome'))) {
2239
                                $commandline                    .= ' -threshold ' . phpthumb_functions::escapeshellarg_replacement(round(min(max((int)$amount, 0), 255) / 2.55) . '%');
2240
                                $commandline                    .= ' -dither';
2241
                                $commandline                    .= ' -monochrome';
2242
                                $successfullyProcessedFilters[] = $filterkey;
2243
                            }
2244
                            break;
2245
2246
                        case 'rcd':
2247
                            if ($this->ImageMagickSwitchAvailable(array('colors', 'dither'))) {
2248
                                @list($colors, $dither) = explode('|', $parameter);
2249
                                $colors                         = ($colors ? (int)$colors : 256);
2250
                                $dither                         = ((strlen($dither) > 0) ? (bool)$dither : true);
2251
                                $commandline                    .= ' -colors ' . phpthumb_functions::escapeshellarg_replacement(max($colors,
2252
                                                                                                                                    8)); // ImageMagick will otherwise fail with "cannot quantize to fewer than 8 colors"
2253
                                $commandline                    .= ($dither ? ' -dither' : ' +dither');
2254
                                $successfullyProcessedFilters[] = $filterkey;
2255
                            }
2256
                            break;
2257
2258
                        case 'flip':
2259
                            if ($this->ImageMagickSwitchAvailable(array('flip', 'flop'))) {
2260
                                if (strpos(strtolower($parameter), 'x') !== false) {
2261
                                    $commandline .= ' -flop';
2262
                                }
2263
                                if (strpos(strtolower($parameter), 'y') !== false) {
2264
                                    $commandline .= ' -flip';
2265
                                }
2266
                                $successfullyProcessedFilters[] = $filterkey;
2267
                            }
2268
                            break;
2269
2270
                        case 'edge':
2271
                            if ($this->ImageMagickSwitchAvailable('edge')) {
2272
                                $parameter                      = (!empty($parameter) ? $parameter : 2);
2273
                                $commandline                    .= ' -edge ' . phpthumb_functions::escapeshellarg_replacement(!empty($parameter) ? (int)$parameter : 1);
2274
                                $successfullyProcessedFilters[] = $filterkey;
2275
                            }
2276
                            break;
2277
2278
                        case 'emb':
2279
                            if ($this->ImageMagickSwitchAvailable(array('emboss', 'negate'))) {
2280
                                $parameter   = (!empty($parameter) ? $parameter : 2);
2281
                                $commandline .= ' -emboss ' . phpthumb_functions::escapeshellarg_replacement((int)$parameter);
2282
                                if ($parameter < 2) {
2283
                                    $commandline .= ' -negate'; // ImageMagick negates the image for some reason with '-emboss 1';
2284
                                }
2285
                                $successfullyProcessedFilters[] = $filterkey;
2286
                            }
2287
                            break;
2288
2289
                        case 'lvl':
2290
                            @list($band, $method, $threshold) = explode('|', $parameter);
2291
                            $band      = ($band ? preg_replace('#[^RGBA\\*]#', '', strtoupper($band)) : '*');
2292
                            $method    = ((strlen($method) > 0) ? (int)$method : 2);
2293
                            $threshold = ((strlen($threshold) > 0) ? min(max((float)$threshold, 0), 100) : 0.1);
2294
2295
                            $band = preg_replace('#[^RGBA\\*]#', '', strtoupper($band));
2296
2297
                            if (($method > 1)
2298
                                && !$this->ImageMagickSwitchAvailable(array(
2299
                                                                          'channel',
2300
                                                                          'contrast-stretch'
2301
                                                                      ))
2302
                            ) {
2303
                                // Because ImageMagick processing happens before PHP-GD filters, and because some
2304
                                // clipping is involved in the "lvl" filter, if "lvl" happens before "wb" then the
2305
                                // "wb" filter will have (almost) no effect. Therefore, if "wb" is enabled then
2306
                                // force the "lvl" filter to be processed by GD, not ImageMagick.
2307
                                foreach ($this->fltr as $fltr_key => $fltr_value) {
2308
                                    list($fltr_cmd) = explode('|', $fltr_value);
2309
                                    if ($fltr_cmd == 'wb') {
2310
                                        $this->DebugMessage('Setting "lvl" filter method to "0" (from "' . $method . '") because white-balance filter also enabled', __FILE__, __LINE__);
2311
                                        $method = 0;
2312
                                    }
2313
                                }
2314
                            }
2315
2316
                            switch ($method) {
2317
                                case 0: // internal RGB
2318
                                case 1: // internal grayscale
2319
                                    break;
2320
                                case 2: // ImageMagick "contrast-stretch"
2321
                                    if ($this->ImageMagickSwitchAvailable('contrast-stretch')) {
2322
                                        if ($band != '*') {
2323
                                            $commandline .= ' -channel ' . phpthumb_functions::escapeshellarg_replacement(strtoupper($band));
2324
                                        }
2325
                                        $threshold = preg_replace('#[^0-9\\.]#', '', $threshold); // should be unneccesary, but just to be double-sure
2326
                                        //$commandline .= ' -contrast-stretch '.phpthumb_functions::escapeshellarg_replacement($threshold.'%');
2327
                                        $commandline .= ' -contrast-stretch \'' . $threshold . '%\'';
2328
                                        if ($band != '*') {
2329
                                            $commandline .= ' +channel';
2330
                                        }
2331
                                        $successfullyProcessedFilters[] = $filterkey;
2332
                                    }
2333
                                    break;
2334
                                case 3: // ImageMagick "normalize"
2335
                                    if ($this->ImageMagickSwitchAvailable('normalize')) {
2336
                                        if ($band != '*') {
2337
                                            $commandline .= ' -channel ' . phpthumb_functions::escapeshellarg_replacement(strtoupper($band));
2338
                                        }
2339
                                        $commandline .= ' -normalize';
2340
                                        if ($band != '*') {
2341
                                            $commandline .= ' +channel';
2342
                                        }
2343
                                        $successfullyProcessedFilters[] = $filterkey;
2344
                                    }
2345
                                    break;
2346
                                default:
2347
                                    $this->DebugMessage('unsupported method (' . $method . ') for "lvl" filter', __FILE__, __LINE__);
2348
                                    break;
2349
                            }
2350
                            if (isset($this->fltr[$filterkey]) && ($method > 1)) {
2351
                                $this->fltr[$filterkey] = $command . '|' . $band . '|0|' . $threshold;
2352
                                $this->DebugMessage('filter "lvl" remapped from method "' . $method . '" to method "0" because ImageMagick support is missing', __FILE__, __LINE__);
2353
                            }
2354
                            break;
2355
2356
                        case 'wb':
2357
                            if ($this->ImageMagickSwitchAvailable(array('channel', 'contrast-stretch'))) {
2358
                                @list($threshold) = explode('|', $parameter);
2359
                                $threshold = (!empty($threshold) ? min(max((float)$threshold, 0), 100) : 0.1);
2360
                                $threshold = preg_replace('#[^0-9\\.]#', '', $threshold); // should be unneccesary, but just to be double-sure
2361
                                //$commandline .= ' -channel R -contrast-stretch '.phpthumb_functions::escapeshellarg_replacement($threshold.'%'); // doesn't work on Windows because most versions of PHP do not properly
2362
                                //$commandline .= ' -channel G -contrast-stretch '.phpthumb_functions::escapeshellarg_replacement($threshold.'%'); // escape special characters (such as %) and just replace them with spaces
2363
                                //$commandline .= ' -channel B -contrast-stretch '.phpthumb_functions::escapeshellarg_replacement($threshold.'%'); // https://bugs.php.net/bug.php?id=43261
2364
                                $commandline                    .= ' -channel R -contrast-stretch \'' . $threshold . '%\'';
2365
                                $commandline                    .= ' -channel G -contrast-stretch \'' . $threshold . '%\'';
2366
                                $commandline                    .= ' -channel B -contrast-stretch \'' . $threshold . '%\'';
2367
                                $commandline                    .= ' +channel';
2368
                                $successfullyProcessedFilters[] = $filterkey;
2369
                            }
2370
                            break;
2371
2372 View Code Duplication
                        case 'blur':
2373
                            if ($this->ImageMagickSwitchAvailable('blur')) {
2374
                                @list($radius) = explode('|', $parameter);
2375
                                $radius                         = (!empty($radius) ? min(max((int)$radius, 0), 25) : 1);
2376
                                $commandline                    .= ' -blur ' . phpthumb_functions::escapeshellarg_replacement($radius);
2377
                                $successfullyProcessedFilters[] = $filterkey;
2378
                            }
2379
                            break;
2380
2381
                        case 'gblr':
2382
                            @list($radius) = explode('|', $parameter);
2383
                            $radius = (!empty($radius) ? min(max((int)$radius, 0), 25) : 1);
2384
                            // "-gaussian" changed to "-gaussian-blur" sometime around 2009
2385
                            if ($this->ImageMagickSwitchAvailable('gaussian-blur')) {
2386
                                $commandline                    .= ' -gaussian-blur ' . phpthumb_functions::escapeshellarg_replacement($radius);
2387
                                $successfullyProcessedFilters[] = $filterkey;
2388
                            } elseif ($this->ImageMagickSwitchAvailable('gaussian')) {
2389
                                $commandline                    .= ' -gaussian ' . phpthumb_functions::escapeshellarg_replacement($radius);
2390
                                $successfullyProcessedFilters[] = $filterkey;
2391
                            }
2392
                            break;
2393
2394
                        case 'usm':
2395
                            if ($this->ImageMagickSwitchAvailable('unsharp')) {
2396
                                @list($amount, $radius, $threshold) = explode('|', $parameter);
2397
                                $amount                         = ($amount ? min(max((int)$radius, 0), 255) : 80);
2398
                                $radius                         = ($radius ? min(max((int)$radius, 0), 10) : 0.5);
2399
                                $threshold                      = (strlen($threshold) ? min(max((int)$radius, 0), 50) : 3);
2400
                                $commandline                    .= ' -unsharp ' . phpthumb_functions::escapeshellarg_replacement(number_format(($radius * 2) - 1, 2, '.', '')
2401
                                                                                                                                 . 'x1+'
2402
                                                                                                                                 . number_format($amount / 100, 2, '.', '')
2403
                                                                                                                                 . '+'
2404
                                                                                                                                 . number_format($threshold / 100, 2, '.', ''));
2405
                                $successfullyProcessedFilters[] = $filterkey;
2406
                            }
2407
                            break;
2408
2409
                        case 'bord':
2410
                            if ($this->ImageMagickSwitchAvailable(array(
2411
                                                                      'border',
2412
                                                                      'bordercolor',
2413
                                                                      'thumbnail',
2414
                                                                      'crop'
2415
                                                                  ))
2416
                            ) {
2417
                                if (!$this->zc) {
2418
                                    @list($width, $rX, $rY, $color) = explode('|', $parameter);
2419
                                    $width = (int)$width;
2420
                                    $rX    = (int)$rX;
2421
                                    $rY    = (int)$rY;
2422
                                    if ($width && !$rX && !$rY) {
2423
                                        if (!phpthumb_functions::IsHexColor($color)) {
2424
                                            $color = ((!empty($this->bc)
2425
                                                       && phpthumb_functions::IsHexColor($this->bc)) ? $this->bc : '000000');
2426
                                        }
2427
                                        $commandline .= ' -border ' . phpthumb_functions::escapeshellarg_replacement((int)$width);
2428
                                        $commandline .= ' -bordercolor ' . phpthumb_functions::escapeshellarg_replacement('#' . $color);
2429
2430
                                        if (preg_match('# \\-crop "([0-9]+)x([0-9]+)\\+0\\+0" #', $commandline, $matches)) {
2431
                                            $commandline = str_replace(' -crop "' . $matches[1] . 'x' . $matches[2] . '+0+0" ',
2432
                                                                       ' -crop ' . phpthumb_functions::escapeshellarg_replacement(($matches[1] - (2 * $width))
2433
                                                                                                                                  . 'x'
2434
                                                                                                                                  . ($matches[2] - (2 * $width))
2435
                                                                                                                                  . '+0+0') . ' ', $commandline);
2436
                                        } elseif (preg_match('# \\-' . $IMresizeParameter . ' "([0-9]+)x([0-9]+)" #', $commandline, $matches)) {
2437
                                            $commandline = str_replace(' -' . $IMresizeParameter . ' "' . $matches[1] . 'x' . $matches[2] . '" ',
2438
                                                                       ' -' . $IMresizeParameter . ' ' . phpthumb_functions::escapeshellarg_replacement(($matches[1] - (2 * $width))
2439
                                                                                                                                                        . 'x'
2440
                                                                                                                                                        . ($matches[2] - (2 * $width))) . ' ',
2441
                                                                       $commandline);
2442
                                        }
2443
                                        $successfullyProcessedFilters[] = $filterkey;
2444
                                    }
2445
                                }
2446
                            }
2447
                            break;
2448
2449
                        case 'crop':
2450
                            break;
2451
2452
                        case 'sblr':
2453
                            break;
2454
2455
                        case 'mean':
2456
                            break;
2457
2458
                        case 'smth':
2459
                            break;
2460
2461
                        case 'bvl':
2462
                            break;
2463
2464
                        case 'wmi':
2465
                            break;
2466
2467
                        case 'wmt':
2468
                            break;
2469
2470
                        case 'over':
2471
                            break;
2472
2473
                        case 'hist':
2474
                            break;
2475
2476
                        case 'fram':
2477
                            break;
2478
2479
                        case 'drop':
2480
                            break;
2481
2482
                        case 'mask':
2483
                            break;
2484
2485
                        case 'elip':
2486
                            break;
2487
2488
                        case 'ric':
2489
                            break;
2490
2491
                        case 'stc':
2492
                            break;
2493
2494
                        case 'size':
2495
                            break;
2496
2497
                        default:
2498
                            $this->DebugMessage('Unknown $this->fltr[' . $filterkey . '] (' . $filtercommand . ') -- deleting filter command', __FILE__, __LINE__);
2499
                            $successfullyProcessedFilters[] = $filterkey;
2500
                            break;
2501
                    }
2502
                    if (!isset($this->fltr[$filterkey])) {
2503
                        $this->DebugMessage('Processed $this->fltr[' . $filterkey . '] (' . $filtercommand . ') with ImageMagick', __FILE__, __LINE__);
2504
                    } else {
2505
                        $this->DebugMessage('Skipping $this->fltr[' . $filterkey . '] (' . $filtercommand . ') with ImageMagick', __FILE__, __LINE__);
2506
                    }
2507
                }
2508
                $this->DebugMessage('Remaining $this->fltr after ImageMagick: (' . $this->phpThumbDebugVarDump($this->fltr) . ')', __FILE__, __LINE__);
2509
                if (count($this->fltr) > 0) {
2510
                    $this->useRawIMoutput = false;
2511
                }
2512
2513
                if (preg_match('#jpe?g#i', $outputFormat) && $this->q) {
2514
                    if ($this->ImageMagickSwitchAvailable(array('quality', 'interlace'))) {
2515
                        $commandline .= ' -quality ' . phpthumb_functions::escapeshellarg_replacement($this->thumbnailQuality);
2516
                        if ($this->config_output_interlace) {
2517
                            // causes weird things with animated GIF... leave for JPEG only
2518
                            $commandline .= ' -interlace line '; // Use Line or Plane to create an interlaced PNG or GIF or progressive JPEG image
2519
                        }
2520
                    }
2521
                }
2522
                $commandline .= ' ' . phpthumb_functions::escapeshellarg_replacement(preg_replace('#[/\\\\]#', DIRECTORY_SEPARATOR, $this->sourceFilename) . (($outputFormat == 'gif') ? '' : '['
2523
                                                                                                                                                                                              . (int)$this->sfn
2524
                                                                                                                                                                                              . ']')); // [0] means first frame of (GIF) animation, can be ignored
2525
                $commandline .= ' ' . $outputFormat . ':' . phpthumb_functions::escapeshellarg_replacement($IMtempfilename);
2526
                if (!$this->iswindows) {
2527
                    $commandline .= ' 2>&1';
2528
                }
2529
                $this->DebugMessage('ImageMagick called as (' . $commandline . ')', __FILE__, __LINE__);
2530
                $IMresult = phpthumb_functions::SafeExec($commandline);
2531
                clearstatcache();
2532
                if (!@file_exists($IMtempfilename) || !@filesize($IMtempfilename)) {
2533
                    $this->FatalError('ImageMagick failed with message (' . trim($IMresult) . ')');
2534
                    $this->DebugMessage('ImageMagick failed with message (' . trim($IMresult) . ')', __FILE__, __LINE__);
2535
                    if ($this->iswindows && !$IMresult) {
2536
                        $this->DebugMessage('Check to make sure that PHP has read+write permissions to "' . dirname($IMtempfilename) . '"', __FILE__, __LINE__);
2537
                    }
2538
                } else {
2539
                    foreach ($successfullyProcessedFilters as $dummy => $filterkey) {
2540
                        unset($this->fltr[$filterkey]);
2541
                    }
2542
                    $this->IMresizedData    = file_get_contents($IMtempfilename);
2543
                    $getimagesize_imresized = @getimagesize($IMtempfilename);
2544
                    $this->DebugMessage('GetImageSize('
2545
                                        . $IMtempfilename
2546
                                        . ') returned [w='
2547
                                        . $getimagesize_imresized[0]
2548
                                        . ';h='
2549
                                        . $getimagesize_imresized[1]
2550
                                        . ';f='
2551
                                        . $getimagesize_imresized[2]
2552
                                        . ']', __FILE__, __LINE__);
2553
                    if (($this->config_max_source_pixels > 0)
2554
                        && (($getimagesize_imresized[0] * $getimagesize_imresized[1]) > $this->config_max_source_pixels)
2555
                    ) {
2556
                        $this->DebugMessage('skipping ImageMagickThumbnailToGD::'
2557
                                            . $ImageCreateFunction
2558
                                            . '() because IM output is too large ('
2559
                                            . $getimagesize_imresized[0]
2560
                                            . 'x'
2561
                                            . $getimagesize_imresized[0]
2562
                                            . ' = '
2563
                                            . ($getimagesize_imresized[0] * $getimagesize_imresized[1])
2564
                                            . ' > '
2565
                                            . $this->config_max_source_pixels
2566
                                            . ')', __FILE__, __LINE__);
2567
                    } elseif (function_exists(@$ImageCreateFunction)
2568
                              && ($this->gdimg_source = @$ImageCreateFunction($IMtempfilename))
2569
                    ) {
2570
                        $this->source_width  = imagesx($this->gdimg_source);
2571
                        $this->source_height = imagesy($this->gdimg_source);
2572
                        $this->DebugMessage('ImageMagickThumbnailToGD::' . $ImageCreateFunction . '() succeeded, $this->gdimg_source is now (' . $this->source_width . 'x' . $this->source_height . ')',
2573
                                            __FILE__, __LINE__);
2574
                        $this->DebugMessage('ImageMagickThumbnailToGD() returning $this->IMresizedData (' . strlen($this->IMresizedData) . ' bytes)', __FILE__, __LINE__);
2575
                    } else {
2576
                        $this->useRawIMoutput = true;
2577
                        $this->DebugMessage('$this->useRawIMoutput set to TRUE because ' . @$ImageCreateFunction . '(' . $IMtempfilename . ') failed', __FILE__, __LINE__);
2578
                    }
2579 View Code Duplication
                    if (file_exists($IMtempfilename)) {
2580
                        $this->DebugMessage('deleting "' . $IMtempfilename . '"', __FILE__, __LINE__);
2581
                        @unlink($IMtempfilename);
2582
                    }
2583
2584
                    return true;
2585
                }
2586 View Code Duplication
                if (file_exists($IMtempfilename)) {
2587
                    $this->DebugMessage('deleting "' . $IMtempfilename . '"', __FILE__, __LINE__);
2588
                    @unlink($IMtempfilename);
2589
                }
2590
            } elseif ($this->issafemode) {
2591
                $this->DebugMessage('ImageMagickThumbnailToGD() aborting because PHP safe_mode is enabled and phpThumb_tempnam() failed', __FILE__, __LINE__);
2592
                $this->useRawIMoutput = false;
2593
            } else {
2594 View Code Duplication
                if (file_exists($IMtempfilename)) {
2595
                    $this->DebugMessage('deleting "' . $IMtempfilename . '"', __FILE__, __LINE__);
2596
                    @unlink($IMtempfilename);
2597
                }
2598
                $this->DebugMessage('ImageMagickThumbnailToGD() aborting, phpThumb_tempnam() failed', __FILE__, __LINE__);
2599
            }
2600
        } else {
2601
            $this->DebugMessage('ImageMagickThumbnailToGD() aborting because ImageMagickCommandlineBase() failed', __FILE__, __LINE__);
2602
        }
2603
        $this->useRawIMoutput = false;
2604
2605
        return false;
2606
    }
2607
2608
    /**
2609
     * @return bool
2610
     */
2611
    public function Rotate()
2612
    {
2613
        if ($this->ra || $this->ar) {
2614
            if (!function_exists('ImageRotate')) {
2615
                $this->DebugMessage('!function_exists(ImageRotate)', __FILE__, __LINE__);
2616
2617
                return false;
2618
            }
2619 View Code Duplication
            if (!require_once __DIR__ . '/phpthumb.filters.php') {
2620
                $this->DebugMessage('Error including "' . __DIR__ . '/phpthumb.filters.php" which is required for applying filters (' . implode(';', $this->fltr) . ')', __FILE__, __LINE__);
2621
2622
                return false;
2623
            }
2624
2625
            $this->config_background_hexcolor = ($this->bg ?: $this->config_background_hexcolor);
2626
            if (!phpthumb_functions::IsHexColor($this->config_background_hexcolor)) {
2627
                return $this->ErrorImage('Invalid hex color string "' . $this->config_background_hexcolor . '" for parameter "bg"');
2628
            }
2629
2630
            $rotate_angle = 0;
2631
            if ($this->ra) {
2632
                $rotate_angle = (float)$this->ra;
2633
            } else {
2634
                if ($this->ar == 'x') {
2635
                    if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '4.2.0', '>=')) {
2636
                        if ($this->sourceFilename) {
2637
                            if (function_exists('exif_read_data')) {
2638
                                if ($exif_data = @exif_read_data($this->sourceFilename, 'IFD0')) {
2639
                                    // http://sylvana.net/jpegcrop/exif_orientation.html
2640
                                    switch (@$exif_data['Orientation']) {
2641
                                        case 1:
2642
                                            $rotate_angle = 0;
2643
                                            break;
2644
                                        case 3:
2645
                                            $rotate_angle = 180;
2646
                                            break;
2647
                                        case 6:
2648
                                            $rotate_angle = 270;
2649
                                            break;
2650
                                        case 8:
2651
                                            $rotate_angle = 90;
2652
                                            break;
2653
2654
                                        default:
2655
                                            $this->DebugMessage('EXIF auto-rotate failed because unknown $exif_data[Orientation] "' . @$exif_data['Orientation'] . '"', __FILE__, __LINE__);
2656
2657
                                            return false;
2658
                                            break;
2659
                                    }
2660
                                    $this->DebugMessage('EXIF auto-rotate set to ' . $rotate_angle . ' degrees ($exif_data[Orientation] = "' . @$exif_data['Orientation'] . '")', __FILE__, __LINE__);
2661
                                } else {
2662
                                    $this->DebugMessage('failed: exif_read_data(' . $this->sourceFilename . ')', __FILE__, __LINE__);
2663
2664
                                    return false;
2665
                                }
2666
                            } else {
2667
                                $this->DebugMessage('!function_exists(exif_read_data)', __FILE__, __LINE__);
2668
2669
                                return false;
2670
                            }
2671
                        } else {
2672
                            $this->DebugMessage('Cannot auto-rotate from EXIF data because $this->sourceFilename is empty', __FILE__, __LINE__);
2673
2674
                            return false;
2675
                        }
2676
                    } else {
2677
                        $this->DebugMessage('Cannot auto-rotate from EXIF data because PHP is less than v4.2.0 (' . PHP_VERSION . ')', __FILE__, __LINE__);
2678
2679
                        return false;
2680
                    }
2681
                } elseif (($this->ar == 'l') && ($this->source_height > $this->source_width)) {
2682
                    $rotate_angle = 270;
2683
                } elseif (($this->ar == 'L') && ($this->source_height > $this->source_width)) {
2684
                    $rotate_angle = 90;
2685
                } elseif (($this->ar == 'p') && ($this->source_width > $this->source_height)) {
2686
                    $rotate_angle = 90;
2687
                } elseif (($this->ar == 'P') && ($this->source_width > $this->source_height)) {
2688
                    $rotate_angle = 270;
2689
                }
2690
            }
2691
            if ($rotate_angle % 90) {
2692
                $this->is_alpha = true;
2693
            }
2694
            phpthumb_filters::ImprovedImageRotate($this->gdimg_source, $rotate_angle, $this->config_background_hexcolor, $this->bg, $this);
2695
            $this->source_width  = imagesx($this->gdimg_source);
2696
            $this->source_height = imagesy($this->gdimg_source);
2697
        }
2698
2699
        return true;
2700
    }
2701
2702
    /**
2703
     * @return bool
2704
     */
2705
    public function FixedAspectRatio()
2706
    {
2707
        // optional fixed-dimension images (regardless of aspect ratio)
2708
2709
        if (!$this->far) {
2710
            // do nothing
2711
            return true;
2712
        }
2713
2714
        if (!$this->w || !$this->h) {
2715
            return false;
2716
        }
2717
        $this->thumbnail_width  = $this->w;
2718
        $this->thumbnail_height = $this->h;
2719
        $this->is_alpha         = true;
2720
        if ($this->thumbnail_image_width >= $this->thumbnail_width) {
2721
            $aspectratio = $this->thumbnail_image_height / $this->thumbnail_image_width;
2722 View Code Duplication
            if ($this->w) {
2723
                $this->thumbnail_image_height = round($this->thumbnail_image_width * $aspectratio);
2724
                $this->thumbnail_height       = ($this->h ?: $this->thumbnail_image_height);
2725
            } elseif ($this->thumbnail_image_height < $this->thumbnail_height) {
2726
                $this->thumbnail_image_height = $this->thumbnail_height;
2727
                $this->thumbnail_image_width  = round($this->thumbnail_image_height / $aspectratio);
2728
            }
2729 View Code Duplication
        } else {
2730
            $aspectratio = $this->thumbnail_image_width / $this->thumbnail_image_height;
2731
            if ($this->h) {
2732
                $this->thumbnail_image_width = round($this->thumbnail_image_height * $aspectratio);
2733
            } elseif ($this->thumbnail_image_width < $this->thumbnail_width) {
2734
                $this->thumbnail_image_width  = $this->thumbnail_width;
2735
                $this->thumbnail_image_height = round($this->thumbnail_image_width / $aspectratio);
2736
            }
2737
        }
2738
2739
        return true;
2740
    }
2741
2742
    /**
2743
     * @param $hostname
2744
     * @param $allowed_domains
2745
     * @return mixed
2746
     */
2747
    public function OffsiteDomainIsAllowed($hostname, $allowed_domains)
2748
    {
2749
        static $domain_is_allowed = array();
2750
        $hostname = strtolower($hostname);
2751
        if (!isset($domain_is_allowed[$hostname])) {
2752
            $domain_is_allowed[$hostname] = false;
2753
            foreach ($allowed_domains as $valid_domain) {
2754
                $starpos = strpos($valid_domain, '*');
2755
                if ($starpos !== false) {
2756
                    $valid_domain = substr($valid_domain, $starpos + 1);
2757
                    if (preg_match('#' . preg_quote($valid_domain) . '$#', $hostname)) {
2758
                        $domain_is_allowed[$hostname] = true;
2759
                        break;
2760
                    }
2761
                } else {
2762
                    if (strtolower($valid_domain) === $hostname) {
2763
                        $domain_is_allowed[$hostname] = true;
2764
                        break;
2765
                    }
2766
                }
2767
            }
2768
        }
2769
2770
        return $domain_is_allowed[$hostname];
2771
    }
2772
2773
    /**
2774
     * @return bool
2775
     */
2776
    public function AntiOffsiteLinking()
2777
    {
2778
        // Optional anti-offsite hijacking of the thumbnail script
2779
        $allow = true;
2780
        if ($allow && $this->config_nooffsitelink_enabled
2781
            && (@$_SERVER['HTTP_REFERER']
2782
                || $this->config_nooffsitelink_require_refer)
2783
        ) {
2784
            $this->DebugMessage('AntiOffsiteLinking() checking $_SERVER[HTTP_REFERER] "' . @$_SERVER['HTTP_REFERER'] . '"', __FILE__, __LINE__);
2785
            foreach ($this->config_nooffsitelink_valid_domains as $key => $valid_domain) {
2786
                // $_SERVER['HTTP_HOST'] contains the port number, so strip it out here to make default configuration work
2787
                list($clean_domain) = explode(':', $valid_domain);
2788
                $this->config_nooffsitelink_valid_domains[$key] = $clean_domain;
2789
            }
2790
            $parsed_url = phpthumb_functions::ParseURLbetter(@$_SERVER['HTTP_REFERER']);
2791 View Code Duplication
            if (!$this->OffsiteDomainIsAllowed(@$parsed_url['host'], $this->config_nooffsitelink_valid_domains)) {
2792
                $allow   = false;
2793
                $erase   = $this->config_nooffsitelink_erase_image;
2794
                $message = $this->config_nooffsitelink_text_message;
2795
                //$this->DebugMessage('AntiOffsiteLinking() - "'.@$parsed_url['host'].'" is NOT in $this->config_nooffsitelink_valid_domains ('.implode(';', $this->config_nooffsitelink_valid_domains).')', __FILE__, __LINE__);
2796
                $this->ErrorImage('AntiOffsiteLinking() - "'
2797
                                  . @$parsed_url['host']
2798
                                  . '" is NOT in $this->config_nooffsitelink_valid_domains ('
2799
                                  . implode(';', $this->config_nooffsitelink_valid_domains)
2800
                                  . ')');
2801
            } else {
2802
                $this->DebugMessage('AntiOffsiteLinking() - "'
2803
                                    . @$parsed_url['host']
2804
                                    . '" is in $this->config_nooffsitelink_valid_domains ('
2805
                                    . implode(';', $this->config_nooffsitelink_valid_domains)
2806
                                    . ')', __FILE__, __LINE__);
2807
            }
2808
        }
2809
2810
        if ($allow && $this->config_nohotlink_enabled && preg_match('#^(f|ht)tps?\://#i', $this->src)) {
2811
            $parsed_url = phpthumb_functions::ParseURLbetter($this->src);
2812
            //if (!phpthumb_functions::CaseInsensitiveInArray(@$parsed_url['host'], $this->config_nohotlink_valid_domains)) {
2813 View Code Duplication
            if (!$this->OffsiteDomainIsAllowed(@$parsed_url['host'], $this->config_nohotlink_valid_domains)) {
2814
                // This domain is not allowed
2815
                $allow   = false;
2816
                $erase   = $this->config_nohotlink_erase_image;
2817
                $message = $this->config_nohotlink_text_message;
2818
                $this->DebugMessage('AntiOffsiteLinking() - "'
2819
                                    . $parsed_url['host']
2820
                                    . '" is NOT in $this->config_nohotlink_valid_domains ('
2821
                                    . implode(';', $this->config_nohotlink_valid_domains)
2822
                                    . ')', __FILE__, __LINE__);
2823
            } else {
2824
                $this->DebugMessage('AntiOffsiteLinking() - "' . $parsed_url['host'] . '" is in $this->config_nohotlink_valid_domains (' . implode(';', $this->config_nohotlink_valid_domains) . ')',
2825
                                    __FILE__, __LINE__);
2826
            }
2827
        }
2828
2829
        if ($allow) {
2830
            $this->DebugMessage('AntiOffsiteLinking() says this is allowed', __FILE__, __LINE__);
2831
2832
            return true;
2833
        }
2834
2835
        if (!phpthumb_functions::IsHexColor($this->config_error_bgcolor)) {
2836
            return $this->ErrorImage('Invalid hex color string "' . $this->config_error_bgcolor . '" for $this->config_error_bgcolor');
2837
        }
2838
        if (!phpthumb_functions::IsHexColor($this->config_error_textcolor)) {
2839
            return $this->ErrorImage('Invalid hex color string "' . $this->config_error_textcolor . '" for $this->config_error_textcolor');
2840
        }
2841
        if ($erase) {
2842
            return $this->ErrorImage($message, $this->thumbnail_width, $this->thumbnail_height, $this->config_error_bgcolor, $this->config_error_textcolor, $this->config_error_fontsize);
2843
        } else {
2844
            $this->config_nooffsitelink_watermark_src = $this->ResolveFilenameToAbsolute($this->config_nooffsitelink_watermark_src);
2845
            if (is_file($this->config_nooffsitelink_watermark_src)) {
2846
                if (!require_once __DIR__ . '/phpthumb.filters.php') {
2847
                    $this->DebugMessage('Error including "' . __DIR__ . '/phpthumb.filters.php" which is required for applying watermark', __FILE__, __LINE__);
2848
2849
                    return false;
2850
                }
2851
                $watermark_img                   = $this->ImageCreateFromStringReplacement(file_get_contents($this->config_nooffsitelink_watermark_src));
2852
                $phpthumbFilters                 = new phpthumb_filters();
2853
                $phpthumbFilters->phpThumbObject = &$this;
2854
                $opacity                         = 50;
2855
                $margin                          = 5;
2856
                $phpthumbFilters->WatermarkOverlay($this->gdimg_output, $watermark_img, '*', $opacity, $margin);
2857
                imagedestroy($watermark_img);
2858
                unset($phpthumbFilters);
2859
            } else {
2860
                $nohotlink_text_array = explode("\n", wordwrap($message, floor($this->thumbnail_width / imagefontwidth($this->config_error_fontsize)), "\n"));
2861
                $nohotlink_text_color = phpthumb_functions::ImageHexColorAllocate($this->gdimg_output, $this->config_error_textcolor);
2862
2863
                $topoffset = round(($this->thumbnail_height - (count($nohotlink_text_array) * imagefontheight($this->config_error_fontsize))) / 2);
2864
2865
                $rowcounter = 0;
2866
                $this->DebugMessage('AntiOffsiteLinking() writing ' . count($nohotlink_text_array) . ' lines of text "' . $message . '" (in #' . $this->config_error_textcolor . ') on top of image',
2867
                                    __FILE__, __LINE__);
2868
                foreach ($nohotlink_text_array as $textline) {
2869
                    $leftoffset = max(0, round(($this->thumbnail_width - (strlen($textline) * imagefontwidth($this->config_error_fontsize))) / 2));
2870
                    imagestring($this->gdimg_output, $this->config_error_fontsize, $leftoffset, $topoffset + ($rowcounter++ * imagefontheight($this->config_error_fontsize)), $textline,
2871
                                $nohotlink_text_color);
2872
                }
2873
            }
2874
        }
2875
2876
        return true;
2877
    }
2878
2879
    /**
2880
     * @return bool
2881
     */
2882
    public function AlphaChannelFlatten()
2883
    {
2884
        if (!$this->is_alpha) {
2885
            // image doesn't have alpha transparency, no need to flatten
2886
            $this->DebugMessage('skipping AlphaChannelFlatten() because !$this->is_alpha', __FILE__, __LINE__);
2887
2888
            return false;
2889
        }
2890
        switch ($this->thumbnailFormat) {
2891
            case 'png':
2892 View Code Duplication
            case 'ico':
2893
                // image has alpha transparency, but output as PNG or ICO which can handle it
2894
                $this->DebugMessage('skipping AlphaChannelFlatten() because ($this->thumbnailFormat == "' . $this->thumbnailFormat . '")', __FILE__, __LINE__);
2895
2896
                return false;
2897
                break;
2898
2899
            case 'gif':
2900
                // image has alpha transparency, but output as GIF which can handle only single-color transparency
2901
                $CurrentImageColorTransparent = imagecolortransparent($this->gdimg_output);
2902
                if ($CurrentImageColorTransparent == -1) {
2903
                    // no transparent color defined
2904
2905
                    if (phpthumb_functions::gd_version() < 2.0) {
2906
                        $this->DebugMessage('AlphaChannelFlatten() failed because GD version is "' . phpthumb_functions::gd_version() . '"', __FILE__, __LINE__);
2907
2908
                        return false;
2909
                    }
2910
2911
                    if ($img_alpha_mixdown_dither = @imagecreatetruecolor(imagesx($this->gdimg_output), imagesy($this->gdimg_output))) {
2912
                        for ($i = 0; $i <= 255; $i++) {
2913
                            $dither_color[$i] = imagecolorallocate($img_alpha_mixdown_dither, $i, $i, $i);
0 ignored issues
show
Coding Style Comprehensibility introduced by
$dither_color was never initialized. Although not strictly required by PHP, it is generally a good practice to add $dither_color = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
2914
                        }
2915
2916
                        // scan through current truecolor image copy alpha channel to temp image as grayscale
2917 View Code Duplication
                        for ($x = 0; $x < $this->thumbnail_width; $x++) {
2918
                            for ($y = 0; $y < $this->thumbnail_height; $y++) {
2919
                                $PixelColor = phpthumb_functions::GetPixelColor($this->gdimg_output, $x, $y);
2920
                                imagesetpixel($img_alpha_mixdown_dither, $x, $y, $dither_color[$PixelColor['alpha'] * 2]);
2921
                            }
2922
                        }
2923
2924
                        // dither alpha channel grayscale version down to 2 colors
2925
                        imagetruecolortopalette($img_alpha_mixdown_dither, true, 2);
2926
2927
                        // reduce color palette to 256-1 colors (leave one palette position for transparent color)
2928
                        imagetruecolortopalette($this->gdimg_output, true, 255);
2929
2930
                        // allocate a new color for transparent color index
2931
                        $TransparentColor = imagecolorallocate($this->gdimg_output, 1, 254, 253);
2932
                        imagecolortransparent($this->gdimg_output, $TransparentColor);
2933
2934
                        // scan through alpha channel image and note pixels with >50% transparency
2935
                        $TransparentPixels = array();
2936 View Code Duplication
                        for ($x = 0; $x < $this->thumbnail_width; $x++) {
2937
                            for ($y = 0; $y < $this->thumbnail_height; $y++) {
2938
                                $AlphaChannelPixel = phpthumb_functions::GetPixelColor($img_alpha_mixdown_dither, $x, $y);
2939
                                if ($AlphaChannelPixel['red'] > 127) {
2940
                                    imagesetpixel($this->gdimg_output, $x, $y, $TransparentColor);
2941
                                }
2942
                            }
2943
                        }
2944
                        imagedestroy($img_alpha_mixdown_dither);
2945
2946
                        $this->DebugMessage('AlphaChannelFlatten() set image to 255+1 colors with transparency for GIF output', __FILE__, __LINE__);
2947
2948
                        return true;
2949 View Code Duplication
                    } else {
2950
                        $this->DebugMessage('AlphaChannelFlatten() failed ImageCreate(' . imagesx($this->gdimg_output) . ', ' . imagesy($this->gdimg_output) . ')', __FILE__, __LINE__);
2951
2952
                        return false;
2953
                    }
2954
                } else {
2955
                    // a single transparent color already defined, leave as-is
2956
                    $this->DebugMessage('skipping AlphaChannelFlatten() because ($this->thumbnailFormat == "'
2957
                                        . $this->thumbnailFormat
2958
                                        . '") and ImageColorTransparent returned "'
2959
                                        . $CurrentImageColorTransparent
2960
                                        . '"', __FILE__, __LINE__);
2961
2962
                    return true;
2963
                }
2964
                break;
2965
        }
2966
        $this->DebugMessage('continuing AlphaChannelFlatten() for output format "' . $this->thumbnailFormat . '"', __FILE__, __LINE__);
2967
        // image has alpha transparency, and is being output in a format that doesn't support it -- flatten
2968
        if ($gdimg_flatten_temp = phpthumb_functions::ImageCreateFunction($this->thumbnail_width, $this->thumbnail_height)) {
2969
            $this->config_background_hexcolor = ($this->bg ?: $this->config_background_hexcolor);
2970
            if (!phpthumb_functions::IsHexColor($this->config_background_hexcolor)) {
2971
                return $this->ErrorImage('Invalid hex color string "' . $this->config_background_hexcolor . '" for parameter "bg"');
2972
            }
2973
            $background_color = phpthumb_functions::ImageHexColorAllocate($this->gdimg_output, $this->config_background_hexcolor);
2974
            imagefilledrectangle($gdimg_flatten_temp, 0, 0, $this->thumbnail_width, $this->thumbnail_height, $background_color);
2975
            imagecopy($gdimg_flatten_temp, $this->gdimg_output, 0, 0, 0, 0, $this->thumbnail_width, $this->thumbnail_height);
2976
2977
            ImageAlphaBlending($this->gdimg_output, true);
2978
            ImageSaveAlpha($this->gdimg_output, false);
2979
            imagecolortransparent($this->gdimg_output, -1);
2980
            imagecopy($this->gdimg_output, $gdimg_flatten_temp, 0, 0, 0, 0, $this->thumbnail_width, $this->thumbnail_height);
2981
2982
            imagedestroy($gdimg_flatten_temp);
2983
2984
            return true;
2985
        } else {
2986
            $this->DebugMessage('ImageCreateFunction() failed', __FILE__, __LINE__);
2987
        }
2988
2989
        return false;
2990
    }
2991
2992
    /**
2993
     * @return bool
2994
     */
2995
    public function ApplyFilters()
2996
    {
2997
        if ($this->fltr && is_array($this->fltr)) {
2998 View Code Duplication
            if (!require_once __DIR__ . '/phpthumb.filters.php') {
2999
                $this->DebugMessage('Error including "' . __DIR__ . '/phpthumb.filters.php" which is required for applying filters (' . implode(';', $this->fltr) . ')', __FILE__, __LINE__);
3000
3001
                return false;
3002
            }
3003
            $phpthumbFilters                 = new phpthumb_filters();
3004
            $phpthumbFilters->phpThumbObject = &$this;
3005
            foreach ($this->fltr as $filtercommand) {
3006
                @list($command, $parameter) = explode('|', $filtercommand, 2);
3007
                $this->DebugMessage('Attempting to process filter command "' . $command . '(' . $parameter . ')"', __FILE__, __LINE__);
3008
                switch ($command) {
3009
                    case 'brit': // Brightness
3010
                        $phpthumbFilters->Brightness($this->gdimg_output, $parameter);
3011
                        break;
3012
3013
                    case 'cont': // Contrast
3014
                        $phpthumbFilters->Contrast($this->gdimg_output, $parameter);
3015
                        break;
3016
3017
                    case 'ds': // Desaturation
3018
                        $phpthumbFilters->Desaturate($this->gdimg_output, $parameter, '');
3019
                        break;
3020
3021
                    case 'sat': // Saturation
3022
                        $phpthumbFilters->Saturation($this->gdimg_output, $parameter, '');
3023
                        break;
3024
3025
                    case 'gray': // Grayscale
3026
                        $phpthumbFilters->Grayscale($this->gdimg_output);
3027
                        break;
3028
3029 View Code Duplication
                    case 'clr': // Colorize
3030
                        if (phpthumb_functions::gd_version() < 2) {
3031
                            $this->DebugMessage('Skipping Colorize() because gd_version is "' . phpthumb_functions::gd_version() . '"', __FILE__, __LINE__);
3032
                            break;
3033
                        }
3034
                        @list($amount, $color) = explode('|', $parameter, 2);
3035
                        $phpthumbFilters->Colorize($this->gdimg_output, $amount, $color);
3036
                        break;
3037
3038 View Code Duplication
                    case 'sep': // Sepia
3039
                        if (phpthumb_functions::gd_version() < 2) {
3040
                            $this->DebugMessage('Skipping Sepia() because gd_version is "' . phpthumb_functions::gd_version() . '"', __FILE__, __LINE__);
3041
                            break;
3042
                        }
3043
                        @list($amount, $color) = explode('|', $parameter, 2);
3044
                        $phpthumbFilters->Sepia($this->gdimg_output, $amount, $color);
3045
                        break;
3046
3047
                    case 'gam': // Gamma correction
3048
                        $phpthumbFilters->Gamma($this->gdimg_output, $parameter);
3049
                        break;
3050
3051
                    case 'neg': // Negative colors
3052
                        $phpthumbFilters->Negative($this->gdimg_output);
3053
                        break;
3054
3055
                    case 'th': // Threshold
3056
                        $phpthumbFilters->Threshold($this->gdimg_output, $parameter);
3057
                        break;
3058
3059
                    case 'rcd': // ReduceColorDepth
3060
                        if (phpthumb_functions::gd_version() < 2) {
3061
                            $this->DebugMessage('Skipping ReduceColorDepth() because gd_version is "' . phpthumb_functions::gd_version() . '"', __FILE__, __LINE__);
3062
                            break;
3063
                        }
3064
                        @list($colors, $dither) = explode('|', $parameter, 2);
3065
                        $colors = ($colors ? (int)$colors : 256);
3066
                        $dither = ((strlen($dither) > 0) ? (bool)$dither : true);
3067
                        $phpthumbFilters->ReduceColorDepth($this->gdimg_output, $colors, $dither);
3068
                        break;
3069
3070
                    case 'flip': // Flip
3071
                        $phpthumbFilters->Flip($this->gdimg_output, strpos(strtolower($parameter), 'x') !== false, strpos(strtolower($parameter), 'y') !== false);
3072
                        break;
3073
3074
                    case 'edge': // EdgeDetect
3075
                        $phpthumbFilters->EdgeDetect($this->gdimg_output);
3076
                        break;
3077
3078
                    case 'emb': // Emboss
3079
                        $phpthumbFilters->Emboss($this->gdimg_output);
3080
                        break;
3081
3082
                    case 'bvl': // Bevel
3083
                        @list($width, $color1, $color2) = explode('|', $parameter, 3);
3084
                        $phpthumbFilters->Bevel($this->gdimg_output, $width, $color1, $color2);
3085
                        break;
3086
3087
                    case 'lvl': // autoLevels
3088
                        @list($band, $method, $threshold) = explode('|', $parameter, 3);
3089
                        $band      = ($band ? preg_replace('#[^RGBA\\*]#', '', strtoupper($band)) : '*');
3090
                        $method    = ((strlen($method) > 0) ? (int)$method : 2);
3091
                        $threshold = ((strlen($threshold) > 0) ? (float)$threshold : 0.1);
3092
3093
                        $phpthumbFilters->HistogramStretch($this->gdimg_output, $band, $method, $threshold);
3094
                        break;
3095
3096
                    case 'wb': // WhiteBalance
3097
                        $phpthumbFilters->WhiteBalance($this->gdimg_output, $parameter);
3098
                        break;
3099
3100
                    case 'hist': // Histogram overlay
3101
                        if (phpthumb_functions::gd_version() < 2) {
3102
                            $this->DebugMessage('Skipping HistogramOverlay() because gd_version is "' . phpthumb_functions::gd_version() . '"', __FILE__, __LINE__);
3103
                            break;
3104
                        }
3105
                        @list($bands, $colors, $width, $height, $alignment, $opacity, $margin_x, $margin_y) = explode('|', $parameter, 8);
3106
                        $bands     = ($bands ?: '*');
3107
                        $colors    = ($colors ?: '');
3108
                        $width     = ($width ?: 0.25);
3109
                        $height    = ($height ?: 0.25);
3110
                        $alignment = ($alignment ?: 'BR');
3111
                        $opacity   = ($opacity ?: 50);
3112
                        $margin_x  = ($margin_x ?: 5);
3113
                        $margin_y  = $margin_y; // just to note it wasn't forgotten, but let the value always pass unchanged
3114
                        $phpthumbFilters->HistogramOverlay($this->gdimg_output, $bands, $colors, $width, $height, $alignment, $opacity, $margin_x, $margin_y);
3115
                        break;
3116
3117
                    case 'fram': // Frame
3118
                        @list($frame_width, $edge_width, $color_frame, $color1, $color2) = explode('|', $parameter, 5);
3119
                        $phpthumbFilters->Frame($this->gdimg_output, $frame_width, $edge_width, $color_frame, $color1, $color2);
3120
                        break;
3121
3122
                    case 'drop': // DropShadow
3123
                        if (phpthumb_functions::gd_version() < 2) {
3124
                            $this->DebugMessage('Skipping DropShadow() because gd_version is "' . phpthumb_functions::gd_version() . '"', __FILE__, __LINE__);
3125
3126
                            return false;
3127
                        }
3128
                        $this->is_alpha = true;
3129
                        @list($distance, $width, $color, $angle, $fade) = explode('|', $parameter, 5);
3130
                        $phpthumbFilters->DropShadow($this->gdimg_output, $distance, $width, $color, $angle, $fade);
3131
                        break;
3132
3133
                    case 'mask': // Mask cropping
3134
                        if (phpthumb_functions::gd_version() < 2) {
3135
                            $this->DebugMessage('Skipping Mask() because gd_version is "' . phpthumb_functions::gd_version() . '"', __FILE__, __LINE__);
3136
3137
                            return false;
3138
                        }
3139
                        @list($mask_filename, $invert) = explode('|', $parameter, 2);
3140
                        $mask_filename = $this->ResolveFilenameToAbsolute($mask_filename);
3141
                        if (@is_readable($mask_filename) && ($fp_mask = @fopen($mask_filename, 'rb'))) {
3142
                            $MaskImageData = '';
3143
                            do {
3144
                                $buffer        = fread($fp_mask, 8192);
3145
                                $MaskImageData .= $buffer;
3146
                            } while (strlen($buffer) > 0);
3147
                            fclose($fp_mask);
3148
                            if ($gdimg_mask = $this->ImageCreateFromStringReplacement($MaskImageData)) {
3149
                                if ($invert
3150
                                    && phpthumb_functions::version_compare_replacement(PHP_VERSION, '5.0.0', '>=')
3151
                                    && phpthumb_functions::gd_is_bundled()
3152
                                ) {
3153
                                    imagefilter($gdimg_mask, IMG_FILTER_NEGATE);
3154
                                }
3155
                                $this->is_alpha = true;
3156
                                $phpthumbFilters->ApplyMask($gdimg_mask, $this->gdimg_output);
3157
                                imagedestroy($gdimg_mask);
3158
                            } else {
3159
                                $this->DebugMessage('ImageCreateFromStringReplacement() failed for "' . $mask_filename . '"', __FILE__, __LINE__);
3160
                            }
3161
                        } else {
3162
                            $this->DebugMessage('Cannot open mask file "' . $mask_filename . '"', __FILE__, __LINE__);
3163
                        }
3164
                        break;
3165
3166
                    case 'elip': // Ellipse cropping
3167
                        if (phpthumb_functions::gd_version() < 2) {
3168
                            $this->DebugMessage('Skipping Ellipse() because gd_version is "' . phpthumb_functions::gd_version() . '"', __FILE__, __LINE__);
3169
3170
                            return false;
3171
                        }
3172
                        $this->is_alpha = true;
3173
                        $phpthumbFilters->Ellipse($this->gdimg_output);
3174
                        break;
3175
3176
                    case 'ric': // RoundedImageCorners
3177
                        if (phpthumb_functions::gd_version() < 2) {
3178
                            $this->DebugMessage('Skipping RoundedImageCorners() because gd_version is "' . phpthumb_functions::gd_version() . '"', __FILE__, __LINE__);
3179
3180
                            return false;
3181
                        }
3182
                        @list($radius_x, $radius_y) = explode('|', $parameter, 2);
3183
                        if (($radius_x < 1) || ($radius_y < 1)) {
3184
                            $this->DebugMessage('Skipping RoundedImageCorners(' . $radius_x . ', ' . $radius_y . ') because x/y radius is less than 1', __FILE__, __LINE__);
3185
                            break;
3186
                        }
3187
                        $this->is_alpha = true;
3188
                        $phpthumbFilters->RoundedImageCorners($this->gdimg_output, $radius_x, $radius_y);
3189
                        break;
3190
3191
                    case 'crop': // Crop
3192
                        @list($left, $right, $top, $bottom) = explode('|', $parameter, 4);
3193
                        $phpthumbFilters->Crop($this->gdimg_output, $left, $right, $top, $bottom);
3194
                        break;
3195
3196
                    case 'bord': // Border
3197
                        @list($border_width, $radius_x, $radius_y, $hexcolor_border) = explode('|', $parameter, 4);
3198
                        $this->is_alpha = true;
3199
                        $phpthumbFilters->ImageBorder($this->gdimg_output, $border_width, $radius_x, $radius_y, $hexcolor_border);
3200
                        break;
3201
3202
                    case 'over': // Overlay
3203
                        @list($filename, $underlay, $margin, $opacity) = explode('|', $parameter, 4);
3204
                        $underlay = (bool)($underlay ?: false);
3205
                        $margin   = ((strlen($margin) > 0) ? $margin : ($underlay ? 0.1 : 0.0));
3206
                        $opacity  = ((strlen($opacity) > 0) ? $opacity : 100);
3207
                        if (($margin > 0) && ($margin < 1)) {
3208
                            $margin = min(0.499, $margin);
3209
                        } elseif (($margin > -1) && ($margin < 0)) {
3210
                            $margin = max(-0.499, $margin);
3211
                        }
3212
3213
                        $filename = $this->ResolveFilenameToAbsolute($filename);
3214
                        if (@is_readable($filename) && ($fp_watermark = @fopen($filename, 'rb'))) {
3215
                            $WatermarkImageData = '';
3216
                            do {
3217
                                $buffer             = fread($fp_watermark, 8192);
3218
                                $WatermarkImageData .= $buffer;
3219
                            } while (strlen($buffer) > 0);
3220
                            fclose($fp_watermark);
3221
                            if ($img_watermark = $this->ImageCreateFromStringReplacement($WatermarkImageData)) {
3222
                                if ($margin < 1) {
3223
                                    $resized_x = max(1, imagesx($this->gdimg_output) - round(2 * (imagesx($this->gdimg_output) * $margin)));
3224
                                    $resized_y = max(1, imagesy($this->gdimg_output) - round(2 * (imagesy($this->gdimg_output) * $margin)));
3225
                                } else {
3226
                                    $resized_x = max(1, imagesx($this->gdimg_output) - round(2 * $margin));
3227
                                    $resized_y = max(1, imagesy($this->gdimg_output) - round(2 * $margin));
3228
                                }
3229
3230
                                if ($underlay) {
3231
                                    if ($img_watermark_resized = phpthumb_functions::ImageCreateFunction(imagesx($this->gdimg_output), imagesy($this->gdimg_output))) {
3232
                                        ImageAlphaBlending($img_watermark_resized, false);
3233
                                        ImageSaveAlpha($img_watermark_resized, true);
3234
                                        $this->ImageResizeFunction($img_watermark_resized, $img_watermark, 0, 0, 0, 0, imagesx($img_watermark_resized), imagesy($img_watermark_resized),
3235
                                                                   imagesx($img_watermark), imagesy($img_watermark));
3236
                                        if ($img_source_resized = phpthumb_functions::ImageCreateFunction($resized_x, $resized_y)) {
3237
                                            ImageAlphaBlending($img_source_resized, false);
3238
                                            ImageSaveAlpha($img_source_resized, true);
3239
                                            $this->ImageResizeFunction($img_source_resized, $this->gdimg_output, 0, 0, 0, 0, imagesx($img_source_resized), imagesy($img_source_resized),
3240
                                                                       imagesx($this->gdimg_output), imagesy($this->gdimg_output));
3241
                                            $phpthumbFilters->WatermarkOverlay($img_watermark_resized, $img_source_resized, 'C', $opacity, $margin);
3242
                                            imagecopy($this->gdimg_output, $img_watermark_resized, 0, 0, 0, 0, imagesx($this->gdimg_output), imagesy($this->gdimg_output));
3243
                                        } else {
3244
                                            $this->DebugMessage('phpthumb_functions::ImageCreateFunction(' . $resized_x . ', ' . $resized_y . ')', __FILE__, __LINE__);
3245
                                        }
3246
                                        imagedestroy($img_watermark_resized);
3247 View Code Duplication
                                    } else {
3248
                                        $this->DebugMessage('phpthumb_functions::ImageCreateFunction(' . imagesx($this->gdimg_output) . ', ' . imagesy($this->gdimg_output) . ')', __FILE__, __LINE__);
3249
                                    }
3250
                                } else { // overlay
3251
3252
                                    if ($img_watermark_resized = phpthumb_functions::ImageCreateFunction($resized_x, $resized_y)) {
3253
                                        ImageAlphaBlending($img_watermark_resized, false);
3254
                                        ImageSaveAlpha($img_watermark_resized, true);
3255
                                        $this->ImageResizeFunction($img_watermark_resized, $img_watermark, 0, 0, 0, 0, imagesx($img_watermark_resized), imagesy($img_watermark_resized),
3256
                                                                   imagesx($img_watermark), imagesy($img_watermark));
3257
                                        $phpthumbFilters->WatermarkOverlay($this->gdimg_output, $img_watermark_resized, 'C', $opacity, $margin);
3258
                                        imagedestroy($img_watermark_resized);
3259
                                    } else {
3260
                                        $this->DebugMessage('phpthumb_functions::ImageCreateFunction(' . $resized_x . ', ' . $resized_y . ')', __FILE__, __LINE__);
3261
                                    }
3262
                                }
3263
                                imagedestroy($img_watermark);
3264
                            } else {
3265
                                $this->DebugMessage('ImageCreateFromStringReplacement() failed for "' . $filename . '"', __FILE__, __LINE__);
3266
                            }
3267
                        } else {
3268
                            $this->DebugMessage('Cannot open overlay file "' . $filename . '"', __FILE__, __LINE__);
3269
                        }
3270
                        break;
3271
3272
                    case 'wmi': // WaterMarkImage
3273
                        @list($filename, $alignment, $opacity, $margin['x'], $margin['y'], $rotate_angle) = explode('|', $parameter, 6);
3274
                        // $margin can be pixel margin or percent margin if $alignment is text, or max width/height if $alignment is position like "50x75"
3275
                        $alignment    = ($alignment ?: 'BR');
3276
                        $opacity      = (strlen($opacity) ? (int)$opacity : 50);
3277
                        $rotate_angle = (strlen($rotate_angle) ? (int)$rotate_angle : 0);
3278
                        if (!preg_match('#^([0-9\\.\\-]*)x([0-9\\.\\-]*)$#i', $alignment, $matches)) {
3279
                            $margins = array('x', 'y');
3280
                            foreach ($margins as $xy) {
3281
                                $margin[$xy] = (strlen($margin[$xy]) ? $margin[$xy] : 5);
0 ignored issues
show
Coding Style Comprehensibility introduced by
$margin was never initialized. Although not strictly required by PHP, it is generally a good practice to add $margin = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
3282
                                if (($margin[$xy] > 0) && ($margin[$xy] < 1)) {
3283
                                    $margin[$xy] = min(0.499, $margin[$xy]);
3284
                                } elseif (($margin[$xy] > -1) && ($margin[$xy] < 0)) {
3285
                                    $margin[$xy] = max(-0.499, $margin[$xy]);
3286
                                }
3287
                            }
3288
                        }
3289
3290
                        $filename = $this->ResolveFilenameToAbsolute($filename);
3291
                        if (@is_readable($filename)) {
3292
                            if ($img_watermark = $this->ImageCreateFromFilename($filename)) {
3293
                                if ($rotate_angle !== 0) {
3294
                                    $phpthumbFilters->ImprovedImageRotate($img_watermark, $rotate_angle, 'FFFFFF', null, $this);
3295
                                }
3296
                                if (preg_match('#^([0-9\\.\\-]*)x([0-9\\.\\-]*)$#i', $alignment, $matches)) {
3297
                                    $watermark_max_width  = (int)($margin['x'] ?: imagesx($img_watermark));
3298
                                    $watermark_max_height = (int)($margin['y'] ?: imagesy($img_watermark));
3299
                                    $scale                = phpthumb_functions::ScaleToFitInBox(imagesx($img_watermark), imagesy($img_watermark), $watermark_max_width, $watermark_max_height, true,
3300
                                                                                                true);
3301
                                    $this->DebugMessage('Scaling watermark by a factor of ' . number_format($scale, 4), __FILE__, __LINE__);
3302
                                    if (($scale > 1) || ($scale < 1)) {
3303
                                        if ($img_watermark2 = phpthumb_functions::ImageCreateFunction($scale * imagesx($img_watermark), $scale * imagesy($img_watermark))) {
3304
                                            ImageAlphaBlending($img_watermark2, false);
3305
                                            ImageSaveAlpha($img_watermark2, true);
3306
                                            $this->ImageResizeFunction($img_watermark2, $img_watermark, 0, 0, 0, 0, imagesx($img_watermark2), imagesy($img_watermark2), imagesx($img_watermark),
3307
                                                                       imagesy($img_watermark));
3308
                                            $img_watermark = $img_watermark2;
3309
                                        } else {
3310
                                            $this->DebugMessage('ImageCreateFunction(' . ($scale * imagesx($img_watermark)) . ', ' . ($scale * imagesx($img_watermark)) . ') failed', __FILE__,
3311
                                                                __LINE__);
3312
                                        }
3313
                                    }
3314
                                    $watermark_dest_x = round($matches[1] - (imagesx($img_watermark) / 2));
3315
                                    $watermark_dest_y = round($matches[2] - (imagesy($img_watermark) / 2));
3316
                                    $alignment        = $watermark_dest_x . 'x' . $watermark_dest_y;
3317
                                }
3318
                                $phpthumbFilters->WatermarkOverlay($this->gdimg_output, $img_watermark, $alignment, $opacity, $margin['x'], $margin['y']);
3319
                                imagedestroy($img_watermark);
3320
                                if (isset($img_watermark2) && is_resource($img_watermark2)) {
3321
                                    imagedestroy($img_watermark2);
3322
                                }
3323
                            } else {
3324
                                $this->DebugMessage('ImageCreateFromFilename() failed for "' . $filename . '"', __FILE__, __LINE__);
3325
                            }
3326
                        } else {
3327
                            $this->DebugMessage('!is_readable(' . $filename . ')', __FILE__, __LINE__);
3328
                        }
3329
                        break;
3330
3331
                    case 'wmt': // WaterMarkText
3332
                        @list($text, $size, $alignment, $hex_color, $ttffont, $opacity, $margin, $angle, $bg_color, $bg_opacity, $fillextend) = explode('|', $parameter, 11);
3333
                        $text       = ($text ?: '');
3334
                        $size       = ($size ?: 3);
3335
                        $alignment  = ($alignment ?: 'BR');
3336
                        $hex_color  = ($hex_color ?: '000000');
3337
                        $ttffont    = ($ttffont ?: '');
3338
                        $opacity    = (strlen($opacity) ? $opacity : 50);
3339
                        $margin     = (strlen($margin) ? $margin : 5);
3340
                        $angle      = (strlen($angle) ? $angle : 0);
3341
                        $bg_color   = ($bg_color ?: false);
3342
                        $bg_opacity = ($bg_opacity ?: 0);
3343
                        $fillextend = ($fillextend ?: '');
3344
3345
                        if (basename($ttffont) == $ttffont) {
3346
                            $ttffont = $this->realPathSafe($this->config_ttf_directory . DIRECTORY_SEPARATOR . $ttffont);
3347
                        } else {
3348
                            $ttffont = $this->ResolveFilenameToAbsolute($ttffont);
3349
                        }
3350
                        $phpthumbFilters->WatermarkText($this->gdimg_output, $text, $size, $alignment, $hex_color, $ttffont, $opacity, $margin, $angle, $bg_color, $bg_opacity, $fillextend);
3351
                        break;
3352
3353 View Code Duplication
                    case 'blur': // Blur
3354
                        @list($radius) = explode('|', $parameter, 1);
3355
                        $radius = ($radius ?: 1);
3356
                        if (phpthumb_functions::gd_version() >= 2) {
3357
                            $phpthumbFilters->Blur($this->gdimg_output, $radius);
3358
                        } else {
3359
                            $this->DebugMessage('Skipping Blur() because gd_version is "' . phpthumb_functions::gd_version() . '"', __FILE__, __LINE__);
3360
                        }
3361
                        break;
3362
3363
                    case 'gblr': // Gaussian Blur
3364
                        $phpthumbFilters->BlurGaussian($this->gdimg_output);
3365
                        break;
3366
3367
                    case 'sblr': // Selective Blur
3368
                        $phpthumbFilters->BlurSelective($this->gdimg_output);
3369
                        break;
3370
3371
                    case 'mean': // MeanRemoval blur
3372
                        $phpthumbFilters->MeanRemoval($this->gdimg_output);
3373
                        break;
3374
3375
                    case 'smth': // Smooth blur
3376
                        $phpthumbFilters->Smooth($this->gdimg_output, $parameter);
3377
                        break;
3378
3379
                    case 'usm': // UnSharpMask sharpening
3380
                        @list($amount, $radius, $threshold) = explode('|', $parameter, 3);
3381
                        $amount    = ($amount ?: 80);
3382
                        $radius    = ($radius ?: 0.5);
3383
                        $threshold = (strlen($threshold) ? $threshold : 3);
3384
                        if (phpthumb_functions::gd_version() >= 2.0) {
3385
                            ob_start();
3386
                            if (!@require_once __DIR__ . '/phpthumb.unsharp.php') {
3387
                                $include_error = ob_get_contents();
3388
                                if ($include_error) {
3389
                                    $this->DebugMessage('include_once("' . __DIR__ . '/phpthumb.unsharp.php") generated message: "' . $include_error . '"', __FILE__, __LINE__);
3390
                                }
3391
                                $this->DebugMessage('Error including "' . __DIR__ . '/phpthumb.unsharp.php" which is required for unsharp masking', __FILE__, __LINE__);
3392
                                ob_end_clean();
3393
3394
                                return false;
3395
                            }
3396
                            ob_end_clean();
3397
                            phpUnsharpMask::applyUnsharpMask($this->gdimg_output, $amount, $radius, $threshold);
3398
                        } else {
3399
                            $this->DebugMessage('Skipping unsharp mask because gd_version is "' . phpthumb_functions::gd_version() . '"', __FILE__, __LINE__);
3400
3401
                            return false;
3402
                        }
3403
                        break;
3404
3405
                    case 'size': // Resize
3406
                        @list($newwidth, $newheight, $stretch) = explode('|', $parameter);
3407
                        $newwidth  = (!$newwidth ? imagesx($this->gdimg_output) : ((($newwidth > 0)
3408
                                                                                    && ($newwidth < 1)) ? round($newwidth * imagesx($this->gdimg_output)) : round($newwidth)));
3409
                        $newheight = (!$newheight ? imagesy($this->gdimg_output) : ((($newheight > 0)
3410
                                                                                     && ($newheight < 1)) ? round($newheight * imagesy($this->gdimg_output)) : round($newheight)));
3411
                        $stretch   = ($stretch ? true : false);
3412
                        if ($stretch) {
3413
                            $scale_x = phpthumb_functions::ScaleToFitInBox(imagesx($this->gdimg_output), imagesx($this->gdimg_output), $newwidth, $newwidth, true, true);
3414
                            $scale_y = phpthumb_functions::ScaleToFitInBox(imagesy($this->gdimg_output), imagesy($this->gdimg_output), $newheight, $newheight, true, true);
3415
                        } else {
3416
                            $scale_x = phpthumb_functions::ScaleToFitInBox(imagesx($this->gdimg_output), imagesy($this->gdimg_output), $newwidth, $newheight, true, true);
3417
                            $scale_y = $scale_x;
3418
                        }
3419
                        $this->DebugMessage('Scaling watermark ('
3420
                                            . ($stretch ? 'with' : 'without')
3421
                                            . ' stretch) by a factor of "'
3422
                                            . number_format($scale_x, 4)
3423
                                            . ' x '
3424
                                            . number_format($scale_y, 4)
3425
                                            . '"', __FILE__, __LINE__);
3426
                        if (($scale_x > 1) || ($scale_x < 1) || ($scale_y > 1) || ($scale_y < 1)) {
3427
                            if ($img_temp = phpthumb_functions::ImageCreateFunction(imagesx($this->gdimg_output), imagesy($this->gdimg_output))) {
3428
                                imagecopy($img_temp, $this->gdimg_output, 0, 0, 0, 0, imagesx($this->gdimg_output), imagesy($this->gdimg_output));
3429
                                //ImageDestroy($this->gdimg_output);
3430
                                if ($this->gdimg_output = phpthumb_functions::ImageCreateFunction($scale_x * imagesx($img_temp), $scale_y * imagesy($img_temp))) {
3431
                                    ImageAlphaBlending($this->gdimg_output, false);
3432
                                    ImageSaveAlpha($this->gdimg_output, true);
3433
                                    $this->ImageResizeFunction($this->gdimg_output, $img_temp, 0, 0, 0, 0, imagesx($this->gdimg_output), imagesy($this->gdimg_output), imagesx($img_temp),
3434
                                                               imagesy($img_temp));
3435
                                } else {
3436
                                    $this->DebugMessage('ImageCreateFunction(' . ($scale_x * imagesx($img_temp)) . ', ' . ($scale_y * imagesy($img_temp)) . ') failed', __FILE__, __LINE__);
3437
                                }
3438
                                imagedestroy($img_temp);
3439 View Code Duplication
                            } else {
3440
                                $this->DebugMessage('ImageCreateFunction(' . imagesx($this->gdimg_output) . ', ' . imagesy($this->gdimg_output) . ') failed', __FILE__, __LINE__);
3441
                            }
3442
                        }
3443
                        break;
3444
3445
                    case 'rot': // ROTate
3446
                        @list($angle, $bgcolor) = explode('|', $parameter, 2);
3447
                        $phpthumbFilters->ImprovedImageRotate($this->gdimg_output, $angle, $bgcolor, null, $this);
3448
                        break;
3449
3450
                    case 'stc': // Source Transparent Color
3451
                        @list($hexcolor, $min_limit, $max_limit) = explode('|', $parameter, 3);
3452
                        if (!phpthumb_functions::IsHexColor($hexcolor)) {
3453
                            $this->DebugMessage('Skipping SourceTransparentColor hex color is invalid (' . $hexcolor . ')', __FILE__, __LINE__);
3454
3455
                            return false;
3456
                        }
3457
                        $min_limit = (strlen($min_limit) ? $min_limit : 5);
3458
                        $max_limit = (strlen($max_limit) ? $max_limit : 10);
3459
                        if ($gdimg_mask = $phpthumbFilters->SourceTransparentColorMask($this->gdimg_output, $hexcolor, $min_limit, $max_limit)) {
3460
                            $this->is_alpha = true;
3461
                            $phpthumbFilters->ApplyMask($gdimg_mask, $this->gdimg_output);
3462
                            imagedestroy($gdimg_mask);
3463
                        } else {
3464
                            $this->DebugMessage('SourceTransparentColorMask() failed for "' . $mask_filename . '"', __FILE__, __LINE__);
3465
                        }
3466
                        break;
3467
                }
3468
                $this->DebugMessage('Finished processing filter command "' . $command . '(' . $parameter . ')"', __FILE__, __LINE__);
3469
            }
3470
        }
3471
3472
        return true;
3473
    }
3474
3475
    /**
3476
     * @return bool
3477
     */
3478
    public function MaxFileSize()
3479
    {
3480
        if (phpthumb_functions::gd_version() < 2) {
3481
            $this->DebugMessage('Skipping MaxFileSize() because gd_version is "' . phpthumb_functions::gd_version() . '"', __FILE__, __LINE__);
3482
3483
            return false;
3484
        }
3485
        if ($this->maxb > 0) {
3486
            switch ($this->thumbnailFormat) {
3487
                case 'png':
3488
                case 'gif':
3489
                    $imgRenderFunction = 'image' . $this->thumbnailFormat;
3490
3491
                    ob_start();
3492
                    $imgRenderFunction($this->gdimg_output);
3493
                    $imgdata = ob_get_contents();
3494
                    ob_end_clean();
3495
3496
                    if (strlen($imgdata) > $this->maxb) {
3497
                        for ($i = 8; $i >= 1; $i--) {
3498
                            $tempIMG = imagecreatetruecolor(imagesx($this->gdimg_output), imagesy($this->gdimg_output));
3499
                            imagecopy($tempIMG, $this->gdimg_output, 0, 0, 0, 0, imagesx($this->gdimg_output), imagesy($this->gdimg_output));
3500
                            imagetruecolortopalette($tempIMG, true, pow(2, $i));
3501
                            ob_start();
3502
                            $imgRenderFunction($tempIMG);
3503
                            $imgdata = ob_get_contents();
3504
                            ob_end_clean();
3505
3506 View Code Duplication
                            if (strlen($imgdata) <= $this->maxb) {
3507
                                imagetruecolortopalette($this->gdimg_output, true, pow(2, $i));
3508
                                break;
3509
                            }
3510
                        }
3511
                    }
3512 View Code Duplication
                    if (strlen($imgdata) > $this->maxb) {
3513
                        imagetruecolortopalette($this->gdimg_output, true, pow(2, $i));
3514
3515
                        return false;
3516
                    }
3517
                    break;
3518
3519
                case 'jpeg':
3520
                    ob_start();
3521
                    imagejpeg($this->gdimg_output);
3522
                    $imgdata = ob_get_contents();
3523
                    ob_end_clean();
3524
3525
                    $OriginalJPEGquality = $this->thumbnailQuality;
3526
                    if (strlen($imgdata) > $this->maxb) {
3527
                        for ($i = 3; $i < 20; $i++) {
3528
                            $q = round(100 * (1 - log10($i / 2)));
3529
                            ob_start();
3530
                            imagejpeg($this->gdimg_output, null, $q);
3531
                            $imgdata = ob_get_contents();
3532
                            ob_end_clean();
3533
3534
                            $this->thumbnailQuality = $q;
3535
                            if (strlen($imgdata) <= $this->maxb) {
3536
                                break;
3537
                            }
3538
                        }
3539
                    }
3540
                    if (strlen($imgdata) > $this->maxb) {
3541
                        return false;
3542
                    }
3543
                    break;
3544
3545
                default:
3546
                    return false;
3547
                    break;
3548
            }
3549
        }
3550
3551
        return true;
3552
    }
3553
3554
    /**
3555
     * @return bool
3556
     */
3557
    public function CalculateThumbnailDimensions()
3558
    {
3559
        $this->DebugMessage('CalculateThumbnailDimensions() starting with [W,H,sx,sy,sw,sh] initially set to ['
3560
                            . $this->source_width
3561
                            . ','
3562
                            . $this->source_height
3563
                            . ','
3564
                            . $this->sx
3565
                            . ','
3566
                            . $this->sy
3567
                            . ','
3568
                            . $this->sw
3569
                            . ','
3570
                            . $this->sh
3571
                            . ']', __FILE__, __LINE__);
3572
        //echo $this->source_width.'x'.$this->source_height.'<hr>';
3573
        $this->thumbnailCropX = ($this->sx ? (($this->sx >= 2) ? $this->sx : round($this->sx * $this->source_width)) : 0);
3574
        //echo $this->thumbnailCropX.'<br>';
3575
        $this->thumbnailCropY = ($this->sy ? (($this->sy >= 2) ? $this->sy : round($this->sy * $this->source_height)) : 0);
3576
        //echo $this->thumbnailCropY.'<br>';
3577
        $this->thumbnailCropW = ($this->sw ? (($this->sw >= 2) ? $this->sw : round($this->sw * $this->source_width)) : $this->source_width);
3578
        //echo $this->thumbnailCropW.'<br>';
3579
        $this->thumbnailCropH = ($this->sh ? (($this->sh >= 2) ? $this->sh : round($this->sh * $this->source_height)) : $this->source_height);
3580
        //echo $this->thumbnailCropH.'<hr>';
3581
3582
        // limit source area to original image area
3583
        $this->thumbnailCropW = max(1, min($this->thumbnailCropW, $this->source_width - $this->thumbnailCropX));
3584
        $this->thumbnailCropH = max(1, min($this->thumbnailCropH, $this->source_height - $this->thumbnailCropY));
3585
3586
        $this->DebugMessage('CalculateThumbnailDimensions() starting with [x,y,w,h] initially set to ['
3587
                            . $this->thumbnailCropX
3588
                            . ','
3589
                            . $this->thumbnailCropY
3590
                            . ','
3591
                            . $this->thumbnailCropW
3592
                            . ','
3593
                            . $this->thumbnailCropH
3594
                            . ']', __FILE__, __LINE__);
3595
3596
        if ($this->zc && $this->w && $this->h) {
3597
            // Zoom Crop
3598
            // retain proportional resizing we did above, but crop off larger dimension so smaller
3599
            // dimension fully fits available space
3600
3601
            $scaling_X = $this->source_width / $this->w;
3602
            $scaling_Y = $this->source_height / $this->h;
3603
            if ($scaling_X > $scaling_Y) {
3604
                // some of the width will need to be cropped
3605
                $allowable_width      = $this->source_width / $scaling_X * $scaling_Y;
3606
                $this->thumbnailCropW = round($allowable_width);
3607
                $this->thumbnailCropX = round(($this->source_width - $allowable_width) / 2);
3608
            } elseif ($scaling_Y > $scaling_X) {
3609
                // some of the height will need to be cropped
3610
                $allowable_height     = $this->source_height / $scaling_Y * $scaling_X;
3611
                $this->thumbnailCropH = round($allowable_height);
3612
                $this->thumbnailCropY = round(($this->source_height - $allowable_height) / 2);
3613
            } else {
3614
                // image fits perfectly, no cropping needed
3615
            }
3616
            $this->thumbnail_width        = $this->w;
3617
            $this->thumbnail_height       = $this->h;
3618
            $this->thumbnail_image_width  = $this->thumbnail_width;
3619
            $this->thumbnail_image_height = $this->thumbnail_height;
3620
        } elseif ($this->iar && $this->w && $this->h) {
3621
3622
            // Ignore Aspect Ratio
3623
            // stretch image to fit exactly 'w' x 'h'
3624
            $this->thumbnail_width        = $this->w;
3625
            $this->thumbnail_height       = $this->h;
3626
            $this->thumbnail_image_width  = $this->thumbnail_width;
3627
            $this->thumbnail_image_height = $this->thumbnail_height;
3628
        } else {
3629
            $original_aspect_ratio = $this->thumbnailCropW / $this->thumbnailCropH;
3630
            if ($this->aoe) {
3631
                if ($this->w && $this->h) {
3632
                    $maxwidth  = min($this->w, $this->h * $original_aspect_ratio);
3633
                    $maxheight = min($this->h, $this->w / $original_aspect_ratio);
3634
                } elseif ($this->w) {
3635
                    $maxwidth  = $this->w;
3636
                    $maxheight = $this->w / $original_aspect_ratio;
3637
                } elseif ($this->h) {
3638
                    $maxwidth  = $this->h * $original_aspect_ratio;
3639
                    $maxheight = $this->h;
3640
                } else {
3641
                    $maxwidth  = $this->thumbnailCropW;
3642
                    $maxheight = $this->thumbnailCropH;
3643
                }
3644
            } else {
3645
                $maxwidth  = phpthumb_functions::nonempty_min($this->w, $this->thumbnailCropW, $this->config_output_maxwidth);
3646
                $maxheight = phpthumb_functions::nonempty_min($this->h, $this->thumbnailCropH, $this->config_output_maxheight);
3647
                //echo $maxwidth.'x'.$maxheight.'<br>';
3648
                $maxwidth  = min($maxwidth, $maxheight * $original_aspect_ratio);
3649
                $maxheight = min($maxheight, $maxwidth / $original_aspect_ratio);
3650
                //echo $maxwidth.'x'.$maxheight.'<hr>';
3651
            }
3652
3653
            $this->thumbnail_image_width  = $maxwidth;
3654
            $this->thumbnail_image_height = $maxheight;
3655
            $this->thumbnail_width        = $maxwidth;
3656
            $this->thumbnail_height       = $maxheight;
3657
3658
            $this->FixedAspectRatio();
3659
        }
3660
3661
        $this->thumbnail_width  = max(1, floor($this->thumbnail_width));
3662
        $this->thumbnail_height = max(1, floor($this->thumbnail_height));
3663
3664
        return true;
3665
    }
3666
3667
    /**
3668
     * @return bool
3669
     */
3670
    public function CreateGDoutput()
3671
    {
3672
        $this->CalculateThumbnailDimensions();
3673
3674
        // Create the GD image (either true-color or 256-color, depending on GD version)
3675
        $this->gdimg_output = phpthumb_functions::ImageCreateFunction($this->thumbnail_width, $this->thumbnail_height);
3676
3677
        // Images that have transparency must have the background filled with the configured 'bg' color
3678
        // otherwise the transparent color will appear as black
3679
        ImageSaveAlpha($this->gdimg_output, true);
3680
        if ($this->is_alpha && phpthumb_functions::gd_version() >= 2) {
3681
            ImageAlphaBlending($this->gdimg_output, false);
3682
            $output_full_alpha = phpthumb_functions::ImageColorAllocateAlphaSafe($this->gdimg_output, 255, 255, 255, 127);
3683
            imagefilledrectangle($this->gdimg_output, 0, 0, $this->thumbnail_width, $this->thumbnail_height, $output_full_alpha);
3684
        } else {
3685
            $current_transparent_color = imagecolortransparent($this->gdimg_source);
3686
            if ($this->bg || (@$current_transparent_color >= 0)) {
3687
                $this->config_background_hexcolor = ($this->bg ?: $this->config_background_hexcolor);
3688
                if (!phpthumb_functions::IsHexColor($this->config_background_hexcolor)) {
3689
                    return $this->ErrorImage('Invalid hex color string "' . $this->config_background_hexcolor . '" for parameter "bg"');
3690
                }
3691
                $background_color = phpthumb_functions::ImageHexColorAllocate($this->gdimg_output, $this->config_background_hexcolor);
3692
                imagefilledrectangle($this->gdimg_output, 0, 0, $this->thumbnail_width, $this->thumbnail_height, $background_color);
3693
            }
3694
        }
3695
        $this->DebugMessage('CreateGDoutput() returning canvas "' . $this->thumbnail_width . 'x' . $this->thumbnail_height . '"', __FILE__, __LINE__);
3696
3697
        return true;
3698
    }
3699
3700
    /**
3701
     * @return bool
3702
     */
3703
    public function SetOrientationDependantWidthHeight()
3704
    {
3705
        $this->DebugMessage('SetOrientationDependantWidthHeight() starting with "' . $this->source_width . '"x"' . $this->source_height . '"', __FILE__, __LINE__);
3706
        if ($this->source_height > $this->source_width) {
3707
            // portrait
3708
            $this->w = phpthumb_functions::OneOfThese($this->wp, $this->w, $this->ws, $this->wl);
3709
            $this->h = phpthumb_functions::OneOfThese($this->hp, $this->h, $this->hs, $this->hl);
3710
        } elseif ($this->source_height < $this->source_width) {
3711
            // landscape
3712
            $this->w = phpthumb_functions::OneOfThese($this->wl, $this->w, $this->ws, $this->wp);
3713
            $this->h = phpthumb_functions::OneOfThese($this->hl, $this->h, $this->hs, $this->hp);
3714
        } else {
3715
            // square
3716
            $this->w = phpthumb_functions::OneOfThese($this->ws, $this->w, $this->wl, $this->wp);
3717
            $this->h = phpthumb_functions::OneOfThese($this->hs, $this->h, $this->hl, $this->hp);
3718
        }
3719
        //$this->w = round($this->w ? $this->w : (($this->h && $this->source_height) ? $this->h * $this->source_width  / $this->source_height : $this->w));
3720
        //$this->h = round($this->h ? $this->h : (($this->w && $this->source_width)  ? $this->w * $this->source_height / $this->source_width  : $this->h));
3721
        $this->DebugMessage('SetOrientationDependantWidthHeight() setting w="' . (int)$this->w . '", h="' . (int)$this->h . '"', __FILE__, __LINE__);
3722
3723
        return true;
3724
    }
3725
3726
    /**
3727
     * @return bool
3728
     */
3729
    public function ExtractEXIFgetImageSize()
3730
    {
3731
        $this->DebugMessage('starting ExtractEXIFgetImageSize()', __FILE__, __LINE__);
3732
3733
        if (preg_match('#^http:#i', $this->src) && !$this->sourceFilename && $this->rawImageData) {
3734
            !$this->SourceDataToTempFile();
3735
        }
3736
        if (is_null($this->getimagesizeinfo)) {
3737
            if ($this->sourceFilename) {
3738
                $this->getimagesizeinfo = @getimagesize($this->sourceFilename);
3739
                $this->source_width     = $this->getimagesizeinfo[0];
3740
                $this->source_height    = $this->getimagesizeinfo[1];
3741
                $this->DebugMessage('GetImageSize(' . $this->sourceFilename . ') says image is ' . $this->source_width . 'x' . $this->source_height, __FILE__, __LINE__);
3742
            } else {
3743
                $this->DebugMessage('skipping GetImageSize() because $this->sourceFilename is empty', __FILE__, __LINE__);
3744
            }
3745
        } else {
3746
            $this->DebugMessage('skipping GetImageSize() because !is_null($this->getimagesizeinfo)', __FILE__, __LINE__);
3747
        }
3748
3749
        if (is_resource($this->gdimg_source)) {
3750
            $this->source_width  = imagesx($this->gdimg_source);
3751
            $this->source_height = imagesy($this->gdimg_source);
3752
3753
            $this->SetOrientationDependantWidthHeight();
3754
        } elseif ($this->rawImageData && !$this->sourceFilename) {
3755
            if ($this->SourceImageIsTooLarge($this->source_width, $this->source_height)) {
3756
                $this->DebugMessage('NOT bypassing EXIF and GetImageSize sections because source image is too large for GD ('
3757
                                    . $this->source_width
3758
                                    . 'x'
3759
                                    . $this->source_width
3760
                                    . '='
3761
                                    . ($this->source_width * $this->source_height * 5)
3762
                                    . 'MB)', __FILE__, __LINE__);
3763
            } else {
3764
                $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 ('
3765
                                    . $this->source_width
3766
                                    . 'x'
3767
                                    . $this->source_width
3768
                                    . '='
3769
                                    . ($this->source_width * $this->source_height * 5)
3770
                                    . 'MB)', __FILE__, __LINE__);
3771
            }
3772
        }
3773
3774
        if (is_null($this->getimagesizeinfo)) {
3775
            $this->getimagesizeinfo = @getimagesize($this->sourceFilename);
3776
        }
3777
3778
        if (!empty($this->getimagesizeinfo)) {
3779
            // great
3780
            $this->getimagesizeinfo['filesize'] = @filesize($this->sourceFilename);
3781
        } elseif (!$this->rawImageData) {
3782
            $this->DebugMessage('GetImageSize("' . $this->sourceFilename . '") failed', __FILE__, __LINE__);
3783
        }
3784
3785
        if ($this->config_prefer_imagemagick) {
3786
            if ($this->ImageMagickThumbnailToGD()) {
3787
                return true;
3788
            }
3789
            $this->DebugMessage('ImageMagickThumbnailToGD() failed', __FILE__, __LINE__);
3790
        }
3791
3792
        $this->source_width  = $this->getimagesizeinfo[0];
3793
        $this->source_height = $this->getimagesizeinfo[1];
3794
3795
        $this->SetOrientationDependantWidthHeight();
3796
3797
        if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '4.2.0', '>=')
3798
            && function_exists('exif_read_data')
3799
        ) {
3800
            switch ($this->getimagesizeinfo[2]) {
3801
                case IMAGETYPE_JPEG:
3802
                case IMAGETYPE_TIFF_II:
3803
                case IMAGETYPE_TIFF_MM:
3804
                    $this->exif_raw_data = @exif_read_data($this->sourceFilename, 0, true);
3805
                    break;
3806
            }
3807
        }
3808
        if (function_exists('exif_thumbnail') && ($this->getimagesizeinfo[2] == IMAGETYPE_JPEG)) {
3809
            // Extract EXIF info from JPEGs
3810
3811
            $this->exif_thumbnail_width  = '';
3812
            $this->exif_thumbnail_height = '';
3813
            $this->exif_thumbnail_type   = '';
3814
3815
            // The parameters width, height and imagetype are available since PHP v4.3.0
3816
            if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '4.3.0', '>=')) {
3817
                $this->exif_thumbnail_data = @exif_thumbnail($this->sourceFilename, $this->exif_thumbnail_width, $this->exif_thumbnail_height, $this->exif_thumbnail_type);
3818
            } else {
3819
3820
                // older versions of exif_thumbnail output an error message but NOT return false on failure
3821
                ob_start();
3822
                $this->exif_thumbnail_data = exif_thumbnail($this->sourceFilename);
3823
                $exit_thumbnail_error      = ob_get_contents();
3824
                ob_end_clean();
3825
                if (!$exit_thumbnail_error && $this->exif_thumbnail_data) {
3826
                    if ($gdimg_exif_temp = $this->ImageCreateFromStringReplacement($this->exif_thumbnail_data, false)) {
3827
                        $this->exif_thumbnail_width  = imagesx($gdimg_exif_temp);
3828
                        $this->exif_thumbnail_height = imagesy($gdimg_exif_temp);
3829
                        $this->exif_thumbnail_type   = 2; // (2 == JPEG) before PHP v4.3.0 only JPEG format EXIF thumbnails are returned
3830
                        unset($gdimg_exif_temp);
3831
                    } else {
3832
                        return $this->ErrorImage('Failed - $this->ImageCreateFromStringReplacement($this->exif_thumbnail_data) in ' . __FILE__ . ' on line ' . __LINE__);
3833
                    }
3834
                }
3835
            }
3836
        } elseif (!function_exists('exif_thumbnail')) {
3837
            $this->DebugMessage('exif_thumbnail() does not exist, cannot extract EXIF thumbnail', __FILE__, __LINE__);
3838
        }
3839
3840
        $this->DebugMessage('EXIF thumbnail extraction: (size='
3841
                            . strlen($this->exif_thumbnail_data)
3842
                            . '; type="'
3843
                            . $this->exif_thumbnail_type
3844
                            . '"; '
3845
                            . (int)$this->exif_thumbnail_width
3846
                            . 'x'
3847
                            . (int)$this->exif_thumbnail_height
3848
                            . ')', __FILE__, __LINE__);
3849
3850
        // see if EXIF thumbnail can be used directly with no processing
3851
        if ($this->config_use_exif_thumbnail_for_speed && $this->exif_thumbnail_data) {
3852
            while (true) {
3853
                if (!$this->xto) {
3854
                    $source_ar = $this->source_width / $this->source_height;
3855
                    $exif_ar   = $this->exif_thumbnail_width / $this->exif_thumbnail_height;
3856 View Code Duplication
                    if (number_format($source_ar, 2) != number_format($exif_ar, 2)) {
3857
                        $this->DebugMessage('not using EXIF thumbnail because $source_ar != $exif_ar (' . $source_ar . ' != ' . $exif_ar . ')', __FILE__, __LINE__);
3858
                        break;
3859
                    }
3860
                    if ($this->w && ($this->w != $this->exif_thumbnail_width)) {
3861
                        $this->DebugMessage('not using EXIF thumbnail because $this->w != $this->exif_thumbnail_width (' . $this->w . ' != ' . $this->exif_thumbnail_width . ')', __FILE__, __LINE__);
3862
                        break;
3863
                    }
3864
                    if ($this->h && ($this->h != $this->exif_thumbnail_height)) {
3865
                        $this->DebugMessage('not using EXIF thumbnail because $this->h != $this->exif_thumbnail_height (' . $this->h . ' != ' . $this->exif_thumbnail_height . ')', __FILE__, __LINE__);
3866
                        break;
3867
                    }
3868
                    $CannotBeSetParameters = array('sx', 'sy', 'sh', 'sw', 'far', 'bg', 'bc', 'fltr', 'phpThumbDebug');
3869
                    foreach ($CannotBeSetParameters as $parameter) {
3870
                        if ($this->$parameter) {
3871
                            break 2;
3872
                        }
3873
                    }
3874
                }
3875
3876
                $this->DebugMessage('setting $this->gdimg_source = $this->ImageCreateFromStringReplacement($this->exif_thumbnail_data)', __FILE__, __LINE__);
3877
                $this->gdimg_source  = $this->ImageCreateFromStringReplacement($this->exif_thumbnail_data);
3878
                $this->source_width  = imagesx($this->gdimg_source);
3879
                $this->source_height = imagesy($this->gdimg_source);
3880
3881
                return true;
3882
            }
3883
        }
3884
3885
        if (($this->config_max_source_pixels > 0)
3886
            && (($this->source_width * $this->source_height) > $this->config_max_source_pixels)
3887
        ) {
3888
3889
            // Source image is larger than would fit in available PHP memory.
3890
            // If ImageMagick is installed, use it to generate the thumbnail.
3891
            // Else, if an EXIF thumbnail is available, use that as the source image.
3892
            // Otherwise, no choice but to fail with an error message
3893
            $this->DebugMessage('image is '
3894
                                . $this->source_width
3895
                                . 'x'
3896
                                . $this->source_height
3897
                                . ' and therefore contains more pixels ('
3898
                                . ($this->source_width * $this->source_height)
3899
                                . ') than $this->config_max_source_pixels setting ('
3900
                                . $this->config_max_source_pixels
3901
                                . ')', __FILE__, __LINE__);
3902
            if (!$this->config_prefer_imagemagick && $this->ImageMagickThumbnailToGD()) {
3903
                // excellent, we have a thumbnailed source image
3904
                return true;
3905
            }
3906
        }
3907
3908
        return true;
3909
    }
3910
3911
    /**
3912
     * @return bool
3913
     */
3914
    public function SetCacheFilename()
3915
    {
3916
        if (!is_null($this->cache_filename)) {
3917
            $this->DebugMessage('$this->cache_filename already set, skipping SetCacheFilename()', __FILE__, __LINE__);
3918
3919
            return true;
3920
        }
3921
        if (is_null($this->config_cache_directory)) {
3922
            $this->setCacheDirectory();
3923
            if (!$this->config_cache_directory) {
3924
                $this->DebugMessage('SetCacheFilename() failed because $this->config_cache_directory is empty', __FILE__, __LINE__);
3925
3926
                return false;
3927
            }
3928
        }
3929
        $this->setOutputFormat();
3930
3931
        if (!$this->sourceFilename && !$this->rawImageData && $this->src) {
3932
            $this->sourceFilename = $this->ResolveFilenameToAbsolute($this->src);
3933
        }
3934
3935
        if ($this->config_cache_default_only_suffix && $this->sourceFilename) {
3936
            // simplified cache filenames:
3937
            // only use default parameters in phpThumb.config.php
3938
            // substitute source filename into * in $this->config_cache_default_only_suffix
3939
            // (eg: '*_thumb' becomes 'picture_thumb.jpg')
3940
            if (strpos($this->config_cache_default_only_suffix, '*') === false) {
3941
                $this->DebugMessage('aborting simplified caching filename because no * in "' . $this->config_cache_default_only_suffix . '"', __FILE__, __LINE__);
3942
            } else {
3943
                preg_match('#(.+)(\\.[a-z0-9]+)?$#i', basename($this->sourceFilename), $matches);
3944
                $this->cache_filename = $this->config_cache_directory
3945
                                        . DIRECTORY_SEPARATOR
3946
                                        . rawurlencode(str_replace('*', @$matches[1], $this->config_cache_default_only_suffix))
3947
                                        . '.'
3948
                                        . strtolower($this->thumbnailFormat);
3949
3950
                return true;
3951
            }
3952
        }
3953
3954
        $this->cache_filename = '';
3955
        $broad_directory_name = '';
3956
        if ($this->new) {
3957
            $broad_directory_name = strtolower(md5($this->new));
3958
            $this->cache_filename .= '_new' . $broad_directory_name;
3959
        } elseif ($this->md5s) {
3960
            // source image MD5 hash provided
3961
            $this->DebugMessage('SetCacheFilename() _raw set from $this->md5s = "' . $this->md5s . '"', __FILE__, __LINE__);
3962
            $broad_directory_name = $this->md5s;
3963
            $this->cache_filename .= '_raw' . $this->md5s;
3964
        } elseif (!$this->src && $this->rawImageData) {
3965
            $this->DebugMessage('SetCacheFilename() _raw set from md5($this->rawImageData) = "' . md5($this->rawImageData) . '"', __FILE__, __LINE__);
3966
            $broad_directory_name = strtolower(md5($this->rawImageData));
3967
            $this->cache_filename .= '_raw' . $broad_directory_name;
3968
        } else {
3969
            $this->DebugMessage('SetCacheFilename() _src set from md5($this->sourceFilename) "' . $this->sourceFilename . '" = "' . md5($this->sourceFilename) . '"', __FILE__, __LINE__);
3970
            $broad_directory_name = strtolower(md5($this->sourceFilename));
3971
            $this->cache_filename .= '_src' . $broad_directory_name;
3972
        }
3973
        if (!empty($_SERVER['HTTP_REFERER']) && $this->config_nooffsitelink_enabled) {
3974
            $parsed_url1 = @phpthumb_functions::ParseURLbetter(@$_SERVER['HTTP_REFERER']);
3975
            $parsed_url2 = @phpthumb_functions::ParseURLbetter('http://' . @$_SERVER['HTTP_HOST']);
3976
            if (@$parsed_url1['host'] && @$parsed_url2['host'] && ($parsed_url1['host'] != $parsed_url2['host'])) {
3977
                // include "_offsite" only if nooffsitelink_enabled and if referrer doesn't match the domain of the current server
3978
                $this->cache_filename .= '_offsite';
3979
            }
3980
        }
3981
3982
        $ParametersString = '';
3983
        if ($this->fltr && is_array($this->fltr)) {
3984
            $ParametersString .= '_fltr' . implode('_fltr', $this->fltr);
3985
        }
3986
        $FilenameParameters1 = array('ar', 'bg', 'bc', 'far', 'sx', 'sy', 'sw', 'sh', 'zc');
3987
        foreach ($FilenameParameters1 as $key) {
3988
            if ($this->$key) {
3989
                $ParametersString .= '_' . $key . $this->$key;
3990
            }
3991
        }
3992
        $FilenameParameters2 = array(
3993
            'h',
3994
            'w',
3995
            'wl',
3996
            'wp',
3997
            'ws',
3998
            'hp',
3999
            'hs',
4000
            'xto',
4001
            'ra',
4002
            'iar',
4003
            'aoe',
4004
            'maxb',
4005
            'sfn',
4006
            'dpi'
4007
        );
4008
        foreach ($FilenameParameters2 as $key) {
4009
            if ($this->$key) {
4010
                $ParametersString .= '_' . $key . (int)$this->$key;
4011
            }
4012
        }
4013
        if ($this->thumbnailFormat == 'jpeg') {
4014
            // only JPEG output has variable quality option
4015
            $ParametersString .= '_q' . (int)$this->thumbnailQuality;
4016
        }
4017
        $this->DebugMessage('SetCacheFilename() _par set from md5(' . $ParametersString . ')', __FILE__, __LINE__);
4018
        $this->cache_filename .= '_par' . strtolower(md5($ParametersString));
4019
4020
        if ($this->md5s) {
4021
            // source image MD5 hash provided
4022
            // do not source image modification date --
4023
            // cached image will be used even if file was modified or removed
4024
        } elseif (!$this->config_cache_source_filemtime_ignore_remote && preg_match('#^(f|ht)tps?\://#i', $this->src)) {
4025
            $this->cache_filename .= '_dat' . (int)phpthumb_functions::filedate_remote($this->src);
4026
        } elseif (!$this->config_cache_source_filemtime_ignore_local && $this->src && !$this->rawImageData) {
4027
            $this->cache_filename .= '_dat' . (int)(@filemtime($this->sourceFilename));
4028
        }
4029
4030
        $this->cache_filename .= '.' . strtolower($this->thumbnailFormat);
4031
        $broad_directories    = '';
4032
        for ($i = 0; $i < $this->config_cache_directory_depth; $i++) {
4033
            $broad_directories .= DIRECTORY_SEPARATOR . substr($broad_directory_name, 0, $i + 1);
4034
        }
4035
4036
        $this->cache_filename = $this->config_cache_directory . $broad_directories . DIRECTORY_SEPARATOR . $this->config_cache_prefix . rawurlencode($this->cache_filename);
4037
4038
        return true;
4039
    }
4040
4041
    /**
4042
     * @param $width
4043
     * @param $height
4044
     * @return bool
4045
     */
4046
    public function SourceImageIsTooLarge($width, $height)
4047
    {
4048
        if (!$this->config_max_source_pixels) {
4049
            return false;
4050
        }
4051
        if ($this->php_memory_limit && function_exists('memory_get_usage')) {
4052
            $available_memory = $this->php_memory_limit - memory_get_usage();
4053
4054
            return (bool)(($width * $height * 5) > $available_memory);
4055
        }
4056
4057
        return (bool)(($width * $height) > $this->config_max_source_pixels);
4058
    }
4059
4060
    /**
4061
     * @param $filename
4062
     * @return bool|resource
4063
     */
4064
    public function ImageCreateFromFilename($filename)
4065
    {
4066
        // try to create GD image source directly via GD, if possible,
4067
        // rather than buffering to memory and creating with ImageCreateFromString
4068
        $ImageCreateWasAttempted = false;
4069
        $gd_image                = false;
4070
4071
        $this->DebugMessage('starting ImageCreateFromFilename(' . $filename . ')', __FILE__, __LINE__);
4072
        if ($filename && ($getimagesizeinfo = @getimagesize($filename))) {
4073
            if (!$this->SourceImageIsTooLarge($getimagesizeinfo[0], $getimagesizeinfo[1])) {
4074
                $ImageCreateFromFunction = array(
4075
                    1  => 'ImageCreateFromGIF',
4076
                    2  => 'ImageCreateFromJPEG',
4077
                    3  => 'ImageCreateFromPNG',
4078
                    15 => 'ImageCreateFromWBMP'
4079
                );
4080
                $this->DebugMessage('ImageCreateFromFilename found ($getimagesizeinfo[2]==' . @$getimagesizeinfo[2] . ')', __FILE__, __LINE__);
4081
                switch (@$getimagesizeinfo[2]) {
4082
                    case 1:  // GIF
4083
                    case 2:  // JPEG
4084
                    case 3:  // PNG
4085
                    case 15: // WBMP
4086
                        $ImageCreateFromFunctionName = $ImageCreateFromFunction[$getimagesizeinfo[2]];
4087
                        if (function_exists($ImageCreateFromFunctionName)) {
4088
                            $this->DebugMessage('Calling ' . $ImageCreateFromFunctionName . '(' . $filename . ')', __FILE__, __LINE__);
4089
                            $ImageCreateWasAttempted = true;
4090
                            $gd_image                = $ImageCreateFromFunctionName($filename);
4091
                        } else {
4092
                            $this->DebugMessage('NOT calling ' . $ImageCreateFromFunctionName . '(' . $filename . ') because !function_exists(' . $ImageCreateFromFunctionName . ')', __FILE__,
4093
                                                __LINE__);
4094
                        }
4095
                        break;
4096
4097
                    case 4:  // SWF
4098
                    case 5:  // PSD
4099
                    case 6:  // BMP
4100
                    case 7:  // TIFF (LE)
4101
                    case 8:  // TIFF (BE)
4102
                    case 9:  // JPC
4103
                    case 10: // JP2
4104
                    case 11: // JPX
4105
                    case 12: // JB2
4106
                    case 13: // SWC
4107
                    case 14: // IFF
4108
                    case 16: // XBM
4109
                        $this->DebugMessage('No built-in image creation function for image type "' . @$getimagesizeinfo[2] . '" ($getimagesizeinfo[2])', __FILE__, __LINE__);
4110
                        break;
4111
4112
                    default:
4113
                        $this->DebugMessage('Unknown value for $getimagesizeinfo[2]: "' . @$getimagesizeinfo[2] . '"', __FILE__, __LINE__);
4114
                        break;
4115
                }
4116
            } else {
4117
                $this->DebugMessage('image is '
4118
                                    . $getimagesizeinfo[0]
4119
                                    . 'x'
4120
                                    . $getimagesizeinfo[1]
4121
                                    . ' and therefore contains more pixels ('
4122
                                    . ($getimagesizeinfo[0] * $getimagesizeinfo[1])
4123
                                    . ') than $this->config_max_source_pixels setting ('
4124
                                    . $this->config_max_source_pixels
4125
                                    . ')', __FILE__, __LINE__);
4126
4127
                return false;
4128
            }
4129
        } else {
4130
            $this->DebugMessage('empty $filename or GetImageSize(' . $filename . ') failed', __FILE__, __LINE__);
4131
        }
4132
4133
        if (!$gd_image) {
4134
            // cannot create from filename, attempt to create source image with ImageCreateFromString, if possible
4135
            if ($ImageCreateWasAttempted) {
4136
                $this->DebugMessage(@$ImageCreateFromFunctionName . '() was attempted but FAILED', __FILE__, __LINE__);
4137
            }
4138
            $this->DebugMessage('Populating $rawimagedata', __FILE__, __LINE__);
4139
            $rawimagedata = '';
4140
            if ($fp = @fopen($filename, 'rb')) {
4141
                $filesize   = filesize($filename);
4142
                $blocksize  = 8192;
4143
                $blockreads = ceil($filesize / $blocksize);
4144
                for ($i = 0; $i < $blockreads; $i++) {
4145
                    $rawimagedata .= fread($fp, $blocksize);
4146
                }
4147
                fclose($fp);
4148
            } else {
4149
                $this->DebugMessage('cannot fopen(' . $filename . ')', __FILE__, __LINE__);
4150
            }
4151
            if ($rawimagedata) {
4152
                $this->DebugMessage('attempting ImageCreateFromStringReplacement($rawimagedata (' . strlen($rawimagedata) . ' bytes), true)', __FILE__, __LINE__);
4153
                $gd_image = $this->ImageCreateFromStringReplacement($rawimagedata, true);
4154
            }
4155
        }
4156
4157
        return $gd_image;
4158
    }
4159
4160
    /**
4161
     * @return bool
4162
     */
4163
    public function SourceImageToGD()
4164
    {
4165
        if (is_resource($this->gdimg_source)) {
4166
            $this->source_width  = imagesx($this->gdimg_source);
4167
            $this->source_height = imagesy($this->gdimg_source);
4168
            $this->DebugMessage('skipping SourceImageToGD() because $this->gdimg_source is already a resource (' . $this->source_width . 'x' . $this->source_height . ')', __FILE__, __LINE__);
4169
4170
            return true;
4171
        }
4172
        $this->DebugMessage('starting SourceImageToGD()', __FILE__, __LINE__);
4173
4174
        if ($this->config_prefer_imagemagick) {
4175
            if (empty($this->sourceFilename) && !empty($this->rawImageData)) {
4176
                $this->DebugMessage('Copying raw image data to temp file and trying again with ImageMagick', __FILE__, __LINE__);
4177
                if ($tempnam = $this->phpThumb_tempnam()) {
4178
                    if (file_put_contents($tempnam, $this->rawImageData)) {
4179
                        $this->sourceFilename = $tempnam;
4180
                        if ($this->ImageMagickThumbnailToGD()) {
4181
                            // excellent, we have a thumbnailed source image
4182
                            $this->DebugMessage('ImageMagickThumbnailToGD() succeeded', __FILE__, __LINE__);
4183
                        } else {
4184
                            $this->DebugMessage('ImageMagickThumbnailToGD() failed', __FILE__, __LINE__);
4185
                        }
4186
                    } else {
4187
                        $this->DebugMessage('failed to put $this->rawImageData into temp file "' . $tempnam . '"', __FILE__, __LINE__);
4188
                    }
4189
                } else {
4190
                    $this->DebugMessage('failed to generate temp file name', __FILE__, __LINE__);
4191
                }
4192
            }
4193
        }
4194
        if (!$this->gdimg_source && $this->rawImageData) {
4195
            if ($this->SourceImageIsTooLarge($this->source_width, $this->source_height)) {
4196
                $memory_get_usage = (function_exists('memory_get_usage') ? memory_get_usage() : 0);
4197
4198
                return $this->ErrorImage('Source image is too large ('
4199
                                         . $this->source_width
4200
                                         . 'x'
4201
                                         . $this->source_height
4202
                                         . ' = '
4203
                                         . number_format($this->source_width * $this->source_height / 1000000, 1)
4204
                                         . 'Mpx, max='
4205
                                         . number_format($this->config_max_source_pixels / 1000000, 1)
4206
                                         . 'Mpx) for GD creation (either install ImageMagick or increase PHP memory_limit to at least '
4207
                                         . ceil(($memory_get_usage + (5 * $this->source_width * $this->source_height)) / 1048576)
4208
                                         . 'M).');
4209
            }
4210 View Code Duplication
            if ($this->md5s && ($this->md5s != md5($this->rawImageData))) {
4211
                return $this->ErrorImage('$this->md5s != md5($this->rawImageData)' . "\n" . '"' . $this->md5s . '" != ' . "\n" . '"' . md5($this->rawImageData) . '"');
4212
            }
4213
            //if ($this->issafemode) {
4214
            //  return $this->ErrorImage('Cannot generate thumbnails from raw image data when PHP SAFE_MODE enabled');
4215
            //}
4216
            $this->gdimg_source = $this->ImageCreateFromStringReplacement($this->rawImageData);
4217
            if (!$this->gdimg_source) {
4218
                if (substr($this->rawImageData, 0, 2) === 'BM') {
4219
                    $this->getimagesizeinfo[2] = 6; // BMP
4220
                } elseif (substr($this->rawImageData, 0, 4) === 'II' . "\x2A\x00") {
4221
                    $this->getimagesizeinfo[2] = 7; // TIFF (littlendian)
4222
                } elseif (substr($this->rawImageData, 0, 4) === 'MM' . "\x00\x2A") {
4223
                    $this->getimagesizeinfo[2] = 8; // TIFF (bigendian)
4224
                }
4225
                $this->DebugMessage('SourceImageToGD.ImageCreateFromStringReplacement() failed with unknown image type "'
4226
                                    . substr($this->rawImageData, 0, 4)
4227
                                    . '" ('
4228
                                    . phpthumb_functions::HexCharDisplay(substr($this->rawImageData, 0, 4))
4229
                                    . ')', __FILE__, __LINE__);
4230
                //              return $this->ErrorImage('Unknown image type identified by "'.substr($this->rawImageData, 0, 4).'" ('.phpthumb_functions::HexCharDisplay(substr($this->rawImageData, 0, 4)).') in SourceImageToGD()['.__LINE__.']');
4231
            }
4232
        } elseif (!$this->gdimg_source && $this->sourceFilename) {
4233 View Code Duplication
            if ($this->md5s && ($this->md5s != phpthumb_functions::md5_file_safe($this->sourceFilename))) {
4234
                return $this->ErrorImage('$this->md5s != md5(sourceFilename)' . "\n" . '"' . $this->md5s . '" != ' . "\n" . '"' . phpthumb_functions::md5_file_safe($this->sourceFilename) . '"');
4235
            }
4236
            switch (@$this->getimagesizeinfo[2]) {
4237
                case 1:
4238
                case 3:
4239
                    // GIF or PNG input file may have transparency
4240
                    $this->is_alpha = true;
4241
                    break;
4242
            }
4243
            if (!$this->SourceImageIsTooLarge($this->source_width, $this->source_height)) {
4244
                $this->gdimg_source = $this->ImageCreateFromFilename($this->sourceFilename);
4245
            }
4246
        }
4247
4248
        while (true) {
4249
            if ($this->gdimg_source) {
4250
                $this->DebugMessage('Not using EXIF thumbnail data because $this->gdimg_source is already set', __FILE__, __LINE__);
4251
                break;
4252
            }
4253
            if (!$this->exif_thumbnail_data) {
4254
                $this->DebugMessage('Not using EXIF thumbnail data because $this->exif_thumbnail_data is empty', __FILE__, __LINE__);
4255
                break;
4256
            }
4257
            if (ini_get('safe_mode')) {
4258
                if (!$this->SourceImageIsTooLarge($this->source_width, $this->source_height)) {
4259
                    $this->DebugMessage('Using EXIF thumbnail data because source image too large and safe_mode enabled', __FILE__, __LINE__);
4260
                    $this->aoe = true;
4261
                } else {
4262
                    break;
4263
                }
4264
            } else {
4265
                if (!$this->config_use_exif_thumbnail_for_speed) {
4266
                    $this->DebugMessage('Not using EXIF thumbnail data because $this->config_use_exif_thumbnail_for_speed is FALSE', __FILE__, __LINE__);
4267
                    break;
4268
                }
4269
                if (($this->thumbnailCropX != 0) || ($this->thumbnailCropY != 0)) {
4270
                    $this->DebugMessage('Not using EXIF thumbnail data because source cropping is enabled (' . $this->thumbnailCropX . ',' . $this->thumbnailCropY . ')', __FILE__, __LINE__);
4271
                    break;
4272
                }
4273
                if (($this->w > $this->exif_thumbnail_width) || ($this->h > $this->exif_thumbnail_height)) {
4274
                    $this->DebugMessage('Not using EXIF thumbnail data because EXIF thumbnail is too small ('
4275
                                        . $this->exif_thumbnail_width
4276
                                        . 'x'
4277
                                        . $this->exif_thumbnail_height
4278
                                        . ' vs '
4279
                                        . $this->w
4280
                                        . 'x'
4281
                                        . $this->h
4282
                                        . ')', __FILE__, __LINE__);
4283
                    break;
4284
                }
4285
                $source_ar = $this->source_width / $this->source_height;
4286
                $exif_ar   = $this->exif_thumbnail_width / $this->exif_thumbnail_height;
4287 View Code Duplication
                if (number_format($source_ar, 2) != number_format($exif_ar, 2)) {
4288
                    $this->DebugMessage('not using EXIF thumbnail because $source_ar != $exif_ar (' . $source_ar . ' != ' . $exif_ar . ')', __FILE__, __LINE__);
4289
                    break;
4290
                }
4291
            }
4292
4293
            // EXIF thumbnail exists, and is equal to or larger than destination thumbnail, and will be use as source image
4294
            $this->DebugMessage('Trying to use EXIF thumbnail as source image', __FILE__, __LINE__);
4295
4296
            if ($gdimg_exif_temp = $this->ImageCreateFromStringReplacement($this->exif_thumbnail_data, false)) {
4297
                $this->DebugMessage('Successfully using EXIF thumbnail as source image', __FILE__, __LINE__);
4298
                $this->gdimg_source   = $gdimg_exif_temp;
4299
                $this->source_width   = $this->exif_thumbnail_width;
4300
                $this->source_height  = $this->exif_thumbnail_height;
4301
                $this->thumbnailCropW = $this->source_width;
4302
                $this->thumbnailCropH = $this->source_height;
4303
4304
                return true;
4305
            } else {
4306
                $this->DebugMessage('$this->ImageCreateFromStringReplacement($this->exif_thumbnail_data, false) failed', __FILE__, __LINE__);
4307
            }
4308
4309
            break;
4310
        }
4311
4312
        if (!$this->gdimg_source) {
4313
            $this->DebugMessage('$this->gdimg_source is still empty', __FILE__, __LINE__);
4314
4315
            $this->DebugMessage('ImageMagickThumbnailToGD() failed', __FILE__, __LINE__);
4316
4317
            $imageHeader   = '';
4318
            $gd_info       = gd_info();
4319
            $GDreadSupport = false;
4320
            switch (@$this->getimagesizeinfo[2]) {
4321
                case 1:
4322
                    $imageHeader   = 'Content-Type: image/gif';
4323
                    $GDreadSupport = (bool)@$gd_info['GIF Read Support'];
4324
                    break;
4325
                case 2:
4326
                    $imageHeader   = 'Content-Type: image/jpeg';
4327
                    $GDreadSupport = (bool)@$gd_info['JPG Support'];
4328
                    break;
4329
                case 3:
4330
                    $imageHeader   = 'Content-Type: image/png';
4331
                    $GDreadSupport = (bool)@$gd_info['PNG Support'];
4332
                    break;
4333
            }
4334
            if ($imageHeader) {
4335
                // cannot create image for whatever reason (maybe ImageCreateFromJPEG et al are not available?)
4336
                // and ImageMagick is not available either, no choice but to output original (not resized/modified) data and exit
4337
                if ($this->config_error_die_on_source_failure) {
4338
                    $errormessages   = array();
4339
                    $errormessages[] = 'All attempts to create GD image source failed.';
4340
                    if ($this->fatalerror) {
4341
                        $errormessages[] = $this->fatalerror;
4342
                    }
4343
                    if ($this->issafemode) {
4344
                        $errormessages[] = 'Safe Mode enabled, therefore ImageMagick is unavailable. (disable Safe Mode if possible)';
4345
                    } elseif (!$this->ImageMagickVersion()) {
4346
                        $errormessages[] = 'ImageMagick is not installed (it is highly recommended that you install it).';
4347
                    }
4348
                    if ($this->SourceImageIsTooLarge($this->getimagesizeinfo[0], $this->getimagesizeinfo[1])) {
4349
                        $memory_get_usage = (function_exists('memory_get_usage') ? memory_get_usage() : 0);
4350
                        $errormessages[]  = 'Source image is too large ('
4351
                                            . $this->getimagesizeinfo[0]
4352
                                            . 'x'
4353
                                            . $this->getimagesizeinfo[1]
4354
                                            . ' = '
4355
                                            . number_format($this->getimagesizeinfo[0]
4356
                                                            * $this->getimagesizeinfo[1]
4357
                                                            / 1000000, 1)
4358
                                            . 'Mpx, max='
4359
                                            . number_format($this->config_max_source_pixels / 1000000, 1)
4360
                                            . 'Mpx) for GD creation (either install ImageMagick or increase PHP memory_limit to at least '
4361
                                            . ceil(($memory_get_usage + (5 * $this->getimagesizeinfo[0] * $this->getimagesizeinfo[1])) / 1048576)
4362
                                            . 'M).';
4363
                    } elseif (!$GDreadSupport) {
4364
                        $errormessages[] = 'GD does not have read support for "' . $imageHeader . '".';
4365
                    } else {
4366
                        $errormessages[] = 'Source image probably corrupt.';
4367
                    }
4368
                    $this->ErrorImage(implode("\n", $errormessages));
4369
                } else {
4370
                    $this->DebugMessage('All attempts to create GD image source failed ('
4371
                                        . (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 "'
4372
                                                                                                                                                                                                                . $imageHeader
4373
                                                                                                                                                                                                                . '"'))
4374
                                        . '), cannot generate thumbnail');
4375
                    //$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__);
4376
                    //if (!$this->phpThumbDebug) {
4377
                    //  header($imageHeader);
4378
                    //  echo $this->rawImageData;
4379
                    //  exit;
4380
                    //}
4381
                    return false;
4382
                }
4383
            }
4384
4385
            //switch (substr($this->rawImageData, 0, 2)) {
4386
            //  case 'BM':
4387
            switch (@$this->getimagesizeinfo[2]) {
4388
                case 6:
4389
                    ob_start();
4390
                    if (!@require_once __DIR__ . '/phpthumb.bmp.php') {
4391
                        ob_end_clean();
4392
4393
                        return $this->ErrorImage('include_once(' . __DIR__ . '/phpthumb.bmp.php) failed');
4394
                    }
4395
                    ob_end_clean();
4396
                    if ($fp = @fopen($this->sourceFilename, 'rb')) {
4397
                        $this->rawImageData = '';
4398
                        while (!feof($fp)) {
4399
                            $this->rawImageData .= fread($fp, 32768);
4400
                        }
4401
                        fclose($fp);
4402
                    }
4403
                    $phpthumb_bmp       = new phpthumb_bmp();
4404
                    $this->gdimg_source = $phpthumb_bmp->phpthumb_bmp2gd($this->rawImageData, phpthumb_functions::gd_version() >= 2.0);
4405
                    unset($phpthumb_bmp);
4406
                    if ($this->gdimg_source) {
4407
                        $this->DebugMessage('$phpthumb_bmp->phpthumb_bmp2gd() succeeded', __FILE__, __LINE__);
4408
                    } else {
4409
                        return $this->ErrorImage($this->ImageMagickVersion() ? 'ImageMagick failed on BMP source conversion' : 'phpthumb_bmp2gd() failed');
4410
                    }
4411
                    break;
4412
                //}
4413
                //switch (substr($this->rawImageData, 0, 4)) {
4414
                //  case 'II'."\x2A\x00":
4415
                //  case 'MM'."\x00\x2A":
4416
                case 7:
4417
                case 8:
4418
                    return $this->ErrorImage($this->ImageMagickVersion() ? 'ImageMagick failed on TIFF source conversion' : 'ImageMagick is unavailable and phpThumb() does not support TIFF source images without it');
4419
                    break;
4420
4421
                //case "\xD7\xCD\xC6\x9A":
4422
                //  return $this->ErrorImage($this->ImageMagickVersion() ? 'ImageMagick failed on WMF source conversion' : 'ImageMagick is unavailable and phpThumb() does not support WMF source images without it');
4423
                //  break;
4424
            }
4425
4426
            if (!$this->gdimg_source) {
4427
                $HeaderFourBytes = '';
4428
                if ($this->rawImageData) {
4429
                    $HeaderFourBytes = substr($this->rawImageData, 0, 4);
4430
                } elseif ($this->sourceFilename) {
4431
                    if ($fp = @fopen($this->sourceFilename, 'rb')) {
4432
                        $HeaderFourBytes = fread($fp, 4);
4433
                        fclose($fp);
4434
                    } else {
4435
                        return $this->ErrorImage('failed to open "' . $this->sourceFilename . '" SourceImageToGD() [' . __LINE__ . ']');
4436
                    }
4437
                } else {
4438
                    return $this->ErrorImage('Unable to create image, neither filename nor image data suppplied in SourceImageToGD() [' . __LINE__ . ']');
4439
                }
4440
                if (!$this->ImageMagickVersion() && !phpthumb_functions::gd_version()) {
4441
                    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.');
4442
                } elseif ($HeaderFourBytes == "\xD7\xCD\xC6\x9A") { // WMF
4443
                    return $this->ErrorImage($this->ImageMagickVersion() ? 'ImageMagick failed on WMF source conversion' : 'ImageMagick is unavailable and phpThumb() does not support WMF source images without it');
4444
                } elseif ($HeaderFourBytes == '%PDF') { // "%PDF"
4445
                    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');
4446
                } elseif (substr($HeaderFourBytes, 0, 3) == "\xFF\xD8\xFF") { // JPEG
4447
                    return $this->ErrorImage('Image (JPEG) is too large for PHP-GD memory_limit, please install ImageMagick or increase php.ini memory_limit setting');
4448
                } elseif ($HeaderFourBytes == '%PNG') { // "%PNG"
4449
                    return $this->ErrorImage('Image (PNG) is too large for PHP-GD memory_limit, please install ImageMagick or increase php.ini memory_limit setting');
4450
                } elseif (substr($HeaderFourBytes, 0, 3) == 'GIF') { // GIF
4451
                    return $this->ErrorImage('Image (GIF) is too large for PHP-GD memory_limit, please install ImageMagick or increase php.ini memory_limit setting');
4452
                }
4453
4454
                return $this->ErrorImage('Unknown image type identified by "'
4455
                                         . $HeaderFourBytes
4456
                                         . '" ('
4457
                                         . phpthumb_functions::HexCharDisplay($HeaderFourBytes)
4458
                                         . ') in SourceImageToGD() ['
4459
                                         . __LINE__
4460
                                         . ']');
4461
            }
4462
        }
4463
4464
        if (!$this->gdimg_source) {
4465
            if ($gdimg_exif_temp = $this->ImageCreateFromStringReplacement($this->exif_thumbnail_data, false)) {
4466
                $this->DebugMessage('All other attempts failed, but successfully using EXIF thumbnail as source image', __FILE__, __LINE__);
4467
                $this->gdimg_source = $gdimg_exif_temp;
4468
                // override allow-enlarging setting if EXIF thumbnail is the only source available
4469
                // otherwise thumbnails larger than the EXIF thumbnail will be created at EXIF size
4470
                $this->aoe = true;
4471
4472
                return true;
4473
            }
4474
4475
            return false;
4476
        }
4477
4478
        $this->source_width  = imagesx($this->gdimg_source);
4479
        $this->source_height = imagesy($this->gdimg_source);
4480
4481
        return true;
4482
    }
4483
4484
    /**
4485
     * @param $var
4486
     * @return string
4487
     */
4488
    public function phpThumbDebugVarDump($var)
4489
    {
4490
        if (is_null($var)) {
4491
            return 'NULL';
4492
        } elseif (is_bool($var)) {
4493
            return ($var ? 'TRUE' : 'FALSE');
4494
        } elseif (is_string($var)) {
4495
            return 'string(' . strlen($var) . ')' . str_repeat(' ', max(0, 3 - strlen(strlen($var)))) . ' "' . $var . '"';
4496
        } elseif (is_int($var)) {
4497
            return 'integer     ' . $var;
4498
        } elseif (is_float($var)) {
4499
            return 'float       ' . $var;
4500
        } elseif (is_array($var)) {
4501
            ob_start();
4502
            var_dump($var);
4503
            $vardumpoutput = ob_get_contents();
4504
            ob_end_clean();
4505
4506
            return strtr($vardumpoutput, "\n\r\t", '   ');
4507
        }
4508
4509
        return gettype($var);
4510
    }
4511
4512
    /**
4513
     * @param  string $level
4514
     * @return bool
4515
     */
4516
    public function phpThumbDebug($level = '')
4517
    {
4518
        if ($level && ($this->phpThumbDebug !== $level)) {
4519
            return true;
4520
        }
4521
        if ($this->config_disable_debug) {
4522
            return $this->ErrorImage('phpThumbDebug disabled');
4523
        }
4524
4525
        $FunctionsExistance  = array(
4526
            'exif_thumbnail',
4527
            'gd_info',
4528
            'image_type_to_mime_type',
4529
            'GetImageSize',
4530
            'ImageCopyResampled',
4531
            'ImageCopyResized',
4532
            'ImageCreate',
4533
            'ImageCreateFromString',
4534
            'ImageCreateTrueColor',
4535
            'ImageIsTrueColor',
4536
            'ImageRotate',
4537
            'ImageTypes',
4538
            'version_compare',
4539
            'ImageCreateFromGIF',
4540
            'ImageCreateFromJPEG',
4541
            'ImageCreateFromPNG',
4542
            'ImageCreateFromWBMP',
4543
            'ImageCreateFromXBM',
4544
            'ImageCreateFromXPM',
4545
            'ImageCreateFromString',
4546
            'ImageCreateFromGD',
4547
            'ImageCreateFromGD2',
4548
            'ImageCreateFromGD2Part',
4549
            'ImageJPEG',
4550
            'ImageGIF',
4551
            'ImagePNG',
4552
            'ImageWBMP'
4553
        );
4554
        $ParameterNames      = array(
4555
            'src',
4556
            'new',
4557
            'w',
4558
            'h',
4559
            'f',
4560
            'q',
4561
            'sx',
4562
            'sy',
4563
            'sw',
4564
            'sh',
4565
            'far',
4566
            'bg',
4567
            'bc',
4568
            'file',
4569
            'goto',
4570
            'err',
4571
            'xto',
4572
            'ra',
4573
            'ar',
4574
            'aoe',
4575
            'iar',
4576
            'maxb'
4577
        );
4578
        $ConfigVariableNames = array(
4579
            'document_root',
4580
            'temp_directory',
4581
            'output_format',
4582
            'output_maxwidth',
4583
            'output_maxheight',
4584
            'error_message_image_default',
4585
            'error_bgcolor',
4586
            'error_textcolor',
4587
            'error_fontsize',
4588
            'error_die_on_error',
4589
            'error_silent_die_on_error',
4590
            'error_die_on_source_failure',
4591
            'nohotlink_enabled',
4592
            'nohotlink_valid_domains',
4593
            'nohotlink_erase_image',
4594
            'nohotlink_text_message',
4595
            'nooffsitelink_enabled',
4596
            'nooffsitelink_valid_domains',
4597
            'nooffsitelink_require_refer',
4598
            'nooffsitelink_erase_image',
4599
            'nooffsitelink_text_message',
4600
            'high_security_enabled',
4601
            'allow_src_above_docroot',
4602
            'allow_src_above_phpthumb',
4603
            'max_source_pixels',
4604
            'use_exif_thumbnail_for_speed',
4605
            'border_hexcolor',
4606
            'background_hexcolor',
4607
            'ttf_directory',
4608
            'disable_pathinfo_parsing',
4609
            'disable_imagecopyresampled'
4610
        );
4611
        $OtherVariableNames  = array(
4612
            'phpThumbDebug',
4613
            'thumbnailQuality',
4614
            'thumbnailFormat',
4615
            'gdimg_output',
4616
            'gdimg_source',
4617
            'sourceFilename',
4618
            'source_width',
4619
            'source_height',
4620
            'thumbnailCropX',
4621
            'thumbnailCropY',
4622
            'thumbnailCropW',
4623
            'thumbnailCropH',
4624
            'exif_thumbnail_width',
4625
            'exif_thumbnail_height',
4626
            'exif_thumbnail_type',
4627
            'thumbnail_width',
4628
            'thumbnail_height',
4629
            'thumbnail_image_width',
4630
            'thumbnail_image_height'
4631
        );
4632
4633
        $DebugOutput   = array();
4634
        $DebugOutput[] = 'phpThumb() version          = ' . $this->phpthumb_version;
4635
        $DebugOutput[] = 'PHP_VERSION                = ' . @PHP_VERSION;
4636
        $DebugOutput[] = 'PHP_OS                      = ' . PHP_OS;
4637
        $DebugOutput[] = '$_SERVER[SERVER_SOFTWARE]   = ' . @$_SERVER['SERVER_SOFTWARE'];
4638
        $DebugOutput[] = '__FILE__                    = ' . __FILE__;
4639
        $DebugOutput[] = 'realpath(.)                 = ' . @realpath('.');
4640
        $DebugOutput[] = '$_SERVER[PHP_SELF]          = ' . @$_SERVER['PHP_SELF'];
4641
        $DebugOutput[] = '$_SERVER[HOST_NAME]         = ' . @$_SERVER['HOST_NAME'];
4642
        $DebugOutput[] = '$_SERVER[HTTP_REFERER]      = ' . @$_SERVER['HTTP_REFERER'];
4643
        $DebugOutput[] = '$_SERVER[QUERY_STRING]      = ' . @$_SERVER['QUERY_STRING'];
4644
        $DebugOutput[] = '$_SERVER[PATH_INFO]         = ' . @$_SERVER['PATH_INFO'];
4645
        $DebugOutput[] = '$_SERVER[DOCUMENT_ROOT]     = ' . @$_SERVER['DOCUMENT_ROOT'];
4646
        $DebugOutput[] = 'getenv(DOCUMENT_ROOT)       = ' . @getenv('DOCUMENT_ROOT');
4647
        $DebugOutput[] = '';
4648
4649
        $DebugOutput[] = 'get_magic_quotes_gpc()         = ' . $this->phpThumbDebugVarDump(@get_magic_quotes_gpc());
4650
        $DebugOutput[] = 'get_magic_quotes_runtime()     = ' . $this->phpThumbDebugVarDump(@get_magic_quotes_runtime());
4651
        $DebugOutput[] = 'error_reporting()              = ' . $this->phpThumbDebugVarDump(error_reporting());
4652
        $DebugOutput[] = 'ini_get(error_reporting)       = ' . $this->phpThumbDebugVarDump(@ini_get('error_reporting'));
4653
        $DebugOutput[] = 'ini_get(display_errors)        = ' . $this->phpThumbDebugVarDump(@ini_get('display_errors'));
4654
        $DebugOutput[] = 'ini_get(allow_url_fopen)       = ' . $this->phpThumbDebugVarDump(@ini_get('allow_url_fopen'));
4655
        $DebugOutput[] = 'ini_get(disable_functions)     = ' . $this->phpThumbDebugVarDump(@ini_get('disable_functions'));
4656
        $DebugOutput[] = 'get_cfg_var(disable_functions) = ' . $this->phpThumbDebugVarDump(@get_cfg_var('disable_functions'));
4657
        $DebugOutput[] = 'ini_get(safe_mode)             = ' . $this->phpThumbDebugVarDump(@ini_get('safe_mode'));
4658
        $DebugOutput[] = 'ini_get(open_basedir)          = ' . $this->phpThumbDebugVarDump(@ini_get('open_basedir'));
4659
        $DebugOutput[] = 'ini_get(max_execution_time)    = ' . $this->phpThumbDebugVarDump(@ini_get('max_execution_time'));
4660
        $DebugOutput[] = 'ini_get(memory_limit)          = ' . $this->phpThumbDebugVarDump(@ini_get('memory_limit'));
4661
        $DebugOutput[] = 'get_cfg_var(memory_limit)      = ' . $this->phpThumbDebugVarDump(@get_cfg_var('memory_limit'));
4662
        $DebugOutput[] = 'memory_get_usage()             = ' . (function_exists('memory_get_usage') ? $this->phpThumbDebugVarDump(@memory_get_usage()) : 'n/a');
4663
        $DebugOutput[] = '';
4664
4665
        $DebugOutput[] = '$this->config_prefer_imagemagick            = ' . $this->phpThumbDebugVarDump($this->config_prefer_imagemagick);
4666
        $DebugOutput[] = '$this->config_imagemagick_path              = ' . $this->phpThumbDebugVarDump($this->config_imagemagick_path);
4667
        $DebugOutput[] = '$this->ImageMagickWhichConvert()            = ' . $this->ImageMagickWhichConvert();
4668
        $IMpathUsed    = ($this->config_imagemagick_path ?: $this->ImageMagickWhichConvert());
4669
        $DebugOutput[] = '[actual ImageMagick path used]              = ' . $this->phpThumbDebugVarDump($IMpathUsed);
4670
        $DebugOutput[] = 'file_exists([actual ImageMagick path used]) = ' . $this->phpThumbDebugVarDump(@file_exists($IMpathUsed));
4671
        $DebugOutput[] = 'ImageMagickVersion(false)                   = ' . $this->ImageMagickVersion(false);
4672
        $DebugOutput[] = 'ImageMagickVersion(true)                    = ' . $this->ImageMagickVersion(true);
4673
        $DebugOutput[] = '';
4674
4675
        $DebugOutput[] = '$this->config_cache_directory               = ' . $this->phpThumbDebugVarDump($this->config_cache_directory);
4676
        $DebugOutput[] = '$this->config_cache_directory_depth         = ' . $this->phpThumbDebugVarDump($this->config_cache_directory_depth);
4677
        $DebugOutput[] = '$this->config_cache_disable_warning         = ' . $this->phpThumbDebugVarDump($this->config_cache_disable_warning);
4678
        $DebugOutput[] = '$this->config_cache_maxage                  = ' . $this->phpThumbDebugVarDump($this->config_cache_maxage);
4679
        $DebugOutput[] = '$this->config_cache_maxsize                 = ' . $this->phpThumbDebugVarDump($this->config_cache_maxsize);
4680
        $DebugOutput[] = '$this->config_cache_maxfiles                = ' . $this->phpThumbDebugVarDump($this->config_cache_maxfiles);
4681
        $DebugOutput[] = '$this->config_cache_force_passthru          = ' . $this->phpThumbDebugVarDump($this->config_cache_force_passthru);
4682
        $DebugOutput[] = '$this->cache_filename                       = ' . $this->phpThumbDebugVarDump($this->cache_filename);
4683
        $DebugOutput[] = 'is_readable($this->config_cache_directory)  = ' . $this->phpThumbDebugVarDump(@is_readable($this->config_cache_directory));
4684
        $DebugOutput[] = 'is_writable($this->config_cache_directory)  = ' . $this->phpThumbDebugVarDump(@is_writable($this->config_cache_directory));
4685
        $DebugOutput[] = 'is_readable($this->cache_filename)          = ' . $this->phpThumbDebugVarDump(@is_readable($this->cache_filename));
4686
        $DebugOutput[] = 'is_writable($this->cache_filename)          = ' . (@file_exists($this->cache_filename) ? $this->phpThumbDebugVarDump(@is_writable($this->cache_filename)) : 'n/a');
4687
        $DebugOutput[] = '';
4688
4689
        foreach ($ConfigVariableNames as $varname) {
4690
            $varname       = 'config_' . $varname;
4691
            $value         = $this->$varname;
4692
            $DebugOutput[] = '$this->' . str_pad($varname, 37, ' ', STR_PAD_RIGHT) . ' = ' . $this->phpThumbDebugVarDump($value);
4693
        }
4694
        $DebugOutput[] = '';
4695 View Code Duplication
        foreach ($OtherVariableNames as $varname) {
4696
            $value         = $this->$varname;
4697
            $DebugOutput[] = '$this->' . str_pad($varname, 27, ' ', STR_PAD_RIGHT) . ' = ' . $this->phpThumbDebugVarDump($value);
4698
        }
4699
        $DebugOutput[] = 'strlen($this->rawImageData)        = ' . strlen(@$this->rawImageData);
4700
        $DebugOutput[] = 'strlen($this->exif_thumbnail_data) = ' . strlen(@$this->exif_thumbnail_data);
4701
        $DebugOutput[] = '';
4702
4703 View Code Duplication
        foreach ($ParameterNames as $varname) {
4704
            $value         = $this->$varname;
4705
            $DebugOutput[] = '$this->' . str_pad($varname, 4, ' ', STR_PAD_RIGHT) . ' = ' . $this->phpThumbDebugVarDump($value);
4706
        }
4707
        $DebugOutput[] = '';
4708
4709
        foreach ($FunctionsExistance as $functionname) {
4710
            $DebugOutput[] = 'builtin_function_exists('
4711
                             . $functionname
4712
                             . ')'
4713
                             . str_repeat(' ', 23 - strlen($functionname))
4714
                             . ' = '
4715
                             . $this->phpThumbDebugVarDump(phpthumb_functions::builtin_function_exists($functionname));
4716
        }
4717
        $DebugOutput[] = '';
4718
4719
        $gd_info = gd_info();
4720 View Code Duplication
        foreach ($gd_info as $key => $value) {
4721
            $DebugOutput[] = 'gd_info.' . str_pad($key, 34, ' ', STR_PAD_RIGHT) . ' = ' . $this->phpThumbDebugVarDump($value);
4722
        }
4723
        $DebugOutput[] = '';
4724
4725
        $exif_info = phpthumb_functions::exif_info();
4726 View Code Duplication
        foreach ($exif_info as $key => $value) {
4727
            $DebugOutput[] = 'exif_info.' . str_pad($key, 26, ' ', STR_PAD_RIGHT) . ' = ' . $this->phpThumbDebugVarDump($value);
4728
        }
4729
        $DebugOutput[] = '';
4730
4731
        if ($ApacheLookupURIarray = phpthumb_functions::ApacheLookupURIarray(dirname(@$_SERVER['PHP_SELF']))) {
4732 View Code Duplication
            foreach ($ApacheLookupURIarray as $key => $value) {
4733
                $DebugOutput[] = 'ApacheLookupURIarray.' . str_pad($key, 15, ' ', STR_PAD_RIGHT) . ' = ' . $this->phpThumbDebugVarDump($value);
4734
            }
4735
        } else {
4736
            $DebugOutput[] = 'ApacheLookupURIarray() -- FAILED';
4737
        }
4738
        $DebugOutput[] = '';
4739
4740 View Code Duplication
        if (isset($_GET) && is_array($_GET)) {
4741
            foreach ($_GET as $key => $value) {
4742
                $DebugOutput[] = '$_GET[' . $key . ']' . str_repeat(' ', 30 - strlen($key)) . '= ' . $this->phpThumbDebugVarDump($value);
4743
            }
4744
        }
4745 View Code Duplication
        if (isset($_POST) && is_array($_POST)) {
4746
            foreach ($_POST as $key => $value) {
4747
                $DebugOutput[] = '$_POST[' . $key . ']' . str_repeat(' ', 29 - strlen($key)) . '= ' . $this->phpThumbDebugVarDump($value);
4748
            }
4749
        }
4750
        $DebugOutput[] = '';
4751
4752
        $DebugOutput[] = '$this->debugmessages:';
4753
        foreach ($this->debugmessages as $errorstring) {
4754
            $DebugOutput[] = '  * ' . $errorstring;
4755
        }
4756
        $DebugOutput[] = '';
4757
4758
        $DebugOutput[] = '$this->debugtiming:';
4759
        foreach ($this->debugtiming as $timestamp => $timingstring) {
4760
            $DebugOutput[] = '  * ' . $timestamp . ' ' . $timingstring;
4761
        }
4762
        $DebugOutput[] = '  * Total processing time: ' . number_format(max(array_keys($this->debugtiming)) - min(array_keys($this->debugtiming)), 6);
4763
4764
        $this->f = (isset($_GET['f']) ? $_GET['f'] : $this->f); // debug modes 0-2 don't recognize text mode otherwise
4765
        return $this->ErrorImage(implode("\n", $DebugOutput), 700, 500, true);
4766
    }
4767
4768
    /**
4769
     * @param $text
4770
     * @return bool
4771
     */
4772
    public function FatalError($text)
4773
    {
4774
        if (is_null($this->fatalerror)) {
4775
            $this->fatalerror = $text;
4776
        }
4777
4778
        return true;
4779
    }
4780
4781
    /**
4782
     * @param       $text
4783
     * @param  int  $width
4784
     * @param  int  $height
4785
     * @param  bool $forcedisplay
4786
     * @return bool
4787
     */
4788
    public function ErrorImage($text, $width = 0, $height = 0, $forcedisplay = false)
4789
    {
4790
        $width  = ($width ?: $this->config_error_image_width);
4791
        $height = ($height ?: $this->config_error_image_height);
4792
4793
        $text = 'phpThumb() v' . $this->phpthumb_version . "\n" . 'http://phpthumb.sourceforge.net' . "\n\n" . ($this->config_disable_debug ? 'Error messages disabled.'
4794
                                                                                                                                              . "\n\n"
4795
                                                                                                                                              . 'edit phpThumb.config.php and (temporarily) set'
4796
                                                                                                                                              . "\n"
4797
                                                                                                                                              . '$PHPTHUMB_CONFIG[\'disable_debug\'] = false;'
4798
                                                                                                                                              . "\n"
4799
                                                                                                                                              . 'to view the details of this error' : $text);
4800
4801
        $this->FatalError($text);
4802
        $this->DebugMessage($text, __FILE__, __LINE__);
4803
        $this->purgeTempFiles();
4804
        if ($this->config_error_silent_die_on_error) {
4805
            exit;
4806
        }
4807
        if ($this->phpThumbDebug && !$forcedisplay) {
4808
            return false;
4809
        }
4810
        if (!$this->config_error_die_on_error && !$forcedisplay) {
4811
            return false;
4812
        }
4813
        if ($this->err || $this->config_error_message_image_default) {
4814
            // Show generic custom error image instead of error message
4815
            // for use on production sites where you don't want debug messages
4816
            if (($this->err == 'showerror') || $this->phpThumbDebug) {
4817
                // fall through and actually show error message even if default error image is set
4818
            } else {
4819
                header('Location: ' . ($this->err ?: $this->config_error_message_image_default));
4820
                exit;
4821
            }
4822
        }
4823
        $this->setOutputFormat();
4824
        if (!$this->thumbnailFormat || !$this->config_disable_debug || (phpthumb_functions::gd_version() < 1)) {
4825
            $this->thumbnailFormat = 'text';
4826
        }
4827
        if (@$this->thumbnailFormat == 'text') {
4828
            // bypass all GD functions and output text error message
4829
            if (!headers_sent()) {
4830
                header('Content-type: text/plain');
4831
                echo $text;
4832
            } else {
4833
                echo '<pre>' . htmlspecialchars($text) . '</pre>';
4834
            }
4835
            exit;
4836
        }
4837
4838
        $FontWidth  = imagefontwidth($this->config_error_fontsize);
4839
        $FontHeight = imagefontheight($this->config_error_fontsize);
4840
4841
        $LinesOfText = explode("\n", @wordwrap($text, floor($width / $FontWidth), "\n", true));
4842
        $height      = max($height, count($LinesOfText) * $FontHeight);
4843
4844
        $headers_file = '';
4845
        $headers_line = '';
4846
        if (phpthumb_functions::version_compare_replacement(PHP_VERSION, '4.3.0', '>=')
4847
            && headers_sent($headers_file, $headers_line)
4848
        ) {
4849
            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>';
4850
        } elseif (headers_sent()) {
4851
            echo "\n" . '**Headers already sent, dumping error message as text:**<br><pre>' . "\n\n" . $text . "\n" . '</pre>';
4852
        } elseif ($gdimg_error = imagecreate($width, $height)) {
4853
            $background_color = phpthumb_functions::ImageHexColorAllocate($gdimg_error, $this->config_error_bgcolor, true);
4854
            $text_color       = phpthumb_functions::ImageHexColorAllocate($gdimg_error, $this->config_error_textcolor, true);
4855
            imagefilledrectangle($gdimg_error, 0, 0, $width, $height, $background_color);
4856
            $lineYoffset = 0;
4857
            foreach ($LinesOfText as $line) {
4858
                imagestring($gdimg_error, $this->config_error_fontsize, 2, $lineYoffset, $line, $text_color);
4859
                $lineYoffset += $FontHeight;
4860
            }
4861
            if (function_exists('ImageTypes')) {
4862
                $imagetypes = imagetypes();
4863
                if ($imagetypes & IMG_PNG) {
4864
                    header('Content-Type: image/png');
4865
                    imagepng($gdimg_error);
4866
                } elseif ($imagetypes & IMG_GIF) {
4867
                    header('Content-Type: image/gif');
4868
                    imagegif($gdimg_error);
4869
                } elseif ($imagetypes & IMG_JPG) {
4870
                    header('Content-Type: image/jpeg');
4871
                    imagejpeg($gdimg_error);
4872
                } elseif ($imagetypes & IMG_WBMP) {
4873
                    header('Content-Type: image/vnd.wap.wbmp');
4874
                    imagewbmp($gdimg_error);
4875
                }
4876
            }
4877
            imagedestroy($gdimg_error);
4878
        }
4879
        if (!headers_sent()) {
4880
            echo "\n" . '**Failed to send graphical error image, dumping error message as text:**<br>' . "\n\n" . $text;
4881
        }
4882
        exit;
4883
4884
        return true;
4885
    }
4886
4887
    /**
4888
     * @param                $RawImageData
4889
     * @param  bool          $DieOnErrors
4890
     * @return bool|resource
4891
     */
4892
    public function ImageCreateFromStringReplacement(&$RawImageData, $DieOnErrors = false)
4893
    {
4894
        // there are serious bugs in the non-bundled versions of GD which may cause
4895
        // PHP to segfault when calling ImageCreateFromString() - avoid if at all possible
4896
        // when not using a bundled version of GD2
4897
        if (!phpthumb_functions::gd_version()) {
4898
            if ($DieOnErrors) {
4899
                if (!headers_sent()) {
4900
                    // base64-encoded error image in GIF format
4901
                    $ERROR_NOGD = 'R0lGODlhIAAgALMAAAAAABQUFCQkJDY2NkZGRldXV2ZmZnJycoaGhpSUlKWlpbe3t8XFxdXV1eTk5P7+/iwAAAAAIAAgAAAE/vDJSau9WILtTAACUinDNijZtAHfCojS4W5H+qxD8xibIDE9h0OwWaRWDIljJSkUJYsN4bihMB8th3IToAKs1VtYM75cyV8sZ8vygtOE5yMKmGbO4jRdICQCjHdlZzwzNW4qZSQmKDaNjhUMBX4BBAlmMywFSRWEmAI6b5gAlhNxokGhooAIK5o/pi9vEw4Lfj4OLTAUpj6IabMtCwlSFw0DCKBoFqwAB04AjI54PyZ+yY3TD0ss2YcVmN/gvpcu4TOyFivWqYJlbAHPpOntvxNAACcmGHjZzAZqzSzcq5fNjxFmAFw9iFRunD1epU6tsIPmFCAJnWYE0FURk7wJDA0MTKpEzoWAAskiAAA7';
4902
                    header('Content-Type: image/gif');
4903
                    echo base64_decode($ERROR_NOGD);
4904
                } else {
4905
                    echo '*** ERROR: No PHP-GD support available ***';
4906
                }
4907
                exit;
4908
            } else {
4909
                $this->DebugMessage('ImageCreateFromStringReplacement() failed: gd_version says "' . phpthumb_functions::gd_version() . '"', __FILE__, __LINE__);
4910
4911
                return false;
4912
            }
4913
        }
4914
        if (phpthumb_functions::gd_is_bundled()) {
4915
            $this->DebugMessage('ImageCreateFromStringReplacement() calling built-in ImageCreateFromString()', __FILE__, __LINE__);
4916
4917
            return @imagecreatefromstring($RawImageData);
4918
        }
4919
        if ($this->issafemode) {
4920
            $this->DebugMessage('ImageCreateFromStringReplacement() failed: cannot create temp file in SAFE_MODE', __FILE__, __LINE__);
4921
4922
            return false;
4923
        }
4924
4925
        switch (substr($RawImageData, 0, 3)) {
4926
            case 'GIF':
4927
                $ICFSreplacementFunctionName = 'ImageCreateFromGIF';
4928
                break;
4929
            case "\xFF\xD8\xFF":
4930
                $ICFSreplacementFunctionName = 'ImageCreateFromJPEG';
4931
                break;
4932
            case "\x89" . 'PN':
4933
                $ICFSreplacementFunctionName = 'ImageCreateFromPNG';
4934
                break;
4935
            default:
4936
                $this->DebugMessage('ImageCreateFromStringReplacement() failed: unknown fileformat signature "' . phpthumb_functions::HexCharDisplay(substr($RawImageData, 0, 3)) . '"', __FILE__,
4937
                                    __LINE__);
4938
4939
                return false;
4940
                break;
4941
        }
4942
        if ($tempnam = $this->phpThumb_tempnam()) {
4943
            if ($fp_tempnam = @fopen($tempnam, 'wb')) {
4944
                fwrite($fp_tempnam, $RawImageData);
4945
                fclose($fp_tempnam);
4946
                if (($ICFSreplacementFunctionName == 'ImageCreateFromGIF')
4947
                    && !function_exists($ICFSreplacementFunctionName)
4948
                ) {
4949
4950
                    // Need to create from GIF file, but ImageCreateFromGIF does not exist
4951
                    ob_start();
4952
                    if (!@require_once __DIR__ . '/phpthumb.gif.php') {
4953
                        $ErrorMessage = 'Failed to include required file "' . __DIR__ . '/phpthumb.gif.php" in ' . __FILE__ . ' on line ' . __LINE__;
4954
                        $this->DebugMessage($ErrorMessage, __FILE__, __LINE__);
4955
                    }
4956
                    ob_end_clean();
4957
                    // gif_loadFileToGDimageResource() cannot read from raw data, write to file first
4958
                    if ($tempfilename = $this->phpThumb_tempnam()) {
4959
                        if ($fp_tempfile = @fopen($tempfilename, 'wb')) {
4960
                            fwrite($fp_tempfile, $RawImageData);
4961
                            fclose($fp_tempfile);
4962
                            $gdimg_source = gif_loadFileToGDimageResource($tempfilename);
4963
                            $this->DebugMessage('gif_loadFileToGDimageResource(' . $tempfilename . ') completed', __FILE__, __LINE__);
4964
                            $this->DebugMessage('deleting "' . $tempfilename . '"', __FILE__, __LINE__);
4965
                            unlink($tempfilename);
4966
4967
                            return $gdimg_source;
4968
                        } else {
4969
                            $ErrorMessage = 'Failed to open tempfile in ' . __FILE__ . ' on line ' . __LINE__;
4970
                            $this->DebugMessage($ErrorMessage, __FILE__, __LINE__);
4971
                        }
4972
                    } else {
4973
                        $ErrorMessage = 'Failed to open generate tempfile name in ' . __FILE__ . ' on line ' . __LINE__;
4974
                        $this->DebugMessage($ErrorMessage, __FILE__, __LINE__);
4975
                    }
4976
                } elseif (function_exists($ICFSreplacementFunctionName)
4977
                          && ($gdimg_source = @$ICFSreplacementFunctionName($tempnam))
4978
                ) {
4979
4980
                    // great
4981
                    $this->DebugMessage($ICFSreplacementFunctionName . '(' . $tempnam . ') succeeded', __FILE__, __LINE__);
4982
                    $this->DebugMessage('deleting "' . $tempnam . '"', __FILE__, __LINE__);
4983
                    unlink($tempnam);
4984
4985
                    return $gdimg_source;
4986
                } else {
4987
4988
                    // GD functions not available, or failed to create image
4989
                    $this->DebugMessage($ICFSreplacementFunctionName . '(' . $tempnam . ') ' . (function_exists($ICFSreplacementFunctionName) ? 'failed' : 'does not exist'), __FILE__, __LINE__);
4990
                    if (isset($_GET['phpThumbDebug'])) {
4991
                        $this->phpThumbDebug();
4992
                    }
4993
                }
4994
            } else {
4995
                $ErrorMessage = 'Failed to fopen('
4996
                                . $tempnam
4997
                                . ', "wb") in '
4998
                                . __FILE__
4999
                                . ' on line '
5000
                                . __LINE__
5001
                                . "\n"
5002
                                . 'You may need to set $PHPTHUMB_CONFIG[temp_directory] in phpThumb.config.php';
5003
                if ($this->issafemode) {
5004
                    $ErrorMessage = 'ImageCreateFromStringReplacement() failed in ' . __FILE__ . ' on line ' . __LINE__ . ': cannot create temp file in SAFE_MODE';
5005
                }
5006
                $this->DebugMessage($ErrorMessage, __FILE__, __LINE__);
5007
            }
5008
            $this->DebugMessage('deleting "' . $tempnam . '"', __FILE__, __LINE__);
5009
            @unlink($tempnam);
5010
        } else {
5011
            $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';
5012
            if ($this->issafemode) {
5013
                $ErrorMessage = 'ImageCreateFromStringReplacement() failed in ' . __FILE__ . ' on line ' . __LINE__ . ': cannot create temp file in SAFE_MODE';
5014
            }
5015
        }
5016
        if ($DieOnErrors && $ErrorMessage) {
5017
            return $this->ErrorImage($ErrorMessage);
5018
        }
5019
5020
        return false;
5021
    }
5022
5023
    /**
5024
     * @param $dst_im
5025
     * @param $src_im
5026
     * @param $dstX
5027
     * @param $dstY
5028
     * @param $srcX
5029
     * @param $srcY
5030
     * @param $dstW
5031
     * @param $dstH
5032
     * @param $srcW
5033
     * @param $srcH
5034
     * @return bool
5035
     */
5036
    public function ImageResizeFunction(&$dst_im, &$src_im, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH)
5037
    {
5038
        $this->DebugMessage('ImageResizeFunction($o, $s, ' . $dstX . ', ' . $dstY . ', ' . $srcX . ', ' . $srcY . ', ' . $dstW . ', ' . $dstH . ', ' . $srcW . ', ' . $srcH . ')', __FILE__, __LINE__);
5039
        if (($dstW == $srcW) && ($dstH == $srcH)) {
5040
            return imagecopy($dst_im, $src_im, $dstX, $dstY, $srcX, $srcY, $srcW, $srcH);
5041
        }
5042
        if (phpthumb_functions::gd_version() >= 2.0) {
5043
            if ($this->config_disable_imagecopyresampled) {
5044
                return phpthumb_functions::ImageCopyResampleBicubic($dst_im, $src_im, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH);
5045
            }
5046
5047
            return imagecopyresampled($dst_im, $src_im, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH);
5048
        }
5049
5050
        return imagecopyresized($dst_im, $src_im, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH);
5051
    }
5052
5053
    /**
5054
     * @return bool
5055
     */
5056
    public function InitializeTempDirSetting()
5057
    {
5058
        $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
5059
        $this->config_temp_directory = ($this->config_temp_directory ?: getenv('TMPDIR'));
5060
        $this->config_temp_directory = ($this->config_temp_directory ?: getenv('TMP'));
5061
        $this->config_temp_directory = ($this->config_temp_directory ?: ini_get('upload_tmp_dir'));
5062
        $this->config_temp_directory = $this->realPathSafe($this->config_temp_directory);
5063
5064
        return true;
5065
    }
5066
5067
    /**
5068
     * @return mixed|string
5069
     */
5070
    public function phpThumb_tempnam()
5071
    {
5072
        $this->InitializeTempDirSetting();
5073
        $tempnam                           = $this->realPathSafe(tempnam($this->config_temp_directory, 'pThumb'));
5074
        $this->tempFilesToDelete[$tempnam] = $tempnam;
5075
        $this->DebugMessage('phpThumb_tempnam() returning "' . $tempnam . '"', __FILE__, __LINE__);
5076
5077
        return $tempnam;
5078
    }
5079
5080
    /**
5081
     * @param         $message
5082
     * @param  string $file
5083
     * @param  string $line
5084
     * @return bool
5085
     */
5086
    public function DebugMessage($message, $file = '', $line = '')
5087
    {
5088
        $this->debugmessages[] = $message . ($file ? ' in file "' . (basename($file) ?: $file) . '"' : '') . ($line ? ' on line ' . $line : '');
5089
5090
        return true;
5091
    }
5092
5093
    /**
5094
     * @param         $message
5095
     * @param  string $file
5096
     * @param  string $line
5097
     * @param  int    $timestamp
5098
     * @return bool
5099
     */
5100
    public function DebugTimingMessage($message, $file = '', $line = '', $timestamp = 0)
5101
    {
5102
        if (!$timestamp) {
5103
            $timestamp = array_sum(explode(' ', microtime()));
5104
        }
5105
        $this->debugtiming[number_format($timestamp, 6, '.', '')] = ': ' . $message . ($file ? ' in file "' . (basename($file) ?: $file) . '"' : '') . ($line ? ' on line ' . $line : '');
5106
5107
        return true;
5108
    }
5109
}
5110