Source for file phpthumb.class.php
Documentation is available at phpthumb.class.php
//////////////////////////////////////////////////////////////
/// phpThumb() by James Heinrich <info@silisoftware.com> //
// available at http://phpthumb.sourceforge.net ///
//////////////////////////////////////////////////////////////
// See: phpthumb.readme.txt for usage instructions //
//////////////////////////////////////////////////////////////
if (!include_once(dirname(__FILE__ ). '/phpthumb.functions.php')) {
die('failed to include_once("'. realpath(dirname(__FILE__ ). '/phpthumb.functions.php'). '")');
// START PARAMETERS (for object mode and phpThumb.php)
// See phpthumb.readme.txt for descriptions of what each of these values are
var $src = null; // SouRCe filename
var $new = null; // NEW image (phpThumb.php only)
var $wp = null; // Width (Portrait Images Only)
var $hp = null; // Height (Portrait Images Only)
var $wl = null; // Width (Landscape Images Only)
var $hl = null; // Height (Landscape Images Only)
var $ws = null; // Width (Square Images Only)
var $hs = null; // Height (Square Images Only)
var $f = null; // output image Format
var $q = 75; // jpeg output Quality
var $sx = null; // Source crop top-left X position
var $sy = null; // Source crop top-left Y position
var $sw = null; // Source crop Width
var $sh = null; // Source crop Height
var $zc = null; // Zoom Crop
var $bc = null; // Border Color
var $bg = null; // BackGround color
var $fltr = array(); // FiLTeRs
var $goto = null; // GO TO url after processing
var $err = null; // default ERRor image filename
var $xto = null; // extract eXif Thumbnail Only
var $ra = null; // Rotate by Angle
var $ar = null; // Auto Rotate
var $aoe = null; // Allow Output Enlargement
var $far = null; // Fixed Aspect Ratio
var $iar = null; // Ignore Aspect Ratio
var $maxb = null; // MAXimum Bytes
var $down = null; // DOWNload thumbnail filename
var $md5s = null; // MD5 hash of Source image
var $sfn = 0; // Source Frame Number
var $dpi = 150; // Dots Per Inch for vector source formats
var $sia = null; // Save Image As filename
var $file = null; // >>>deprecated, DO NOT USE, will be removed in future versions<<<
// START CONFIGURATION OPTIONS (for object mode only)
// See phpThumb.config.php for descriptions of what each of these settings do
// * Directory Configuration
// * Default output configuration:
// * Error message configuration
// * Anti-Hotlink Configuration:
// * Off-server Linking Configuration:
// * Border & Background default colors
var $config_http_user_agent = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.12) Gecko/20050915 Firefox/1.0.7';
// END CONFIGURATION OPTIONS
// public: error messages (read-only; persistant)
// private: (should not be modified directly)
//////////////////////////////////////////////////////////////////////
if ($php_sapi_name == 'cli') {
//$this->rawImageData = null;
$this->src = $sourceFilename;
if (ereg('^[a-z]{3,4}$', $sourceFileExtension)) {
$this->DebugMessage('setSourceFilename('. $sourceFilename. ') set $this->config_output_format to "'. $sourceFileExtension. '"', __FILE__ , __LINE__ );
$this->DebugMessage('setSourceFilename('. $sourceFilename. ') did NOT set $this->config_output_format to "'. $sourceFileExtension. '" because it did not seem like an appropriate image format', __FILE__ , __LINE__ );
$this->DebugMessage('setSourceFilename('. $sourceFilename. ') set $this->sourceFilename to "'. $this->sourceFilename. '"', __FILE__ , __LINE__ );
//$this->sourceFilename = null;
$sourceFilename = ($sourceFilename ? $sourceFilename : md5($rawImageData));
foreach ($value as $arraykey => $arrayvalue) {
//if (property_exists('phpThumb', $param)) {
//$this->DebugMessage('setParameter() attempting to get non-existant parameter "'.$param.'"', __FILE__, __LINE__);
$this->DebugMessage('Skipping rest of GenerateThumbnail() because $this->useRawIMoutput', __FILE__ , __LINE__ );
$this->DebugMessage('SourceImageToGD() failed', __FILE__ , __LINE__ );
$destination_offset_x = 0;
$destination_offset_y = 0;
// // copy/resize image to appropriate dimensions
// if (!empty($this->fltr)) {
// foreach ($this->fltr as $key => $value) {
// if (ereg('^bord\|([0-9]+)', $value, $matches)) {
// $borderThickness = $matches[1];
// if ($borderThickness > 0) {
// //$this->DebugMessage('Skipping ImageResizeFunction() because BorderThickness="'.$borderThickness.'"', __FILE__, __LINE__);
// $this->thumbnail_image_height /= 2;
$this->DebugMessage('GenerateThumbnail() completed successfully', __FILE__ , __LINE__ );
$this->DebugMessage('RenderOutput() failed because !is_resource($this->gdimg_output)', __FILE__ , __LINE__ );
$this->DebugMessage('RenderOutput() failed because $this->thumbnailFormat is empty', __FILE__ , __LINE__ );
$builtin_formats = array();
$imagetypes = ImageTypes();
$builtin_formats['wbmp'] = (bool) ($imagetypes & IMG_WBMP);
$builtin_formats['jpg'] = (bool) ($imagetypes & IMG_JPG);
$builtin_formats['gif'] = (bool) ($imagetypes & IMG_GIF);
$builtin_formats['png'] = (bool) ($imagetypes & IMG_PNG);
if (!@$builtin_formats['wbmp']) {
$this->DebugMessage('GD does not have required built-in support for WBMP output', __FILE__ , __LINE__ );
case 'jpg': // should be "jpeg" not "jpg" but just in case...
if (!@$builtin_formats['jpg']) {
$this->DebugMessage('GD does not have required built-in support for JPEG output', __FILE__ , __LINE__ );
if (!@$builtin_formats['png']) {
$this->DebugMessage('GD does not have required built-in support for PNG output', __FILE__ , __LINE__ );
if (!@$builtin_formats['gif']) {
$this->DebugMessage('GD does not have required built-in support for GIF output', __FILE__ , __LINE__ );
$ImageOutFunction = '"builtin BMP output"';
if (!@include_once(dirname(__FILE__ ). '/phpthumb.bmp.php')) {
$this->DebugMessage('Error including "'. dirname(__FILE__ ). '/phpthumb.bmp.php" which is required for BMP format output', __FILE__ , __LINE__ );
$ImageOutFunction = '"builtin ICO output"';
if (!@include_once(dirname(__FILE__ ). '/phpthumb.ico.php')) {
$this->DebugMessage('Error including "'. dirname(__FILE__ ). '/phpthumb.ico.php" which is required for ICO format output', __FILE__ , __LINE__ );
$this->outputImageData = $phpthumb_ico->GD2ICOstring($arrayOfOutputImages);
$this->DebugMessage('RenderOutput failed because $this->thumbnailFormat "'. $this->thumbnailFormat. '" is not valid', __FILE__ , __LINE__ );
if (eregi('^(f|ht)tps?\://', $filename)) {
$this->DebugMessage('RenderToFile() failed because $filename ('. $filename. ') is a URL', __FILE__ , __LINE__ );
// render thumbnail to this file only, do not cache, do not output to browser
//$renderfilename = $this->ResolveFilenameToAbsolute(dirname($filename)).DIRECTORY_SEPARATOR.basename($filename);
$renderfilename = $filename;
if (($filename{0} != '/') && ($filename{0} != '\\') && ($filename{1} != ':')) {
$this->DebugMessage('RenderToFile() failed because "'. dirname($renderfilename). '/" is not writable', __FILE__ , __LINE__ );
$this->DebugMessage('RenderToFile() failed because "'. $renderfilename. '" is not writable', __FILE__ , __LINE__ );
$this->DebugMessage('RenderToFile('. $renderfilename. ') succeeded', __FILE__ , __LINE__ );
$this->DebugMessage('RenderOutput ['. $this->thumbnailFormat. '('. $renderfilename. ')] did not appear to fail, but the output image does not exist either...', __FILE__ , __LINE__ );
$this->DebugMessage('OutputThumbnail() failed because !is_resource($this->gdimg_output)', __FILE__ , __LINE__ );
return $this->ErrorImage('OutputThumbnail() failed - headers already sent');
$this->DebugMessage('Content-Disposition header filename set to "'. $downloadfilename. '"', __FILE__ , __LINE__ );
header('Content-Disposition: '. ($this->down ? 'attachment' : 'inline'). '; filename="'. $downloadfilename. '"');
$this->DebugMessage('failed to send Content-Disposition header because $downloadfilename is empty', __FILE__ , __LINE__ );
if (!@include_once(dirname(__FILE__ ). '/phpthumb.bmp.php')) {
$this->DebugMessage('Error including "'. dirname(__FILE__ ). '/phpthumb.bmp.php" which is required for BMP format output', __FILE__ , __LINE__ );
$bmp_data = $phpthumb_bmp->GD2BMPstring($this->gdimg_output);
$this->DebugMessage('$phpthumb_bmp->GD2BMPstring() failed', __FILE__ , __LINE__ );
$this->DebugMessage('new phpthumb_bmp() failed', __FILE__ , __LINE__ );
if (!@include_once(dirname(__FILE__ ). '/phpthumb.ico.php')) {
$this->DebugMessage('Error including "'. dirname(__FILE__ ). '/phpthumb.ico.php" which is required for ICO format output', __FILE__ , __LINE__ );
$ico_data = $phpthumb_ico->GD2ICOstring($arrayOfOutputImages);
$this->DebugMessage('$phpthumb_ico->GD2ICOstring() failed', __FILE__ , __LINE__ );
$this->DebugMessage('new phpthumb_ico() failed', __FILE__ , __LINE__ );
$this->DebugMessage('OutputThumbnail failed because $this->thumbnailFormat "'. $this->thumbnailFormat. '" is not valid', __FILE__ , __LINE__ );
$CacheDirOldFilesAge = array();
$CacheDirOldFilesSize = array();
foreach ($AllFilesInCacheDirectory as $fullfilename) {
$CacheDirOldFilesAge[$fullfilename] = @fileatime($fullfilename);
if ($CacheDirOldFilesAge[$fullfilename] == 0) {
$CacheDirOldFilesAge[$fullfilename] = @filemtime($fullfilename);
$CacheDirOldFilesSize[$fullfilename] = @filesize($fullfilename);
if (empty($CacheDirOldFilesSize)) {
$DeletedKeys['zerobyte'] = array();
foreach ($CacheDirOldFilesSize as $fullfilename => $filesize) {
// purge all zero-size files more than an hour old (to prevent trying to delete just-created and/or in-use files)
$cutofftime = time() - 3600;
if (($filesize == 0) && ($CacheDirOldFilesAge[$fullfilename] < $cutofftime)) {
$DeletedKeys['zerobyte'][] = $fullfilename;
unset ($CacheDirOldFilesSize[$fullfilename]);
unset ($CacheDirOldFilesAge[$fullfilename]);
$this->DebugMessage('CleanUpCacheDirectory() purged '. count($DeletedKeys['zerobyte']). ' zero-byte files', __FILE__ , __LINE__ );
asort($CacheDirOldFilesAge);
$TotalCachedFiles = count($CacheDirOldFilesAge);
$DeletedKeys['maxfiles'] = array();
foreach ($CacheDirOldFilesAge as $fullfilename => $filedate) {
$DeletedKeys['maxfiles'][] = $fullfilename;
// there are few enough files to keep the rest
foreach ($DeletedKeys['maxfiles'] as $fullfilename) {
unset ($CacheDirOldFilesAge[$fullfilename]);
unset ($CacheDirOldFilesSize[$fullfilename]);
$DeletedKeys['maxage'] = array();
foreach ($CacheDirOldFilesAge as $fullfilename => $filedate) {
if ($filedate < $mindate) {
$DeletedKeys['maxage'][] = $fullfilename;
// the rest of the files are new enough to keep
foreach ($DeletedKeys['maxage'] as $fullfilename) {
unset ($CacheDirOldFilesAge[$fullfilename]);
unset ($CacheDirOldFilesSize[$fullfilename]);
$TotalCachedFileSize = array_sum($CacheDirOldFilesSize);
$DeletedKeys['maxsize'] = array();
foreach ($CacheDirOldFilesAge as $fullfilename => $filedate) {
$TotalCachedFileSize -= $CacheDirOldFilesSize[$fullfilename];
$DeletedKeys['maxsize'][] = $fullfilename;
// the total filesizes are small enough to keep the rest of the files
foreach ($DeletedKeys['maxsize'] as $fullfilename) {
unset ($CacheDirOldFilesAge[$fullfilename]);
unset ($CacheDirOldFilesSize[$fullfilename]);
$this->DebugMessage('skipping CleanUpCacheDirectory() because config set to not use it', __FILE__ , __LINE__ );
foreach ($DeletedKeys as $key => $value) {
$totalpurged += count($value);
$this->DebugMessage('CleanUpCacheDirectory() purged '. $totalpurged. ' files (from '. count($AllFilesInCacheDirectory). ') based on config settings', __FILE__ , __LINE__ );
foreach ($AllFilesInCacheDirectory as $fullfilename) {
$empty_dirs[realpath($fullfilename)] = 1;
foreach ($empty_dirs as $empty_dir => $dummy) {
// shouldn't happen, but just in case, don't let it delete actual cache directory
} elseif (@rmdir($empty_dir)) {
$this->DebugMessage('failed to rmdir('. $empty_dir. ')', __FILE__ , __LINE__ );
$this->DebugMessage('purged '. $totalpurgeddirs. ' empty directories', __FILE__ , __LINE__ );
//////////////////////////////////////////////////////////////////////
// private: re-initializator (call between rendering multiple images with one object)
foreach ($class_vars as $key => $value) {
// do not clobber debug or config info
if (!eregi('^(config_|debug|fatalerror)', $key)) {
$this->phpThumb(); // re-initialize some class variables
//////////////////////////////////////////////////////////////////////
$this->DebugMessage('ResolveSource() exiting because is_resource($this->gdimg_source)', __FILE__ , __LINE__ );
return $this->ErrorImage('$this->sourceFilename and $this->src are both empty');
// Windows \\share\filename.ext
static $alreadyCalled = false;
if ($this->thumbnailFormat && $alreadyCalled) {
$AvailableImageOutputFormats = array();
$AvailableImageOutputFormats[] = 'text';
if (@is_readable(dirname(__FILE__ ). '/phpthumb.ico.php')) {
$AvailableImageOutputFormats[] = 'ico';
$AvailableImageOutputFormats[] = 'bmp';
// Set default output format based on what image types are available
$imagetypes = ImageTypes();
if ($imagetypes & IMG_WBMP) {
$AvailableImageOutputFormats[] = 'wbmp';
if ($imagetypes & IMG_GIF) {
$AvailableImageOutputFormats[] = 'gif';
if ($imagetypes & IMG_PNG) {
$AvailableImageOutputFormats[] = 'png';
if ($imagetypes & IMG_JPG) {
$AvailableImageOutputFormats[] = 'jpeg';
//return $this->ErrorImage('ImageTypes() does not exist - GD support might not be enabled?');
$this->DebugMessage('ImageTypes() does not exist - GD support might not be enabled?', __FILE__ , __LINE__ );
$IMformats = array('jpeg', 'png', 'gif', 'bmp', 'ico', 'wbmp');
$this->DebugMessage('Addding ImageMagick formats to $AvailableImageOutputFormats ('. implode(';', $AvailableImageOutputFormats). ')', __FILE__ , __LINE__ );
foreach ($IMformats as $key => $format) {
$AvailableImageOutputFormats[] = $format;
$AvailableImageOutputFormats = array_unique($AvailableImageOutputFormats);
$this->DebugMessage('$AvailableImageOutputFormats = array('. implode(';', $AvailableImageOutputFormats). ')', __FILE__ , __LINE__ );
// set output format to config default if that format is available
// override output format if $this->f is set and that format is available
// for JPEG images, quality 1 (worst) to 99 (best)
// quality < 25 is nasty, with not much size savings - not recommended
// problems with 100 - invalid JPEG?
// resolve cache directory to absolute pathname
if (eregi('^(f|ht)tps?\://', $this->src)) {
$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');
// resolve relative cache directory to source image
// $this->new is probably set
$this->ErrorImage('$this->config_cache_directory ('. $this->config_cache_directory. ') does not exist. Adjust "cache_directory" or "cache_disable_warning" in phpThumb.config.php');
//if (eregi('^(f|ht)tps?\://', $filename)) {
if (eregi('^[a-z0-9]+\:/{1,2}', $filename)) {
// eg: http://host/path/file.jpg (HTTP URL)
// eg: ftp://host/path/file.jpg (FTP URL)
// eg: data1:/path/file.jpg (Netware path)
//$AbsoluteFilename = $filename;
} elseif ($this->iswindows && ($filename{1} == ':')) {
// absolute pathname (Windows)
$AbsoluteFilename = $filename;
} elseif ($this->iswindows && ((substr($filename, 0, 2) == '//') || (substr($filename, 0, 2) == '\\\\'))) {
// absolute pathname (Windows)
$AbsoluteFilename = $filename;
} elseif ($filename{0} == '/') {
// absolute filename (*nix)
$AbsoluteFilename = $filename;
} elseif ($filename{1} == '~') {
$AbsoluteFilename = $ApacheLookupURIarray['filename'];
$AbsoluteFilename = realpath($filename);
$this->DebugMessage('phpthumb_functions::ApacheLookupURIarray() failed for "'. $filename. '", but the correct filename ('. $AbsoluteFilename. ') seems to have been resolved with realpath($filename)', __FILE__ , __LINE__ );
$this->DebugMessage('phpthumb_functions::ApacheLookupURIarray() failed for "'. dirname($filename). '", but the correct directory ('. dirname($AbsoluteFilename). ') seems to have been resolved with realpath(.)', __FILE__ , __LINE__ );
return $this->ErrorImage('phpthumb_functions::ApacheLookupURIarray() failed for "'. $filename. '". This has been known to fail on Apache2 - try using the absolute filename for the source image (ex: "/home/user/httpdocs/image.jpg" instead of "/~user/image.jpg")');
// relative filename (any OS)
$AbsoluteFilename = $filename;
$this->DebugMessage('ResolveFilenameToAbsolute() NOT prepending $this->config_document_root ('. $this->config_document_root. ') to $filename ('. $filename. ') resulting in ($AbsoluteFilename = "'. $AbsoluteFilename. '")', __FILE__ , __LINE__ );
$this->DebugMessage('ResolveFilenameToAbsolute() prepending $this->config_document_root ('. $this->config_document_root. ') to $filename ('. $filename. ') resulting in ($AbsoluteFilename = "'. $AbsoluteFilename. '")', __FILE__ , __LINE__ );
// relative to current directory (any OS)
//if (!@file_exists($AbsoluteFilename) && @file_exists(realpath($this->DotPadRelativeDirectoryPath($filename)))) {
// $AbsoluteFilename = realpath($this->DotPadRelativeDirectoryPath($filename));
$AbsoluteFilename = $ApacheLookupURIarray['filename']. DIRECTORY_SEPARATOR. $filename;
$AbsoluteFilename = realpath('.'). DIRECTORY_SEPARATOR. $filename;
$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__ );
$this->DebugMessage('phpthumb_functions::ApacheLookupURIarray() failed for "'. dirname(@$_SERVER['PHP_SELF']). '", but the correct directory ('. dirname($AbsoluteFilename). ') seems to have been resolved with realpath(.)', __FILE__ , __LINE__ );
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');
$this->DebugMessage('is_link()==true, changing "'. $AbsoluteFilename. '" to "'. readlink($AbsoluteFilename). '"', __FILE__ , __LINE__ );
$AbsoluteFilename = readlink($AbsoluteFilename);
$AbsoluteFilename = realpath($AbsoluteFilename);
$AbsoluteFilename = str_replace(DIRECTORY_SEPARATOR, '/', $AbsoluteFilename);
$this->DebugMessage('!$this->config_allow_src_above_phpthumb therefore setting "'. $AbsoluteFilename. '" (outside "'. dirname(__FILE__ ). '") to null', __FILE__ , __LINE__ );
return $AbsoluteFilename;
static $WhichConvert = null;
if (is_null($WhichConvert)) {
$WhichConvert = trim(phpthumb_functions::SafeExec('which convert'));
static $commandline = null;
if (is_null($commandline)) {
$commandline = (!is_null($this->config_imagemagick_path) ? $this->config_imagemagick_path : '');
if ($this->config_imagemagick_path && ($this->config_imagemagick_path != realpath($this->config_imagemagick_path))) {
if (@is_executable(realpath($this->config_imagemagick_path))) {
$this->DebugMessage('Changing $this->config_imagemagick_path ('. $this->config_imagemagick_path. ') to realpath($this->config_imagemagick_path) ('. realpath($this->config_imagemagick_path). ')', __FILE__ , __LINE__ );
if ($which_convert && ($which_convert{0} == '/') && @file_exists($which_convert)) {
// `which convert` *should* return the path if "convert" exist, or nothing if it doesn't
// other things *may* get returned, like "sh: convert: not found" or "no convert in /usr/local/bin /usr/sbin /usr/bin /usr/ccs/bin"
// so only do this if the value returned exists as a file
$this->DebugMessage('using ImageMagick path from `which convert` ('. $which_convert. ')', __FILE__ , __LINE__ );
$commandline = 'convert';
$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__ );
static $versionstring = null;
if (is_null($versionstring)) {
$commandline = $this->ImageMagickCommandlineBase();
$commandline = (!is_null($commandline) ? $commandline : '');
$versionstring = array(0=> '', 1=> '');
$commandline .= ' --version';
$this->DebugMessage('ImageMagick version checked with "'. $commandline. '"', __FILE__ , __LINE__ );
if (eregi('^Version: [^0-9]*([ 0-9\\.\\:Q/]+) (http|file)\:', $versionstring[1], $matches)) {
$versionstring[0] = $matches[1];
$versionstring[0] = false;
$this->DebugMessage('ImageMagick did not return recognized version string ('. $versionstring[1]. ')', __FILE__ , __LINE__ );
$this->DebugMessage('ImageMagick convert --version says "'. $matches[0]. '"', __FILE__ , __LINE__ );
return @$versionstring[intval($returnRAW)];
static $IMoptions = null;
if (is_null($IMoptions)) {
$commandline = $this->ImageMagickCommandlineBase();
if (!is_null($commandline)) {
$commandline .= ' -help';
foreach ($IMhelp_lines as $line) {
if (ereg('^[\+\-]([a-z\-]+) ', trim($line), $matches)) {
$IMoptions[$matches[1]] = true;
foreach ($switchname as $key => $value) {
if (!isset ($IMoptions[$value])) {
$allOK = isset ($IMoptions[$switchname]);
$this->DebugMessage('ImageMagickSwitchAvailable('. $switchname. ') = '. intval($allOK). '', __FILE__ , __LINE__ );
static $IMformatsList = null;
if (is_null($IMformatsList)) {
$commandline = $this->ImageMagickCommandlineBase();
if (!is_null($commandline)) {
$commandline = dirname($commandline). DIRECTORY_SEPARATOR. str_replace('convert', 'identify', basename($commandline));
$commandline .= ' -list format';
// http://www.imagemagick.org/script/command-line-options.php
// if GD is not available, must use whatever ImageMagick can output
// $UnAllowedParameters contains options that can only be processed in GD, not ImageMagick
// note: 'fltr' *may* need to be processed by GD, but we'll check that in more detail below
$UnAllowedParameters = array('xto', 'ra', 'ar', 'bg', 'bc');
foreach ($UnAllowedParameters as $parameter) {
if (isset ($this->$parameter)) {
$this->DebugMessage('$this->useRawIMoutput=false because "'. $parameter. '" is set', __FILE__ , __LINE__ );
$this->DebugMessage('$this->useRawIMoutput='. ($this->useRawIMoutput ? 'true' : 'false'). ' after checking $UnAllowedParameters', __FILE__ , __LINE__ );
$ImageCreateFunction = 'ImageCreateFromGIF';
$ImageCreateFunction = 'ImageCreateFromPNG';
$ImageCreateFunction = 'ImageCreateFromJPEG';
$this->DebugMessage('Forcing output to PNG because $this->thumbnailFormat ('. $this->thumbnailFormat. ' is not a GD-supported format)', __FILE__ , __LINE__ );
$ImageCreateFunction = 'ImageCreateFromPNG';
// ImageMagickThumbnailToGD() depends on ImageCreateFromPNG/ImageCreateFromGIF
//$this->DebugMessage('ImageMagickThumbnailToGD() aborting because '.@$ImageCreateFunction.'() is not available', __FILE__, __LINE__);
$ImageCreateFunction = 'ImageCreateFromPNG';
$IMtempSourceFilename = realpath($IMtempSourceFilename);
$this->DebugMessage('ImageMagickThumbnailToGD() setting $this->sourceFilename to "'. $IMtempSourceFilename. '" from $this->rawImageData ('. strlen($this->rawImageData). ' bytes)', __FILE__ , __LINE__ );
$this->DebugMessage('ImageMagickThumbnailToGD() aborting because $this->sourceFilename is empty', __FILE__ , __LINE__ );
$this->DebugMessage('ImageMagickThumbnailToGD() aborting because safe_mode is enabled', __FILE__ , __LINE__ );
$IMtempfilename = realpath($IMtempfilename);
$IMuseExplicitImageOutputDimensions = false;
$IMresizeParameter = 'thumbnail';
$IMresizeParameter = 'resize';
// some (older? around 2002) versions of IM won't accept "-resize 100x" but require "-resize 100x100"
$IMuseExplicitImageOutputDimensions = eregi('image dimensions are zero', $IMresult_test);
$this->DebugMessage('IMuseExplicitImageOutputDimensions = '. intval($IMuseExplicitImageOutputDimensions), __FILE__ , __LINE__ );
if ($fp_im_temp = @fopen($IMtempfilename, 'wb')) {
// erase temp image so ImageMagick logo doesn't get output if other processing fails
// for raster source formats only (WMF, PDF, etc)
$commandline .= ' -density '. $this->dpi;
$this->DebugMessage('GetImageSize('. $this->sourceFilename. ') returned [w='. $getimagesize[0]. ';h='. $getimagesize[1]. ';f='. $getimagesize[2]. ']', __FILE__ , __LINE__ );
// not a transparency-capable format
$commandline .= ' -background "#'. ($this->bg ? $this->bg : 'FFFFFF'). '"';
if ($getimagesize[2] == 1) {
$commandline .= ' -flatten';
if ($getimagesize[2] == 1) {
$commandline .= ' -coalesce'; // may be needed for animated GIFs
if (!empty($this->fltr)) {
foreach ($this->fltr as $key => $value) {
if (ereg('^bord\|([0-9]+)', $value, $matches)) {
$borderThickness = $matches[1];
$wAll = intval(max($this->w, $this->wp, $this->wl, $this->ws)) - (2 * $borderThickness);
$hAll = intval(max($this->h, $this->hp, $this->hl, $this->hs)) - (2 * $borderThickness);
$zcAR = (($wAll && $hAll) ? $wAll / $hAll : 1);
$thumbnailH = round(max($sideY, ($sideY * $zcAR) / $imAR));
if ($IMuseExplicitImageOutputDimensions) {
$commandline .= ' -'. $IMresizeParameter. ' '. $thumbnailH. 'x'. $thumbnailH;
$commandline .= ' -'. $IMresizeParameter. ' x'. $thumbnailH;
$commandline .= ' -gravity north';
$commandline .= ' -gravity south';
$commandline .= ' -gravity west';
$commandline .= ' -gravity east';
$commandline .= ' -gravity northwest';
$commandline .= ' -gravity northeast';
$commandline .= ' -gravity southwest';
$commandline .= ' -gravity southeast';
$commandline .= ' -gravity center';
if (($wAll > 0) && ($hAll > 0)) {
$commandline .= ' -crop '. $wAll. 'x'. $hAll. '+0+0';
$commandline .= ' -crop '. $side. 'x'. $side. '+0+0';
$commandline .= ' +repage';
} elseif ($this->sw || $this->sh || $this->sx || $this->sy) {
// this is broken for aoe=1, but unsure how to fix. Send advice to info@silisoftware.com
if ($this->w || $this->h) {
$commandline .= ' -repage';
if ($IMuseExplicitImageOutputDimensions) {
if ($this->w && !$this->h) {
} elseif ($this->h && !$this->w) {
$commandline .= ' -'. $IMresizeParameter. ' '. $this->w. 'x'. $this->h;
$commandline .= ' -'. $IMresizeParameter. ' '. $this->w. 'x'. $this->h. '!';
if ($this->w || $this->h) {
if ($IMuseExplicitImageOutputDimensions) {
if ($this->w && !$this->h) {
} elseif ($this->h && !$this->w) {
$commandline .= ' -'. $IMresizeParameter. ' '. $this->w. 'x'. $this->h;
if ($this->w || $this->h) {
if ($IMuseExplicitImageOutputDimensions) {
// unknown source aspect ration, just put large number and hope IM figures it out
$commandline .= ' -'. $IMresizeParameter. ' '. ($this->w ? $this->w : '9999'). 'x'. ($this->h ? $this->h : '9999');
$commandline .= ' -'. $IMresizeParameter. ' '. $this->w. 'x'. $this->h;
foreach ($this->fltr as $filterkey => $filtercommand) {
@list ($command, $parameter) = explode('|', $filtercommand, 2);
$commandline .= ' -modulate '. (100 + $parameter). ',100,100';
unset ($this->fltr[$filterkey]);
$contDiv10 = round($parameter / 10);
for ($i = 0; $i < $contDiv10; $i++ ) {
$commandline .= ' -contrast'; // increase contrast by 10%
} elseif ($contDiv10 < 0) {
for ($i = $contDiv10; $i < 0; $i++ ) {
$commandline .= ' +contrast'; // decrease contrast by 10%
unset ($this->fltr[$filterkey]);
$commandline .= ' -colorspace GRAY -modulate 100,0,100';
$commandline .= ' -modulate 100,'. (100 - $parameter). ',100';
unset ($this->fltr[$filterkey]);
if ($parameter == - 100) {
$commandline .= ' -colorspace GRAY -modulate 100,0,100';
$commandline .= ' -modulate 100,'. (100 + $parameter). ',100';
unset ($this->fltr[$filterkey]);
$commandline .= ' -colorspace GRAY -modulate 100,0,100';
//$commandline .= ' -colorspace GRAY';
unset ($this->fltr[$filterkey]);
@list ($amount, $color) = explode('|', $parameter);
$commandline .= ' -fill "#'. $color. '" -colorize '. $amount;
@list ($amount, $color) = explode('|', $parameter);
$amount = ($amount ? $amount : 80);
$commandline .= ' -sepia-tone '. $amount. '%';
unset ($this->fltr[$filterkey]);
$commandline .= ' -gamma '. $parameter;
unset ($this->fltr[$filterkey]);
$commandline .= ' -negate';
unset ($this->fltr[$filterkey]);
$commandline .= ' -threshold '. round($parameter / 2.55). '% -dither -monochrome';
unset ($this->fltr[$filterkey]);
@list ($colors, $dither) = explode('|', $parameter);
$colors = ($colors ? (int) $colors : 256);
$dither = ((strlen($dither) > 0) ? (bool) $dither : true);
$commandline .= ' -colors '. max($colors, 8); // ImageMagick will otherwise fail with "cannot quantize to fewer than 8 colors"
$commandline .= ($dither ? ' -dither' : ' +dither');
unset ($this->fltr[$filterkey]);
$commandline .= ' -flop';
$commandline .= ' -flip';
unset ($this->fltr[$filterkey]);
$parameter = ($parameter ? $parameter : 2);
$commandline .= ' -edge '. ($parameter ? $parameter : 1);
unset ($this->fltr[$filterkey]);
$parameter = ($parameter ? $parameter : 2);
$commandline .= ' -emboss '. $parameter;
$commandline .= ' -negate'; // ImageMagick negates the image for some reason with '-emboss 1';
unset ($this->fltr[$filterkey]);
@list ($band, $method, $threshold) = explode('|', $parameter);
// Because ImageMagick processing happens before PHP-GD filters, and because some
// clipping is involved in the "lvl" filter, if "lvl" happens before "wb" then the
// "wb" filter will have (almost) no effect. Therefore, if "wb" is enabled then
// force the "lvl" filter to be processed by GD, not ImageMagick.
foreach ($this->fltr as $fltr_key => $fltr_value) {
list ($fltr_cmd) = explode('|', $fltr_value);
$this->DebugMessage('Setting "lvl" filter method to "0" (from "'. $method. '") because white-balance filter also enabled', __FILE__ , __LINE__ );
case 1: // internal grayscale
case 2: // ImageMagick "contrast-stretch"
$thiscommand = ' -contrast-stretch '. $threshold. '%';
$commandline .= (($band == '*') ? $thiscommand : ' -channel '. strtoupper($band). $thiscommand. ' +channel');
unset ($this->fltr[$filterkey]);
case 3: // ImageMagick "normalize"
$thiscommand = ' -normalize';
$commandline .= (($band == '*') ? $thiscommand : ' -channel '. strtoupper($band). $thiscommand. ' +channel');
unset ($this->fltr[$filterkey]);
$this->DebugMessage('unsupported method ('. $method. ') for "lvl" filter', __FILE__ , __LINE__ );
if (isset ($this->fltr[$filterkey]) && ($method > 1)) {
$this->fltr[$filterkey] = $command. '|'. $band. '|0|'. $threshold;
$this->DebugMessage('filter "lvl" remapped from method "'. $method. '" to method "0" because ImageMagick support is missing', __FILE__ , __LINE__ );
@list ($threshold) = explode('|', $parameter);
$threshold = (is_float($threshold) ? $threshold : 0.1);
$commandline .= ' -channel R -contrast-stretch '. $threshold. '%';
$commandline .= ' -channel G -contrast-stretch '. $threshold. '%';
$commandline .= ' -channel B -contrast-stretch '. $threshold. '%';
$commandline .= ' +channel';
unset ($this->fltr[$filterkey]);
@list ($radius) = explode('|', $parameter);
$radius = ($radius ? $radius : 1);
$commandline .= ' -blur '. $radius;
unset ($this->fltr[$filterkey]);
@list ($radius) = explode('|', $parameter);
$radius = ($radius ? $radius : 1);
$commandline .= ' -gaussian '. $radius;
unset ($this->fltr[$filterkey]);
@list ($amount, $radius, $threshold) = explode('|', $parameter);
$amount = ($amount ? $amount : 80);
$radius = ($radius ? $radius : 0.5);
$threshold = (strlen($threshold) ? $threshold : 3);
unset ($this->fltr[$filterkey]);
@list ($width, $rX, $rY, $color) = explode('|', $parameter);
if ($width && !$rX && !$rY) {
$color = ($this->bc ? $this->bc : '000000');
$commandline .= ' -border '. $width. ' -bordercolor "#'. $color. '"';
if (ereg(' \-crop ([0-9]+)x([0-9]+)\+0\+0 ', $commandline, $matches)) {
$commandline = str_replace(' -crop '. $matches[1]. 'x'. $matches[2]. '+0+0 ', ' -crop '. ($matches[1] - (2 * $width)). 'x'. ($matches[2] - (2 * $width)). '+0+0 ', $commandline);
} elseif (ereg(' \-'. $IMresizeParameter. ' ([0-9]+)x([0-9]+) ', $commandline, $matches)) {
$commandline = str_replace(' -'. $IMresizeParameter. ' '. $matches[1]. 'x'. $matches[2]. ' ', ' -'. $IMresizeParameter. ' '. ($matches[1] - (2 * $width)). 'x'. ($matches[2] - (2 * $width)). ' ', $commandline);
unset ($this->fltr[$filterkey]);
$this->DebugMessage('Unknown $this->fltr['. $filterkey. '] ('. $filtercommand. ') -- deleting filter command', __FILE__ , __LINE__ );
unset ($this->fltr[$filterkey]);
if (!isset ($this->fltr[$filterkey])) {
$this->DebugMessage('Processed $this->fltr['. $filterkey. '] ('. $filtercommand. ') with ImageMagick', __FILE__ , __LINE__ );
$this->DebugMessage('Skipping $this->fltr['. $filterkey. '] ('. $filtercommand. ') with ImageMagick', __FILE__ , __LINE__ );
if (eregi('jpe?g', $outputFormat) && $this->q) {
// causes weird things with animated GIF... leave for JPEG only
$commandline .= ' -interlace line '; // Use Line or Plane to create an interlaced PNG or GIF or progressive JPEG image
$commandline .= ' "'. str_replace('/', DIRECTORY_SEPARATOR, $this->sourceFilename). (($outputFormat == 'gif') ? '' : '['. intval($this->sfn). ']'). '"'; // [0] means first frame of (GIF) animation, can be ignored
$commandline .= ' '. $outputFormat. ':"'. $IMtempfilename. '"';
$this->DebugMessage('ImageMagick called as ('. $commandline. ')', __FILE__ , __LINE__ );
if (@$IMtempSourceFilename && file_exists($IMtempSourceFilename)) {
@unlink($IMtempSourceFilename);
$this->FatalError('ImageMagick failed with message ('. trim($IMresult). ')');
$this->DebugMessage('ImageMagick failed with message ('. trim($IMresult). ')', __FILE__ , __LINE__ );
$this->DebugMessage('Check to make sure that PHP has read+write permissions to "'. dirname($IMtempfilename). '"', __FILE__ , __LINE__ );
$getimagesize_imresized = @GetImageSize($IMtempfilename);
$this->DebugMessage('GetImageSize('. $IMtempfilename. ') returned [w='. $getimagesize_imresized[0]. ';h='. $getimagesize_imresized[1]. ';f='. $getimagesize_imresized[2]. ']', __FILE__ , __LINE__ );
$this->DebugMessage('skipping ImageMagickThumbnailToGD::'. $ImageCreateFunction. '() because IM output is too large ('. $getimagesize_imresized[0]. 'x'. $getimagesize_imresized[0]. ' = '. ($getimagesize_imresized[0] * $getimagesize_imresized[1]). ' > '. $this->config_max_source_pixels. ')', __FILE__ , __LINE__ );
$this->DebugMessage('ImageMagickThumbnailToGD::'. $ImageCreateFunction. '() succeeded, $this->gdimg_source is now ('. $this->source_width. 'x'. $this->source_height. ')', __FILE__ , __LINE__ );
$this->DebugMessage('$this->useRawIMoutput set to TRUE because '. @$ImageCreateFunction. '('. $IMtempfilename. ') failed', __FILE__ , __LINE__ );
$this->DebugMessage('ImageMagickThumbnailToGD() aborting, phpThumb_tempnam() failed', __FILE__ , __LINE__ );
$this->DebugMessage('ImageMagickThumbnailToGD() aborting because ImageMagickCommandlineBase() failed', __FILE__ , __LINE__ );
if ($this->ra || $this->ar) {
$this->DebugMessage('!function_exists(ImageRotate)', __FILE__ , __LINE__ );
if (!include_once(dirname(__FILE__ ). '/phpthumb.filters.php')) {
$this->DebugMessage('Error including "'. dirname(__FILE__ ). '/phpthumb.filters.php" which is required for applying filters ('. implode(';', $this->fltr). ')', __FILE__ , __LINE__ );
// http://sylvana.net/jpegcrop/exif_orientation.html
switch (@$exif_data['Orientation']) {
$this->DebugMessage('EXIF auto-rotate failed because unknown $exif_data[Orientation] "'. @$exif_data['Orientation']. '"', __FILE__ , __LINE__ );
$this->DebugMessage('EXIF auto-rotate set to '. $rotate_angle. ' degrees ($exif_data[Orientation] = "'. @$exif_data['Orientation']. '")', __FILE__ , __LINE__ );
$this->DebugMessage('!function_exists(exif_read_data)', __FILE__ , __LINE__ );
$this->DebugMessage('Cannot auto-rotate from EXIF data because $this->sourceFilename is empty', __FILE__ , __LINE__ );
$this->DebugMessage('Cannot auto-rotate from EXIF data because PHP is less than v4.2.0 ('. phpversion(). ')', __FILE__ , __LINE__ );
if ($rotate_angle % 90) {
// optional fixed-dimension images (regardless of aspect ratio)
if (!$this->w || !$this->h) {
static $domain_is_allowed = array();
$hostname = strtolower($hostname);
if (!isset ($domain_is_allowed[$hostname])) {
$domain_is_allowed[$hostname] = false;
foreach ($allowed_domains as $valid_domain) {
$starpos = strpos($valid_domain, '*');
if ($starpos !== false) {
$valid_domain = substr($valid_domain, $starpos + 1);
if (eregi($valid_domain. '$', $hostname)) {
$domain_is_allowed[$hostname] = true;
$domain_is_allowed[$hostname] = true;
return $domain_is_allowed[$hostname];
// Optional anti-offsite hijacking of the thumbnail script
$this->DebugMessage('AntiOffsiteLinking() checking $_SERVER[HTTP_REFERER] "'. @$_SERVER['HTTP_REFERER']. '"', __FILE__ , __LINE__ );
// $_SERVER['HTTP_HOST'] contains the port number, so strip it out here to make default configuration work
list ($clean_domain) = explode(':', $valid_domain);
//if (!phpthumb_functions::CaseInsensitiveInArray(@$parsed_url['host'], $this->config_nohotlink_valid_domains)) {
// This domain is not allowed
$this->DebugMessage('AntiOffsiteLinking() says this is allowed', __FILE__ , __LINE__ );
if (!include_once(dirname(__FILE__ ). '/phpthumb.filters.php')) {
$this->DebugMessage('Error including "'. dirname(__FILE__ ). '/phpthumb.filters.php" which is required for applying watermark', __FILE__ , __LINE__ );
$phpthumbFilters->phpThumbObject = &$this;
$phpthumbFilters->WatermarkOverlay($this->gdimg_output, $watermark_img, '*', $opacity, $margin);
ImageDestroy($watermark_img);
foreach ($nohotlink_text_array as $textline) {
// image doesn't have alpha transparency, no need to flatten
$this->DebugMessage('skipping AlphaChannelFlatten() because !$this->is_alpha', __FILE__ , __LINE__ );
// image has alpha transparency, but output as PNG or ICO which can handle it
$this->DebugMessage('skipping AlphaChannelFlatten() because ($this->thumbnailFormat == "'. $this->thumbnailFormat. '")', __FILE__ , __LINE__ );
// image has alpha transparency, but output as GIF which can handle only single-color transparency
$CurrentImageColorTransparent = ImageColorTransparent($this->gdimg_output);
if ($CurrentImageColorTransparent == - 1) {
// no transparent color defined
for ($i = 0; $i <= 255; $i++ ) {
$dither_color[$i] = ImageColorAllocate($img_alpha_mixdown_dither, $i, $i, $i);
// scan through current truecolor image copy alpha channel to temp image as grayscale
ImageSetPixel($img_alpha_mixdown_dither, $x, $y, $dither_color[($PixelColor['alpha'] * 2)]);
// dither alpha channel grayscale version down to 2 colors
ImageTrueColorToPalette($img_alpha_mixdown_dither, true, 2);
// reduce color palette to 256-1 colors (leave one palette position for transparent color)
// allocate a new color for transparent color index
$TransparentColor = ImageColorAllocate($this->gdimg_output, 1, 254, 253);
ImageColorTransparent($this->gdimg_output, $TransparentColor);
// scan through alpha channel image and note pixels with >50% transparency
$TransparentPixels = array();
if ($AlphaChannelPixel['red'] > 127) {
ImageSetPixel($this->gdimg_output, $x, $y, $TransparentColor);
ImageDestroy($img_alpha_mixdown_dither);
$this->DebugMessage('AlphaChannelFlatten() set image to 255+1 colors with transparency for GIF output', __FILE__ , __LINE__ );
// a single transparent color already defined, leave as-is
$this->DebugMessage('skipping AlphaChannelFlatten() because ($this->thumbnailFormat == "'. $this->thumbnailFormat. '") and ImageColorTransparent returned "'. $CurrentImageColorTransparent. '"', __FILE__ , __LINE__ );
// image has alpha transparency, and is being output in a format that doesn't support it -- flatten
ImageDestroy($gdimg_flatten_temp);
$this->DebugMessage('ImageCreateFunction() failed', __FILE__ , __LINE__ );
if (!include_once(dirname(__FILE__ ). '/phpthumb.filters.php')) {
$this->DebugMessage('Error including "'. dirname(__FILE__ ). '/phpthumb.filters.php" which is required for applying filters ('. implode(';', $this->fltr). ')', __FILE__ , __LINE__ );
$phpthumbFilters->phpThumbObject = &$this;
foreach ($this->fltr as $filtercommand) {
@list ($command, $parameter) = explode('|', $filtercommand, 2);
$this->DebugMessage('Attempting to process filter command "'. $command. '('. $parameter. ')"', __FILE__ , __LINE__ );
case 'brit': // Brightness
$phpthumbFilters->Brightness($this->gdimg_output, $parameter);
$phpthumbFilters->Contrast($this->gdimg_output, $parameter);
case 'ds': // Desaturation
$phpthumbFilters->Desaturate($this->gdimg_output, $parameter, '');
case 'sat': // Saturation
$phpthumbFilters->Saturation($this->gdimg_output, $parameter, '');
case 'gray': // Grayscale
@list ($amount, $color) = explode('|', $parameter);
$phpthumbFilters->Colorize($this->gdimg_output, $amount, $color);
@list ($amount, $color) = explode('|', $parameter);
$phpthumbFilters->Sepia($this->gdimg_output, $amount, $color);
case 'gam': // Gamma correction
case 'neg': // Negative colors
$phpthumbFilters->Threshold($this->gdimg_output, $parameter);
case 'rcd': // ReduceColorDepth
@list ($colors, $dither) = explode('|', $parameter);
$colors = ($colors ? (int) $colors : 256);
$dither = ((strlen($dither) > 0) ? (bool) $dither : true);
$phpthumbFilters->ReduceColorDepth($this->gdimg_output, $colors, $dither);
case 'edge': // EdgeDetect
@list ($width, $color1, $color2) = explode('|', $parameter);
$phpthumbFilters->Bevel($this->gdimg_output, $width, $color1, $color2);
case 'lvl': // autoLevels
@list ($band, $method, $threshold) = explode('|', $parameter);
$phpthumbFilters->HistogramStretch($this->gdimg_output, $band, $method, $threshold);
case 'wb': // WhiteBalance
$phpthumbFilters->WhiteBalance($this->gdimg_output, $parameter);
case 'hist': // Histogram overlay
@list ($bands, $colors, $width, $height, $alignment, $opacity, $margin_x, $margin_y) = explode('|', $parameter);
$bands = ($bands ? $bands : '*');
$colors = ($colors ? $colors : '');
$width = ($width ? $width : 0.25);
$height = ($height ? $height : 0.25);
$alignment = ($alignment ? $alignment : 'BR');
$opacity = ($opacity ? $opacity : 50);
$margin_x = ($margin_x ? $margin_x : 5);
$margin_y = $margin_y; // just to note it wasn't forgotten, but let the value always pass unchanged
$phpthumbFilters->HistogramOverlay($this->gdimg_output, $bands, $colors, $width, $height, $alignment, $opacity, $margin_x, $margin_y);
@list ($frame_width, $edge_width, $color_frame, $color1, $color2) = explode('|', $parameter);
$phpthumbFilters->Frame($this->gdimg_output, $frame_width, $edge_width, $color_frame, $color1, $color2);
case 'drop': // DropShadow
@list ($distance, $width, $color, $angle, $fade) = explode('|', $parameter);
$phpthumbFilters->DropShadow($this->gdimg_output, $distance, $width, $color, $angle, $fade);
case 'mask': // Mask cropping
if (@is_readable($mask_filename) && ($fp_mask = @fopen($mask_filename, 'rb'))) {
$buffer = fread($fp_mask, 8192);
$MaskImageData .= $buffer;
} while (strlen($buffer) > 0);
$phpthumbFilters->ApplyMask($gdimg_mask, $this->gdimg_output);
ImageDestroy($gdimg_mask);
$this->DebugMessage('ImageCreateFromStringReplacement() failed for "'. $mask_filename. '"', __FILE__ , __LINE__ );
$this->DebugMessage('Cannot open mask file "'. $mask_filename. '"', __FILE__ , __LINE__ );
case 'elip': // Elipse cropping
case 'ric': // RoundedImageCorners
@list ($radius_x, $radius_y) = explode('|', $parameter);
if (($radius_x < 1) || ($radius_y < 1)) {
$this->DebugMessage('Skipping RoundedImageCorners('. $radius_x. ', '. $radius_y. ') because x/y radius is less than 1', __FILE__ , __LINE__ );
$phpthumbFilters->RoundedImageCorners($this->gdimg_output, $radius_x, $radius_y);
@list ($left, $right, $top, $bottom) = explode('|', $parameter);
$phpthumbFilters->Crop($this->gdimg_output, $left, $right, $top, $bottom);
@list ($border_width, $radius_x, $radius_y, $hexcolor_border) = explode('|', $parameter);
$phpthumbFilters->ImageBorder($this->gdimg_output, $border_width, $radius_x, $radius_y, $hexcolor_border);
@list ($filename, $underlay, $margin, $opacity) = explode('|', $parameter);
$underlay = (bool) ($underlay ? $underlay : false);
$margin = ((strlen($margin) > 0) ? $margin : ($underlay ? 0.1 : 0.0));
$opacity = ((strlen($opacity) > 0) ? $opacity : 100);
if (($margin > 0) && ($margin < 1)) {
$margin = min(0.499, $margin);
} elseif (($margin > - 1) && ($margin < 0)) {
$margin = max(- 0.499, $margin);
$WatermarkImageData = '';
$buffer = fread($fp_watermark, 8192);
$WatermarkImageData .= $buffer;
} while (strlen($buffer) > 0);
ImageAlphaBlending($img_watermark_resized, false);
ImageSaveAlpha($img_watermark_resized, true);
$this->ImageResizeFunction($img_watermark_resized, $img_watermark, 0, 0, 0, 0, ImageSX($img_watermark_resized), ImageSY($img_watermark_resized), ImageSX($img_watermark), ImageSY($img_watermark));
ImageAlphaBlending($img_source_resized, false);
ImageSaveAlpha($img_source_resized, true);
$phpthumbFilters->WatermarkOverlay($img_watermark_resized, $img_source_resized, 'C', $opacity, $margin);
$this->DebugMessage('phpthumb_functions::ImageCreateFunction('. $resized_x. ', '. $resized_y. ')', __FILE__ , __LINE__ );
ImageDestroy($img_watermark_resized);
ImageAlphaBlending($img_watermark_resized, false);
ImageSaveAlpha($img_watermark_resized, true);
$this->ImageResizeFunction($img_watermark_resized, $img_watermark, 0, 0, 0, 0, ImageSX($img_watermark_resized), ImageSY($img_watermark_resized), ImageSX($img_watermark), ImageSY($img_watermark));
$phpthumbFilters->WatermarkOverlay($this->gdimg_output, $img_watermark_resized, 'C', $opacity, $margin);
ImageDestroy($img_watermark_resized);
$this->DebugMessage('phpthumb_functions::ImageCreateFunction('. $resized_x. ', '. $resized_y. ')', __FILE__ , __LINE__ );
ImageDestroy($img_watermark);
$this->DebugMessage('ImageCreateFromStringReplacement() failed for "'. $filename. '"', __FILE__ , __LINE__ );
$this->DebugMessage('Cannot open overlay file "'. $filename. '"', __FILE__ , __LINE__ );
case 'wmi': // WaterMarkImage
@list ($filename, $alignment, $opacity, $margin['x'], $margin['y'], $rotate_angle) = explode('|', $parameter);
// $margin can be pixel margin or percent margin if $alignment is text, or max width/height if $alignment is position like "50x75"
$alignment = ($alignment ? $alignment : 'BR');
$rotate_angle = (strlen($rotate_angle) ? intval($rotate_angle) : 0);
if (!eregi('^([0-9\\.\\-]*)x([0-9\\.\\-]*)$', $alignment, $matches)) {
$margins = array('x', 'y');
foreach ($margins as $xy) {
$margin[$xy] = (strlen($margin[$xy]) ? $margin[$xy] : 5);
if (($margin[$xy] > 0) && ($margin[$xy] < 1)) {
$margin[$xy] = min(0.499, $margin[$xy]);
} elseif (($margin[$xy] > - 1) && ($margin[$xy] < 0)) {
$margin[$xy] = max(- 0.499, $margin[$xy]);
if ($rotate_angle !== 0) {
$phpthumbFilters->ImprovedImageRotate($img_watermark, $rotate_angle);
if (eregi('^([0-9\\.\\-]*)x([0-9\\.\\-]*)$', $alignment, $matches)) {
$watermark_max_width = intval($margin['x'] ? $margin['x'] : ImageSX($img_watermark));
$watermark_max_height = intval($margin['y'] ? $margin['y'] : ImageSY($img_watermark));
if (($scale > 1) || ($scale < 1)) {
ImageAlphaBlending($img_watermark2, false);
ImageSaveAlpha($img_watermark2, true);
$this->ImageResizeFunction($img_watermark2, $img_watermark, 0, 0, 0, 0, ImageSX($img_watermark2), ImageSY($img_watermark2), ImageSX($img_watermark), ImageSY($img_watermark));
$img_watermark = $img_watermark2;
$this->DebugMessage('ImageCreateFunction('. ($scale * ImageSX($img_watermark)). ', '. ($scale * ImageSX($img_watermark)). ') failed', __FILE__ , __LINE__ );
$watermark_dest_x = round($matches[1] - (ImageSX($img_watermark) / 2));
$watermark_dest_y = round($matches[2] - (ImageSY($img_watermark) / 2));
$alignment = $watermark_dest_x. 'x'. $watermark_dest_y;
$phpthumbFilters->WatermarkOverlay($this->gdimg_output, $img_watermark, $alignment, $opacity, $margin['x'], $margin['y']);
ImageDestroy($img_watermark);
if (isset ($img_watermark2) && is_resource($img_watermark2)) {
ImageDestroy($img_watermark2);
$this->DebugMessage('ImageCreateFromFilename() failed for "'. $filename. '"', __FILE__ , __LINE__ );
$this->DebugMessage('!is_readable('. $filename. ')', __FILE__ , __LINE__ );
case 'wmt': // WaterMarkText
@list ($text, $size, $alignment, $hex_color, $ttffont, $opacity, $margin, $angle, $bg_color, $bg_opacity, $fillextend) = explode('|', $parameter);
$text = ($text ? $text : '');
$size = ($size ? $size : 3);
$alignment = ($alignment ? $alignment : 'BR');
$hex_color = ($hex_color ? $hex_color : '000000');
$ttffont = ($ttffont ? $ttffont : '');
$opacity = (strlen($opacity) ? $opacity : 50);
$margin = (strlen($margin) ? $margin : 5);
$angle = (strlen($angle) ? $angle : 0);
$bg_color = ($bg_color ? $bg_color : false);
$bg_opacity = ($bg_opacity ? $bg_opacity : 0);
$fillextend = ($fillextend ? $fillextend : '');
$phpthumbFilters->WatermarkText($this->gdimg_output, $text, $size, $alignment, $hex_color, $ttffont, $opacity, $margin, $angle, $bg_color, $bg_opacity, $fillextend);
@list ($radius) = explode('|', $parameter);
$radius = ($radius ? $radius : 1);
@list ($newwidth, $newheight, $stretch) = explode('|', $parameter);
$newheight = (!$newheight ? ImageSY($this->gdimg_output) : ((($newheight > 0) && ($newheight < 1)) ? round($newheight * ImageSY($this->gdimg_output)) : round($newheight)));
$stretch = ($stretch ? true : false);
if (($scale_x > 1) || ($scale_x < 1) || ($scale_y > 1) || ($scale_y < 1)) {
//ImageDestroy($this->gdimg_output);
$this->DebugMessage('ImageCreateFunction('. ($scale_x * ImageSX($img_temp)). ', '. ($scale_y * ImageSY($img_temp)). ') failed', __FILE__ , __LINE__ );
case 'gblr': // Gaussian Blur
case 'sblr': // Selective Blur
case 'mean': // MeanRemoval blur
case 'smth': // Smooth blur
case 'usm': // UnSharpMask sharpening
@list ($amount, $radius, $threshold) = explode('|', $parameter);
$amount = ($amount ? $amount : 80);
$radius = ($radius ? $radius : 0.5);
$threshold = (strlen($threshold) ? $threshold : 3);
if (!@include_once(dirname(__FILE__ ). '/phpthumb.unsharp.php')) {
$this->DebugMessage('include_once("'. dirname(__FILE__ ). '/phpthumb.unsharp.php") generated message: "'. $include_error. '"', __FILE__ , __LINE__ );
$this->DebugMessage('Error including "'. dirname(__FILE__ ). '/phpthumb.unsharp.php" which is required for unsharp masking', __FILE__ , __LINE__ );
@list ($angle, $bgcolor) = explode('|', $parameter);
$phpthumbFilters->ImprovedImageRotate($this->gdimg_output, $angle, $bgcolor);
case 'stc': // Source Transparent Color
@list ($hexcolor, $min_limit, $max_limit) = explode('|', $parameter);
$this->DebugMessage('Skipping SourceTransparentColor hex color is invalid ('. $hexcolor. ')', __FILE__ , __LINE__ );
$min_limit = (strlen($min_limit) ? $min_limit : 5);
$max_limit = (strlen($max_limit) ? $max_limit : 10);
if ($gdimg_mask = $phpthumbFilters->SourceTransparentColorMask($this->gdimg_output, $hexcolor, $min_limit, $max_limit)) {
$phpthumbFilters->ApplyMask($gdimg_mask, $this->gdimg_output);
ImageDestroy($gdimg_mask);
$this->DebugMessage('SourceTransparentColorMask() failed for "'. $mask_filename. '"', __FILE__ , __LINE__ );
$this->DebugMessage('Finished processing filter command "'. $command. '('. $parameter. ')"', __FILE__ , __LINE__ );
for ($i = 8; $i >= 1; $i-- ) {
ImageTrueColorToPalette($tempIMG, true, pow(2, $i));
$imgRenderFunction($tempIMG);
for ($i = 3; $i < 20; $i++ ) {
//echo $this->source_width.'x'.$this->source_height.'<hr>';
//echo $this->thumbnailCropX.'<br>';
//echo $this->thumbnailCropY.'<br>';
//echo $this->thumbnailCropW.'<br>';
//echo $this->thumbnailCropH.'<hr>';
// limit source area to original image area
if ($this->zc && $this->w && $this->h) {
// retain proportional resizing we did above, but crop off larger dimension so smaller
// dimension fully fits available space
if ($scaling_X > $scaling_Y) {
// some of the width will need to be cropped
$allowable_width = $this->source_width / $scaling_X * $scaling_Y;
} elseif ($scaling_Y > $scaling_X) {
// some of the height will need to be cropped
$allowable_height = $this->source_height / $scaling_Y * $scaling_X;
// image fits perfectly, no cropping needed
} elseif ($this->iar && $this->w && $this->h) {
// stretch image to fit exactly 'w' x 'h'
if ($this->w && $this->h) {
$maxwidth = min($this->w, $this->h * $original_aspect_ratio);
$maxheight = min($this->h, $this->w / $original_aspect_ratio);
$maxheight = $this->w / $original_aspect_ratio;
$maxwidth = $this->h * $original_aspect_ratio;
//echo $maxwidth.'x'.$maxheight.'<br>';
$maxwidth = min($maxwidth, $maxheight * $original_aspect_ratio);
$maxheight = min($maxheight, $maxwidth / $original_aspect_ratio);
//echo $maxwidth.'x'.$maxheight.'<hr>';
// Create the GD image (either true-color or 256-color, depending on GD version)
// Images that have transparency must have the background filled with the configured 'bg' color
// otherwise the transparent color will appear as black
$current_transparent_color = ImageColorTransparent($this->gdimg_source);
if ($this->bg || (@$current_transparent_color >= 0)) {
//$this->w = round($this->w ? $this->w : (($this->h && $this->source_height) ? $this->h * $this->source_width / $this->source_height : $this->w));
//$this->h = round($this->h ? $this->h : (($this->w && $this->source_width) ? $this->w * $this->source_height / $this->source_width : $this->h));
$this->DebugMessage('SetOrientationDependantWidthHeight() setting w="'. intval($this->w). '", h="'. intval($this->h). '"', __FILE__ , __LINE__ );
$this->DebugMessage('starting ExtractEXIFgetImageSize()', __FILE__ , __LINE__ );
$this->DebugMessage('bypassing EXIF and GetImageSize sections because $this->rawImageData is set and $this->sourceFilename is not set', __FILE__ , __LINE__ );
$this->DebugMessage('ImageMagickThumbnailToGD() failed', __FILE__ , __LINE__ );
// Extract EXIF info from JPEGs
// The parameters width, height and imagetype are available since PHP v4.3.0
// older versions of exif_thumbnail output an error message but NOT return false on failure
$this->exif_thumbnail_type = 2; // (2 == JPEG) before PHP v4.3.0 only JPEG format EXIF thumbnails are returned
return $this->ErrorImage('Failed - $this->ImageCreateFromStringReplacement($this->exif_thumbnail_data) in '.__FILE__. ' on line '.__LINE__ );
$this->DebugMessage('exif_thumbnail() does not exist, cannot extract EXIF thumbnail', __FILE__ , __LINE__ );
// see if EXIF thumbnail can be used directly with no processing
$this->DebugMessage('not using EXIF thumbnail because $source_ar != $exif_ar ('. $source_ar. ' != '. $exif_ar. ')', __FILE__ , __LINE__ );
$this->DebugMessage('not using EXIF thumbnail because $this->w != $this->exif_thumbnail_width ('. $this->w. ' != '. $this->exif_thumbnail_width. ')', __FILE__ , __LINE__ );
$CannotBeSetParameters = array('sx', 'sy', 'sh', 'sw', 'far', 'bg', 'bc', 'fltr', 'phpThumbDebug');
foreach ($CannotBeSetParameters as $parameter) {
$this->DebugMessage('setting $this->gdimg_source = $this->ImageCreateFromStringReplacement($this->exif_thumbnail_data)', __FILE__ , __LINE__ );
// Source image is larger than would fit in available PHP memory.
// If ImageMagick is installed, use it to generate the thumbnail.
// Else, if an EXIF thumbnail is available, use that as the source image.
// Otherwise, no choice but to fail with an error message
// excellent, we have a thumbnailed source image
$this->DebugMessage('$this->cache_filename already set, skipping SetCacheFilename()', __FILE__ , __LINE__ );
$this->DebugMessage('SetCacheFilename() failed because $this->config_cache_directory is empty', __FILE__ , __LINE__ );
// simplified cache filenames:
// only use default parameters in phpThumb.config.php
// substitute source filename into * in $this->config_cache_default_only_suffix
// (eg: '*_thumb' becomes 'picture_thumb.jpg')
$broad_directory_name = '';
// source image MD5 hash provided
$this->DebugMessage('SetCacheFilename() _raw set from $this->md5s = "'. $this->md5s. '"', __FILE__ , __LINE__ );
$broad_directory_name = $this->md5s;
if (@$parsed_url1['host'] && @$parsed_url2['host'] && ($parsed_url1['host'] != $parsed_url2['host'])) {
// include "_offsite" only if nooffsitelink_enabled and if referrer doesn't match the domain of the current server
$ParametersString .= '_fltr'. implode('_fltr', $this->fltr);
$FilenameParameters1 = array('ar', 'bg', 'bc', 'far', 'sx', 'sy', 'sw', 'sh', 'zc');
foreach ($FilenameParameters1 as $key) {
$ParametersString .= '_'. $key. $this->$key;
$FilenameParameters2 = array('h', 'w', 'wl', 'wp', 'ws', 'hp', 'hs', 'xto', 'ra', 'iar', 'aoe', 'maxb', 'sfn', 'dpi');
foreach ($FilenameParameters2 as $key) {
$ParametersString .= '_'. $key. intval($this->$key);
// only JPEG output has variable quality option
$this->DebugMessage('SetCacheFilename() _par set from md5('. $ParametersString. ')', __FILE__ , __LINE__ );
// source image MD5 hash provided
// do not source image modification date --
// cached image will be used even if file was modified or removed
$broad_directories .= DIRECTORY_SEPARATOR. substr($broad_directory_name, 0, $i + 1);
return (bool) (($width * $height * 5) > $available_memory);
// try to create GD image source directly via GD, if possible,
// rather than buffering to memory and creating with ImageCreateFromString
$ImageCreateWasAttempted = false;
$this->DebugMessage('starting ImageCreateFromFilename('. $filename. ')', __FILE__ , __LINE__ );
if ($filename && ($getimagesizeinfo = @GetImageSize($filename))) {
$ImageCreateFromFunction = array(
1 => 'ImageCreateFromGIF',
2 => 'ImageCreateFromJPEG',
3 => 'ImageCreateFromPNG',
15 => 'ImageCreateFromWBMP',
$this->DebugMessage('ImageCreateFromFilename found ($getimagesizeinfo[2]=='. @$getimagesizeinfo[2]. ')', __FILE__ , __LINE__ );
switch (@$getimagesizeinfo[2]) {
$ImageCreateFromFunctionName = $ImageCreateFromFunction[$getimagesizeinfo[2]];
$this->DebugMessage('Calling '. $ImageCreateFromFunctionName. '('. $filename. ')', __FILE__ , __LINE__ );
$ImageCreateWasAttempted = true;
$gd_image = $ImageCreateFromFunctionName($filename);
$this->DebugMessage('NOT calling '. $ImageCreateFromFunctionName. '('. $filename. ') because !function_exists('. $ImageCreateFromFunctionName. ')', __FILE__ , __LINE__ );
$this->DebugMessage('No built-in image creation function for image type "'. @$getimagesizeinfo[2]. '" ($getimagesizeinfo[2])', __FILE__ , __LINE__ );
$this->DebugMessage('Unknown value for $getimagesizeinfo[2]: "'. @$getimagesizeinfo[2]. '"', __FILE__ , __LINE__ );
$this->DebugMessage('image is '. $getimagesizeinfo[0]. 'x'. $getimagesizeinfo[1]. ' and therefore contains more pixels ('. ($getimagesizeinfo[0] * $getimagesizeinfo[1]). ') than $this->config_max_source_pixels setting ('. $this->config_max_source_pixels. ')', __FILE__ , __LINE__ );
$this->DebugMessage('empty $filename or GetImageSize('. $filename. ') failed', __FILE__ , __LINE__ );
// cannot create from filename, attempt to create source image with ImageCreateFromString, if possible
if ($ImageCreateWasAttempted) {
$this->DebugMessage(@$ImageCreateFromFunctionName. '() was attempted but FAILED', __FILE__ , __LINE__ );
$this->DebugMessage('Populating $rawimagedata', __FILE__ , __LINE__ );
if ($fp = @fopen($filename, 'rb')) {
$blockreads = ceil($filesize / $blocksize);
for ($i = 0; $i < $blockreads; $i++ ) {
$rawimagedata .= fread($fp, $blocksize);
$this->DebugMessage('cannot fopen('. $filename. ')', __FILE__ , __LINE__ );
$this->DebugMessage('attempting ImageCreateFromStringReplacement($rawimagedata ('. strlen($rawimagedata). ' bytes), true)', __FILE__ , __LINE__ );
$this->DebugMessage('starting SourceImageToGD()', __FILE__ , __LINE__ );
// excellent, we have a thumbnailed source image
$this->DebugMessage('ImageMagickThumbnailToGD() succeeded', __FILE__ , __LINE__ );
// return $this->ErrorImage('Unknown image type identified by "'.substr($this->rawImageData, 0, 4).'" ('.phpthumb_functions::HexCharDisplay(substr($this->rawImageData, 0, 4)).') in SourceImageToGD()['.__LINE__.']');
// GIF or PNG input file may have transparency
$this->DebugMessage('Not using EXIF thumbnail data because $this->gdimg_source is already set', __FILE__ , __LINE__ );
$this->DebugMessage('Not using EXIF thumbnail data because $this->exif_thumbnail_data is empty', __FILE__ , __LINE__ );
$this->DebugMessage('Using EXIF thumbnail data because source image too large and safe_mode enabled', __FILE__ , __LINE__ );
$this->DebugMessage('Not using EXIF thumbnail data because $this->config_use_exif_thumbnail_for_speed is FALSE', __FILE__ , __LINE__ );
$this->DebugMessage('not using EXIF thumbnail because $source_ar != $exif_ar ('. $source_ar. ' != '. $exif_ar. ')', __FILE__ , __LINE__ );
// EXIF thumbnail exists, and is equal to or larger than destination thumbnail, and will be use as source image
$this->DebugMessage('Trying to use EXIF thumbnail as source image', __FILE__ , __LINE__ );
$this->DebugMessage('Successfully using EXIF thumbnail as source image', __FILE__ , __LINE__ );
$this->DebugMessage('$this->ImageCreateFromStringReplacement($this->exif_thumbnail_data, false) failed', __FILE__ , __LINE__ );
$this->DebugMessage('$this->gdimg_source is still empty', __FILE__ , __LINE__ );
$this->DebugMessage('ImageMagickThumbnailToGD() failed', __FILE__ , __LINE__ );
$imageHeader = 'Content-Type: image/gif';
$GDreadSupport = (bool) @$gd_info['GIF Read Support'];
$imageHeader = 'Content-Type: image/jpeg';
$GDreadSupport = (bool) @$gd_info['JPG Support'];
$imageHeader = 'Content-Type: image/png';
$GDreadSupport = (bool) @$gd_info['PNG Support'];
// cannot create image for whatever reason (maybe ImageCreateFromJPEG et al are not available?)
// and ImageMagick is not available either, no choice but to output original (not resized/modified) data and exit
$errormessages = array();
$errormessages[] = 'All attempts to create GD image source failed.';
$errormessages[] = 'Safe Mode enabled, therefore ImageMagick is unavailable. (disable Safe Mode if possible)';
$errormessages[] = 'ImageMagick is not installed (it is highly recommended that you install it).';
} elseif (!$GDreadSupport) {
$errormessages[] = 'GD does not have read support for "'. $imageHeader. '".';
$errormessages[] = 'Source image probably corrupt.';
$this->DebugMessage('All attempts to create GD image source failed ('. (ini_get('safe_mode') ? 'Safe Mode enabled, ImageMagick unavailable and source image probably too large for GD': ($GDreadSupport ? 'source image probably corrupt' : 'GD does not have read support for "'. $imageHeader. '"')). '), cannot generate thumbnail');
//$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__);
//if (!$this->phpThumbDebug) {
// echo $this->rawImageData;
//switch (substr($this->rawImageData, 0, 2)) {
if (!@include_once(dirname(__FILE__ ). '/phpthumb.bmp.php')) {
return $this->ErrorImage('include_once('. dirname(__FILE__ ). '/phpthumb.bmp.php) failed');
$this->DebugMessage('$phpthumb_bmp->phpthumb_bmp2gd() succeeded', __FILE__ , __LINE__ );
//switch (substr($this->rawImageData, 0, 4)) {
return $this->ErrorImage($this->ImageMagickVersion() ? 'ImageMagick failed on TIFF source conversion' : 'ImageMagick is unavailable and phpThumb() does not support TIFF source images without it');
//case "\xD7\xCD\xC6\x9A":
// return $this->ErrorImage($this->ImageMagickVersion() ? 'ImageMagick failed on WMF source conversion' : 'ImageMagick is unavailable and phpThumb() does not support WMF source images without it');
$HeaderFourBytes = fread($fp, 4);
if ($HeaderFourBytes == "\xD7\xCD\xC6\x9A") { // WMF
return $this->ErrorImage($this->ImageMagickVersion() ? 'ImageMagick failed on WMF source conversion' : 'ImageMagick is unavailable and phpThumb() does not support WMF source images without it');
} elseif ($HeaderFourBytes == '%PDF') { // "%PDF"
return $this->ErrorImage($this->ImageMagickVersion() ? 'ImageMagick and GhostScript are both required for PDF source images; GhostScript may not be properly configured' : 'ImageMagick and/or GhostScript are unavailable and phpThumb() does not support PDF source images without them');
} elseif (substr($HeaderFourBytes, 0, 3) == "\xFF\xD8\xFF") { // JPEG
return $this->ErrorImage('Image is too large for PHP-GD memory_limit, please install ImageMagick or increase php.ini memory_limit setting');
} elseif ($HeaderFourBytes == '%PNG') { // "%PNG"
return $this->ErrorImage('Image is too large for PHP-GD memory_limit, please install ImageMagick or increase php.ini memory_limit setting');
} elseif (substr($HeaderFourBytes, 0, 3) == 'GIF') { // GIF
return $this->ErrorImage('Image is too large for PHP-GD memory_limit, please install ImageMagick or increase php.ini memory_limit setting');
$this->DebugMessage('All other attempts failed, but successfully using EXIF thumbnail as source image', __FILE__ , __LINE__ );
// override allow-enlarging setting if EXIF thumbnail is the only source available
// otherwise thumbnails larger than the EXIF thumbnail will be created at EXIF size
return ($var ? 'TRUE' : 'FALSE');
return strtr($vardumpoutput, "\n\r\t", ' ');
return $this->ErrorImage('phpThumbDebug disabled');
$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');
$ParameterNames = array('src', 'new', 'w', 'h', 'f', 'q', 'sx', 'sy', 'sw', 'sh', 'far', 'bg', 'bc', 'file', 'goto', 'err', 'xto', 'ra', 'ar', 'aoe', 'iar', 'maxb');
$ConfigVariableNames = array('document_root', 'temp_directory', 'output_format', 'output_maxwidth', 'output_maxheight', 'error_message_image_default', 'error_bgcolor', 'error_textcolor', 'error_fontsize', 'error_die_on_error', 'error_silent_die_on_error', 'error_die_on_source_failure', 'nohotlink_enabled', 'nohotlink_valid_domains', 'nohotlink_erase_image', 'nohotlink_text_message', 'nooffsitelink_enabled', 'nooffsitelink_valid_domains', 'nooffsitelink_require_refer', 'nooffsitelink_erase_image', 'nooffsitelink_text_message', 'high_security_enabled', 'allow_src_above_docroot', 'allow_src_above_phpthumb', 'allow_parameter_file', 'allow_parameter_goto', 'max_source_pixels', 'use_exif_thumbnail_for_speed', 'border_hexcolor', 'background_hexcolor', 'ttf_directory', 'disable_pathinfo_parsing', 'disable_imagecopyresampled');
$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');
$DebugOutput[] = 'PHP_OS = '. PHP_OS;
$DebugOutput[] = '__FILE__ = '.__FILE__ ;
$DebugOutput[] = 'realpath(.) = '. @realpath('.');
$DebugOutput[] = '$_SERVER[PHP_SELF] = '. @$_SERVER['PHP_SELF'];
$DebugOutput[] = '$_SERVER[HOST_NAME] = '. @$_SERVER['HOST_NAME'];
$DebugOutput[] = '$_SERVER[HTTP_REFERER] = '. @$_SERVER['HTTP_REFERER'];
$DebugOutput[] = '$_SERVER[QUERY_STRING] = '. @$_SERVER['QUERY_STRING'];
$DebugOutput[] = '$_SERVER[PATH_INFO] = '. @$_SERVER['PATH_INFO'];
$DebugOutput[] = '$_SERVER[DOCUMENT_ROOT] = '. @$_SERVER['DOCUMENT_ROOT'];
$DebugOutput[] = 'getenv(DOCUMENT_ROOT) = '. @getenv('DOCUMENT_ROOT');
foreach ($ConfigVariableNames as $varname) {
$varname = 'config_'. $varname;
$value = $this->$varname;
foreach ($OtherVariableNames as $varname) {
$value = $this->$varname;
foreach ($ParameterNames as $varname) {
$value = $this->$varname;
foreach ($FunctionsExistance as $functionname) {
foreach ($gd_info as $key => $value) {
foreach ($exif_info as $key => $value) {
foreach ($ApacheLookupURIarray as $key => $value) {
$DebugOutput[] = 'ApacheLookupURIarray() -- FAILED';
foreach ($_GET as $key => $value) {
if (isset ($_POST) && is_array($_POST)) {
foreach ($_POST as $key => $value) {
$DebugOutput[] = '$this->debugmessages:';
$DebugOutput[] = ' * '. $errorstring;
$DebugOutput[] = '$this->debugtiming:';
foreach ($this->debugtiming as $timestamp => $timingstring) {
$DebugOutput[] = ' * '. $timestamp. ' '. $timingstring;
$this->f = (isset ($_GET['f']) ? $_GET['f'] : $this->f); // debug modes 0-2 don't recognize text mode otherwise
function ErrorImage($text, $width= 0, $height= 0, $forcedisplay= false) {
$text = 'Error messages disabled';
// Show generic custom error image instead of error message
// for use on production sites where you don't want debug messages
if ($this->err == 'showerror') {
// fall through and actually show error message even if default error image is set
// bypass all GD functions and output text error message
header('Content-type: text/plain');
$height = max($height, count($LinesOfText) * $FontHeight);
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>';
echo "\n". '**Headers already sent, dumping error message as text:**<br><pre>'. "\n\n". $text. "\n". '</pre>';
} elseif ($gdimg_error = ImageCreate($width, $height)) {
ImageFilledRectangle($gdimg_error, 0, 0, $width, $height, $background_color);
foreach ($LinesOfText as $line) {
$lineYoffset += $FontHeight;
$imagetypes = ImageTypes();
if ($imagetypes & IMG_PNG) {
header('Content-Type: image/png');
} elseif ($imagetypes & IMG_GIF) {
header('Content-Type: image/gif');
} elseif ($imagetypes & IMG_JPG) {
header('Content-Type: image/jpeg');
} elseif ($imagetypes & IMG_WBMP) {
header('Content-Type: image/vnd.wap.wbmp');
ImageDestroy($gdimg_error);
echo "\n". '**Failed to send graphical error image, dumping error message as text:**<br>'. "\n\n". $text;
// there are serious bugs in the non-bundled versions of GD which may cause
// PHP to segfault when calling ImageCreateFromString() - avoid if at all possible
// when not using a bundled version of GD2
// base64-encoded error image in GIF format
$ERROR_NOGD = 'R0lGODlhIAAgALMAAAAAABQUFCQkJDY2NkZGRldXV2ZmZnJycoaGhpSUlKWlpbe3t8XFxdXV1eTk5P7+/iwAAAAAIAAgAAAE/vDJSau9WILtTAACUinDNijZtAHfCojS4W5H+qxD8xibIDE9h0OwWaRWDIljJSkUJYsN4bihMB8th3IToAKs1VtYM75cyV8sZ8vygtOE5yMKmGbO4jRdICQCjHdlZzwzNW4qZSQmKDaNjhUMBX4BBAlmMywFSRWEmAI6b5gAlhNxokGhooAIK5o/pi9vEw4Lfj4OLTAUpj6IabMtCwlSFw0DCKBoFqwAB04AjI54PyZ+yY3TD0ss2YcVmN/gvpcu4TOyFivWqYJlbAHPpOntvxNAACcmGHjZzAZqzSzcq5fNjxFmAFw9iFRunD1epU6tsIPmFCAJnWYE0FURk7wJDA0MTKpEzoWAAskiAAA7';
header('Content-Type: image/gif');
echo '*** ERROR: No PHP-GD support available ***';
$this->DebugMessage('ImageCreateFromStringReplacement() calling built-in ImageCreateFromString()', __FILE__ , __LINE__ );
return @ImageCreateFromString($RawImageData);
$this->DebugMessage('ImageCreateFromStringReplacement() failed: cannot create temp file in SAFE_MODE', __FILE__ , __LINE__ );
switch (substr($RawImageData, 0, 3)) {
$ICFSreplacementFunctionName = 'ImageCreateFromGIF';
$ICFSreplacementFunctionName = 'ImageCreateFromJPEG';
$ICFSreplacementFunctionName = 'ImageCreateFromPNG';
if ($fp_tempnam = @fopen($tempnam, 'wb')) {
fwrite($fp_tempnam, $RawImageData);
if (($ICFSreplacementFunctionName == 'ImageCreateFromGIF') && !function_exists($ICFSreplacementFunctionName)) {
// Need to create from GIF file, but ImageCreateFromGIF does not exist
if (!@include_once(dirname(__FILE__ ). '/phpthumb.gif.php')) {
$ErrorMessage = 'Failed to include required file "'. dirname(__FILE__ ). '/phpthumb.gif.php" in '.__FILE__. ' on line '.__LINE__ ;
// gif_loadFileToGDimageResource() cannot read from raw data, write to file first
if ($fp_tempfile = @fopen($tempfilename, 'wb')) {
fwrite($fp_tempfile, $RawImageData);
$this->DebugMessage('gif_loadFileToGDimageResource('. $tempfilename. ') completed', __FILE__ , __LINE__ );
$ErrorMessage = 'Failed to open tempfile in '.__FILE__. ' on line '.__LINE__ ;
$ErrorMessage = 'Failed to open generate tempfile name in '.__FILE__. ' on line '.__LINE__ ;
} elseif (function_exists($ICFSreplacementFunctionName) && ($gdimg_source = @$ICFSreplacementFunctionName($tempnam))) {
$this->DebugMessage($ICFSreplacementFunctionName. '('. $tempnam. ') succeeded', __FILE__ , __LINE__ );
// GD functions not available, or failed to create image
$this->DebugMessage($ICFSreplacementFunctionName. '('. $tempnam. ') '. (function_exists($ICFSreplacementFunctionName) ? 'failed' : 'does not exist'), __FILE__ , __LINE__ );
if (isset ($_GET['phpThumbDebug'])) {
$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';
$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';
if ($DieOnErrors && $ErrorMessage) {
function ImageResizeFunction(&$dst_im, &$src_im, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH) {
$this->DebugMessage('ImageResizeFunction($o, $s, '. $dstX. ', '. $dstY. ', '. $srcX. ', '. $srcY. ', '. $dstW. ', '. $dstH. ', '. $srcW. ', '. $srcH. ')', __FILE__ , __LINE__ );
if (($dstW == $srcW) && ($dstH == $srcH)) {
return ImageCopy($dst_im, $src_im, $dstX, $dstY, $srcX, $srcY, $srcW, $srcH);
return ImageCopyResampled($dst_im, $src_im, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH);
return ImageCopyResized($dst_im, $src_im, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH);
$this->DebugMessage('phpThumb_tempnam() returning "'. $tempnam. '"', __FILE__ , __LINE__ );
|