2 //////////////////////////////////////////////////////////////
3 /// phpThumb() by James Heinrich <info@silisoftware.com> //
4 // available at http://phpthumb.sourceforge.net ///
5 //////////////////////////////////////////////////////////////
7 // See: phpthumb.readme.txt for usage instructions //
9 //////////////////////////////////////////////////////////////
12 if (!include_once(dirname(__FILE__).'/phpthumb.functions.php')) {
14 die('failed to include_once("'.realpath(dirname(__FILE__).'/phpthumb.functions.php').'")');
21 // START PARAMETERS (for object mode and phpThumb.php)
22 // See phpthumb.readme.txt for descriptions of what each of these values are
23 var $src = null; // SouRCe filename
24 var $new = null; // NEW image (phpThumb.php only)
25 var $w = null; // Width
26 var $h = null; // Height
27 var $wp = null; // Width (Portrait Images Only)
28 var $hp = null; // Height (Portrait Images Only)
29 var $wl = null; // Width (Landscape Images Only)
30 var $hl = null; // Height (Landscape Images Only)
31 var $ws = null; // Width (Square Images Only)
32 var $hs = null; // Height (Square Images Only)
33 var $f = null; // Format
34 var $q = 75; // jpeg output Quality
35 var $sx = null; // Source crop top-left X position
36 var $sy = null; // Source crop top-left Y position
37 var $sw = null; // Source crop Width
38 var $sh = null; // Source crop Height
39 var $zc = null; // Zoom Crop
40 var $bc = null; // Border Color
41 var $bg = null; // BackGround color
42 var $fltr = array(); // FiLTeRs
43 var $goto = null; // GO TO url after processing
44 var $err = null; // default ERRor image filename
45 var $xto = null; // extract eXif Thumbnail Only
46 var $ra = null; // Rotate by Angle
47 var $ar = null; // Auto Rotate
48 var $aoe = null; // Allow Output Enlargement
49 var $far = null; // Fixed Aspect Ratio
50 var $iar = null; // Ignore Aspect Ratio
51 var $maxb = null; // MAXimum Bytes
52 var $down = null; // DOWNload thumbnail filename
53 var $md5s = null; // MD5 hash of Source image
54 var $file = null; // >>deprecated, do not use<<
56 var $phpThumbDebug = null;
61 // START CONFIGURATION OPTIONS (for object mode only)
62 // See phpThumb.config.php for descriptions of what each of these settings do
64 // * Directory Configuration
65 var $config_cache_directory = null;
66 var $config_cache_disable_warning = true;
67 var $config_cache_source_enabled = false;
68 var $config_cache_source_directory = null;
69 var $config_temp_directory = null;
70 var $config_document_root = null;
72 // * Default output configuration:
73 var $config_output_format = 'jpeg';
74 var $config_output_maxwidth = 0;
75 var $config_output_maxheight = 0;
76 var $config_output_interlace = true;
78 // * Error message configuration
79 var $config_error_image_width = 400;
80 var $config_error_image_height = 100;
81 var $config_error_message_image_default = '';
82 var $config_error_bgcolor = 'CCCCFF';
83 var $config_error_textcolor = 'FF0000';
84 var $config_error_fontsize = 1;
85 var $config_error_die_on_error = false;
86 var $config_error_silent_die_on_error = false;
87 var $config_error_die_on_source_failure = true;
89 // * Anti-Hotlink Configuration:
90 var $config_nohotlink_enabled = true;
91 var $config_nohotlink_valid_domains = array();
92 var $config_nohotlink_erase_image = true;
93 var $config_nohotlink_text_message = 'Off-server thumbnailing is not allowed';
94 // * Off-server Linking Configuration:
95 var $config_nooffsitelink_enabled = false;
96 var $config_nooffsitelink_valid_domains = array();
97 var $config_nooffsitelink_require_refer = false;
98 var $config_nooffsitelink_erase_image = true;
99 var $config_nooffsitelink_text_message = 'Off-server linking is not allowed';
100 var $config_cache_differentiate_offsite = true;
102 // * Border & Background default colors
103 var $config_border_hexcolor = '000000';
104 var $config_background_hexcolor = 'FFFFFF';
107 var $config_ttf_directory = '.';
109 var $config_max_source_pixels = null;
110 var $config_use_exif_thumbnail_for_speed = false;
112 var $config_imagemagick_path = null;
113 var $config_prefer_imagemagick = true;
115 var $config_cache_maxage = null;
116 var $config_cache_maxsize = null;
117 var $config_cache_maxfiles = null;
119 var $config_cache_source_filemtime_ignore_local = false;
120 var $config_cache_source_filemtime_ignore_remote = false;
122 var $config_cache_default_only_suffix = false;
125 var $config_mysql_query = null;
126 var $config_mysql_hostname = null;
127 var $config_mysql_username = null;
128 var $config_mysql_password = null;
129 var $config_mysql_database = null;
132 var $config_high_security_enabled = false;
133 var $config_config_high_security_password = null;
135 var $config_disable_debug = false;
136 var $config_allow_src_above_docroot = false;
137 var $config_allow_src_above_phpthumb = true;
138 var $config_allow_parameter_file = false;
139 var $config_allow_parameter_goto = false;
141 // END CONFIGURATION OPTIONS
144 // public: error messages (read-only)
145 var $debugmessages = array();
146 var $debugtiming = array();
147 var $fatalerror = null;
150 // private: (should not be modified directly)
151 var $thumbnailQuality = 75;
152 var $thumbnailFormat = null;
154 var $sourceFilename = null;
155 var $rawImageData = null;
157 var $gdimg_output = null;
158 var $gdimg_source = null;
160 var $getimagesizeinfo = null;
162 var $source_width = null;
163 var $source_height = null;
165 var $thumbnailCropX = null;
166 var $thumbnailCropY = null;
167 var $thumbnailCropW = null;
168 var $thumbnailCropH = null;
170 var $exif_thumbnail_width = null;
171 var $exif_thumbnail_height = null;
172 var $exif_thumbnail_type = null;
173 var $exif_thumbnail_data = null;
175 var $thumbnail_width = null;
176 var $thumbnail_height = null;
177 var $thumbnail_image_width = null;
178 var $thumbnail_image_height = null;
180 var $cache_filename = null;
182 var $is_alpha = false;
184 var $iswindows = null;
187 var $phpthumb_version = '1.6.1a-200508260902';
189 //////////////////////////////////////////////////////////////////////
191 // public: constructor
192 function phpThumb() {
193 $this->DebugTimingMessage('phpThumb() constructor', __FILE__, __LINE__);
194 $this->config_max_source_pixels = round(max(intval(ini_get('memory_limit')), intval(get_cfg_var('memory_limit'))) * 1048576 * 0.20); // 20% of memory_limit
196 if (phpthumb_functions::gd_version() < 1) {
197 die('No GD support detected');
199 if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') {
200 $this->iswindows = true;
201 $this->osslash = '\\';
203 $this->iswindows = false;
204 $this->osslash = '/';
206 if (@$_SERVER['DOCUMENT_ROOT']) {
207 $this->config_document_root = $_SERVER['DOCUMENT_ROOT'];
212 function setSourceFilename($sourceFilename) {
213 $this->rawImageData = null;
214 $this->sourceFilename = $sourceFilename;
215 $this->DebugMessage('setSourceFilename('.$sourceFilename.') set $this->sourceFilename to "'.$this->sourceFilename.'"', __FILE__, __LINE__);
220 function setSourceData($rawImageData, $sourceFilename='') {
221 $this->sourceFilename = null;
222 $this->rawImageData = $rawImageData;
223 if ($this->config_cache_source_enabled) {
224 $sourceFilename = ($sourceFilename ? $sourceFilename : md5($rawImageData));
225 if (!is_dir($this->config_cache_source_directory) && !$this->phpThumbDebug) {
226 $this->ErrorImage('$this->config_cache_source_directory ('.$this->config_cache_source_directory.') is not a directory');
227 } elseif (!is_writable($this->config_cache_source_directory) && !$this->phpThumbDebug) {
228 $this->ErrorImage('$this->config_cache_source_directory ('.$this->config_cache_source_directory.') is not writable');
230 $this->DebugMessage('setSourceData() attempting to save source image to "'.$this->config_cache_source_directory.$this->osslash.urlencode($sourceFilename).'"', __FILE__, __LINE__);
231 if ($fp = @fopen($this->config_cache_source_directory.$this->osslash.urlencode($sourceFilename), 'wb')) {
232 fwrite($fp, $rawImageData);
234 } elseif (!$this->phpThumbDebug) {
235 $this->ErrorImage('setSourceData() failed to write to source cache ('.$this->config_cache_source_directory.$this->osslash.urlencode($sourceFilename).')');
242 function setSourceImageResource($gdimg) {
243 $this->gdimg_source = $gdimg;
248 function setParameter($param, $value) {
251 $this->setSourceFilename($this->ResolveFilenameToAbsolute($value));
255 $this->$param = $value;
258 $this->$param = $value;
263 function getParameter($param) {
264 //if (property_exists('phpThumb', $param)) {
265 return $this->$param;
267 //$this->DebugMessage('setParameter() attempting to set non-existant parameter "'.$param.'"', __FILE__, __LINE__);
273 function GenerateThumbnail() {
275 $this->setOutputFormat();
276 $this->ResolveSource();
277 $this->SetCacheFilename();
278 $this->ExtractEXIFgetImageSize();
279 if (!$this->SourceImageToGD()) {
283 $this->CreateGDoutput();
285 switch ($this->far) {
289 $destination_offset_x = 0;
290 $destination_offset_y = round(($this->thumbnail_height - $this->thumbnail_image_height) / 2);
295 $destination_offset_x = round($this->thumbnail_width - $this->thumbnail_image_width);
296 $destination_offset_y = round(($this->thumbnail_height - $this->thumbnail_image_height) / 2);
301 $destination_offset_x = round(($this->thumbnail_width - $this->thumbnail_image_width) / 2);
302 $destination_offset_y = 0;
307 $destination_offset_x = round(($this->thumbnail_width - $this->thumbnail_image_width) / 2);
308 $destination_offset_y = round($this->thumbnail_height - $this->thumbnail_image_height);
312 $destination_offset_x = round(($this->thumbnail_width - $this->thumbnail_image_width) / 2);
313 $destination_offset_y = round(($this->thumbnail_height - $this->thumbnail_image_height) / 2);
316 // copy/resize image to appropriate dimensions
317 phpthumb_functions::ImageResizeFunction(
320 $destination_offset_x,
321 $destination_offset_y,
322 $this->thumbnailCropX,
323 $this->thumbnailCropY,
324 $this->thumbnail_image_width,
325 $this->thumbnail_image_height,
326 $this->thumbnailCropW,
327 $this->thumbnailCropH
330 $this->AntiOffsiteLinking();
331 $this->ApplyFilters();
332 $this->AlphaChannelFlatten();
333 $this->MaxFileSize();
335 $this->DebugMessage('GenerateThumbnail() completed successfully', __FILE__, __LINE__);
341 function RenderToFile($filename) {
342 if (!is_resource($this->gdimg_output)) {
343 $this->DebugMessage('RenderToFile('.$filename.') failed because !is_resource($this->gdimg_output)', __FILE__, __LINE__);
346 if (!$this->thumbnailFormat) {
347 $this->DebugMessage('RenderToFile() failed because $this->thumbnailFormat is empty', __FILE__, __LINE__);
350 // render thumbnail to this file only, do not cache, do not output to browser
351 $ImageOutFunction = 'image'.$this->thumbnailFormat;
352 //$renderfilename = $this->ResolveFilenameToAbsolute(dirname($filename)).$this->osslash.basename($filename);
353 $renderfilename = $filename;
354 if (($filename{0} != '/') && ($filename{0} != '\\') && ($filename{1} != ':')) {
355 $renderfilename = $this->ResolveFilenameToAbsolute($renderfilename);
357 $this->DebugMessage('RenderToFile('.$filename.') attempting '.$ImageOutFunction.'($this->gdimg_output, '.$renderfilename.')', __FILE__, __LINE__);
358 if (!is_writable(dirname($renderfilename))) {
359 $this->DebugMessage(dirname($renderfilename).'/ is not writable', __FILE__, __LINE__);
361 if (is_file($renderfilename) && !is_writable($renderfilename)) {
362 $this->DebugMessage($renderfilename.' is not writable', __FILE__, __LINE__);
365 switch ($this->thumbnailFormat) {
367 $ImageOutFunction($this->gdimg_output, $renderfilename, $this->thumbnailQuality);
372 $ImageOutFunction($this->gdimg_output, $renderfilename);
375 $errormessage = strip_tags(ob_get_contents());
378 $this->DebugMessage('RenderToFile ['.$ImageOutFunction.'('.$renderfilename.')] failed with message "'.$errormessage.'"', __FILE__, __LINE__);
380 } elseif (!file_exists($renderfilename)) {
381 $this->DebugMessage('RenderToFile ['.$ImageOutFunction.'('.$renderfilename.')] did not appear to fail, but the output image does not exist either...', __FILE__, __LINE__);
388 function OutputThumbnail() {
389 if (!is_resource($this->gdimg_output)) {
390 $this->DebugMessage('OutputThumbnail() failed because !is_resource($this->gdimg_output)', __FILE__, __LINE__);
393 if (headers_sent()) {
394 return $this->ErrorImage('OutputThumbnail() failed - headers already sent');
399 $downloadfilename = ereg_replace('[/\\:\*\?"<>|]', '_', $this->down);
400 if (phpthumb_functions::version_compare_replacement(phpversion(), '4.1.0', '>=')) {
401 $downloadfilename = trim($downloadfilename, '.');
403 if ($downloadfilename != $this->down) {
404 $this->DebugMessage('renaming output file for "down" from "'.$this->down.'" to "'.$downloadfilename.'"', __FILE__, __LINE__);
406 if ($downloadfilename) {
407 header('Content-Disposition: attachment; filename="'.$downloadfilename.'"');
409 $this->DebugMessage('failed to send Content-Disposition header because $downloadfilename is empty', __FILE__, __LINE__);
413 ImageInterlace($this->gdimg_output, intval($this->config_output_interlace));
414 $ImageOutFunction = 'image'.$this->thumbnailFormat;
415 switch ($this->thumbnailFormat) {
417 header('Content-Type: image/'.$this->thumbnailFormat);
418 @$ImageOutFunction($this->gdimg_output, '', $this->thumbnailQuality);
423 header('Content-Type: image/'.$this->thumbnailFormat);
424 @$ImageOutFunction($this->gdimg_output);
431 ImageDestroy($this->gdimg_output);
437 function CleanUpCacheDirectory() {
438 if (($this->config_cache_maxage > 0) || ($this->config_cache_maxsize > 0) || ($this->config_cache_maxfiles > 0)) {
439 $CacheDirOldFilesAge = array();
440 $CacheDirOldFilesSize = array();
441 if ($dirhandle = opendir($this->config_cache_directory)) {
442 while ($oldcachefile = readdir($dirhandle)) {
443 if (eregi('^phpThumb_cache_', $oldcachefile)) {
444 $CacheDirOldFilesAge[$oldcachefile] = fileatime($this->config_cache_directory.$this->osslash.$oldcachefile);
445 if ($CacheDirOldFilesAge[$oldcachefile] == 0) {
446 $CacheDirOldFilesAge[$oldcachefile] = filemtime($this->config_cache_directory.$this->osslash.$oldcachefile);
449 $CacheDirOldFilesSize[$oldcachefile] = filesize($this->config_cache_directory.$this->osslash.$oldcachefile);
453 asort($CacheDirOldFilesAge);
455 if ($this->config_cache_maxfiles > 0) {
456 $TotalCachedFiles = count($CacheDirOldFilesAge);
457 $DeletedKeys = array();
458 foreach ($CacheDirOldFilesAge as $oldcachefile => $filedate) {
459 if ($TotalCachedFiles > $this->config_cache_maxfiles) {
461 if (@unlink($this->config_cache_directory.$this->osslash.$oldcachefile)) {
462 $DeletedKeys[] = $oldcachefile;
465 // there are few enough files to keep the rest
469 foreach ($DeletedKeys as $oldcachefile) {
470 unset($CacheDirOldFilesAge[$oldcachefile]);
471 unset($CacheDirOldFilesSize[$oldcachefile]);
475 if ($this->config_cache_maxage > 0) {
476 $mindate = time() - $this->config_cache_maxage;
477 $DeletedKeys = array();
478 foreach ($CacheDirOldFilesAge as $oldcachefile => $filedate) {
480 if ($filedate < $mindate) {
481 if (@unlink($this->config_cache_directory.$this->osslash.$oldcachefile)) {
482 $DeletedKeys[] = $oldcachefile;
485 // the rest of the files are new enough to keep
490 foreach ($DeletedKeys as $oldcachefile) {
491 unset($CacheDirOldFilesAge[$oldcachefile]);
492 unset($CacheDirOldFilesSize[$oldcachefile]);
496 if ($this->config_cache_maxsize > 0) {
497 $TotalCachedFileSize = array_sum($CacheDirOldFilesSize);
498 $DeletedKeys = array();
499 foreach ($CacheDirOldFilesAge as $oldcachefile => $filedate) {
500 if ($TotalCachedFileSize > $this->config_cache_maxsize) {
501 $TotalCachedFileSize -= $CacheDirOldFilesSize[$oldcachefile];
502 if (@unlink($this->config_cache_directory.$this->osslash.$oldcachefile)) {
503 $DeletedKeys[] = $oldcachefile;
506 // the total filesizes are small enough to keep the rest of the files
510 foreach ($DeletedKeys as $oldcachefile) {
511 unset($CacheDirOldFilesAge[$oldcachefile]);
512 unset($CacheDirOldFilesSize[$oldcachefile]);
520 //////////////////////////////////////////////////////////////////////
522 function ResolveSource() {
523 if (is_resource($this->gdimg_source)) {
526 if ($this->rawImageData) {
527 $this->sourceFilename = null;
530 if ($this->sourceFilename) {
531 $this->sourceFilename = $this->ResolveFilenameToAbsolute($this->sourceFilename);
532 $this->DebugMessage('$this->sourceFilename set to "'.$this->sourceFilename.'"', __FILE__, __LINE__);
534 $this->sourceFilename = $this->ResolveFilenameToAbsolute($this->src);
535 $this->DebugMessage('$this->sourceFilename set to "'.$this->sourceFilename.'" from $this->src ('.$this->src.')', __FILE__, __LINE__);
537 if ($this->iswindows && ((substr($this->sourceFilename, 0, 2) == '//') || (substr($this->sourceFilename, 0, 2) == '\\\\'))) {
538 // Windows \\share\filename.ext
539 } elseif (eregi('^(f|ht)tps?://', $this->sourceFilename)) {
541 } elseif (!file_exists($this->sourceFilename)) {
542 return $this->ErrorImage('"'.$this->sourceFilename.'" does not exist');
543 } elseif (!is_file($this->sourceFilename)) {
544 return $this->ErrorImage('"'.$this->sourceFilename.'" is not a file');
549 function setOutputFormat() {
550 static $alreadyCalled = false;
551 if ($this->thumbnailFormat && $alreadyCalled) {
554 $alreadyCalled = true;
556 $AvailableImageOutputFormats = array();
557 $AvailableImageOutputFormats[] = 'text';
558 $this->thumbnailFormat = 'text';
560 // Set default output format based on what image types are available
561 if (!function_exists('ImageTypes')) {
562 return $this->ErrorImage('ImageTypes() does not exist - GD support might not be enabled?');
564 $imagetypes = ImageTypes();
565 if ($imagetypes & IMG_WBMP) {
566 $this->thumbnailFormat = 'wbmp';
567 $AvailableImageOutputFormats[] = 'wbmp';
569 if ($imagetypes & IMG_GIF) {
570 $this->thumbnailFormat = 'gif';
571 $AvailableImageOutputFormats[] = 'gif';
573 if ($imagetypes & IMG_PNG) {
574 $this->thumbnailFormat = 'png';
575 $AvailableImageOutputFormats[] = 'png';
577 if ($imagetypes & IMG_JPG) {
578 $this->thumbnailFormat = 'jpeg';
579 $AvailableImageOutputFormats[] = 'jpeg';
581 $this->DebugMessage('$AvailableImageOutputFormats = array('.implode(';', $AvailableImageOutputFormats).')', __FILE__, __LINE__);
583 if (strtolower($this->config_output_format) == 'jpg') {
584 $this->config_output_format = 'jpeg';
586 if (strtolower($this->f) == 'jpg') {
589 if (in_array(strtolower($this->config_output_format), $AvailableImageOutputFormats)) {
590 // set output format to config default if that format is available
591 $this->DebugMessage('$this->thumbnailFormat set to $this->config_output_format "'.strtolower($this->config_output_format).'"', __FILE__, __LINE__);
592 $this->thumbnailFormat = strtolower($this->config_output_format);
593 } elseif ($this->config_output_format) {
594 $this->DebugMessage('$this->thumbnailFormat staying as "'.$this->thumbnailFormat.'" because $this->config_output_format ('.strtolower($this->config_output_format).') is not in $AvailableImageOutputFormats', __FILE__, __LINE__);
596 if ($this->f && (in_array(strtolower($this->f), $AvailableImageOutputFormats))) {
597 // override output format if $this->f is set and that format is available
598 $this->DebugMessage('$this->thumbnailFormat set to $this->f "'.strtolower($this->f).'"', __FILE__, __LINE__);
599 $this->thumbnailFormat = strtolower($this->f);
600 } elseif ($this->f) {
601 $this->DebugMessage('$this->thumbnailFormat staying as "'.$this->thumbnailFormat.'" because $this->f ('.strtolower($this->f).') is not in $AvailableImageOutputFormats', __FILE__, __LINE__);
604 // for JPEG images, quality 1 (worst) to 99 (best)
605 // quality < 25 is nasty, with not much size savings - not recommended
606 // problems with 100 - invalid JPEG?
607 $this->thumbnailQuality = max(1, min(99, ($this->q ? $this->q : 75)));
608 $this->DebugMessage('$this->thumbnailQuality set to "'.$this->thumbnailQuality.'"', __FILE__, __LINE__);
613 function setCacheDirectory() {
614 // resolve cache directory to absolute pathname
615 if (substr($this->config_cache_directory, 0, 1) == '.') {
616 if (eregi('^(f|ht)tps?://', $this->src)) {
617 if (!$this->config_cache_disable_warning && !$this->phpThumbDebug) {
618 $this->ErrorImage('$this->config_cache_directory ('.$this->config_cache_directory.') cannot be used for remote images. Adjust "cache_directory" or "cache_disable_warning" in phpThumb.config.php');
620 } elseif ($this->src) {
621 // resolve relative cache directory to source image
622 $this->config_cache_directory = dirname($this->ResolveFilenameToAbsolute($this->src)).$this->osslash.$this->config_cache_directory;
624 // $this->new is probably set
627 if (substr($this->config_cache_directory, -1) == '/') {
628 $this->config_cache_directory = substr($this->config_cache_directory, 0, -1);
630 if ($this->iswindows) {
631 $this->config_cache_directory = str_replace('/', $this->osslash, $this->config_cache_directory);
633 if ($this->config_cache_directory) {
634 $real_cache_path = realpath($this->config_cache_directory);
635 if (!$real_cache_path) {
636 $this->DebugMessage('realpath($this->config_cache_directory) failed for "'.$this->config_cache_directory.'"', __FILE__, __LINE__);
637 if (!is_dir($this->config_cache_directory)) {
638 $this->DebugMessage('!is_dir('.$this->config_cache_directory.')', __FILE__, __LINE__);
641 if ($real_cache_path) {
642 $this->config_cache_directory = $real_cache_path;
645 if (!is_dir($this->config_cache_directory)) {
646 if (!$this->config_cache_disable_warning && !$this->phpThumbDebug) {
647 $this->ErrorImage('$this->config_cache_directory ('.$this->config_cache_directory.') does not exist. Adjust "cache_directory" or "cache_disable_warning" in phpThumb.config.php');
649 $this->DebugMessage('$this->config_cache_directory ('.$this->config_cache_directory.') is not a directory', __FILE__, __LINE__);
650 $this->config_cache_directory = null;
651 } elseif (!is_writable($this->config_cache_directory)) {
652 $this->DebugMessage('$this->config_cache_directory is not writable ('.$this->config_cache_directory.')', __FILE__, __LINE__);
658 function ResolveFilenameToAbsolute($filename) {
659 if (eregi('^(f|ht)tps?://', $filename)) {
662 $AbsoluteFilename = $filename;
664 } elseif ($this->iswindows && ($filename{1} == ':')) {
666 // absolute pathname (Windows)
667 $AbsoluteFilename = $filename;
669 } elseif ($this->iswindows && ((substr($filename, 0, 2) == '//') || (substr($filename, 0, 2) == '\\\\'))) {
671 // absolute pathname (Windows)
672 $AbsoluteFilename = $filename;
674 } elseif ($filename{0} == '/') {
676 if (@is_readable($filename) && !@is_readable($this->config_document_root.$filename)) {
677 // absolute filename (*nix)
678 $AbsoluteFilename = $filename;
679 } elseif ($filename{1} == '~') {
681 if ($ApacheLookupURIarray = phpthumb_functions::ApacheLookupURIarray($filename)) {
682 $AbsoluteFilename = $ApacheLookupURIarray['filename'];
684 $AbsoluteFilename = realpath($filename);
685 if (@is_readable($AbsoluteFilename)) {
686 $this->DebugMessage('phpthumb_functions::ApacheLookupURIarray() failed for "'.$filename.'", but the correct filename ('.$AbsoluteFilename.') seems to have been resolved with realpath($filename)', __FILE__, __LINE__);
688 if ($this->phpThumbDebug) {
689 $this->DebugMessage('phpthumb_functions::ApacheLookupURIarray() failed for "'.$filename.'". This has been known to fail on Apache2 - try using the absolute filename for the source image');
692 return $this->ErrorImage('phpthumb_functions::ApacheLookupURIarray() failed for "'.$filename.'". This has been known to fail on Apache2 - try using the absolute filename for the source image');
697 // relative filename (any OS)
698 $AbsoluteFilename = $this->config_document_root.$filename;
703 // relative to current directory (any OS)
704 $AbsoluteFilename = $this->config_document_root.dirname(@$_SERVER['PHP_SELF']).$this->osslash.$filename;
705 //if (!file_exists($AbsoluteFilename) && file_exists(realpath($this->DotPadRelativeDirectoryPath($filename)))) {
706 // $AbsoluteFilename = realpath($this->DotPadRelativeDirectoryPath($filename));
709 if (substr(dirname(@$_SERVER['PHP_SELF']), 0, 2) == '/~') {
710 if ($ApacheLookupURIarray = phpthumb_functions::ApacheLookupURIarray(dirname(@$_SERVER['PHP_SELF']))) {
711 $AbsoluteFilename = $ApacheLookupURIarray['filename'].$this->osslash.$filename;
713 $AbsoluteFilename = realpath('.').$this->osslash.$filename;
714 if (@is_readable($AbsoluteFilename)) {
715 $this->DebugMessage('phpthumb_functions::ApacheLookupURIarray() failed for "'.dirname(@$_SERVER['PHP_SELF']).'", but the correct filename ('.$AbsoluteFilename.') seems to have been resolved with realpath(.)/$filename', __FILE__, __LINE__);
717 return $this->ErrorImage('phpthumb_functions::ApacheLookupURIarray() failed for "'.dirname(@$_SERVER['PHP_SELF']).'". This has been known to fail on Apache2 - try using the absolute filename for the source image');
723 if (is_link($AbsoluteFilename)) {
724 $this->DebugMessage('is_link()==true, changing "'.$AbsoluteFilename.'" to "'.readlink($AbsoluteFilename).'"', __FILE__, __LINE__);
725 $AbsoluteFilename = readlink($AbsoluteFilename);
727 if (realpath($AbsoluteFilename)) {
728 $AbsoluteFilename = realpath($AbsoluteFilename);
730 if ($this->iswindows) {
731 $AbsoluteFilename = eregi_replace('^'.preg_quote(realpath($this->config_document_root)), realpath($this->config_document_root), $AbsoluteFilename);
732 $AbsoluteFilename = str_replace($this->osslash, '/', $AbsoluteFilename);
734 if (!$this->config_allow_src_above_docroot && !ereg('^'.preg_quote(str_replace($this->osslash, '/', realpath($this->config_document_root))), $AbsoluteFilename)) {
735 $this->DebugMessage('!$this->config_allow_src_above_docroot therefore setting "'.$AbsoluteFilename.'" to null', __FILE__, __LINE__);
738 if (!$this->config_allow_src_above_phpthumb && !ereg('^'.preg_quote(str_replace($this->osslash, '/', dirname(__FILE__))), $AbsoluteFilename)) {
739 $this->DebugMessage('!$this->config_allow_src_above_phpthumb therefore setting "'.$AbsoluteFilename.'" to null', __FILE__, __LINE__);
742 return $AbsoluteFilename;
745 function ImageMagickCommandlineBase() {
746 static $commandline = null;
747 if (is_null($commandline)) {
750 $which_convert = trim(phpthumb_functions::SafeExec('which convert'));
752 if ($this->config_imagemagick_path && ($this->config_imagemagick_path != realpath($this->config_imagemagick_path))) {
753 $this->DebugMessage('Changing $this->config_imagemagick_path ('.$this->config_imagemagick_path.') to realpath($this->config_imagemagick_path) ('.realpath($this->config_imagemagick_path).')', __FILE__, __LINE__);
754 $this->config_imagemagick_path = realpath($this->config_imagemagick_path);
756 if (file_exists($this->config_imagemagick_path)) {
758 $this->DebugMessage('using ImageMagick path from $this->config_imagemagick_path ('.$this->config_imagemagick_path.')', __FILE__, __LINE__);
759 if ($this->iswindows) {
760 $commandline = substr($this->config_imagemagick_path, 0, 2).' && cd "'.substr(dirname($this->config_imagemagick_path), 2).'" && '.basename($this->config_imagemagick_path);
762 $commandline = '"'.$this->config_imagemagick_path.'"';
765 } elseif ($which_convert && ($which_convert{0} == '/') && @file_exists($which_convert)) {
767 // `which convert` *should* return the path if "convert" exist, or nothing if it doesn't
768 // other things *may* get returned, like "sh: convert: not found" or "no convert in /usr/local/bin /usr/sbin /usr/bin /usr/ccs/bin"
769 // so only do this if the value returned exists as a file
770 $this->DebugMessage('using ImageMagick path from `which convert` ('.$which_convert.')', __FILE__, __LINE__);
771 $commandline = 'convert';
775 $this->DebugMessage('ImageMagickThumbnailToGD() aborting because cannot find convert in $this->config_imagemagick_path ('.$this->config_imagemagick_path.'), and `which convert` returned ('.$which_convert.')', __FILE__, __LINE__);
782 function ImageMagickVersion() {
783 $commandline = $this->ImageMagickCommandlineBase();
785 $commandline .= ' -version';
786 $versionstring = phpthumb_functions::SafeExec($commandline);
787 if (eregi('^Version: (.*) http', $versionstring, $matches)) {
790 $this->DebugMessage('ImageMagick did not return recognized version string ('.$versionstring.')', __FILE__, __LINE__);
791 return $versionstring;
796 function ImageMagickThumbnailToGD() {
797 // http://freealter.org/doc_distrib/ImageMagick-5.1.1/www/convert.html
798 if (ini_get('safe_mode')) {
799 $this->DebugMessage('ImageMagickThumbnailToGD() aborting because safe_mode is enabled', __FILE__, __LINE__);
802 if (!function_exists('ImageCreateFromPNG')) {
803 // ImageMagickThumbnailToGD() depends on ImageCreateFromPNG()
804 $this->DebugMessage('ImageMagickThumbnailToGD() aborting because ImageCreateFromPNG() is not available', __FILE__, __LINE__);
808 $commandline = $this->ImageMagickCommandlineBase();
810 if ($IMtempfilename = $this->phpThumb_tempnam()) {
812 $IMtempfilename = realpath($IMtempfilename);
813 $this->source_width = max($this->w, $this->wp, $this->wl, $this->ws);
814 $this->source_height = max($this->h, $this->hp, $this->hl, $this->hs);
815 $this->DebugMessage('source dimensions set to '.$this->source_width.'x'.$this->source_height, __FILE__, __LINE__);
816 if (!$this->aoe && !$this->iar && ($getimagesize = @GetImageSize($this->sourceFilename))) {
817 // limit output size to input size unless AllowOutputEnlargement is enabled
818 $this->source_width = min($this->source_width, $getimagesize[0]);
819 $this->source_height = min($this->source_height, $getimagesize[1]);
820 $this->DebugMessage('source dimensions reset to '.$this->source_width.'x'.$this->source_height, __FILE__, __LINE__);
821 $this->SetOrientationDependantWidthHeight();
823 $ar = max($getimagesize[0] / $getimagesize[1], $getimagesize[1] / $getimagesize[0]);
824 $this->source_width = round($this->source_width * $ar);
825 $this->source_height = round($this->source_height * $ar);
826 $this->DebugMessage('source dimensions reset by "zc" to '.$this->source_width.'x'.$this->source_height, __FILE__, __LINE__);
829 //$commandline .= ' -resize '.$this->source_width.'x'.$this->source_height; // behaves badly with IM v5.3.x
830 $commandline .= ' -geometry '.$this->source_width.'x'.$this->source_height;
831 if ($this->iar && (intval($this->w) > 0) && (intval($this->h) > 0)) {
834 $commandline .= ' "'.str_replace('/', $this->osslash, $this->sourceFilename).'"';
835 $commandline .= ' png:'.$IMtempfilename;
836 $commandline .= ' 2>&1';
838 $this->DebugMessage('ImageMagick called as ('.$commandline.')', __FILE__, __LINE__);
839 $IMresult = phpthumb_functions::SafeExec($commandline);
842 //return $this->ErrorImage('ImageMagick was called as:'."\n".$commandline."\n\n".'but failed with message:'."\n".$IMresult);
843 $this->DebugMessage('ImageMagick failed with message ('.$IMresult.')', __FILE__, __LINE__);
845 } elseif ($this->gdimg_source = @ImageCreateFromPNG($IMtempfilename)) {
847 @unlink($IMtempfilename);
848 $this->source_width = ImageSX($this->gdimg_source);
849 $this->source_height = ImageSY($this->gdimg_source);
850 $this->DebugMessage('ImageMagickThumbnailToGD() succeeded, $this->gdimg_source is now ('.$this->source_width.'x'.$this->source_height.')', __FILE__, __LINE__);
854 unlink($IMtempfilename);
857 $this->DebugMessage('ImageMagickThumbnailToGD() aborting, phpThumb_tempnam() failed', __FILE__, __LINE__);
860 $this->DebugMessage('ImageMagickThumbnailToGD() aborting because ImageMagickCommandlineBase() failed', __FILE__, __LINE__);
866 if ($this->ra || $this->ar) {
867 if (!function_exists('ImageRotate')) {
868 $this->DebugMessage('!function_exists(ImageRotate)', __FILE__, __LINE__);
871 if (!include_once(dirname(__FILE__).'/phpthumb.filters.php')) {
872 $this->DebugMessage('Error including "'.dirname(__FILE__).'/phpthumb.filters.php" which is required for applying filters ('.implode(';', $this->fltr).')', __FILE__, __LINE__);
876 $this->config_background_hexcolor = ($this->bg ? $this->bg : $this->config_background_hexcolor);
877 if (!phpthumb_functions::IsHexColor($this->config_background_hexcolor)) {
878 return $this->ErrorImage('Invalid hex color string "'.$this->config_background_hexcolor.'" for parameter "bg"');
884 $rotate_angle = floatval($this->ra);
888 if ($this->ar == 'x') {
889 if (phpthumb_functions::version_compare_replacement(phpversion(), '4.2.0', '>=')) {
890 if ($this->sourceFilename) {
891 if (function_exists('exif_read_data')) {
892 if ($exif_data = @exif_read_data($this->sourceFilename, 'IFD0')) {
893 // http://sylvana.net/jpegcrop/exif_orientation.html
894 switch (@$exif_data['Orientation']) {
909 $this->DebugMessage('EXIF auto-rotate failed because unknown $exif_data[Orientation] "'.@$exif_data['Orientation'].'"', __FILE__, __LINE__);
913 $this->DebugMessage('EXIF auto-rotate set to '.$rotate_angle.' degrees ($exif_data[Orientation] = "'.@$exif_data['Orientation'].'")', __FILE__, __LINE__);
915 $this->DebugMessage('failed: exif_read_data('.$this->sourceFilename.')', __FILE__, __LINE__);
919 $this->DebugMessage('!function_exists(exif_read_data)', __FILE__, __LINE__);
923 $this->DebugMessage('Cannot auto-rotate from EXIF data because $this->sourceFilename is empty', __FILE__, __LINE__);
927 $this->DebugMessage('Cannot auto-rotate from EXIF data because PHP is less than v4.2.0 ('.phpversion().')', __FILE__, __LINE__);
930 } elseif (($this->ar == 'l') && ($this->source_height > $this->source_width)) {
932 } elseif (($this->ar == 'L') && ($this->source_height > $this->source_width)) {
934 } elseif (($this->ar == 'p') && ($this->source_width > $this->source_height)) {
936 } elseif (($this->ar == 'P') && ($this->source_width > $this->source_height)) {
941 while ($rotate_angle < 0) {
942 $rotate_angle += 360;
944 $rotate_angle = $rotate_angle % 360;
945 if ($rotate_angle != 0) {
947 $background_color = phpthumb_functions::ImageHexColorAllocate($this->gdimg_source, $this->config_background_hexcolor);
949 if ((phpthumb_functions::gd_version() >= 2) && ($this->thumbnailFormat == 'png') && !$this->bg && ($rotate_angle % 90)) {
951 if ($gdimg_rotate_mask = phpthumb_functions::ImageCreateFunction(ImageSX($this->gdimg_source), ImageSY($this->gdimg_source))) {
953 $this->gdimg_source = ImageRotate($this->gdimg_source, $rotate_angle, $background_color);
954 $color_mask_opaque = ImageColorAllocate($gdimg_rotate_mask, 0xFF, 0xFF, 0xFF);
955 $color_mask_transparent = ImageColorAllocate($gdimg_rotate_mask, 0x00, 0x00, 0x00);
956 ImageFilledRectangle($gdimg_rotate_mask, 0, 0, ImageSX($gdimg_rotate_mask), ImageSY($gdimg_rotate_mask), $color_mask_opaque);
957 $gdimg_rotate_mask = ImageRotate($gdimg_rotate_mask, $rotate_angle, $color_mask_transparent);
959 ImageAlphaBlending($this->gdimg_source, false);
960 if (phpthumb_functions::version_compare_replacement(phpversion(), '4.3.2', '>=')) {
961 ImageSaveAlpha($this->gdimg_source, true);
963 $this->is_alpha = true;
964 phpthumb_filters::ApplyMask($gdimg_rotate_mask, $this->gdimg_source);
966 ImageDestroy($gdimg_rotate_mask);
967 $this->source_width = ImageSX($this->gdimg_source);
968 $this->source_height = ImageSY($this->gdimg_source);
971 $this->DebugMessage('ImageCreateFromStringReplacement() failed for "'.$MaskFilename.'"', __FILE__, __LINE__);
976 if (phpthumb_functions::gd_version() >= 2) {
977 $this->DebugMessage('Using non-alpha rotate because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
979 $this->DebugMessage('Using non-alpha rotate because $this->thumbnailFormat is "'.$this->thumbnailFormat.'"', __FILE__, __LINE__);
982 if (ImageColorTransparent($this->gdimg_source) >= 0) {
983 // ImageRotate() forgets all about an image's transparency and sets the transparent color to black
984 // To compensate, flood-fill the transparent color of the source image with the specified background color first
985 // then rotate and the colors should match
987 if (!function_exists('ImageIsTrueColor') || !ImageIsTrueColor($this->gdimg_source)) {
988 // convert paletted image to true-color before rotating to prevent nasty aliasing artifacts
990 $this->source_width = ImageSX($this->gdimg_source);
991 $this->source_height = ImageSY($this->gdimg_source);
992 $gdimg_newsrc = phpthumb_functions::ImageCreateFunction($this->source_width, $this->source_height);
993 $background_color = phpthumb_functions::ImageHexColorAllocate($gdimg_newsrc, $this->config_background_hexcolor);
994 ImageFilledRectangle($gdimg_newsrc, 0, 0, $this->source_width, $this->source_height, phpthumb_functions::ImageHexColorAllocate($gdimg_newsrc, $this->config_background_hexcolor));
995 ImageCopy($gdimg_newsrc, $this->gdimg_source, 0, 0, 0, 0, $this->source_width, $this->source_height);
996 ImageDestroy($this->gdimg_source);
997 unset($this->gdimg_source);
998 $this->gdimg_source = $gdimg_newsrc;
999 unset($gdimg_newsrc);
1004 $this->gdimg_source,
1005 ImageColorTransparent($this->gdimg_source),
1006 hexdec(substr($this->config_background_hexcolor, 0, 2)),
1007 hexdec(substr($this->config_background_hexcolor, 2, 2)),
1008 hexdec(substr($this->config_background_hexcolor, 4, 2)));
1010 ImageColorTransparent($this->gdimg_source, -1);
1015 $this->gdimg_source = ImageRotate($this->gdimg_source, $rotate_angle, $background_color);
1016 $this->source_width = ImageSX($this->gdimg_source);
1017 $this->source_height = ImageSY($this->gdimg_source);
1026 function FixedAspectRatio() {
1027 // optional fixed-dimension images (regardless of aspect ratio)
1034 if (!$this->w || !$this->h) {
1037 $this->thumbnail_width = $this->w;
1038 $this->thumbnail_height = $this->h;
1039 $this->is_alpha = true;
1040 if ($this->thumbnail_image_width >= $this->thumbnail_width) {
1043 $aspectratio = $this->thumbnail_image_height / $this->thumbnail_image_width;
1044 $this->thumbnail_image_height = round($this->thumbnail_image_width * $aspectratio);
1046 $this->thumbnail_height = $this->thumbnail_image_height;
1048 } elseif ($this->thumbnail_image_height < $this->thumbnail_height) {
1049 $this->thumbnail_image_height = $this->thumbnail_height;
1050 $this->thumbnail_image_width = round($this->thumbnail_image_height / $aspectratio);
1056 $aspectratio = $this->thumbnail_image_width / $this->thumbnail_image_height;
1057 $this->thumbnail_image_width = round($this->thumbnail_image_height * $aspectratio);
1058 } elseif ($this->thumbnail_image_width < $this->thumbnail_width) {
1059 $this->thumbnail_image_width = $this->thumbnail_width;
1060 $this->thumbnail_image_height = round($this->thumbnail_image_width / $aspectratio);
1068 function AntiOffsiteLinking() {
1069 // Optional anti-offsite hijacking of the thumbnail script
1071 if ($allow && $this->config_nooffsitelink_enabled && $this->config_nooffsitelink_require_refer) {
1072 $this->DebugMessage('AntiOffsiteLinking() checking $_SERVER[HTTP_REFERER] "'.@$_SERVER['HTTP_REFERER'].'"', __FILE__, __LINE__);
1073 $parsed_url = parse_url(@$_SERVER['HTTP_REFERER']);
1074 if (!in_array(@$parsed_url['host'], $this->config_nooffsitelink_valid_domains)) {
1076 $erase = $this->config_nooffsitelink_erase_image;
1077 $message = $this->config_nooffsitelink_text_message;
1078 $this->DebugMessage('AntiOffsiteLinking() - "'.@$parsed_url['host'].'" is NOT in $this->config_nooffsitelink_valid_domains ('.implode(';', $this->config_nooffsitelink_valid_domains).')', __FILE__, __LINE__);
1080 $this->DebugMessage('AntiOffsiteLinking() - "'.@$parsed_url['host'].'" is in $this->config_nooffsitelink_valid_domains ('.implode(';', $this->config_nooffsitelink_valid_domains).')', __FILE__, __LINE__);
1084 if ($allow && $this->config_nohotlink_enabled && eregi('^(f|ht)tps?://', $this->src)) {
1085 $parsed_url = parse_url($this->src);
1086 if (!in_array(@$parsed_url['host'], $this->config_nohotlink_valid_domains)) {
1087 // This domain is not allowed
1089 $erase = $this->config_nohotlink_erase_image;
1090 $message = $this->config_nohotlink_text_message;
1091 $this->DebugMessage('AntiOffsiteLinking() - "'.$parsed_url['host'].'" is NOT in $this->config_nohotlink_valid_domains ('.implode(';', $this->config_nohotlink_valid_domains).')', __FILE__, __LINE__);
1093 $this->DebugMessage('AntiOffsiteLinking() - "'.$parsed_url['host'].'" is in $this->config_nohotlink_valid_domains ('.implode(';', $this->config_nohotlink_valid_domains).')', __FILE__, __LINE__);
1098 $this->DebugMessage('AntiOffsiteLinking() says this is allowed', __FILE__, __LINE__);
1102 if (!phpthumb_functions::IsHexColor($this->config_error_bgcolor)) {
1103 return $this->ErrorImage('Invalid hex color string "'.$this->config_error_bgcolor.'" for $this->config_error_bgcolor');
1105 if (!phpthumb_functions::IsHexColor($this->config_error_textcolor)) {
1106 return $this->ErrorImage('Invalid hex color string "'.$this->config_error_textcolor.'" for $this->config_error_textcolor');
1110 return $this->ErrorImage($message, $this->thumbnail_width, $this->thumbnail_height, $this->config_error_bgcolor, $this->config_error_textcolor, $this->config_error_fontsize);
1114 $nohotlink_text_array = explode("\n", wordwrap($message, floor($this->thumbnail_width / ImageFontWidth($this->config_error_fontsize)), "\n"));
1115 $nohotlink_text_color = phpthumb_functions::ImageHexColorAllocate($this->gdimg_output, $this->config_error_textcolor);
1117 $topoffset = round(($this->thumbnail_height - (count($nohotlink_text_array) * ImageFontHeight($this->config_error_fontsize))) / 2);
1120 $this->DebugMessage('AntiOffsiteLinking() writing '.count($nohotlink_text_array).' lines of text "'.$message.'" (in #'.$this->config_error_textcolor.') on top of image', __FILE__, __LINE__);
1121 foreach ($nohotlink_text_array as $textline) {
1122 $leftoffset = max(0, round(($this->thumbnail_width - (strlen($textline) * ImageFontWidth($this->config_error_fontsize))) / 2));
1123 ImageString($this->gdimg_output, $this->config_error_fontsize, $leftoffset, $topoffset + ($rowcounter++ * ImageFontHeight($this->config_error_fontsize)), $textline, $nohotlink_text_color);
1131 function AlphaChannelFlatten() {
1132 if (!$this->is_alpha) {
1133 // image doesn't have alpha transparency, no need to flatten
1134 $this->DebugMessage('skipping AlphaChannelFlatten() because !$this->is_alpha', __FILE__, __LINE__);
1137 if ($this->thumbnailFormat == 'png') {
1139 // image has alpha transparency, but output as PNG which can handle it
1140 $this->DebugMessage('skipping AlphaChannelFlatten() because ($this->thumbnailFormat == "'.$this->thumbnailFormat.'")', __FILE__, __LINE__);
1143 } elseif ($this->thumbnailFormat == 'gif') {
1145 // image has alpha transparency, but output as GIF which can handle only single-color transparency
1146 $CurrentImageColorTransparent = ImageColorTransparent($this->gdimg_output);
1147 if ($CurrentImageColorTransparent == -1) {
1148 // no transparent color defined
1150 if (phpthumb_functions::gd_version() < 2.0) {
1151 $this->DebugMessage('AlphaChannelFlatten() failed because GD version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
1155 if ($img_alpha_mixdown_dither = @ImageCreateTrueColor(ImageSX($this->gdimg_output), ImageSY($this->gdimg_output))) {
1157 for ($i = 0; $i <= 255; $i++) {
1158 $dither_color[$i] = ImageColorAllocate($img_alpha_mixdown_dither, $i, $i, $i);
1161 // scan through current truecolor image copy alpha channel to temp image as grayscale
1162 for ($x = 0; $x < $this->thumbnail_width; $x++) {
1163 for ($y = 0; $y < $this->thumbnail_height; $y++) {
1164 $PixelColor = phpthumb_functions::GetPixelColor($this->gdimg_output, $x, $y);
1165 ImageSetPixel($img_alpha_mixdown_dither, $x, $y, $dither_color[($PixelColor['alpha'] * 2)]);
1169 // dither alpha channel grayscale version down to 2 colors
1170 ImageTrueColorToPalette($img_alpha_mixdown_dither, true, 2);
1172 // reduce color palette to 256-1 colors (leave one palette position for transparent color)
1173 ImageTrueColorToPalette($this->gdimg_output, true, 255);
1175 // allocate a new color for transparent color index
1176 $TransparentColor = ImageColorAllocate($this->gdimg_output, 1, 254, 253);
1177 ImageColorTransparent($this->gdimg_output, $TransparentColor);
1179 // scan through alpha channel image and note pixels with >50% transparency
1180 $TransparentPixels = array();
1181 for ($x = 0; $x < $this->thumbnail_width; $x++) {
1182 for ($y = 0; $y < $this->thumbnail_height; $y++) {
1183 $AlphaChannelPixel = phpthumb_functions::GetPixelColor($img_alpha_mixdown_dither, $x, $y);
1184 if ($AlphaChannelPixel['red'] > 127) {
1185 ImageSetPixel($this->gdimg_output, $x, $y, $TransparentColor);
1189 ImageDestroy($img_alpha_mixdown_dither);
1191 $this->DebugMessage('AlphaChannelFlatten() set image to 255+1 colors with transparency for GIF output', __FILE__, __LINE__);
1195 $this->DebugMessage('AlphaChannelFlatten() failed ImageCreate('.ImageSX($this->gdimg_output).', '.ImageSY($this->gdimg_output).')', __FILE__, __LINE__);
1200 // a single transparent color already defined, leave as-is
1201 $this->DebugMessage('skipping AlphaChannelFlatten() because ($this->thumbnailFormat == "'.$this->thumbnailFormat.'") and ImageColorTransparent returned "'.$CurrentImageColorTransparent.'"', __FILE__, __LINE__);
1206 $this->DebugMessage('continuing AlphaChannelFlatten() for output format "'.$this->thumbnailFormat.'"', __FILE__, __LINE__);
1208 // image has alpha transparency, and is being output in a format that doesn't support it -- flatten
1209 if ($gdimg_flatten_temp = phpthumb_functions::ImageCreateFunction($this->thumbnail_width, $this->thumbnail_height)) {
1211 $this->config_background_hexcolor = ($this->bg ? $this->bg : $this->config_background_hexcolor);
1212 if (!phpthumb_functions::IsHexColor($this->config_background_hexcolor)) {
1213 return $this->ErrorImage('Invalid hex color string "'.$this->config_background_hexcolor.'" for parameter "bg"');
1215 $background_color = phpthumb_functions::ImageHexColorAllocate($this->gdimg_output, $this->config_background_hexcolor);
1216 ImageFilledRectangle($gdimg_flatten_temp, 0, 0, $this->thumbnail_width, $this->thumbnail_height, $background_color);
1217 ImageCopy($gdimg_flatten_temp, $this->gdimg_output, 0, 0, 0, 0, $this->thumbnail_width, $this->thumbnail_height);
1219 ImageAlphaBlending($this->gdimg_output, true);
1220 if (phpthumb_functions::version_compare_replacement(phpversion(), '4.3.2', '>=')) {
1221 ImageSaveAlpha($this->gdimg_output, false);
1223 ImageColorTransparent($this->gdimg_output, -1);
1224 ImageCopy($this->gdimg_output, $gdimg_flatten_temp, 0, 0, 0, 0, $this->thumbnail_width, $this->thumbnail_height);
1226 ImageDestroy($gdimg_flatten_temp);
1230 $this->DebugMessage('ImageCreateFunction() failed', __FILE__, __LINE__);
1236 function ApplyFilters() {
1237 if ($this->fltr && is_array($this->fltr)) {
1238 if (!include_once(dirname(__FILE__).'/phpthumb.filters.php')) {
1239 $this->DebugMessage('Error including "'.dirname(__FILE__).'/phpthumb.filters.php" which is required for applying filters ('.implode(';', $this->fltr).')', __FILE__, __LINE__);
1242 foreach ($this->fltr as $filtercommand) {
1243 @list($command, $parameter) = explode('|', $filtercommand, 2);
1244 $this->DebugMessage('Attempting to process filter command "'.$command.'"', __FILE__, __LINE__);
1247 phpthumb_filters::Brightness($this->gdimg_output, $parameter);
1251 phpthumb_filters::Contrast($this->gdimg_output, $parameter);
1255 phpthumb_filters::Desaturate($this->gdimg_output, $parameter, '');
1259 phpthumb_filters::Saturation($this->gdimg_output, $parameter, '');
1263 phpthumb_filters::Grayscale($this->gdimg_output);
1267 if (phpthumb_functions::gd_version() < 2) {
1268 $this->DebugMessage('Skipping Colorize() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
1271 @list($amount, $color) = explode('|', $parameter);
1272 phpthumb_filters::Colorize($this->gdimg_output, $amount, $color);
1276 if (phpthumb_functions::gd_version() < 2) {
1277 $this->DebugMessage('Skipping Sepia() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
1280 @list($amount, $color) = explode('|', $parameter);
1281 phpthumb_filters::Sepia($this->gdimg_output, $amount, $color);
1285 phpthumb_filters::Gamma($this->gdimg_output, $parameter);
1289 phpthumb_filters::Negative($this->gdimg_output);
1293 phpthumb_filters::Threshold($this->gdimg_output, $parameter);
1297 if (phpthumb_functions::gd_version() < 2) {
1298 $this->DebugMessage('Skipping ReduceColorDepth() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
1301 @list($colors, $dither) = explode('|', $parameter);
1302 $colors = ($colors ? (int) $colors : 256);
1303 $dither = ((strlen($dither) > 0) ? (bool) $dither : true);
1304 phpthumb_filters::ReduceColorDepth($this->gdimg_output, $colors, $dither);
1308 phpthumb_filters::Flip($this->gdimg_output, (strpos(strtolower($parameter), 'x') !== false), (strpos(strtolower($parameter), 'y') !== false));
1312 phpthumb_filters::EdgeDetect($this->gdimg_output);
1316 phpthumb_filters::Emboss($this->gdimg_output);
1320 @list($width, $color1, $color2) = explode('|', $parameter);
1321 phpthumb_filters::Bevel($this->gdimg_output, $width, $color1, $color2);
1325 @list($band, $min, $max) = explode('|', $parameter);
1326 $band = ($band ? $band : '*');
1327 $min = ((strlen($min) > 0) ? $min : '-1');
1328 $max = ((strlen($max) > 0) ? $max : '-1');
1329 phpthumb_filters::HistogramStretch($this->gdimg_output, $band, $min, $max);
1333 phpthumb_filters::WhiteBalance($this->gdimg_output, $parameter);
1337 if (phpthumb_functions::gd_version() < 2) {
1338 $this->DebugMessage('Skipping HistogramOverlay() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
1341 @list($bands, $colors, $width, $height, $alignment, $opacity, $margin) = explode('|', $parameter);
1342 $bands = ($bands ? $bands : '*');
1343 $colors = ($colors ? $colors : '');
1344 $width = ($width ? $width : 0.25);
1345 $height = ($height ? $height : 0.25);
1346 $alignment = ($alignment ? $alignment : 'BR');
1347 $opacity = ($opacity ? $opacity : 50);
1348 $margin = ($margin ? $margin : 5);
1349 phpthumb_filters::HistogramOverlay($this->gdimg_output, $bands, $colors, $width, $height, $alignment, $opacity, $margin);
1353 @list($frame_width, $edge_width, $color_frame, $color1, $color2) = explode('|', $parameter);
1354 phpthumb_filters::Frame($this->gdimg_output, $frame_width, $edge_width, $color_frame, $color1, $color2);
1358 if (phpthumb_functions::gd_version() < 2) {
1359 $this->DebugMessage('Skipping DropShadow() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
1362 $this->is_alpha = true;
1363 @list($distance, $width, $color, $angle, $fade) = explode('|', $parameter);
1364 phpthumb_filters::DropShadow($this->gdimg_output, $distance, $width, $color, $angle, $fade);
1368 if (phpthumb_functions::gd_version() < 2) {
1369 $this->DebugMessage('Skipping Mask() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
1372 $mask_filename = $this->ResolveFilenameToAbsolute($parameter);
1373 if (@is_readable($mask_filename) && ($fp_mask = @fopen($mask_filename, 'rb'))) {
1374 $MaskImageData = fread($fp_mask, filesize($mask_filename));
1376 if ($gdimg_mask = $this->ImageCreateFromStringReplacement($MaskImageData)) {
1377 $this->is_alpha = true;
1378 phpthumb_filters::ApplyMask($gdimg_mask, $this->gdimg_output);
1379 ImageDestroy($gdimg_mask);
1381 $this->DebugMessage('ImageCreateFromStringReplacement() failed for "'.$mask_filename.'"', __FILE__, __LINE__);
1384 $this->DebugMessage('Cannot open mask file "'.$mask_filename.'"', __FILE__, __LINE__);
1389 if (phpthumb_functions::gd_version() < 2) {
1390 $this->DebugMessage('Skipping Elipse() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
1393 $this->is_alpha = true;
1394 phpthumb_filters::Elipse($this->gdimg_output);
1398 if (phpthumb_functions::gd_version() < 2) {
1399 $this->DebugMessage('Skipping RoundedImageCorners() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
1402 @list($radius_x, $radius_y) = explode('|', $parameter);
1403 if (($radius_x < 1) || ($radius_y < 1)) {
1404 $this->DebugMessage('Skipping RoundedImageCorners('.$radius_x.', '.$radius_y.') because x/y radius is less than 1', __FILE__, __LINE__);
1407 $this->is_alpha = true;
1408 phpthumb_filters::RoundedImageCorners($this->gdimg_output, $radius_x, $radius_y);
1412 @list($border_width, $radius_x, $radius_y, $hexcolor_border) = explode('|', $parameter);
1413 $this->is_alpha = true;
1414 phpthumb_filters::ImageBorder($this->gdimg_output, $border_width, $radius_x, $radius_y, $hexcolor_border);
1418 @list($filename, $underlay, $margin, $opacity) = explode('|', $parameter);
1419 $underlay = (bool) ($underlay ? $underlay : false);
1420 $margin = ((strlen($margin) > 0) ? $margin : ($underlay ? 0.1 : 0.0));
1421 $opacity = ((strlen($opacity) > 0) ? $opacity : 100);
1422 if (($margin > 0) && ($margin < 1)) {
1423 $margin = min(0.499, $margin);
1424 } elseif (($margin > -1) && ($margin < 0)) {
1425 $margin = max(-0.499, $margin);
1428 $filename = $this->ResolveFilenameToAbsolute($filename);
1429 if (@is_readable($filename) && ($fp_watermark = @fopen($filename, 'rb'))) {
1430 $WatermarkImageData = fread($fp_watermark, filesize($filename));
1431 fclose($fp_watermark);
1432 if ($img_watermark = $this->ImageCreateFromStringReplacement($WatermarkImageData)) {
1434 $resized_x = max(1, ImageSX($this->gdimg_output) - round(2 * (ImageSX($this->gdimg_output) * $margin)));
1435 $resized_y = max(1, ImageSY($this->gdimg_output) - round(2 * (ImageSY($this->gdimg_output) * $margin)));
1437 $resized_x = max(1, ImageSX($this->gdimg_output) - round(2 * $margin));
1438 $resized_y = max(1, ImageSY($this->gdimg_output) - round(2 * $margin));
1443 if ($img_watermark_resized = phpthumb_functions::ImageCreateFunction(ImageSX($this->gdimg_output), ImageSY($this->gdimg_output))) {
1444 ImageAlphaBlending($img_watermark_resized, false);
1445 ImageSaveAlpha($img_watermark_resized, true);
1446 phpthumb_functions::ImageResizeFunction($img_watermark_resized, $img_watermark, 0, 0, 0, 0, ImageSX($img_watermark_resized), ImageSY($img_watermark_resized), ImageSX($img_watermark), ImageSY($img_watermark));
1447 if ($img_source_resized = phpthumb_functions::ImageCreateFunction($resized_x, $resized_y)) {
1448 ImageAlphaBlending($img_source_resized, false);
1449 ImageSaveAlpha($img_source_resized, true);
1450 phpthumb_functions::ImageResizeFunction($img_source_resized, $this->gdimg_output, 0, 0, 0, 0, ImageSX($img_source_resized), ImageSY($img_source_resized), ImageSX($this->gdimg_output), ImageSY($this->gdimg_output));
1451 phpthumb_filters::WatermarkOverlay($img_watermark_resized, $img_source_resized, 'C', $opacity, $margin);
1452 ImageCopy($this->gdimg_output, $img_watermark_resized, 0, 0, 0, 0, ImageSX($this->gdimg_output), ImageSY($this->gdimg_output));
1454 $this->DebugMessage('phpthumb_functions::ImageCreateFunction('.$resized_x.', '.$resized_y.')', __FILE__, __LINE__);
1456 ImageDestroy($img_watermark_resized);
1458 $this->DebugMessage('phpthumb_functions::ImageCreateFunction('.ImageSX($this->gdimg_output).', '.ImageSY($this->gdimg_output).')', __FILE__, __LINE__);
1463 if ($img_watermark_resized = phpthumb_functions::ImageCreateFunction($resized_x, $resized_y)) {
1464 ImageAlphaBlending($img_watermark_resized, false);
1465 ImageSaveAlpha($img_watermark_resized, true);
1466 phpthumb_functions::ImageResizeFunction($img_watermark_resized, $img_watermark, 0, 0, 0, 0, ImageSX($img_watermark_resized), ImageSY($img_watermark_resized), ImageSX($img_watermark), ImageSY($img_watermark));
1467 phpthumb_filters::WatermarkOverlay($this->gdimg_output, $img_watermark_resized, 'C', $opacity, $margin);
1468 ImageDestroy($img_watermark_resized);
1470 $this->DebugMessage('phpthumb_functions::ImageCreateFunction('.$resized_x.', '.$resized_y.')', __FILE__, __LINE__);
1474 ImageDestroy($img_watermark);
1477 $this->DebugMessage('ImageCreateFromStringReplacement() failed for "'.$filename.'"', __FILE__, __LINE__);
1480 $this->DebugMessage('Cannot open overlay file "'.$filename.'"', __FILE__, __LINE__);
1485 @list($filename, $alignment, $opacity, $margin) = explode('|', $parameter);
1486 $alignment = ($alignment ? $alignment : 'BR');
1487 $opacity = (strlen($opacity) ? $opacity : 50);
1488 $margin = (strlen($margin) ? $margin : 5);
1490 $filename = $this->ResolveFilenameToAbsolute($filename);
1491 if (@is_readable($filename) && ($fp_watermark = @fopen($filename, 'rb'))) {
1492 $WatermarkImageData = fread($fp_watermark, filesize($filename));
1493 fclose($fp_watermark);
1494 if ($img_watermark = $this->ImageCreateFromStringReplacement($WatermarkImageData)) {
1496 phpthumb_filters::WatermarkOverlay($this->gdimg_output, $img_watermark, $alignment, $opacity, $margin);
1497 ImageDestroy($img_watermark);
1499 $this->DebugMessage('ImageCreateFromStringReplacement() failed for "'.$filename.'"', __FILE__, __LINE__);
1502 $this->DebugMessage('Cannot open watermark file "'.$filename.'"', __FILE__, __LINE__);
1507 @list($text, $size, $alignment, $hex_color, $ttffont, $opacity, $margin, $angle) = explode('|', $parameter);
1508 $text = ($text ? $text : '');
1509 $size = ($size ? $size : 3);
1510 $alignment = ($alignment ? $alignment : 'BR');
1511 $hex_color = ($hex_color ? $hex_color : '000000');
1512 $ttffont = ($ttffont ? $ttffont : '');
1513 $opacity = (strlen($opacity) ? $opacity : 50);
1514 $margin = (strlen($margin) ? $margin : 5);
1515 $angle = (strlen($angle) ? $angle : 0);
1517 if (basename($ttffont) == $ttffont) {
1518 $ttffont = realpath($this->config_ttf_directory.$this->osslash.$ttffont);
1520 $ttffont = $this->ResolveFilenameToAbsolute($ttffont);
1522 phpthumb_filters::WatermarkText($this->gdimg_output, $text, $size, $alignment, $hex_color, $ttffont, $opacity, $margin, $angle);
1526 @list($radius) = explode('|', $parameter);
1527 $radius = ($radius ? $radius : 1);
1528 if (phpthumb_functions::gd_version() < 2) {
1529 $this->DebugMessage('Skipping Blur() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
1532 phpthumb_filters::Blur($this->gdimg_output, $radius);
1536 phpthumb_filters::BlurGaussian($this->gdimg_output);
1540 phpthumb_filters::BlurSelective($this->gdimg_output);
1544 phpthumb_filters::MeanRemoval($this->gdimg_output);
1548 phpthumb_filters::Smooth($this->gdimg_output, $parameter);
1552 @list($amount, $radius, $threshold) = explode('|', $parameter);
1553 $amount = ($amount ? $amount : 80);
1554 $radius = ($radius ? $radius : 0.5);
1555 $threshold = (strlen($threshold) ? $threshold : 3);
1556 if (phpthumb_functions::gd_version() >= 2.0) {
1558 if (!@include_once(dirname(__FILE__).'/phpthumb.unsharp.php')) {
1559 $include_error = ob_get_contents();
1560 if ($include_error) {
1561 $this->DebugMessage('include_once("'.dirname(__FILE__).'/phpthumb.unsharp.php") generated message: "'.$include_error.'"', __FILE__, __LINE__);
1564 $this->DebugMessage('Error including "'.dirname(__FILE__).'/phpthumb.unsharp.php" which is required for unsharp masking', __FILE__, __LINE__);
1568 phpUnsharpMask::applyUnsharpMask($this->gdimg_output, $amount, $radius, $threshold);
1570 $this->DebugMessage('Skipping unsharp mask because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
1581 function MaxFileSize() {
1582 if (phpthumb_functions::gd_version() < 2) {
1583 $this->DebugMessage('Skipping MaxFileSize() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
1586 if ($this->maxb > 0) {
1587 switch ($this->thumbnailFormat) {
1590 $imgRenderFunction = 'image'.$this->thumbnailFormat;
1593 $imgRenderFunction($this->gdimg_output);
1594 $imgdata = ob_get_contents();
1597 if (strlen($imgdata) > $this->maxb) {
1598 for ($i = 8; $i >= 1; $i--) {
1599 $tempIMG = ImageCreateTrueColor(ImageSX($this->gdimg_output), ImageSY($this->gdimg_output));
1600 ImageCopy($tempIMG, $this->gdimg_output, 0, 0, 0, 0, ImageSX($this->gdimg_output), ImageSY($this->gdimg_output));
1601 ImageTrueColorToPalette($tempIMG, true, pow(2, $i));
1603 $imgRenderFunction($tempIMG);
1604 $imgdata = ob_get_contents();
1607 if (strlen($imgdata) <= $this->maxb) {
1608 ImageTrueColorToPalette($this->gdimg_output, true, pow(2, $i));
1613 if (strlen($imgdata) > $this->maxb) {
1614 ImageTrueColorToPalette($this->gdimg_output, true, pow(2, $i));
1621 ImageJPEG($this->gdimg_output);
1622 $imgdata = ob_get_contents();
1625 $OriginalJPEGquality = $this->thumbnailQuality;
1626 if (strlen($imgdata) > $this->maxb) {
1627 for ($i = 3; $i < 20; $i++) {
1628 $q = round(100 * (1 - log10($i / 2)));
1630 ImageJPEG($this->gdimg_output, '', $q);
1631 $imgdata = ob_get_contents();
1634 $this->thumbnailQuality = $q;
1635 if (strlen($imgdata) <= $this->maxb) {
1640 if (strlen($imgdata) > $this->maxb) {
1654 function CalculateThumbnailDimensions() {
1656 $this->thumbnailCropX = ($this->sx ? (($this->sx >= 1) ? $this->sx : round($this->sx * $this->source_width)) : 0);
1657 $this->thumbnailCropY = ($this->sy ? (($this->sy >= 1) ? $this->sy : round($this->sy * $this->source_height)) : 0);
1658 $this->thumbnailCropW = ($this->sw ? (($this->sw >= 1) ? $this->sw : round($this->sw * $this->source_width)) : $this->source_width);
1659 $this->thumbnailCropH = ($this->sh ? (($this->sh >= 1) ? $this->sh : round($this->sh * $this->source_height)) : $this->source_height);
1661 // limit source area to original image area
1662 $this->thumbnailCropW = max(1, min($this->thumbnailCropW, $this->source_width - $this->thumbnailCropX));
1663 $this->thumbnailCropH = max(1, min($this->thumbnailCropH, $this->source_height - $this->thumbnailCropY));
1665 $this->DebugMessage('CalculateThumbnailDimensions() [x,y,w,h] initially set to ['.$this->thumbnailCropX.','.$this->thumbnailCropY.','.$this->thumbnailCropW.','.$this->thumbnailCropH.']', __FILE__, __LINE__);
1668 if ($this->zc && $this->w && $this->h) {
1670 // retain proportional resizing we did above, but crop off larger dimension so smaller
1671 // dimension fully fits available space
1673 $scaling_X = $this->source_width / $this->w;
1674 $scaling_Y = $this->source_height / $this->h;
1675 if ($scaling_X > $scaling_Y) {
1676 // some of the width will need to be cropped
1677 $allowable_width = $this->source_width / $scaling_X * $scaling_Y;
1678 $this->thumbnailCropW = round($allowable_width);
1679 $this->thumbnailCropX = round(($this->source_width - $allowable_width) / 2);
1681 } elseif ($scaling_Y > $scaling_X) {
1682 // some of the height will need to be cropped
1683 $allowable_height = $this->source_height / $scaling_Y * $scaling_X;
1684 $this->thumbnailCropH = round($allowable_height);
1685 $this->thumbnailCropY = round(($this->source_height - $allowable_height) / 2);
1688 // image fits perfectly, no cropping needed
1690 $this->thumbnail_width = $this->w;
1691 $this->thumbnail_height = $this->h;
1692 $this->thumbnail_image_width = $this->thumbnail_width;
1693 $this->thumbnail_image_height = $this->thumbnail_height;
1695 } elseif ($this->iar && $this->w && $this->h) {
1697 // Ignore Aspect Ratio
1698 // stretch image to fit exactly 'w' x 'h'
1699 $this->thumbnail_width = $this->w;
1700 $this->thumbnail_height = $this->h;
1701 $this->thumbnail_image_width = $this->thumbnail_width;
1702 $this->thumbnail_image_height = $this->thumbnail_height;
1706 $original_aspect_ratio = $this->thumbnailCropW / $this->thumbnailCropH;
1708 $maxwidth = max($this->w, $this->thumbnailCropW);
1709 $maxheight = max($this->h, $this->thumbnailCropH);
1710 $maxwidth = max($maxwidth, $maxheight * $original_aspect_ratio);
1711 $maxheight = max($maxheight, $maxwidth / $original_aspect_ratio);
1713 $maxwidth = phpthumb_functions::nonempty_min($this->w, $this->thumbnailCropW, $this->config_output_maxwidth);
1714 $maxheight = phpthumb_functions::nonempty_min($this->h, $this->thumbnailCropH, $this->config_output_maxheight);
1715 $maxwidth = min($maxwidth, $maxheight * $original_aspect_ratio);
1716 $maxheight = min($maxheight, $maxwidth / $original_aspect_ratio);
1719 $this->thumbnail_image_width = $maxwidth;
1720 $this->thumbnail_image_height = $maxheight;
1721 $this->thumbnail_width = $maxwidth;
1722 $this->thumbnail_height = $maxheight;
1724 $this->FixedAspectRatio();
1727 $this->thumbnail_width = max(1, round($this->thumbnail_width));
1728 $this->thumbnail_height = max(1, round($this->thumbnail_height));
1733 function CreateGDoutput() {
1735 $this->CalculateThumbnailDimensions();
1737 // Create the GD image (either true-color or 256-color, depending on GD version)
1738 $this->gdimg_output = phpthumb_functions::ImageCreateFunction($this->thumbnail_width, $this->thumbnail_height);
1740 // Images that have transparency must have the background filled with the configured 'bg' color
1741 // otherwise the transparent color will appear as black
1742 if (phpthumb_functions::version_compare_replacement(phpversion(), '4.3.2', '>=')) {
1743 ImageSaveAlpha($this->gdimg_output, true);
1745 if ($this->is_alpha && phpthumb_functions::gd_version() >= 2) {
1747 ImageAlphaBlending($this->gdimg_output, false);
1748 $output_full_alpha = phpthumb_functions::ImageColorAllocateAlphaSafe($this->gdimg_output, 255, 255, 255, 127);
1749 ImageFilledRectangle($this->gdimg_output, 0, 0, $this->thumbnail_width, $this->thumbnail_height, $output_full_alpha);
1753 $current_transparent_color = ImageColorTransparent($this->gdimg_source);
1754 if ($this->bg || (@$current_transparent_color >= 0)) {
1756 $this->config_background_hexcolor = ($this->bg ? $this->bg : $this->config_background_hexcolor);
1757 if (!phpthumb_functions::IsHexColor($this->config_background_hexcolor)) {
1758 return $this->ErrorImage('Invalid hex color string "'.$this->config_background_hexcolor.'" for parameter "bg"');
1760 $background_color = phpthumb_functions::ImageHexColorAllocate($this->gdimg_output, $this->config_background_hexcolor);
1761 ImageFilledRectangle($this->gdimg_output, 0, 0, $this->thumbnail_width, $this->thumbnail_height, $background_color);
1769 function SetOrientationDependantWidthHeight() {
1770 if ($this->source_height > $this->source_width) {
1772 $this->w = ($this->wp ? $this->wp : $this->w);
1773 $this->h = ($this->hp ? $this->hp : $this->h);
1774 } elseif ($this->source_height < $this->source_width) {
1776 $this->w = ($this->wl ? $this->wl : $this->w);
1777 $this->h = ($this->hl ? $this->hl : $this->h);
1780 $this->w = ($this->ws ? $this->ws : $this->w);
1781 $this->h = ($this->hs ? $this->hs : $this->h);
1783 //$this->w = ($this->w ? $this->w : ($this->wl ? $this->wl : ($this->wp ? $this->wp : ($this->ws ? $this->ws : $this->source_width))));
1784 //$this->h = ($this->h ? $this->h : ($this->hl ? $this->hl : ($this->hp ? $this->hp : ($this->hs ? $this->hs : $this->source_height))));
1788 function ExtractEXIFgetImageSize() {
1790 if (is_resource($this->gdimg_source)) {
1792 $this->source_width = ImageSX($this->gdimg_source);
1793 $this->source_height = ImageSY($this->gdimg_source);
1795 $this->SetOrientationDependantWidthHeight();
1797 } elseif ($this->rawImageData && !$this->sourceFilename) {
1799 $this->DebugMessage('bypassing EXIF and GetImageSize sections because $this->rawImageData is set and $this->sourceFilename is not set', __FILE__, __LINE__);
1802 if ($this->config_prefer_imagemagick) {
1803 if ($this->ImageMagickThumbnailToGD()) {
1806 $this->DebugMessage('ImageMagickThumbnailToGD() failed', __FILE__, __LINE__);
1808 if ($this->getimagesizeinfo = @GetImageSize($this->sourceFilename)) {
1810 $this->source_width = $this->getimagesizeinfo[0];
1811 $this->source_height = $this->getimagesizeinfo[1];
1813 $this->SetOrientationDependantWidthHeight();
1815 if (function_exists('exif_thumbnail') && ($this->getimagesizeinfo[2] == 2)) {
1816 // Extract EXIF info from JPEGs
1818 $this->exif_thumbnail_width = '';
1819 $this->exif_thumbnail_height = '';
1820 $this->exif_thumbnail_type = '';
1822 // The parameters width, height and imagetype are available since PHP v4.3.0
1823 if (phpthumb_functions::version_compare_replacement(phpversion(), '4.3.0', '>=')) {
1825 $this->exif_thumbnail_data = @exif_thumbnail($this->sourceFilename, $this->exif_thumbnail_width, $this->exif_thumbnail_height, $this->exif_thumbnail_type);
1829 // older versions of exif_thumbnail output an error message but NOT return false on failure
1831 $this->exif_thumbnail_data = exif_thumbnail($this->sourceFilename);
1832 $exit_thumbnail_error = ob_get_contents();
1834 if (!$exit_thumbnail_error && $this->exif_thumbnail_data) {
1836 if ($gdimg_exif_temp = $this->ImageCreateFromStringReplacement($this->exif_thumbnail_data, false)) {
1837 $this->exif_thumbnail_width = ImageSX($gdimg_exif_temp);
1838 $this->exif_thumbnail_height = ImageSY($gdimg_exif_temp);
1839 $this->exif_thumbnail_type = 2; // (2 == JPEG) before PHP v4.3.0 only JPEG format EXIF thumbnails are returned
1840 unset($gdimg_exif_temp);
1842 return $this->ErrorImage('Failed - $this->ImageCreateFromStringReplacement($this->exif_thumbnail_data) in '.__FILE__.' on line '.__LINE__);
1849 } elseif (!function_exists('exif_thumbnail')) {
1851 $this->DebugMessage('exif_thumbnail() does not exist, cannot extract EXIF thumbnail', __FILE__, __LINE__);
1856 $this->DebugMessage('EXIF thumbnail extraction: (size='.strlen($this->exif_thumbnail_data).'; type='.$this->exif_thumbnail_type.'; '.$this->exif_thumbnail_width.'x'.$this->exif_thumbnail_height.')', __FILE__, __LINE__);
1858 // see if EXIF thumbnail can be used directly with no processing
1859 if ($this->config_use_exif_thumbnail_for_speed && $this->exif_thumbnail_data) {
1862 $source_ar = $this->source_width / $this->source_height;
1863 $exif_ar = $this->exif_thumbnail_width / $this->exif_thumbnail_height;
1864 if (number_format($source_ar, 2) != number_format($exif_ar, 2)) {
1865 $this->DebugMessage('not using EXIF thumbnail because $source_ar != $exif_ar ('.$source_ar.' != '.$exif_ar.')', __FILE__, __LINE__);
1868 if ($this->w && ($this->w != $this->exif_thumbnail_width)) {
1869 $this->DebugMessage('not using EXIF thumbnail because $this->w != $this->exif_thumbnail_width ('.$this->w.' != '.$this->exif_thumbnail_width.')', __FILE__, __LINE__);
1872 if ($this->h && ($this->h != $this->exif_thumbnail_height)) {
1873 $this->DebugMessage('not using EXIF thumbnail because $this->h != $this->exif_thumbnail_height ('.$this->h.' != '.$this->exif_thumbnail_height.')', __FILE__, __LINE__);
1876 $CannotBeSetParameters = array('sx', 'sy', 'sh', 'sw', 'far', 'bg', 'bc', 'fltr', 'phpThumbDebug');
1877 foreach ($CannotBeSetParameters as $parameter) {
1878 if ($this->$parameter) {
1884 $this->DebugMessage('setting $this->gdimg_source = $this->ImageCreateFromStringReplacement($this->exif_thumbnail_data)', __FILE__, __LINE__);
1885 $this->gdimg_source = $this->ImageCreateFromStringReplacement($this->exif_thumbnail_data);
1886 $this->source_width = ImageSX($this->gdimg_source);
1887 $this->source_height = ImageSY($this->gdimg_source);
1894 $this->DebugMessage('GetImageSize("'.$this->sourceFilename.'") failed', __FILE__, __LINE__);
1898 if (($this->config_max_source_pixels > 0) && (($this->source_width * $this->source_height) > $this->config_max_source_pixels)) {
1900 // Source image is larger than would fit in available PHP memory.
1901 // If ImageMagick is installed, use it to generate the thumbnail.
1902 // Else, if an EXIF thumbnail is available, use that as the source image.
1903 // Otherwise, no choice but to fail with an error message
1904 $this->DebugMessage('image is '.$this->source_width.'x'.$this->source_height.' and therefore contains more pixels ('.($this->source_width * $this->source_height).') than $this->config_max_source_pixels setting ('.$this->config_max_source_pixels.')', __FILE__, __LINE__);
1905 if (!$this->config_prefer_imagemagick && $this->ImageMagickThumbnailToGD()) {
1906 // excellent, we have a thumbnailed source image
1915 function SetCacheFilename() {
1916 if (!is_null($this->cache_filename)) {
1917 $this->DebugMessage('$this->cache_filename already set, skipping SetCacheFilename()', __FILE__, __LINE__);
1920 $this->setOutputFormat();
1921 $this->setCacheDirectory();
1922 if (!$this->config_cache_directory) {
1923 $this->DebugMessage('SetCacheFilename() failed because $this->config_cache_directory is empty', __FILE__, __LINE__);
1927 if (!$this->sourceFilename && !$this->rawImageData && $this->src) {
1928 $this->sourceFilename = $this->ResolveFilenameToAbsolute($this->src);
1931 if ($this->config_cache_default_only_suffix && $this->sourceFilename) {
1932 // simplified cache filenames:
1933 // only use default parameters in phpThumb.config.php
1934 // substitute source filename into * in $this->config_cache_default_only_suffix
1935 // (eg: '*_thumb' becomes 'picture_thumb.jpg')
1936 if (strpos($this->config_cache_default_only_suffix, '*') === false) {
1937 $this->DebugMessage('aborting simplified caching filename because no * in "'.$this->config_cache_default_only_suffix.'"', __FILE__, __LINE__);
1939 preg_match('/(.+)(\.[a-z0-9]+)?$/iU', basename($this->sourceFilename), $matches);
1940 $this->cache_filename = $this->config_cache_directory.$this->osslash.str_replace('*', $matches[1], $this->config_cache_default_only_suffix).'.'.strtolower($this->thumbnailFormat);
1945 $this->cache_filename = $this->config_cache_directory.$this->osslash.'phpThumb_cache_'.@$_SERVER['SERVER_NAME'];
1947 $this->cache_filename .= '_new'.strtolower(md5($this->new));
1948 } elseif ($this->md5s) {
1949 // source image MD5 hash provided
1950 $this->cache_filename .= '_raw'.$this->md5s;
1951 } elseif (!$this->src && $this->rawImageData) {
1952 $this->cache_filename .= '_raw'.strtolower(md5($this->rawImageData));
1954 $this->cache_filename .= '_src'.strtolower(md5($this->sourceFilename));
1956 if (@$_SERVER['HTTP_REFERER'] && $this->config_cache_differentiate_offsite) {
1957 $parsed_url1 = @parse_url(@$_SERVER['HTTP_REFERER']);
1958 $parsed_url2 = @parse_url('http://'.@$_SERVER['HTTP_HOST']);
1959 if (@$parsed_url1['host'] && @$parsed_url2['host'] && ($parsed_url1['host'] != $parsed_url2['host'])) {
1960 // include refering domain only if it doesn't match the domain of the current server
1961 //$this->cache_filename .= '_ref'.strtolower(md5(@$parsed_url2['host']));
1962 $this->cache_filename .= '_offsite';
1966 $ParametersString = '';
1967 if ($this->fltr && is_array($this->fltr)) {
1968 $ParametersString .= '_fltr'.implode('_fltr', $this->fltr);
1970 $FilenameParameters1 = array('ar', 'bg', 'bc', 'far');
1971 foreach ($FilenameParameters1 as $key) {
1973 $ParametersString .= '_'.$key.$this->$key;
1976 $FilenameParameters2 = array('h', 'w', 'wl', 'wp', 'ws', 'h', 'hp', 'hs', 'sx', 'sy', 'sw', 'sh', 'xto', 'ra', 'iar', 'aoe', 'maxb');
1977 foreach ($FilenameParameters2 as $key) {
1979 $ParametersString .= '_'.$key.intval($this->$key);
1982 if ($this->thumbnailFormat == 'jpeg') {
1983 // only JPEG output has variable quality option
1984 $ParametersString .= '_q'.intval($this->thumbnailQuality);
1986 $this->DebugMessage('SetCacheFilename() _par set from md5('.$ParametersString.')', __FILE__, __LINE__);
1987 $this->cache_filename .= '_par'.strtolower(md5($ParametersString));
1990 // source image MD5 hash provided
1991 // do not source image modification date --
1992 // cached image will be used even if file was modified or removed
1993 } elseif (!$this->config_cache_source_filemtime_ignore_remote && eregi('^(f|ht)tps?://', $this->src)) {
1994 $this->cache_filename .= '_dat'.intval(phpthumb_functions::filedate_remote($this->src));
1995 } elseif (!$this->config_cache_source_filemtime_ignore_local && $this->src && !$this->rawImageData) {
1996 $this->cache_filename .= '_dat'.intval(@filemtime($this->sourceFilename));
1999 $this->cache_filename .= '.'.strtolower($this->thumbnailFormat);
2005 function SourceImageToGD() {
2006 if (is_resource($this->gdimg_source)) {
2007 $this->DebugMessage('skipping SourceImageToGD() because $this->gdimg_source is already a resource', __FILE__, __LINE__);
2010 $this->DebugMessage('starting SourceImageToGD()', __FILE__, __LINE__);
2012 if (!$this->config_use_exif_thumbnail_for_speed) {
2013 $this->DebugMessage('Not using EXIF thumbnail data because $this->config_use_exif_thumbnail_for_speed is FALSE', __FILE__, __LINE__);
2016 if (!$this->exif_thumbnail_data) {
2017 $this->DebugMessage('Not using EXIF thumbnail data because $this->exif_thumbnail_data is empty', __FILE__, __LINE__);
2020 if (($this->thumbnailCropX != 0) || ($this->thumbnailCropY != 0)) {
2021 $this->DebugMessage('Not using EXIF thumbnail data because source cropping is enabled ('.$this->thumbnailCropX.','.$this->thumbnailCropY.')', __FILE__, __LINE__);
2024 if (($this->w > $this->exif_thumbnail_width) || ($this->h > $this->exif_thumbnail_height)) {
2025 $this->DebugMessage('Not using EXIF thumbnail data because EXIF thumbnail is too small ('.$this->exif_thumbnail_width.'x'.$this->exif_thumbnail_height.' vs '.$this->w.'x'.$this->h.')', __FILE__, __LINE__);
2028 $source_ar = $this->source_width / $this->source_height;
2029 $exif_ar = $this->exif_thumbnail_width / $this->exif_thumbnail_height;
2030 if (number_format($source_ar, 2) != number_format($exif_ar, 2)) {
2031 $this->DebugMessage('not using EXIF thumbnail because $source_ar != $exif_ar ('.$source_ar.' != '.$exif_ar.')', __FILE__, __LINE__);
2034 // EXIF thumbnail exists, and is equal to or larger than destination thumbnail, and will be use as source image
2035 $this->DebugMessage('Trying to use EXIF thumbnail as source image', __FILE__, __LINE__);
2037 if ($gdimg_exif_temp = $this->ImageCreateFromStringReplacement($this->exif_thumbnail_data, false)) {
2039 $this->DebugMessage('Successfully using EXIF thumbnail as source image', __FILE__, __LINE__);
2041 $this->gdimg_source = $gdimg_exif_temp;
2042 $this->source_width = $this->exif_thumbnail_width;
2043 $this->source_height = $this->exif_thumbnail_height;
2044 $this->thumbnailCropW = $this->source_width;
2045 $this->thumbnailCropH = $this->source_height;
2049 $this->DebugMessage('$this->ImageCreateFromStringReplacement($this->exif_thumbnail_data, false) failed', __FILE__, __LINE__);
2054 if (!$this->gdimg_source) {
2055 // try to create GD image source directly via GD, if possible,
2056 // rather than buffering to memory and creating with ImageCreateFromString
2057 $ImageCreateWasAttempted = false;
2059 $ImageCreateFromFunction = array(
2060 1 => 'ImageCreateFromGIF',
2061 2 => 'ImageCreateFromJPEG',
2062 3 => 'ImageCreateFromPNG',
2063 15 => 'ImageCreateFromWBMP',
2065 switch (@$this->getimagesizeinfo[2]) {
2070 if ($this->md5s && ($this->md5s != phpthumb_functions::md5_file_safe($this->sourceFilename))) {
2071 return $this->ErrorImage('$this->md5s != md5($this->rawImageData)'."\n".'"'.$this->md5s.'" != '."\n".'"'.phpthumb_functions::md5_file_safe($this->sourceFilename).'"');
2073 $ImageCreateFromFunctionName = $ImageCreateFromFunction[$this->getimagesizeinfo[2]];
2074 if (function_exists($ImageCreateFromFunctionName)) {
2075 $this->DebugMessage('Calling '.$ImageCreateFromFunctionName.'('.$this->sourceFilename.')', __FILE__, __LINE__);
2076 $ImageCreateWasAttempted = true;
2077 $this->gdimg_source = @$ImageCreateFromFunctionName($this->sourceFilename);
2078 switch ($this->getimagesizeinfo[2]) {
2081 // GIF or PNG input file may have transparency
2082 $this->is_alpha = true;
2086 $this->DebugMessage('NOT calling '.$ImageCreateFromFunctionName.'('.$this->sourceFilename.') because !function_exists('.$ImageCreateFromFunctionName.')', __FILE__, __LINE__);
2093 case 7: // TIFF (LE)
2094 case 8: // TIFF (BE)
2102 $this->DebugMessage('No built-in image creation function for image type "'.@$this->getimagesizeinfo[2].'" ($this->getimagesizeinfo[2])', __FILE__, __LINE__);
2106 // no source file, source image was probably set by setSourceData()
2110 $this->DebugMessage('Unknown value for $this->getimagesizeinfo[2]: "'.@$this->getimagesizeinfo[2].'"', __FILE__, __LINE__);
2113 if (!$this->gdimg_source) {
2114 // cannot create from filename, attempt to create source image with ImageCreateFromString, if possible
2115 if ($ImageCreateWasAttempted) {
2116 $this->DebugMessage(@$ImageCreateFromFunctionName.'() was attempted but FAILED', __FILE__, __LINE__);
2118 if (!$this->rawImageData) {
2119 $this->DebugMessage('Populating $this->rawImageData and attempting ImageCreateFromStringReplacement()', __FILE__, __LINE__);
2120 if ($fp = @fopen($this->sourceFilename, 'rb')) {
2122 $this->rawImageData = '';
2123 $filesize = filesize($this->sourceFilename);
2125 $blockreads = ceil($filesize / $blocksize);
2126 for ($i = 0; $i < $blockreads; $i++) {
2127 $this->rawImageData .= fread($fp, $blocksize);
2132 return $this->ErrorImage('cannot fopen("'.$this->sourceFilename.'") on line '.__LINE__.' of '.__FILE__);
2135 if ($this->md5s && ($this->md5s != md5($this->rawImageData))) {
2136 return $this->ErrorImage('$this->md5s != md5($this->rawImageData)'."\n".'"'.$this->md5s.'" != '."\n".'"'.md5($this->rawImageData).'"');
2138 $this->gdimg_source = $this->ImageCreateFromStringReplacement($this->rawImageData, true);
2141 if (!$this->gdimg_source) {
2142 $this->DebugMessage('$this->gdimg_source is still empty', __FILE__, __LINE__);
2144 if ($this->ImageMagickThumbnailToGD()) {
2146 // excellent, we have a thumbnailed source image
2147 $this->DebugMessage('ImageMagickThumbnailToGD() succeeded', __FILE__, __LINE__);
2151 $this->DebugMessage('ImageMagickThumbnailToGD() failed', __FILE__, __LINE__);
2154 $gd_info = phpthumb_functions::gd_info();
2155 $GDreadSupport = false;
2156 switch (substr($this->rawImageData, 0, 3)) {
2158 $imageHeader = 'Content-Type: image/gif';
2159 $GDreadSupport = (bool) @$gd_info['GIF Read Support'];
2161 case "\xFF\xD8\xFF":
2162 $imageHeader = 'Content-Type: image/jpeg';
2163 $GDreadSupport = (bool) @$gd_info['JPG Support'];
2166 $imageHeader = 'Content-Type: image/png';
2167 $GDreadSupport = (bool) @$gd_info['PNG Support'];
2171 // cannot create image for whatever reason (maybe ImageCreateFromJPEG et al are not available?)
2172 // and ImageMagick is not available either, no choice but to output original (not resized/modified) data and exit
2173 if ($this->config_error_die_on_source_failure && !$this->phpThumbDebug) {
2174 $this->ErrorImage('All attempts to create GD image source failed ('.($GDreadSupport ? 'source image probably corrupt' : 'GD does not have read support for "'.$imageHeader.'"').'), cannot generate thumbnail');
2176 //$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__);
2177 //if (!$this->phpThumbDebug) {
2178 // header($imageHeader);
2179 // echo $this->rawImageData;
2186 switch (substr($this->rawImageData, 0, 2)) {
2189 if (!@include_once(dirname(__FILE__).'/phpthumb.bmp.php')) {
2191 if ($this->phpThumbDebug) {
2192 $this->DebugMessage('include_once('.dirname(__FILE__).'/phpthumb.bmp.php) failed', __FILE__, __LINE__);
2195 return $this->ErrorImage('include_once('.dirname(__FILE__).'/phpthumb.bmp.php) failed');
2198 $phpthumb_bmp = new phpthumb_bmp();
2199 if ($this->gdimg_source = $phpthumb_bmp->phpthumb_bmp2gd($this->rawImageData, (phpthumb_functions::gd_version() >= 2.0))) {
2200 $this->DebugMessage('$phpthumb_bmp->phpthumb_bmp2gd() succeeded', __FILE__, __LINE__);
2202 } elseif ($this->phpThumbDebug) {
2203 $this->DebugMessage('phpthumb_bmp2db failed', __FILE__, __LINE__);
2206 return $this->ErrorImage('ImageMagick is unavailable and phpThumb() does not support BMP source images without it');
2211 switch (substr($this->rawImageData, 0, 4)) {
2212 case 'II'."\x2A\x00":
2213 case 'MM'."\x00\x2A":
2214 if ($this->phpThumbDebug) {
2215 $this->DebugMessage('ImageMagick is unavailable and phpThumb() does not support TIFF source images without it', __FILE__, __LINE__);
2218 return $this->ErrorImage('ImageMagick is unavailable and phpThumb() does not support TIFF source images without it');
2221 case "\xD7\xCD\xC6\x9A":
2222 if ($this->phpThumbDebug) {
2223 $this->DebugMessage('ImageMagick is unavailable and phpThumb() does not support WMF source images without it', __FILE__, __LINE__);
2226 return $this->ErrorImage('ImageMagick is unavailable and phpThumb() does not support WMF source images without it');
2230 if (!$this->gdimg_source) {
2231 if ($this->phpThumbDebug) {
2232 $this->DebugMessage('Unknown image type identified by "'.substr($this->rawImageData, 0, 4).'" ('.phpthumb_functions::HexCharDisplay(substr($this->rawImageData, 0, 4)).') in SourceImageToGD()', __FILE__, __LINE__);
2235 return $this->ErrorImage('Unknown image type identified by "'.substr($this->rawImageData, 0, 4).'" ('.phpthumb_functions::HexCharDisplay(substr($this->rawImageData, 0, 4)).') in SourceImageToGD()');
2242 if (!$this->gdimg_source) {
2243 if ($gdimg_exif_temp = $this->ImageCreateFromStringReplacement($this->exif_thumbnail_data, false)) {
2244 $this->DebugMessage('All other attempts failed, but successfully using EXIF thumbnail as source image', __FILE__, __LINE__);
2245 $this->gdimg_source = $gdimg_exif_temp;
2246 // override allow-enlarging setting if EXIF thumbnail is the only source available
2247 // otherwise thumbnails larger than the EXIF thumbnail will be created at EXIF size
2253 $this->source_width = ImageSX($this->gdimg_source);
2254 $this->source_height = ImageSY($this->gdimg_source);
2259 function phpThumbDebugVarDump($var) {
2260 if (is_null($var)) {
2262 } elseif (is_bool($var)) {
2263 return ($var ? 'TRUE' : 'FALSE');
2264 } elseif (is_string($var)) {
2265 return 'string('.strlen($var).')'.str_repeat(' ', max(0, 3 - strlen(strlen($var)))).' "'.$var.'"';
2266 } elseif (is_int($var)) {
2267 return 'integer '.$var;
2268 } elseif (is_float($var)) {
2269 return 'float '.$var;
2270 } elseif (is_array($var)) {
2273 $vardumpoutput = ob_get_contents();
2275 return strtr($vardumpoutput, "\n\r\t", ' ');
2277 return gettype($var);
2280 function phpThumbDebug() {
2281 if ($this->config_disable_debug) {
2282 return $this->ErrorImage('phpThumbDebug disabled');
2285 $FunctionsExistance = array('exif_thumbnail', 'gd_info', 'image_type_to_mime_type', 'ImageCopyResampled', 'ImageCopyResized', 'ImageCreate', 'ImageCreateFromString', 'ImageCreateTrueColor', 'ImageIsTrueColor', 'ImageRotate', 'ImageTypes', 'version_compare', 'ImageCreateFromGIF', 'ImageCreateFromJPEG', 'ImageCreateFromPNG', 'ImageCreateFromWBMP', 'ImageCreateFromXBM', 'ImageCreateFromXPM', 'ImageCreateFromString', 'ImageCreateFromGD', 'ImageCreateFromGD2', 'ImageCreateFromGD2Part', 'ImageJPEG', 'ImageGIF', 'ImagePNG', 'ImageWBMP');
2286 $ParameterNames = array('src', 'new', 'w', 'h', 'f', 'q', 'sx', 'sy', 'sw', 'sh', 'far', 'bg', 'bc', 'file', 'goto', 'err', 'xto', 'ra', 'ar', 'aoe', 'iar', 'maxb');
2287 $OtherVariableNames = array('phpThumbDebug', 'thumbnailQuality', 'thumbnailFormat', 'gdimg_output', 'gdimg_source', 'sourceFilename', 'source_width', 'source_height', 'thumbnailCropX', 'thumbnailCropY', 'thumbnailCropW', 'thumbnailCropH', 'exif_thumbnail_width', 'exif_thumbnail_height', 'exif_thumbnail_type', 'thumbnail_width', 'thumbnail_height', 'thumbnail_image_width', 'thumbnail_image_height');
2289 $DebugOutput = array();
2290 $DebugOutput[] = 'phpThumb() version = '.$this->phpthumb_version;
2291 $DebugOutput[] = 'phpversion() = '.@phpversion();
2292 $DebugOutput[] = 'PHP_OS = '.PHP_OS;
2293 $DebugOutput[] = '__FILE__ = '.__FILE__;
2294 $DebugOutput[] = 'realpath(.) = '.@realpath('.');
2295 $DebugOutput[] = '$_SERVER[PHP_SELF] = '.@$_SERVER['PHP_SELF'];
2296 $DebugOutput[] = '$_SERVER[HTTP_REFERER] = '.@$_SERVER['HTTP_REFERER'];
2297 $DebugOutput[] = '$_SERVER[QUERY_STRING] = '.@$_SERVER['QUERY_STRING'];
2298 $DebugOutput[] = '$_SERVER[PATH_INFO] = '.@$_SERVER['PATH_INFO'];
2299 $DebugOutput[] = '$_SERVER[DOCUMENT_ROOT] = '.@$_SERVER['DOCUMENT_ROOT'];
2300 $DebugOutput[] = 'getenv(DOCUMENT_ROOT) = '.@getenv('DOCUMENT_ROOT');
2301 $DebugOutput[] = '';
2303 $DebugOutput[] = 'get_magic_quotes_gpc() = '.$this->phpThumbDebugVarDump(@get_magic_quotes_gpc());
2304 $DebugOutput[] = 'get_magic_quotes_runtime() = '.$this->phpThumbDebugVarDump(@get_magic_quotes_runtime());
2305 $DebugOutput[] = 'error_reporting() = '.$this->phpThumbDebugVarDump(error_reporting());
2306 $DebugOutput[] = 'ini_get(error_reporting) = '.$this->phpThumbDebugVarDump(@ini_get('error_reporting'));
2307 $DebugOutput[] = 'ini_get(display_errors) = '.$this->phpThumbDebugVarDump(@ini_get('display_errors'));
2308 $DebugOutput[] = 'ini_get(allow_url_fopen) = '.$this->phpThumbDebugVarDump(@ini_get('allow_url_fopen'));
2309 $DebugOutput[] = 'ini_get(disable_functions) = '.$this->phpThumbDebugVarDump(@ini_get('disable_functions'));
2310 $DebugOutput[] = 'ini_get(safe_mode) = '.$this->phpThumbDebugVarDump(@ini_get('safe_mode'));
2311 $DebugOutput[] = 'ini_get(open_basedir) = '.$this->phpThumbDebugVarDump(@ini_get('open_basedir'));
2312 $DebugOutput[] = 'ini_get(memory_limit) = '.$this->phpThumbDebugVarDump(@ini_get('memory_limit'));
2313 $DebugOutput[] = 'ini_get(max_execution_time) = '.$this->phpThumbDebugVarDump(@ini_get('max_execution_time'));
2314 $DebugOutput[] = 'get_cfg_var(memory_limit) = '.$this->phpThumbDebugVarDump(@get_cfg_var('memory_limit'));
2315 $DebugOutput[] = 'memory_get_usage() = '.(function_exists('memory_get_usage') ? $this->phpThumbDebugVarDump(@memory_get_usage()) : 'n/a');
2316 $DebugOutput[] = '';
2318 $DebugOutput[] = '$this->config_prefer_imagemagick = '.$this->phpThumbDebugVarDump($this->config_prefer_imagemagick);
2319 $DebugOutput[] = '$this->config_imagemagick_path = '.$this->phpThumbDebugVarDump($this->config_imagemagick_path);
2320 $DebugOutput[] = 'SafeExec(which convert) = '.trim(phpthumb_functions::SafeExec('which convert'));
2321 $IMpathUsed = ($this->config_imagemagick_path ? $this->config_imagemagick_path : trim(phpthumb_functions::SafeExec('which convert')));
2322 $DebugOutput[] = '[actual ImageMagick path used] = '.$this->phpThumbDebugVarDump($IMpathUsed);
2323 $DebugOutput[] = 'file_exists([actual ImageMagick path used]) = '.$this->phpThumbDebugVarDump(file_exists($IMpathUsed));
2324 $DebugOutput[] = 'ImageMagickVersion() = '.$this->ImageMagickVersion();
2325 $DebugOutput[] = '';
2327 $DebugOutput[] = '$this->config_cache_directory = '.$this->phpThumbDebugVarDump($this->config_cache_directory);
2328 $DebugOutput[] = '$this->config_cache_disable_warning = '.$this->phpThumbDebugVarDump($this->config_cache_disable_warning);
2329 $DebugOutput[] = '$this->config_cache_maxage = '.$this->phpThumbDebugVarDump($this->config_cache_maxage);
2330 $DebugOutput[] = '$this->config_cache_maxsize = '.$this->phpThumbDebugVarDump($this->config_cache_maxsize);
2331 $DebugOutput[] = '$this->config_cache_maxfiles = '.$this->phpThumbDebugVarDump($this->config_cache_maxfiles);
2332 $DebugOutput[] = '$this->cache_filename = '.$this->phpThumbDebugVarDump($this->cache_filename);
2333 $DebugOutput[] = 'is_readable($this->config_cache_directory) = '.$this->phpThumbDebugVarDump(is_readable($this->config_cache_directory));
2334 $DebugOutput[] = 'is_writable($this->config_cache_directory) = '.$this->phpThumbDebugVarDump(is_writable($this->config_cache_directory));
2335 $DebugOutput[] = 'is_readable($this->cache_filename) = '.$this->phpThumbDebugVarDump(is_readable($this->cache_filename));
2336 $DebugOutput[] = 'is_writable($this->cache_filename) = '.(file_exists($this->cache_filename) ? $this->phpThumbDebugVarDump(is_writable($this->cache_filename)) : 'n/a');
2337 $DebugOutput[] = '';
2339 $DebugOutput[] = '$this->config_document_root = '.$this->phpThumbDebugVarDump($this->config_document_root);
2340 $DebugOutput[] = '$this->config_temp_directory = '.$this->phpThumbDebugVarDump($this->config_temp_directory);
2341 $DebugOutput[] = '';
2342 $DebugOutput[] = '$this->config_output_format = '.$this->phpThumbDebugVarDump($this->config_output_format);
2343 $DebugOutput[] = '$this->config_output_maxwidth = '.$this->phpThumbDebugVarDump($this->config_output_maxwidth);
2344 $DebugOutput[] = '$this->config_output_maxheight = '.$this->phpThumbDebugVarDump($this->config_output_maxheight);
2345 $DebugOutput[] = '';
2346 $DebugOutput[] = '$this->config_error_message_image_default = '.$this->phpThumbDebugVarDump($this->config_error_message_image_default);
2347 $DebugOutput[] = '$this->config_error_bgcolor = '.$this->phpThumbDebugVarDump($this->config_error_bgcolor);
2348 $DebugOutput[] = '$this->config_error_textcolor = '.$this->phpThumbDebugVarDump($this->config_error_textcolor);
2349 $DebugOutput[] = '$this->config_error_fontsize = '.$this->phpThumbDebugVarDump($this->config_error_fontsize);
2350 $DebugOutput[] = '$this->config_error_die_on_error = '.$this->phpThumbDebugVarDump($this->config_error_die_on_error);
2351 $DebugOutput[] = '$this->config_error_silent_die_on_error = '.$this->phpThumbDebugVarDump($this->config_error_silent_die_on_error);
2352 $DebugOutput[] = '$this->config_error_die_on_source_failure = '.$this->phpThumbDebugVarDump($this->config_error_die_on_source_failure);
2353 $DebugOutput[] = '';
2354 $DebugOutput[] = '$this->config_nohotlink_enabled = '.$this->phpThumbDebugVarDump($this->config_nohotlink_enabled);
2355 $DebugOutput[] = '$this->config_nohotlink_valid_domains = '.$this->phpThumbDebugVarDump($this->config_nohotlink_valid_domains);
2356 $DebugOutput[] = '$this->config_nohotlink_erase_image = '.$this->phpThumbDebugVarDump($this->config_nohotlink_erase_image);
2357 $DebugOutput[] = '$this->config_nohotlink_text_message = '.$this->phpThumbDebugVarDump($this->config_nohotlink_text_message);
2358 $DebugOutput[] = '';
2359 $DebugOutput[] = '$this->config_nooffsitelink_enabled = '.$this->phpThumbDebugVarDump($this->config_nooffsitelink_enabled);
2360 $DebugOutput[] = '$this->config_nooffsitelink_valid_domains = '.$this->phpThumbDebugVarDump($this->config_nooffsitelink_valid_domains);
2361 $DebugOutput[] = '$this->config_nooffsitelink_require_refer = '.$this->phpThumbDebugVarDump($this->config_nooffsitelink_require_refer);
2362 $DebugOutput[] = '$this->config_nooffsitelink_erase_image = '.$this->phpThumbDebugVarDump($this->config_nooffsitelink_erase_image);
2363 $DebugOutput[] = '$this->config_nooffsitelink_text_message = '.$this->phpThumbDebugVarDump($this->config_nooffsitelink_text_message);
2364 $DebugOutput[] = '';
2365 $DebugOutput[] = '$this->config_high_security_enabled = '.$this->phpThumbDebugVarDump($this->config_high_security_enabled);
2366 $DebugOutput[] = '$this->config_allow_src_above_docroot = '.$this->phpThumbDebugVarDump($this->config_allow_src_above_docroot);
2367 $DebugOutput[] = '$this->config_allow_src_above_phpthumb = '.$this->phpThumbDebugVarDump($this->config_allow_src_above_phpthumb);
2368 $DebugOutput[] = '$this->config_allow_parameter_file = '.$this->phpThumbDebugVarDump($this->config_allow_parameter_file);
2369 $DebugOutput[] = '$this->config_allow_parameter_goto = '.$this->phpThumbDebugVarDump($this->config_allow_parameter_goto);
2370 $DebugOutput[] = '';
2371 $DebugOutput[] = '$this->config_max_source_pixels = '.$this->phpThumbDebugVarDump($this->config_max_source_pixels);
2372 $DebugOutput[] = '$this->config_use_exif_thumbnail_for_speed = '.$this->phpThumbDebugVarDump($this->config_use_exif_thumbnail_for_speed);
2373 $DebugOutput[] = '$this->config_border_hexcolor = '.$this->phpThumbDebugVarDump($this->config_border_hexcolor);
2374 $DebugOutput[] = '$this->config_background_hexcolor = '.$this->phpThumbDebugVarDump($this->config_background_hexcolor);
2375 $DebugOutput[] = '$this->config_ttf_directory = '.$this->phpThumbDebugVarDump($this->config_ttf_directory);
2376 $DebugOutput[] = '';
2378 foreach ($OtherVariableNames as $varname) {
2379 $value = $this->$varname;
2380 $DebugOutput[] = '$this->'.str_pad($varname, 27, ' ', STR_PAD_RIGHT).' = '.$this->phpThumbDebugVarDump($value);
2382 $DebugOutput[] = 'strlen($this->rawImageData) = '.strlen(@$this->rawImageData);
2383 $DebugOutput[] = 'strlen($this->exif_thumbnail_data) = '.strlen(@$this->exif_thumbnail_data);
2384 $DebugOutput[] = '';
2386 foreach ($ParameterNames as $varname) {
2387 $value = $this->$varname;
2388 $DebugOutput[] = '$this->'.str_pad($varname, 4, ' ', STR_PAD_RIGHT).' = '.$this->phpThumbDebugVarDump($value);
2390 $DebugOutput[] = '';
2392 foreach ($FunctionsExistance as $functionname) {
2393 $DebugOutput[] = 'builtin_function_exists('.$functionname.')'.str_repeat(' ', 23 - strlen($functionname)).' = '.$this->phpThumbDebugVarDump(phpthumb_functions::builtin_function_exists($functionname));
2395 $DebugOutput[] = '';
2397 $gd_info = phpthumb_functions::gd_info();
2398 foreach ($gd_info as $key => $value) {
2399 $DebugOutput[] = 'gd_info.'.str_pad($key, 34, ' ', STR_PAD_RIGHT).' = '.$this->phpThumbDebugVarDump($value);
2401 $DebugOutput[] = '';
2403 $exif_info = phpthumb_functions::exif_info();
2404 foreach ($exif_info as $key => $value) {
2405 $DebugOutput[] = 'exif_info.'.str_pad($key, 26, ' ', STR_PAD_RIGHT).' = '.$this->phpThumbDebugVarDump($value);
2407 $DebugOutput[] = '';
2409 if ($ApacheLookupURIarray = phpthumb_functions::ApacheLookupURIarray(dirname(@$_SERVER['PHP_SELF']))) {
2410 foreach ($ApacheLookupURIarray as $key => $value) {
2411 $DebugOutput[] = 'ApacheLookupURIarray.'.str_pad($key, 15, ' ', STR_PAD_RIGHT).' = '.$this->phpThumbDebugVarDump($value);
2414 $DebugOutput[] = 'ApacheLookupURIarray() -- FAILED';
2416 $DebugOutput[] = '';
2418 if (isset($_GET) && is_array($_GET)) {
2419 foreach ($_GET as $key => $value) {
2420 $DebugOutput[] = '$_GET['.$key.']'.str_repeat(' ', 30 - strlen($key)).'= '.$this->phpThumbDebugVarDump($value);
2423 if (isset($_POST) && is_array($_POST)) {
2424 foreach ($_POST as $key => $value) {
2425 $DebugOutput[] = '$_POST['.$key.']'.str_repeat(' ', 29 - strlen($key)).'= '.$this->phpThumbDebugVarDump($value);
2428 $DebugOutput[] = '';
2430 $DebugOutput[] = '$this->debugmessages:';
2431 foreach ($this->debugmessages as $errorstring) {
2432 $DebugOutput[] = ' * '.$errorstring;
2434 $DebugOutput[] = '';
2436 $DebugOutput[] = '$this->debugtiming:';
2437 foreach ($this->debugtiming as $timestamp => $timingstring) {
2438 $DebugOutput[] = ' * '.$timestamp.' '.$timingstring;
2440 $DebugOutput[] = ' * Total processing time: '.number_format(max(array_keys($this->debugtiming)) - min(array_keys($this->debugtiming)), 6);
2442 return $this->ErrorImage(implode("\n", $DebugOutput), 700, 500);
2445 function ErrorImage($text, $width=0, $height=0) {
2446 $width = ($width ? $width : $this->config_error_image_width);
2447 $height = ($height ? $height : $this->config_error_image_height);
2449 $text = 'phpThumb() v'.$this->phpthumb_version."\n\n".$text;
2450 if ($this->config_disable_debug) {
2451 $text = 'Error messages disabled';
2454 $this->DebugMessage($text);
2455 if (!$this->config_error_die_on_error) {
2456 $this->fatalerror = $text;
2459 if ($this->config_error_silent_die_on_error) {
2462 if ($this->err || $this->config_error_message_image_default) {
2463 // Show generic custom error image instead of error message
2464 // for use on production sites where you don't want debug messages
2465 if ($this->err == 'showerror') {
2466 // fall through and actually show error message even if default error image is set
2468 header('Location: '.($this->err ? $this->err : $this->config_error_message_image_default));
2472 if (@$this->f == 'text') {
2473 // bypass all GD functions and output text error message
2474 die('<pre>'.$text.'</pre>');
2477 $FontWidth = ImageFontWidth($this->config_error_fontsize);
2478 $FontHeight = ImageFontHeight($this->config_error_fontsize);
2480 $LinesOfText = explode("\n", @wordwrap($text, floor($width / $FontWidth), "\n", true));
2481 $height = max($height, count($LinesOfText) * $FontHeight);
2485 if (phpthumb_functions::version_compare_replacement(phpversion(), '4.3.0', '>=') && headers_sent($headers_file, $headers_line)) {
2487 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>';
2489 } elseif (headers_sent()) {
2491 echo "\n".'**Headers already sent, dumping error message as text:**<br><pre>'."\n\n".$text."\n".'</pre>';
2493 } elseif ($gdimg_error = ImageCreate($width, $height)) {
2495 $background_color = phpthumb_functions::ImageHexColorAllocate($gdimg_error, $this->config_error_bgcolor, true);
2496 $text_color = phpthumb_functions::ImageHexColorAllocate($gdimg_error, $this->config_error_textcolor, true);
2497 ImageFilledRectangle($gdimg_error, 0, 0, $width, $height, $background_color);
2499 foreach ($LinesOfText as $line) {
2500 ImageString($gdimg_error, $this->config_error_fontsize, 2, $lineYoffset, $line, $text_color);
2501 $lineYoffset += $FontHeight;
2503 if (function_exists('ImageTypes')) {
2504 $imagetypes = ImageTypes();
2505 if ($imagetypes & IMG_PNG) {
2506 header('Content-Type: image/png');
2507 ImagePNG($gdimg_error);
2508 } elseif ($imagetypes & IMG_GIF) {
2509 header('Content-Type: image/gif');
2510 ImageGIF($gdimg_error);
2511 } elseif ($imagetypes & IMG_JPG) {
2512 header('Content-Type: image/jpeg');
2513 ImageJPEG($gdimg_error);
2514 } elseif ($imagetypes & IMG_WBMP) {
2515 header('Content-Type: image/wbmp');
2516 ImageWBMP($gdimg_error);
2519 ImageDestroy($gdimg_error);
2522 if (!headers_sent()) {
2523 echo "\n".'**Failed to send graphical error image, dumping error message as text:**<br>'."\n\n".$text;
2529 function ImageCreateFromStringReplacement(&$RawImageData, $DieOnErrors=false) {
2530 // there are serious bugs in the non-bundled versions of GD which may cause
2531 // PHP to segfault when calling ImageCreateFromString() - avoid if at all possible
2532 // when not using a bundled version of GD2
2533 if (phpthumb_functions::gd_is_bundled()) {
2534 return @ImageCreateFromString($RawImageData);
2537 switch (substr($RawImageData, 0, 3)) {
2539 $ICFSreplacementFunctionName = 'ImageCreateFromGIF';
2541 case "\xFF\xD8\xFF":
2542 $ICFSreplacementFunctionName = 'ImageCreateFromJPEG';
2545 $ICFSreplacementFunctionName = 'ImageCreateFromPNG';
2551 if ($tempnam = $this->phpThumb_tempnam()) {
2552 if ($fp_tempnam = @fopen($tempnam, 'wb')) {
2553 fwrite($fp_tempnam, $RawImageData);
2554 fclose($fp_tempnam);
2555 if (($ICFSreplacementFunctionName == 'ImageCreateFromGIF') && !function_exists($ICFSreplacementFunctionName)) {
2557 // Need to create from GIF file, but ImageCreateFromGIF does not exist
2559 if (!@include_once(dirname(__FILE__).'/phpthumb.gif.php')) {
2560 $ErrorMessage = 'Failed to include required file "'.dirname(__FILE__).'/phpthumb.gif.php" in '.__FILE__.' on line '.__LINE__;
2563 // gif_loadFileToGDimageResource() cannot read from raw data, write to file first
2564 if ($tempfilename = $this->phpThumb_tempnam()) {
2565 if ($fp_tempfile = @fopen($tempfilename, 'wb')) {
2566 fwrite($fp_tempfile, $RawImageData);
2567 fclose($fp_tempfile);
2568 $gdimg_source = gif_loadFileToGDimageResource($tempfilename);
2569 unlink($tempfilename);
2570 return $gdimg_source;
2573 $ErrorMessage = 'Failed to open tempfile in '.__FILE__.' on line '.__LINE__;
2576 $ErrorMessage = 'Failed to open generate tempfile name in '.__FILE__.' on line '.__LINE__;
2579 } elseif (function_exists($ICFSreplacementFunctionName) && ($gdimg_source = @$ICFSreplacementFunctionName($tempnam))) {
2583 return $gdimg_source;
2585 } else { // GD functions not available
2587 // base64-encoded error image in GIF format
2588 header('Content-Type: image/gif');
2589 echo base64_decode('R0lGODlhIAAgALMAAAAAABQUFCQkJDY2NkZGRldXV2ZmZnJycoaGhpSUlKWlpbe3t8XFxdXV1eTk5P7+/iwAAAAAIAAgAAAE/vDJSau9WILtTAACUinDNijZtAHfCojS4W5H+qxD8xibIDE9h0OwWaRWDIljJSkUJYsN4bihMB8th3IToAKs1VtYM75cyV8sZ8vygtOE5yMKmGbO4jRdICQCjHdlZzwzNW4qZSQmKDaNjhUMBX4BBAlmMywFSRWEmAI6b5gAlhNxokGhooAIK5o/pi9vEw4Lfj4OLTAUpj6IabMtCwlSFw0DCKBoFqwAB04AjI54PyZ+yY3TD0ss2YcVmN/gvpcu4TOyFivWqYJlbAHPpOntvxNAACcmGHjZzAZqzSzcq5fNjxFmAFw9iFRunD1epU6tsIPmFCAJnWYE0FURk7wJDA0MTKpEzoWAAskiAAA7');
2594 $ErrorMessage = 'Failed to fopen('.$tempnam.', "wb") in '.__FILE__.' on line '.__LINE__."\n".'You may need to set $PHPTHUMB_CONFIG[temp_directory] in phpThumb.config.php';
2598 $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';
2600 if ($DieOnErrors && $ErrorMessage) {
2601 return $this->ErrorImage($ErrorMessage);
2606 function phpThumb_tempnam() {
2607 return tempnam($this->config_temp_directory, 'pThumb');
2610 function DebugMessage($message, $file='', $line='') {
2611 $this->debugmessages[] = $message.($file ? ' in file "'.(basename($file) ? basename($file) : $file).'"' : '').($line ? ' on line '.$line : '');
2615 function DebugTimingMessage($message, $file='', $line='', $timestamp=0) {
2617 $timestamp = array_sum(explode(' ', microtime()));
2619 $this->debugtiming[number_format($timestamp, 6, '.', '')] = ': '.$message.($file ? ' in file "'.(basename($file) ? basename($file) : $file).'"' : '').($line ? ' on line '.$line : '');