XOOPS 2.5.6  Final
 All Classes Namespaces Files Functions Variables Pages
phpthumb.class.php
Go to the documentation of this file.
1 <?php
4 // available at http://phpthumb.sourceforge.net ///
7 // See: phpthumb.readme.txt for usage instructions //
8 // ///
10 
11 ob_start();
12 if (!include_once(dirname(__FILE__).'/phpthumb.functions.php')) {
13  ob_end_flush();
14  die('failed to include_once("'.realpath(dirname(__FILE__).'/phpthumb.functions.php').'")');
15 }
16 ob_end_clean();
17 
18 class phpthumb {
19 
20  // public:
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; // output image 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 $sfn = 0; // Source Frame Number
55  var $dpi = 150; // Dots Per Inch for vector source formats
56  var $sia = null; // Save Image As filename
57 
58  var $file = null; // >>>deprecated, DO NOT USE, will be removed in future versions<<<
59 
60  var $phpThumbDebug = null;
61  // END PARAMETERS
62 
63 
64  // public:
65  // START CONFIGURATION OPTIONS (for object mode only)
66  // See phpThumb.config.php for descriptions of what each of these settings do
67 
68  // * Directory Configuration
76 
77  // * Default output configuration:
78  var $config_output_format = 'jpeg';
82 
83  // * Error message configuration
87  var $config_error_bgcolor = 'CCCCFF';
88  var $config_error_textcolor = 'FF0000';
93 
94  // * Anti-Hotlink Configuration:
98  var $config_nohotlink_text_message = 'Off-server thumbnailing is not allowed';
99  // * Off-server Linking Configuration:
105  var $config_nooffsitelink_text_message = 'Off-server linking is not allowed';
106 
107  // * Border & Background default colors
108  var $config_border_hexcolor = '000000';
110 
111  // * TrueType Fonts
112  var $config_ttf_directory = './fonts';
113 
117 
121 
129  var $config_cache_prefix = ''; // default value set in the constructor below
130 
131  // * MySQL
137 
138  // * Security
144 
145  // * HTTP fopen
148 
149  // * Compatability
153 
154  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';
155 
156  // END CONFIGURATION OPTIONS
157 
158 
159  // public: error messages (read-only; persistant)
160  var $debugmessages = array();
161  var $debugtiming = array();
162  var $fatalerror = null;
163 
164 
165  // private: (should not be modified directly)
167  var $thumbnailFormat = null;
168 
169  var $sourceFilename = null;
170  var $rawImageData = null;
171  var $IMresizedData = null;
172  var $outputImageData = null;
173 
174  var $useRawIMoutput = false;
175 
176  var $gdimg_output = null;
177  var $gdimg_source = null;
178 
179  var $getimagesizeinfo = null;
180 
181  var $source_width = null;
182  var $source_height = null;
183 
184  var $thumbnailCropX = null;
185  var $thumbnailCropY = null;
186  var $thumbnailCropW = null;
187  var $thumbnailCropH = null;
188 
193  var $exif_raw_data = null;
194 
195  var $thumbnail_width = null;
196  var $thumbnail_height = null;
199 
200  var $tempFilesToDelete = array();
201  var $cache_filename = null;
202 
203  var $AlphaCapableFormats = array('png', 'ico', 'gif');
204  var $is_alpha = false;
205 
206  var $iswindows = null;
207  var $issafemode = null;
208 
209  var $phpthumb_version = '1.7.11-201108081537';
210 
212 
213  // public: constructor
214  function phpThumb() {
215  $this->DebugTimingMessage('phpThumb() constructor', __FILE__, __LINE__);
216  $this->DebugMessage('phpThumb() v'.$this->phpthumb_version, __FILE__, __LINE__);
217  $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
218  $this->iswindows = (bool) (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN');
219  $this->issafemode = (bool) preg_match('#(1|ON)#i', ini_get('safe_mode'));
220  $this->config_document_root = (!empty($_SERVER['DOCUMENT_ROOT']) ? $_SERVER['DOCUMENT_ROOT'] : $this->config_document_root);
221  $this->config_cache_prefix = ( isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'].'_' : '');
222 
223  $this->purgeTempFiles(); // purge existing temp files if re-initializing object
224 
225  $php_sapi_name = strtolower(function_exists('php_sapi_name') ? php_sapi_name() : '');
226  if ($php_sapi_name == 'cli') {
227  $this->config_allow_src_above_docroot = true;
228  }
229  }
230 
231  function __destruct() {
232  $this->purgeTempFiles();
233  }
234 
235  // public:
236  function purgeTempFiles() {
237  foreach ($this->tempFilesToDelete as $tempFileToDelete) {
238  if (file_exists($tempFileToDelete)) {
239  $this->DebugMessage('Deleting temp file "'.$tempFileToDelete.'"', __FILE__, __LINE__);
240  @unlink($tempFileToDelete);
241  }
242  }
243  $this->tempFilesToDelete = array();
244  return true;
245  }
246 
247  // public:
249  //$this->resetObject();
250  //$this->rawImageData = null;
251  $this->sourceFilename = $sourceFilename;
252  $this->src = $sourceFilename;
253  if (is_null($this->config_output_format)) {
254  $sourceFileExtension = strtolower(substr(strrchr($sourceFilename, '.'), 1));
255  if (preg_match('#^[a-z]{3,4}$#', $sourceFileExtension)) {
256  $this->config_output_format = $sourceFileExtension;
257  $this->DebugMessage('setSourceFilename('.$sourceFilename.') set $this->config_output_format to "'.$sourceFileExtension.'"', __FILE__, __LINE__);
258  } else {
259  $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__);
260  }
261  }
262  $this->DebugMessage('setSourceFilename('.$sourceFilename.') set $this->sourceFilename to "'.$this->sourceFilename.'"', __FILE__, __LINE__);
263  return true;
264  }
265 
266  // public:
268  //$this->resetObject();
269  //$this->sourceFilename = null;
270  $this->rawImageData = $rawImageData;
271  $this->DebugMessage('setSourceData() setting $this->rawImageData ('.strlen($this->rawImageData).' bytes; magic="'.substr($this->rawImageData, 0, 4).'" ('.phpthumb_functions::HexCharDisplay(substr($this->rawImageData, 0, 4)).'))', __FILE__, __LINE__);
272  if ($this->config_cache_source_enabled) {
274  if (!is_dir($this->config_cache_source_directory)) {
275  $this->ErrorImage('$this->config_cache_source_directory ('.$this->config_cache_source_directory.') is not a directory');
276  } elseif (!@is_writable($this->config_cache_source_directory)) {
277  $this->ErrorImage('$this->config_cache_source_directory ('.$this->config_cache_source_directory.') is not writable');
278  }
279  $this->DebugMessage('setSourceData() attempting to save source image to "'.$this->config_cache_source_directory.DIRECTORY_SEPARATOR.urlencode($sourceFilename).'"', __FILE__, __LINE__);
280  if ($fp = @fopen($this->config_cache_source_directory.DIRECTORY_SEPARATOR.urlencode($sourceFilename), 'wb')) {
281  fwrite($fp, $rawImageData);
282  fclose($fp);
283  } elseif (!$this->phpThumbDebug) {
284  $this->ErrorImage('setSourceData() failed to write to source cache ('.$this->config_cache_source_directory.DIRECTORY_SEPARATOR.urlencode($sourceFilename).')');
285  }
286  }
287  return true;
288  }
289 
290  // public:
291  function setSourceImageResource($gdimg) {
292  //$this->resetObject();
293  $this->gdimg_source = $gdimg;
294  return true;
295  }
296 
297  // public:
298  function setParameter($param, $value) {
299  if ($param == 'src') {
300  $this->setSourceFilename($this->ResolveFilenameToAbsolute($value));
301  } elseif (@is_array($this->$param)) {
302  if (is_array($value)) {
303  foreach ($value as $arraykey => $arrayvalue) {
304  array_push($this->$param, $arrayvalue);
305  }
306  } else {
307  array_push($this->$param, $value);
308  }
309  } else {
310  $this->$param = $value;
311  }
312  return true;
313  }
314 
315  // public:
316  function getParameter($param) {
317  //if (property_exists('phpThumb', $param)) {
318  return $this->$param;
319  //}
320  //$this->DebugMessage('setParameter() attempting to get non-existant parameter "'.$param.'"', __FILE__, __LINE__);
321  //return false;
322  }
323 
324 
325  // public:
326  function GenerateThumbnail() {
327 
328  $this->setOutputFormat();
329  $this->phpThumbDebug('8a');
330  $this->ResolveSource();
331  $this->phpThumbDebug('8b');
332  $this->SetCacheFilename();
333  $this->phpThumbDebug('8c');
334  $this->ExtractEXIFgetImageSize();
335  $this->phpThumbDebug('8d');
336  if ($this->useRawIMoutput) {
337  $this->DebugMessage('Skipping rest of GenerateThumbnail() because ($this->useRawIMoutput == true)', __FILE__, __LINE__);
338  return true;
339  }
340  $this->phpThumbDebug('8e');
341  if (!$this->SourceImageToGD()) {
342  $this->DebugMessage('SourceImageToGD() failed', __FILE__, __LINE__);
343  return false;
344  }
345  $this->phpThumbDebug('8f');
346  $this->Rotate();
347  $this->phpThumbDebug('8g');
348  $this->CreateGDoutput();
349  $this->phpThumbDebug('8h');
350 
351  switch ($this->far) {
352  case 'L':
353  case 'TL':
354  case 'BL':
355  $destination_offset_x = 0;
356  $destination_offset_y = round(($this->thumbnail_height - $this->thumbnail_image_height) / 2);
357  break;
358  case 'R':
359  case 'TR':
360  case 'BR':
361  $destination_offset_x = round($this->thumbnail_width - $this->thumbnail_image_width);
362  $destination_offset_y = round(($this->thumbnail_height - $this->thumbnail_image_height) / 2);
363  break;
364  case 'T':
365  case 'TL':
366  case 'TR':
367  $destination_offset_x = round(($this->thumbnail_width - $this->thumbnail_image_width) / 2);
368  $destination_offset_y = 0;
369  break;
370  case 'B':
371  case 'BL':
372  case 'BR':
373  $destination_offset_x = round(($this->thumbnail_width - $this->thumbnail_image_width) / 2);
374  $destination_offset_y = round($this->thumbnail_height - $this->thumbnail_image_height);
375  break;
376  case 'C':
377  default:
378  $destination_offset_x = round(($this->thumbnail_width - $this->thumbnail_image_width) / 2);
379  $destination_offset_y = round(($this->thumbnail_height - $this->thumbnail_image_height) / 2);
380  }
381 
382 // // copy/resize image to appropriate dimensions
383 // $borderThickness = 0;
384 // if (!empty($this->fltr)) {
385 // foreach ($this->fltr as $key => $value) {
386 // if (preg_match('#^bord\|([0-9]+)#', $value, $matches)) {
387 // $borderThickness = $matches[1];
388 // break;
389 // }
390 // }
391 // }
392 // if ($borderThickness > 0) {
393 // //$this->DebugMessage('Skipping ImageResizeFunction() because BorderThickness="'.$borderThickness.'"', __FILE__, __LINE__);
394 // $this->thumbnail_image_height /= 2;
395 // }
396  $this->ImageResizeFunction(
397  $this->gdimg_output,
398  $this->gdimg_source,
399  $destination_offset_x,
400  $destination_offset_y,
401  $this->thumbnailCropX,
402  $this->thumbnailCropY,
403  $this->thumbnail_image_width,
404  $this->thumbnail_image_height,
405  $this->thumbnailCropW,
406  $this->thumbnailCropH
407  );
408 
409  $this->DebugMessage('memory_get_usage() after copy-resize = '.(function_exists('memory_get_usage') ? @memory_get_usage() : 'n/a'), __FILE__, __LINE__);
410  ImageDestroy($this->gdimg_source);
411  $this->DebugMessage('memory_get_usage() after ImageDestroy = '.(function_exists('memory_get_usage') ? @memory_get_usage() : 'n/a'), __FILE__, __LINE__);
412 
413  $this->phpThumbDebug('8i');
414  $this->AntiOffsiteLinking();
415  $this->phpThumbDebug('8j');
416  $this->ApplyFilters();
417  $this->phpThumbDebug('8k');
418  $this->AlphaChannelFlatten();
419  $this->phpThumbDebug('8l');
420  $this->MaxFileSize();
421  $this->phpThumbDebug('8m');
422 
423  $this->DebugMessage('GenerateThumbnail() completed successfully', __FILE__, __LINE__);
424  return true;
425  }
426 
427 
428  // public:
429  function RenderOutput() {
430  if (!$this->useRawIMoutput && !is_resource($this->gdimg_output)) {
431  $this->DebugMessage('RenderOutput() failed because !is_resource($this->gdimg_output)', __FILE__, __LINE__);
432  return false;
433  }
434  if (!$this->thumbnailFormat) {
435  $this->DebugMessage('RenderOutput() failed because $this->thumbnailFormat is empty', __FILE__, __LINE__);
436  return false;
437  }
438  if ($this->useRawIMoutput) {
439  $this->DebugMessage('RenderOutput copying $this->IMresizedData ('.strlen($this->IMresizedData).' bytes) to $this->outputImage', __FILE__, __LINE__);
440  $this->outputImageData = $this->IMresizedData;
441  return true;
442  }
443 
444  $builtin_formats = array();
445  if (function_exists('ImageTypes')) {
446  $imagetypes = ImageTypes();
447  $builtin_formats['wbmp'] = (bool) ($imagetypes & IMG_WBMP);
448  $builtin_formats['jpg'] = (bool) ($imagetypes & IMG_JPG);
449  $builtin_formats['gif'] = (bool) ($imagetypes & IMG_GIF);
450  $builtin_formats['png'] = (bool) ($imagetypes & IMG_PNG);
451  }
452  $this->DebugMessage('RenderOutput() attempting Image'.strtoupper(@$this->thumbnailFormat).'($this->gdimg_output)', __FILE__, __LINE__);
453  ob_start();
454  switch ($this->thumbnailFormat) {
455  case 'wbmp':
456  if (!@$builtin_formats['wbmp']) {
457  $this->DebugMessage('GD does not have required built-in support for WBMP output', __FILE__, __LINE__);
458  ob_end_clean();
459  return false;
460  }
461  ImageJPEG($this->gdimg_output, null, $this->thumbnailQuality);
462  $this->outputImageData = ob_get_contents();
463  break;
464 
465  case 'jpeg':
466  case 'jpg': // should be "jpeg" not "jpg" but just in case...
467  if (!@$builtin_formats['jpg']) {
468  $this->DebugMessage('GD does not have required built-in support for JPEG output', __FILE__, __LINE__);
469  ob_end_clean();
470  return false;
471  }
472  ImageJPEG($this->gdimg_output, null, $this->thumbnailQuality);
473  $this->outputImageData = ob_get_contents();
474  break;
475 
476  case 'png':
477  if (!@$builtin_formats['png']) {
478  $this->DebugMessage('GD does not have required built-in support for PNG output', __FILE__, __LINE__);
479  ob_end_clean();
480  return false;
481  }
482  ImagePNG($this->gdimg_output);
483  $this->outputImageData = ob_get_contents();
484  break;
485 
486  case 'gif':
487  if (!@$builtin_formats['gif']) {
488  $this->DebugMessage('GD does not have required built-in support for GIF output', __FILE__, __LINE__);
489  ob_end_clean();
490  return false;
491  }
492  ImageGIF($this->gdimg_output);
493  $this->outputImageData = ob_get_contents();
494  break;
495 
496  case 'bmp':
497  $ImageOutFunction = '"builtin BMP output"';
498  if (!@include_once(dirname(__FILE__).'/phpthumb.bmp.php')) {
499  $this->DebugMessage('Error including "'.dirname(__FILE__).'/phpthumb.bmp.php" which is required for BMP format output', __FILE__, __LINE__);
500  ob_end_clean();
501  return false;
502  }
503  $phpthumb_bmp = new phpthumb_bmp();
504  $this->outputImageData = $phpthumb_bmp->GD2BMPstring($this->gdimg_output);
505  unset($phpthumb_bmp);
506  break;
507 
508  case 'ico':
509  $ImageOutFunction = '"builtin ICO output"';
510  if (!@include_once(dirname(__FILE__).'/phpthumb.ico.php')) {
511  $this->DebugMessage('Error including "'.dirname(__FILE__).'/phpthumb.ico.php" which is required for ICO format output', __FILE__, __LINE__);
512  ob_end_clean();
513  return false;
514  }
515  $phpthumb_ico = new phpthumb_ico();
516  $arrayOfOutputImages = array($this->gdimg_output);
517  $this->outputImageData = $phpthumb_ico->GD2ICOstring($arrayOfOutputImages);
518  unset($phpthumb_ico);
519  break;
520 
521  default:
522  $this->DebugMessage('RenderOutput failed because $this->thumbnailFormat "'.$this->thumbnailFormat.'" is not valid', __FILE__, __LINE__);
523  ob_end_clean();
524  return false;
525  }
526  ob_end_clean();
527  if (!$this->outputImageData) {
528  $this->DebugMessage('RenderOutput() for "'.$this->thumbnailFormat.'" failed', __FILE__, __LINE__);
529  ob_end_clean();
530  return false;
531  }
532  $this->DebugMessage('RenderOutput() completing with $this->outputImageData = '.strlen($this->outputImageData).' bytes', __FILE__, __LINE__);
533  return true;
534  }
535 
536 
537  // public:
538  function RenderToFile($filename) {
539  if (preg_match('#^(f|ht)tps?\://#i', $filename)) {
540  $this->DebugMessage('RenderToFile() failed because $filename ('.$filename.') is a URL', __FILE__, __LINE__);
541  return false;
542  }
543  // render thumbnail to this file only, do not cache, do not output to browser
544  //$renderfilename = $this->ResolveFilenameToAbsolute(dirname($filename)).DIRECTORY_SEPARATOR.basename($filename);
545  $renderfilename = $filename;
546  if (($filename{0} != '/') && ($filename{0} != '\\') && ($filename{1} != ':')) {
547  $renderfilename = $this->ResolveFilenameToAbsolute($renderfilename);
548  }
549  if (!@is_writable(dirname($renderfilename))) {
550  $this->DebugMessage('RenderToFile() failed because "'.dirname($renderfilename).'/" is not writable', __FILE__, __LINE__);
551  return false;
552  }
553  if (@is_file($renderfilename) && !@is_writable($renderfilename)) {
554  $this->DebugMessage('RenderToFile() failed because "'.$renderfilename.'" is not writable', __FILE__, __LINE__);
555  return false;
556  }
557 
558  if ($this->RenderOutput()) {
559  if (file_put_contents($renderfilename, $this->outputImageData)) {
560  $this->DebugMessage('RenderToFile('.$renderfilename.') succeeded', __FILE__, __LINE__);
561  return true;
562  }
563  if (!@file_exists($renderfilename)) {
564  $this->DebugMessage('RenderOutput ['.$this->thumbnailFormat.'('.$renderfilename.')] did not appear to fail, but the output image does not exist either...', __FILE__, __LINE__);
565  }
566  } else {
567  $this->DebugMessage('RenderOutput ['.$this->thumbnailFormat.'('.$renderfilename.')] failed', __FILE__, __LINE__);
568  }
569  return false;
570  }
571 
572 
573  // public:
574  function OutputThumbnail() {
575  $this->purgeTempFiles();
576 
577  if (!$this->useRawIMoutput && !is_resource($this->gdimg_output)) {
578  $this->DebugMessage('OutputThumbnail() failed because !is_resource($this->gdimg_output)', __FILE__, __LINE__);
579  return false;
580  }
581  if (headers_sent()) {
582  return $this->ErrorImage('OutputThumbnail() failed - headers already sent');
583  exit;
584  }
585 
586  $downloadfilename = phpthumb_functions::SanitizeFilename(is_string($this->sia) ? $this->sia : ($this->down ? $this->down : 'phpThumb_generated_thumbnail'.'.'.$this->thumbnailFormat));
587  $this->DebugMessage('Content-Disposition header filename set to "'.$downloadfilename.'"', __FILE__, __LINE__);
588  if ($downloadfilename) {
589  header('Content-Disposition: '.($this->down ? 'attachment' : 'inline').'; filename="'.$downloadfilename.'"');
590  } else {
591  $this->DebugMessage('failed to send Content-Disposition header because $downloadfilename is empty', __FILE__, __LINE__);
592  }
593 
594  if ($this->useRawIMoutput) {
595 
596  header('Content-Type: '.phpthumb_functions::ImageTypeToMIMEtype($this->thumbnailFormat));
598 
599  } else {
600 
601  $this->DebugMessage('ImageInterlace($this->gdimg_output, '.intval($this->config_output_interlace).')', __FILE__, __LINE__);
602  ImageInterlace($this->gdimg_output, intval($this->config_output_interlace));
603  switch ($this->thumbnailFormat) {
604  case 'jpeg':
605  header('Content-Type: '.phpthumb_functions::ImageTypeToMIMEtype($this->thumbnailFormat));
606  $ImageOutFunction = 'image'.$this->thumbnailFormat;
607  @$ImageOutFunction($this->gdimg_output, '', $this->thumbnailQuality);
608  break;
609 
610  case 'png':
611  case 'gif':
612  header('Content-Type: '.phpthumb_functions::ImageTypeToMIMEtype($this->thumbnailFormat));
613  $ImageOutFunction = 'image'.$this->thumbnailFormat;
614  @$ImageOutFunction($this->gdimg_output);
615  break;
616 
617  case 'bmp':
618  if (!@include_once(dirname(__FILE__).'/phpthumb.bmp.php')) {
619  $this->DebugMessage('Error including "'.dirname(__FILE__).'/phpthumb.bmp.php" which is required for BMP format output', __FILE__, __LINE__);
620  return false;
621  }
622  $phpthumb_bmp = new phpthumb_bmp();
623  if (is_object($phpthumb_bmp)) {
624  $bmp_data = $phpthumb_bmp->GD2BMPstring($this->gdimg_output);
625  unset($phpthumb_bmp);
626  if (!$bmp_data) {
627  $this->DebugMessage('$phpthumb_bmp->GD2BMPstring() failed', __FILE__, __LINE__);
628  return false;
629  }
630  header('Content-Type: '.phpthumb_functions::ImageTypeToMIMEtype($this->thumbnailFormat));
631  echo $bmp_data;
632  } else {
633  $this->DebugMessage('new phpthumb_bmp() failed', __FILE__, __LINE__);
634  return false;
635  }
636  break;
637 
638  case 'ico':
639  if (!@include_once(dirname(__FILE__).'/phpthumb.ico.php')) {
640  $this->DebugMessage('Error including "'.dirname(__FILE__).'/phpthumb.ico.php" which is required for ICO format output', __FILE__, __LINE__);
641  return false;
642  }
643  $phpthumb_ico = new phpthumb_ico();
644  if (is_object($phpthumb_ico)) {
645  $arrayOfOutputImages = array($this->gdimg_output);
646  $ico_data = $phpthumb_ico->GD2ICOstring($arrayOfOutputImages);
647  unset($phpthumb_ico);
648  if (!$ico_data) {
649  $this->DebugMessage('$phpthumb_ico->GD2ICOstring() failed', __FILE__, __LINE__);
650  return false;
651  }
652  header('Content-Type: '.phpthumb_functions::ImageTypeToMIMEtype($this->thumbnailFormat));
653  echo $ico_data;
654  } else {
655  $this->DebugMessage('new phpthumb_ico() failed', __FILE__, __LINE__);
656  return false;
657  }
658  break;
659 
660  default:
661  $this->DebugMessage('OutputThumbnail failed because $this->thumbnailFormat "'.$this->thumbnailFormat.'" is not valid', __FILE__, __LINE__);
662  return false;
663  break;
664  }
665 
666  }
667  return true;
668  }
669 
670 
671  // public:
673  $this->DebugMessage('CleanUpCacheDirectory() set to purge ('.(is_null($this->config_cache_maxage) ? 'NULL' : number_format($this->config_cache_maxage / 86400, 1)).' days; '.(is_null($this->config_cache_maxsize) ? 'NULL' : number_format($this->config_cache_maxsize / 1048576, 2)).' MB; '.(is_null($this->config_cache_maxfiles) ? 'NULL' : number_format($this->config_cache_maxfiles)).' files)', __FILE__, __LINE__);
674 
675  if (!is_writable($this->config_cache_directory)) {
676  $this->DebugMessage('CleanUpCacheDirectory() skipped because "'.$this->config_cache_directory.'" is not writable', __FILE__, __LINE__);
677  return true;
678  }
679 
680  // cache status of cache directory for 1 hour to avoid hammering the filesystem functions
681  $phpThumbCacheStats_filename = $this->config_cache_directory.DIRECTORY_SEPARATOR.'phpThumbCacheStats.txt';
682  if (file_exists($phpThumbCacheStats_filename) && is_readable($phpThumbCacheStats_filename) && (filemtime($phpThumbCacheStats_filename) >= (time() - 3600))) {
683  $this->DebugMessage('CleanUpCacheDirectory() skipped because "'.$phpThumbCacheStats_filename.'" is recently modified', __FILE__, __LINE__);
684  return true;
685  }
686  touch($phpThumbCacheStats_filename);
687 
688  $DeletedKeys = array();
689  $AllFilesInCacheDirectory = array();
690  if (($this->config_cache_maxage > 0) || ($this->config_cache_maxsize > 0) || ($this->config_cache_maxfiles > 0)) {
691  $CacheDirOldFilesAge = array();
692  $CacheDirOldFilesSize = array();
693  $AllFilesInCacheDirectory = phpthumb_functions::GetAllFilesInSubfolders($this->config_cache_directory);
694  foreach ($AllFilesInCacheDirectory as $fullfilename) {
695  if (preg_match('#^'.preg_quote($this->config_cache_prefix).'#i', $fullfilename) && file_exists($fullfilename)) {
696  $CacheDirOldFilesAge[$fullfilename] = @fileatime($fullfilename);
697  if ($CacheDirOldFilesAge[$fullfilename] == 0) {
698  $CacheDirOldFilesAge[$fullfilename] = @filemtime($fullfilename);
699  }
700  $CacheDirOldFilesSize[$fullfilename] = @filesize($fullfilename);
701  }
702  }
703  if (empty($CacheDirOldFilesSize)) {
704  return true;
705  }
706  $DeletedKeys['zerobyte'] = array();
707  foreach ($CacheDirOldFilesSize as $fullfilename => $filesize) {
708  // purge all zero-size files more than an hour old (to prevent trying to delete just-created and/or in-use files)
709  $cutofftime = time() - 3600;
710  if (($filesize == 0) && ($CacheDirOldFilesAge[$fullfilename] < $cutofftime)) {
711  $this->DebugMessage('deleting "'.$fullfilename.'"', __FILE__, __LINE__);
712  if (@unlink($fullfilename)) {
713  $DeletedKeys['zerobyte'][] = $fullfilename;
714  unset($CacheDirOldFilesSize[$fullfilename]);
715  unset($CacheDirOldFilesAge[$fullfilename]);
716  }
717  }
718  }
719  $this->DebugMessage('CleanUpCacheDirectory() purged '.count($DeletedKeys['zerobyte']).' zero-byte files', __FILE__, __LINE__);
720  asort($CacheDirOldFilesAge);
721 
722  if ($this->config_cache_maxfiles > 0) {
723  $TotalCachedFiles = count($CacheDirOldFilesAge);
724  $DeletedKeys['maxfiles'] = array();
725  foreach ($CacheDirOldFilesAge as $fullfilename => $filedate) {
726  if ($TotalCachedFiles > $this->config_cache_maxfiles) {
727  $this->DebugMessage('deleting "'.$fullfilename.'"', __FILE__, __LINE__);
728  if (@unlink($fullfilename)) {
729  $TotalCachedFiles--;
730  $DeletedKeys['maxfiles'][] = $fullfilename;
731  }
732  } else {
733  // there are few enough files to keep the rest
734  break;
735  }
736  }
737  $this->DebugMessage('CleanUpCacheDirectory() purged '.count($DeletedKeys['maxfiles']).' files based on (config_cache_maxfiles='.$this->config_cache_maxfiles.')', __FILE__, __LINE__);
738  foreach ($DeletedKeys['maxfiles'] as $fullfilename) {
739  unset($CacheDirOldFilesAge[$fullfilename]);
740  unset($CacheDirOldFilesSize[$fullfilename]);
741  }
742  }
743 
744  if ($this->config_cache_maxage > 0) {
745  $mindate = time() - $this->config_cache_maxage;
746  $DeletedKeys['maxage'] = array();
747  foreach ($CacheDirOldFilesAge as $fullfilename => $filedate) {
748  if ($filedate > 0) {
749  if ($filedate < $mindate) {
750  $this->DebugMessage('deleting "'.$fullfilename.'"', __FILE__, __LINE__);
751  if (@unlink($fullfilename)) {
752  $DeletedKeys['maxage'][] = $fullfilename;
753  }
754  } else {
755  // the rest of the files are new enough to keep
756  break;
757  }
758  }
759  }
760  $this->DebugMessage('CleanUpCacheDirectory() purged '.count($DeletedKeys['maxage']).' files based on (config_cache_maxage='.$this->config_cache_maxage.')', __FILE__, __LINE__);
761  foreach ($DeletedKeys['maxage'] as $fullfilename) {
762  unset($CacheDirOldFilesAge[$fullfilename]);
763  unset($CacheDirOldFilesSize[$fullfilename]);
764  }
765  }
766 
767  if ($this->config_cache_maxsize > 0) {
768  $TotalCachedFileSize = array_sum($CacheDirOldFilesSize);
769  $DeletedKeys['maxsize'] = array();
770  foreach ($CacheDirOldFilesAge as $fullfilename => $filedate) {
771  if ($TotalCachedFileSize > $this->config_cache_maxsize) {
772  $this->DebugMessage('deleting "'.$fullfilename.'"', __FILE__, __LINE__);
773  if (@unlink($fullfilename)) {
774  $TotalCachedFileSize -= $CacheDirOldFilesSize[$fullfilename];
775  $DeletedKeys['maxsize'][] = $fullfilename;
776  }
777  } else {
778  // the total filesizes are small enough to keep the rest of the files
779  break;
780  }
781  }
782  $this->DebugMessage('CleanUpCacheDirectory() purged '.count($DeletedKeys['maxsize']).' files based on (config_cache_maxsize='.$this->config_cache_maxsize.')', __FILE__, __LINE__);
783  foreach ($DeletedKeys['maxsize'] as $fullfilename) {
784  unset($CacheDirOldFilesAge[$fullfilename]);
785  unset($CacheDirOldFilesSize[$fullfilename]);
786  }
787  }
788 
789  } else {
790  $this->DebugMessage('skipping CleanUpCacheDirectory() because config set to not use it', __FILE__, __LINE__);
791  }
792  $totalpurged = 0;
793  foreach ($DeletedKeys as $key => $value) {
794  $totalpurged += count($value);
795  }
796  $this->DebugMessage('CleanUpCacheDirectory() purged '.$totalpurged.' files (from '.count($AllFilesInCacheDirectory).') based on config settings', __FILE__, __LINE__);
797  if ($totalpurged > 0) {
798  $empty_dirs = array();
799  foreach ($AllFilesInCacheDirectory as $fullfilename) {
800  if (is_dir($fullfilename)) {
801  $empty_dirs[realpath($fullfilename)] = 1;
802  } else {
803  unset($empty_dirs[realpath(dirname($fullfilename))]);
804  }
805  }
806  krsort($empty_dirs);
807  $totalpurgeddirs = 0;
808  foreach ($empty_dirs as $empty_dir => $dummy) {
809  if ($empty_dir == $this->config_cache_directory) {
810  // shouldn't happen, but just in case, don't let it delete actual cache directory
811  continue;
812  } elseif (@rmdir($empty_dir)) {
813  $totalpurgeddirs++;
814  } else {
815  $this->DebugMessage('failed to rmdir('.$empty_dir.')', __FILE__, __LINE__);
816  }
817  }
818  $this->DebugMessage('purged '.$totalpurgeddirs.' empty directories', __FILE__, __LINE__);
819  }
820  return true;
821  }
822 
824 
825  // private: re-initializator (call between rendering multiple images with one object)
826  function resetObject() {
827  $class_vars = get_class_vars(get_class($this));
828  foreach ($class_vars as $key => $value) {
829  // do not clobber debug or config info
830  if (!preg_match('#^(config_|debug|fatalerror)#i', $key)) {
831  $this->$key = $value;
832  }
833  }
834  $this->phpThumb(); // re-initialize some class variables
835  return true;
836  }
837 
839 
840  function ResolveSource() {
841  if (is_resource($this->gdimg_source)) {
842  $this->DebugMessage('ResolveSource() exiting because is_resource($this->gdimg_source)', __FILE__, __LINE__);
843  return true;
844  }
845  if ($this->rawImageData) {
846  $this->sourceFilename = null;
847  $this->DebugMessage('ResolveSource() exiting because $this->rawImageData is set ('.number_format(strlen($this->rawImageData)).' bytes)', __FILE__, __LINE__);
848  return true;
849  }
850  if ($this->sourceFilename) {
851  $this->sourceFilename = $this->ResolveFilenameToAbsolute($this->sourceFilename);
852  $this->DebugMessage('$this->sourceFilename set to "'.$this->sourceFilename.'"', __FILE__, __LINE__);
853  } elseif ($this->src) {
854  $this->sourceFilename = $this->ResolveFilenameToAbsolute($this->src);
855  $this->DebugMessage('$this->sourceFilename set to "'.$this->sourceFilename.'" from $this->src ('.$this->src.')', __FILE__, __LINE__);
856  } else {
857  return $this->ErrorImage('$this->sourceFilename and $this->src are both empty');
858  }
859  if ($this->iswindows && ((substr($this->sourceFilename, 0, 2) == '//') || (substr($this->sourceFilename, 0, 2) == '\\\\'))) {
860  // Windows \\share\filename.ext
861  } elseif (preg_match('#^(f|ht)tps?\://#i', $this->sourceFilename)) {
862  // URL
863  if ($this->config_http_user_agent) {
864  ini_set('user_agent', $this->config_http_user_agent);
865  }
866  } elseif (!@file_exists($this->sourceFilename)) {
867  return $this->ErrorImage('"'.$this->sourceFilename.'" does not exist');
868  } elseif (!@is_file($this->sourceFilename)) {
869  return $this->ErrorImage('"'.$this->sourceFilename.'" is not a file');
870  }
871  return true;
872  }
873 
874  function setOutputFormat() {
875  static $alreadyCalled = false;
876  if ($this->thumbnailFormat && $alreadyCalled) {
877  return true;
878  }
879  $alreadyCalled = true;
880 
881  $AvailableImageOutputFormats = array();
882  $AvailableImageOutputFormats[] = 'text';
883  if (@is_readable(dirname(__FILE__).'/phpthumb.ico.php')) {
884  $AvailableImageOutputFormats[] = 'ico';
885  }
886  if (@is_readable(dirname(__FILE__).'/phpthumb.bmp.php')) {
887  $AvailableImageOutputFormats[] = 'bmp';
888  }
889 
890  $this->thumbnailFormat = 'ico';
891 
892  // Set default output format based on what image types are available
893  if (function_exists('ImageTypes')) {
894  $imagetypes = ImageTypes();
895  if ($imagetypes & IMG_WBMP) {
896  $this->thumbnailFormat = 'wbmp';
897  $AvailableImageOutputFormats[] = 'wbmp';
898  }
899  if ($imagetypes & IMG_GIF) {
900  $this->thumbnailFormat = 'gif';
901  $AvailableImageOutputFormats[] = 'gif';
902  }
903  if ($imagetypes & IMG_PNG) {
904  $this->thumbnailFormat = 'png';
905  $AvailableImageOutputFormats[] = 'png';
906  }
907  if ($imagetypes & IMG_JPG) {
908  $this->thumbnailFormat = 'jpeg';
909  $AvailableImageOutputFormats[] = 'jpeg';
910  }
911  } else {
912  //return $this->ErrorImage('ImageTypes() does not exist - GD support might not be enabled?');
913  $this->DebugMessage('ImageTypes() does not exist - GD support might not be enabled?', __FILE__, __LINE__);
914  }
915  if ($this->ImageMagickVersion()) {
916  $IMformats = array('jpeg', 'png', 'gif', 'bmp', 'ico', 'wbmp');
917  $this->DebugMessage('Addding ImageMagick formats to $AvailableImageOutputFormats ('.implode(';', $AvailableImageOutputFormats).')', __FILE__, __LINE__);
918  foreach ($IMformats as $key => $format) {
919  $AvailableImageOutputFormats[] = $format;
920  }
921  }
922  $AvailableImageOutputFormats = array_unique($AvailableImageOutputFormats);
923  $this->DebugMessage('$AvailableImageOutputFormats = array('.implode(';', $AvailableImageOutputFormats).')', __FILE__, __LINE__);
924 
925  $this->f = preg_replace('#[^a-z]#', '', strtolower($this->f));
926  if (strtolower($this->config_output_format) == 'jpg') {
927  $this->config_output_format = 'jpeg';
928  }
929  if (strtolower($this->f) == 'jpg') {
930  $this->f = 'jpeg';
931  }
932  if (phpthumb_functions::CaseInsensitiveInArray($this->config_output_format, $AvailableImageOutputFormats)) {
933  // set output format to config default if that format is available
934  $this->DebugMessage('$this->thumbnailFormat set to $this->config_output_format "'.strtolower($this->config_output_format).'"', __FILE__, __LINE__);
935  $this->thumbnailFormat = strtolower($this->config_output_format);
936  } elseif ($this->config_output_format) {
937  $this->DebugMessage('$this->thumbnailFormat staying as "'.$this->thumbnailFormat.'" because $this->config_output_format ('.strtolower($this->config_output_format).') is not in $AvailableImageOutputFormats', __FILE__, __LINE__);
938  }
939  if ($this->f && (phpthumb_functions::CaseInsensitiveInArray($this->f, $AvailableImageOutputFormats))) {
940  // override output format if $this->f is set and that format is available
941  $this->DebugMessage('$this->thumbnailFormat set to $this->f "'.strtolower($this->f).'"', __FILE__, __LINE__);
942  $this->thumbnailFormat = strtolower($this->f);
943  } elseif ($this->f) {
944  $this->DebugMessage('$this->thumbnailFormat staying as "'.$this->thumbnailFormat.'" because $this->f ('.strtolower($this->f).') is not in $AvailableImageOutputFormats', __FILE__, __LINE__);
945  }
946 
947  // for JPEG images, quality 1 (worst) to 99 (best)
948  // quality < 25 is nasty, with not much size savings - not recommended
949  // problems with 100 - invalid JPEG?
950  $this->thumbnailQuality = max(1, min(99, ($this->q ? intval($this->q) : 75)));
951  $this->DebugMessage('$this->thumbnailQuality set to "'.$this->thumbnailQuality.'"', __FILE__, __LINE__);
952 
953  return true;
954  }
955 
956  function setCacheDirectory() {
957  // resolve cache directory to absolute pathname
958  $this->DebugMessage('setCacheDirectory() starting with config_cache_directory = "'.$this->config_cache_directory.'"', __FILE__, __LINE__);
959  if (substr($this->config_cache_directory, 0, 1) == '.') {
960  if (preg_match('#^(f|ht)tps?\://#i', $this->src)) {
961  if (!$this->config_cache_disable_warning) {
962  $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');
963  }
964  } elseif ($this->src) {
965  // resolve relative cache directory to source image
966  $this->config_cache_directory = dirname($this->ResolveFilenameToAbsolute($this->src)).DIRECTORY_SEPARATOR.$this->config_cache_directory;
967  } else {
968  // $this->new is probably set
969  }
970  }
971  if (substr($this->config_cache_directory, -1) == '/') {
972  $this->config_cache_directory = substr($this->config_cache_directory, 0, -1);
973  }
974  if ($this->iswindows) {
975  $this->config_cache_directory = str_replace('/', DIRECTORY_SEPARATOR, $this->config_cache_directory);
976  }
977  if ($this->config_cache_directory) {
978  $real_cache_path = realpath($this->config_cache_directory);
979  if (!$real_cache_path) {
980  $this->DebugMessage('realpath($this->config_cache_directory) failed for "'.$this->config_cache_directory.'"', __FILE__, __LINE__);
981  if (!is_dir($this->config_cache_directory)) {
982  $this->DebugMessage('!is_dir('.$this->config_cache_directory.')', __FILE__, __LINE__);
983  }
984  }
985  if ($real_cache_path) {
986  $this->DebugMessage('setting config_cache_directory to realpath('.$this->config_cache_directory.') = "'.$real_cache_path.'"', __FILE__, __LINE__);
987  $this->config_cache_directory = $real_cache_path;
988  }
989  }
990  if (!is_dir($this->config_cache_directory)) {
991  if (!$this->config_cache_disable_warning) {
992  $this->ErrorImage('$this->config_cache_directory ('.$this->config_cache_directory.') does not exist. Adjust "cache_directory" or "cache_disable_warning" in phpThumb.config.php');
993  }
994  $this->DebugMessage('$this->config_cache_directory ('.$this->config_cache_directory.') is not a directory', __FILE__, __LINE__);
995  $this->config_cache_directory = null;
996  } elseif (!@is_writable($this->config_cache_directory)) {
997  $this->DebugMessage('$this->config_cache_directory is not writable ('.$this->config_cache_directory.')', __FILE__, __LINE__);
998  }
999 
1000  $this->InitializeTempDirSetting();
1001  if (!@is_dir($this->config_temp_directory) && !@is_writable($this->config_temp_directory) && @is_dir($this->config_cache_directory) && @is_writable($this->config_cache_directory)) {
1002  $this->DebugMessage('setting $this->config_temp_directory = $this->config_cache_directory ('.$this->config_cache_directory.')', __FILE__, __LINE__);
1003  $this->config_temp_directory = $this->config_cache_directory;
1004  }
1005  return true;
1006  }
1007 
1008 
1009  function ResolveFilenameToAbsolute($filename) {
1010  if (empty($filename)) {
1011  return false;
1012  }
1013 
1014  if (preg_match('#^[a-z0-9]+\:/{1,2}#i', $filename)) {
1015  // eg: http://host/path/file.jpg (HTTP URL)
1016  // eg: ftp://host/path/file.jpg (FTP URL)
1017  // eg: data1:/path/file.jpg (Netware path)
1018 
1019  //$AbsoluteFilename = $filename;
1020  return $filename;
1021 
1022  } elseif ($this->iswindows && isset($filename{1}) && ($filename{1} == ':')) {
1023 
1024  // absolute pathname (Windows)
1025  $AbsoluteFilename = $filename;
1026 
1027  } elseif ($this->iswindows && ((substr($filename, 0, 2) == '//') || (substr($filename, 0, 2) == '\\\\'))) {
1028 
1029  // absolute pathname (Windows)
1030  $AbsoluteFilename = $filename;
1031 
1032  } elseif ($filename{0} == '/') {
1033 
1034  if (@is_readable($filename) && !@is_readable($this->config_document_root.$filename)) {
1035 
1036  // absolute filename (*nix)
1037  $AbsoluteFilename = $filename;
1038 
1039  } elseif (isset($filename{1}) && ($filename{1} == '~')) {
1040 
1041  // /~user/path
1042  if ($ApacheLookupURIarray = phpthumb_functions::ApacheLookupURIarray($filename)) {
1043  $AbsoluteFilename = $ApacheLookupURIarray['filename'];
1044  } else {
1045  $AbsoluteFilename = realpath($filename);
1046  if (@is_readable($AbsoluteFilename)) {
1047  $this->DebugMessage('phpthumb_functions::ApacheLookupURIarray() failed for "'.$filename.'", but the correct filename ('.$AbsoluteFilename.') seems to have been resolved with realpath($filename)', __FILE__, __LINE__);
1048  } elseif (is_dir(dirname($AbsoluteFilename))) {
1049  $this->DebugMessage('phpthumb_functions::ApacheLookupURIarray() failed for "'.dirname($filename).'", but the correct directory ('.dirname($AbsoluteFilename).') seems to have been resolved with realpath(.)', __FILE__, __LINE__);
1050  } else {
1051  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")');
1052  }
1053  }
1054 
1055  } else {
1056 
1057  // relative filename (any OS)
1058  if (preg_match('#^'.preg_quote($this->config_document_root).'#', $filename)) {
1059  $AbsoluteFilename = $filename;
1060  $this->DebugMessage('ResolveFilenameToAbsolute() NOT prepending $this->config_document_root ('.$this->config_document_root.') to $filename ('.$filename.') resulting in ($AbsoluteFilename = "'.$AbsoluteFilename.'")', __FILE__, __LINE__);
1061  } else {
1062  $AbsoluteFilename = $this->config_document_root.$filename;
1063  $this->DebugMessage('ResolveFilenameToAbsolute() prepending $this->config_document_root ('.$this->config_document_root.') to $filename ('.$filename.') resulting in ($AbsoluteFilename = "'.$AbsoluteFilename.'")', __FILE__, __LINE__);
1064  }
1065 
1066  }
1067 
1068  } else {
1069 
1070  // relative to current directory (any OS)
1071  //$AbsoluteFilename = $this->config_document_root.preg_replace('#[/\\\\]#', DIRECTORY_SEPARATOR, dirname(@$_SERVER['PHP_SELF'])).DIRECTORY_SEPARATOR.preg_replace('#[/\\\\]#', DIRECTORY_SEPARATOR, $filename);
1072  $AbsoluteFilename = dirname(__FILE__).DIRECTORY_SEPARATOR.preg_replace('#[/\\\\]#', DIRECTORY_SEPARATOR, $filename);
1073 
1074  //if (!@file_exists($AbsoluteFilename) && @file_exists(realpath($this->DotPadRelativeDirectoryPath($filename)))) {
1075  // $AbsoluteFilename = realpath($this->DotPadRelativeDirectoryPath($filename));
1076  //}
1077 
1078  if (substr(dirname(@$_SERVER['PHP_SELF']), 0, 2) == '/~') {
1079  if ($ApacheLookupURIarray = phpthumb_functions::ApacheLookupURIarray(dirname(@$_SERVER['PHP_SELF']))) {
1080  $AbsoluteFilename = $ApacheLookupURIarray['filename'].DIRECTORY_SEPARATOR.$filename;
1081  } else {
1082  $AbsoluteFilename = realpath('.').DIRECTORY_SEPARATOR.$filename;
1083  if (@is_readable($AbsoluteFilename)) {
1084  $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__);
1085  } elseif (is_dir(dirname($AbsoluteFilename))) {
1086  $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__);
1087  } else {
1088  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');
1089  }
1090  }
1091  }
1092 
1093  }
1094  if (is_link($AbsoluteFilename)) {
1095  $this->DebugMessage('is_link()==true, changing "'.$AbsoluteFilename.'" to "'.readlink($AbsoluteFilename).'"', __FILE__, __LINE__);
1096  $AbsoluteFilename = readlink($AbsoluteFilename);
1097  }
1098  if (realpath($AbsoluteFilename)) {
1099  $AbsoluteFilename = realpath($AbsoluteFilename);
1100  }
1101  if ($this->iswindows) {
1102  $AbsoluteFilename = preg_replace('#^'.preg_quote(realpath($this->config_document_root)).'#i', realpath($this->config_document_root), $AbsoluteFilename);
1103  $AbsoluteFilename = str_replace(DIRECTORY_SEPARATOR, '/', $AbsoluteFilename);
1104  }
1105  if (!$this->config_allow_src_above_docroot && !preg_match('#^'.preg_quote(str_replace(DIRECTORY_SEPARATOR, '/', realpath($this->config_document_root))).'#', $AbsoluteFilename)) {
1106  $this->DebugMessage('!$this->config_allow_src_above_docroot therefore setting "'.$AbsoluteFilename.'" (outside "'.realpath($this->config_document_root).'") to null', __FILE__, __LINE__);
1107  return false;
1108  }
1109  if (!$this->config_allow_src_above_phpthumb && !preg_match('#^'.preg_quote(str_replace(DIRECTORY_SEPARATOR, '/', dirname(__FILE__))).'#', $AbsoluteFilename)) {
1110  $this->DebugMessage('!$this->config_allow_src_above_phpthumb therefore setting "'.$AbsoluteFilename.'" (outside "'.dirname(__FILE__).'") to null', __FILE__, __LINE__);
1111  return false;
1112  }
1113  return $AbsoluteFilename;
1114  }
1115 
1116  function file_exists_ignoreopenbasedir($filename, $cached=true) {
1117  static $open_basedirs = null;
1118  static $file_exists_cache = array();
1119  if (!$cached || !isset($file_exists_cache[$filename])) {
1120  if (is_null($open_basedirs)) {
1121  $open_basedirs = explode(';', ini_get('open_basedir'));
1122  }
1123  if (empty($open_basedirs) || in_array(dirname($filename), $open_basedirs)) {
1124  $file_exists_cache[$filename] = file_exists($filename);
1125  } elseif ($this->iswindows) {
1126  $ls_filename = trim(phpthumb_functions::SafeExec('dir '.escapeshellarg($filename)));
1127  $file_exists_cache[$filename] = !preg_match('#File Not Found#i', $ls_filename);
1128  } else {
1129  $ls_filename = trim(phpthumb_functions::SafeExec('ls '.escapeshellarg($filename)));
1130  $file_exists_cache[$filename] = ($ls_filename == $filename);
1131  }
1132  }
1133  return $file_exists_cache[$filename];
1134  }
1135 
1137  static $WhichConvert = null;
1138  if (is_null($WhichConvert)) {
1139  if ($this->iswindows) {
1140  $WhichConvert = false;
1141  } else {
1142  $WhichConvert = trim(phpthumb_functions::SafeExec('which convert'));
1143  }
1144  }
1145  return $WhichConvert;
1146  }
1147 
1149  static $commandline = null;
1150  if (is_null($commandline)) {
1151  if ($this->issafemode) {
1152  $commandline = '';
1153  return $commandline;
1154  }
1155  $commandline = (!is_null($this->config_imagemagick_path) ? $this->config_imagemagick_path : '');
1156 
1157  if ($this->config_imagemagick_path && ($this->config_imagemagick_path != realpath($this->config_imagemagick_path))) {
1158  if (@is_executable(realpath($this->config_imagemagick_path))) {
1159  $this->DebugMessage('Changing $this->config_imagemagick_path ('.$this->config_imagemagick_path.') to realpath($this->config_imagemagick_path) ('.realpath($this->config_imagemagick_path).')', __FILE__, __LINE__);
1160  $this->config_imagemagick_path = realpath($this->config_imagemagick_path);
1161  } else {
1162  $this->DebugMessage('Leaving $this->config_imagemagick_path as ('.$this->config_imagemagick_path.') because !is_execuatable(realpath($this->config_imagemagick_path)) ('.realpath($this->config_imagemagick_path).')', __FILE__, __LINE__);
1163  }
1164  }
1165  $this->DebugMessage(' file_exists('.$this->config_imagemagick_path.') = '.intval( @file_exists($this->config_imagemagick_path)), __FILE__, __LINE__);
1166  $this->DebugMessage('file_exists_ignoreopenbasedir('.$this->config_imagemagick_path.') = '.intval($this->file_exists_ignoreopenbasedir($this->config_imagemagick_path)), __FILE__, __LINE__);
1167  $this->DebugMessage(' is_file('.$this->config_imagemagick_path.') = '.intval( @is_file($this->config_imagemagick_path)), __FILE__, __LINE__);
1168  $this->DebugMessage(' is_executable('.$this->config_imagemagick_path.') = '.intval( @is_executable($this->config_imagemagick_path)), __FILE__, __LINE__);
1169 
1170  if ($this->file_exists_ignoreopenbasedir($this->config_imagemagick_path)) {
1171  $this->DebugMessage('using ImageMagick path from $this->config_imagemagick_path ('.$this->config_imagemagick_path.')', __FILE__, __LINE__);
1172  if ($this->iswindows) {
1173  $commandline = substr($this->config_imagemagick_path, 0, 2).' && cd '.escapeshellarg(str_replace('/', DIRECTORY_SEPARATOR, substr(dirname($this->config_imagemagick_path), 2))).' && '.escapeshellarg(basename($this->config_imagemagick_path));
1174  } else {
1175  $commandline = escapeshellarg($this->config_imagemagick_path);
1176  }
1177  return $commandline;
1178  }
1179 
1180  $which_convert = $this->ImageMagickWhichConvert();
1181  $IMversion = $this->ImageMagickVersion();
1182 
1183  if ($which_convert && ($which_convert{0} == '/') && $this->file_exists_ignoreopenbasedir($which_convert)) {
1184 
1185  // `which convert` *should* return the path if "convert" exist, or nothing if it doesn't
1186  // other things *may* get returned, like "sh: convert: not found" or "no convert in /usr/local/bin /usr/sbin /usr/bin /usr/ccs/bin"
1187  // so only do this if the value returned exists as a file
1188  $this->DebugMessage('using ImageMagick path from `which convert` ('.$which_convert.')', __FILE__, __LINE__);
1189  $commandline = 'convert';
1190 
1191  } elseif ($IMversion) {
1192 
1193  $this->DebugMessage('setting ImageMagick path to $this->config_imagemagick_path ('.$this->config_imagemagick_path.') ['.$IMversion.']', __FILE__, __LINE__);
1194  $commandline = $this->config_imagemagick_path;
1195 
1196  } else {
1197 
1198  $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__);
1199  $commandline = '';
1200 
1201  }
1202  }
1203  return $commandline;
1204  }
1205 
1206  function ImageMagickVersion($returnRAW=false) {
1207  static $versionstring = null;
1208  if (is_null($versionstring)) {
1209  $versionstring = array(0=>false, 1=>false);
1210  $commandline = $this->ImageMagickCommandlineBase();
1211  $commandline = (!is_null($commandline) ? $commandline : '');
1212 
1213  if ($commandline) {
1214  $commandline .= ' --version';
1215  $this->DebugMessage('ImageMagick version checked with "'.$commandline.'"', __FILE__, __LINE__);
1216  $versionstring[1] = trim(phpthumb_functions::SafeExec($commandline));
1217  if (preg_match('#^Version: [^0-9]*([ 0-9\\.\\:Q/\\-]+) (http|file)\:#i', $versionstring[1], $matches)) {
1218  $versionstring[0] = $matches[1];
1219  } else {
1220  $versionstring[0] = false;
1221  $this->DebugMessage('ImageMagick did not return recognized version string ('.$versionstring[1].')', __FILE__, __LINE__);
1222  }
1223  $this->DebugMessage('ImageMagick convert --version says "'.@$matches[0].'"', __FILE__, __LINE__);
1224  }
1225  }
1226  return $versionstring[intval($returnRAW)];
1227  }
1228 
1229  function ImageMagickSwitchAvailable($switchname) {
1230  static $IMoptions = null;
1231  if (is_null($IMoptions)) {
1232  $IMoptions = array();
1233  $commandline = $this->ImageMagickCommandlineBase();
1234  if (!is_null($commandline)) {
1235  $commandline .= ' -help';
1236  $IMhelp_lines = explode("\n", phpthumb_functions::SafeExec($commandline));
1237  foreach ($IMhelp_lines as $line) {
1238  if (preg_match('#^[\\+\\-]([a-z\\-]+) #', trim($line), $matches)) {
1239  $IMoptions[$matches[1]] = true;
1240  }
1241  }
1242  }
1243  }
1244  if (is_array($switchname)) {
1245  $allOK = true;
1246  foreach ($switchname as $key => $value) {
1247  if (!isset($IMoptions[$value])) {
1248  $allOK = false;
1249  break;
1250  }
1251  }
1252  $this->DebugMessage('ImageMagickSwitchAvailable('.implode(';', $switchname).') = '.intval($allOK).'', __FILE__, __LINE__);
1253  } else {
1254  $allOK = isset($IMoptions[$switchname]);
1255  $this->DebugMessage('ImageMagickSwitchAvailable('.$switchname.') = '.intval($allOK).'', __FILE__, __LINE__);
1256  }
1257  return $allOK;
1258  }
1259 
1261  static $IMformatsList = null;
1262  if (is_null($IMformatsList)) {
1263  $IMformatsList = '';
1264  $commandline = $this->ImageMagickCommandlineBase();
1265  if (!is_null($commandline)) {
1266  $commandline = dirname($commandline).DIRECTORY_SEPARATOR.str_replace('convert', 'identify', basename($commandline));
1267  $commandline .= ' -list format';
1268  $IMformatsList = phpthumb_functions::SafeExec($commandline);
1269  }
1270  }
1271  return $IMformatsList;
1272  }
1273 
1275  if ($IMtempSourceFilename = $this->phpThumb_tempnam()) {
1276  $IMtempSourceFilename = realpath($IMtempSourceFilename);
1277  ob_start();
1278  $fp_tempfile = fopen($IMtempSourceFilename, 'wb');
1279  $tempfile_open_error = ob_get_contents();
1280  ob_end_clean();
1281  if ($fp_tempfile) {
1282  fwrite($fp_tempfile, $this->rawImageData);
1283  fclose($fp_tempfile);
1284  $this->sourceFilename = $IMtempSourceFilename;
1285  $this->DebugMessage('ImageMagickThumbnailToGD() setting $this->sourceFilename to "'.$IMtempSourceFilename.'" from $this->rawImageData ('.strlen($this->rawImageData).' bytes)', __FILE__, __LINE__);
1286  } else {
1287  $this->DebugMessage('ImageMagickThumbnailToGD() FAILED setting $this->sourceFilename to "'.$IMtempSourceFilename.'" (failed to open for writing: "'.$tempfile_open_error.'")', __FILE__, __LINE__);
1288  }
1289  unset($tempfile_open_error, $IMtempSourceFilename);
1290  return true;
1291  }
1292  $this->DebugMessage('SourceDataToTempFile() FAILED because $this->phpThumb_tempnam() failed', __FILE__, __LINE__);
1293  return false;
1294  }
1295 
1297  // http://www.imagemagick.org/script/command-line-options.php
1298 
1299  $this->useRawIMoutput = true;
1301  // if GD is not available, must use whatever ImageMagick can output
1302 
1303  // $UnAllowedParameters contains options that can only be processed in GD, not ImageMagick
1304  // note: 'fltr' *may* need to be processed by GD, but we'll check that in more detail below
1305  $UnAllowedParameters = array('xto', 'ar', 'bg', 'bc');
1306  // 'ra' may be part of this list, if not a multiple of 90°
1307  foreach ($UnAllowedParameters as $parameter) {
1308  if (isset($this->$parameter)) {
1309  $this->DebugMessage('$this->useRawIMoutput=false because "'.$parameter.'" is set', __FILE__, __LINE__);
1310  $this->useRawIMoutput = false;
1311  break;
1312  }
1313  }
1314  }
1315  $this->DebugMessage('$this->useRawIMoutput='.($this->useRawIMoutput ? 'true' : 'false').' after checking $UnAllowedParameters', __FILE__, __LINE__);
1316  $outputFormat = $this->thumbnailFormat;
1318  if ($this->useRawIMoutput) {
1319  switch ($this->thumbnailFormat) {
1320  case 'gif':
1321  $ImageCreateFunction = 'ImageCreateFromGIF';
1322  $this->is_alpha = true;
1323  break;
1324  case 'png':
1325  $ImageCreateFunction = 'ImageCreateFromPNG';
1326  $this->is_alpha = true;
1327  break;
1328  case 'jpg':
1329  case 'jpeg':
1330  $ImageCreateFunction = 'ImageCreateFromJPEG';
1331  break;
1332  default:
1333  $this->DebugMessage('Forcing output to PNG because $this->thumbnailFormat ('.$this->thumbnailFormat.' is not a GD-supported format)', __FILE__, __LINE__);
1334  $outputFormat = 'png';
1335  $ImageCreateFunction = 'ImageCreateFromPNG';
1336  $this->is_alpha = true;
1337  $this->useRawIMoutput = false;
1338  break;
1339  }
1340  if (!function_exists(@$ImageCreateFunction)) {
1341  // ImageMagickThumbnailToGD() depends on ImageCreateFromPNG/ImageCreateFromGIF
1342  //$this->DebugMessage('ImageMagickThumbnailToGD() aborting because '.@$ImageCreateFunction.'() is not available', __FILE__, __LINE__);
1343  $this->useRawIMoutput = true;
1344  //return false;
1345  }
1346  } else {
1347  $outputFormat = 'png';
1348  $ImageCreateFunction = 'ImageCreateFromPNG';
1349  $this->is_alpha = true;
1350  $this->useRawIMoutput = false;
1351  }
1352  }
1353 
1354  // http://freealter.org/doc_distrib/ImageMagick-5.1.1/www/convert.html
1355  if (!$this->sourceFilename && $this->rawImageData) {
1356  $this->SourceDataToTempFile();
1357  }
1358  if (!$this->sourceFilename) {
1359  $this->DebugMessage('ImageMagickThumbnailToGD() aborting because $this->sourceFilename is empty', __FILE__, __LINE__);
1360  $this->useRawIMoutput = false;
1361  return false;
1362  }
1363  if ($this->issafemode) {
1364  $this->DebugMessage('ImageMagickThumbnailToGD() aborting because safe_mode is enabled', __FILE__, __LINE__);
1365  $this->useRawIMoutput = false;
1366  return false;
1367  }
1368 // TO BE FIXED
1369 //if (true) {
1370 // $this->DebugMessage('ImageMagickThumbnailToGD() aborting it is broken right now', __FILE__, __LINE__);
1371 // $this->useRawIMoutput = false;
1372 // return false;
1373 //}
1374 
1375  $commandline = $this->ImageMagickCommandlineBase();
1376  if ($commandline) {
1377  if ($IMtempfilename = $this->phpThumb_tempnam()) {
1378  $IMtempfilename = realpath($IMtempfilename);
1379 
1380  $IMuseExplicitImageOutputDimensions = false;
1381  if ($this->ImageMagickSwitchAvailable('thumbnail') && $this->config_imagemagick_use_thumbnail) {
1382  $IMresizeParameter = 'thumbnail';
1383  } else {
1384  $IMresizeParameter = 'resize';
1385 
1386  // some (older? around 2002) versions of IM won't accept "-resize 100x" but require "-resize 100x100"
1387  $commandline_test = $this->ImageMagickCommandlineBase().' logo: -resize 1x '.escapeshellarg($IMtempfilename).' 2>&1';
1388  $IMresult_test = phpthumb_functions::SafeExec($commandline_test);
1389  $IMuseExplicitImageOutputDimensions = preg_match('#image dimensions are zero#i', $IMresult_test);
1390  $this->DebugMessage('IMuseExplicitImageOutputDimensions = '.intval($IMuseExplicitImageOutputDimensions), __FILE__, __LINE__);
1391  if ($fp_im_temp = @fopen($IMtempfilename, 'wb')) {
1392  // erase temp image so ImageMagick logo doesn't get output if other processing fails
1393  fclose($fp_im_temp);
1394  }
1395  }
1396 
1397 
1398  if (!is_null($this->dpi) && $this->ImageMagickSwitchAvailable('density')) {
1399  // for raster source formats only (WMF, PDF, etc)
1400  $commandline .= ' -density '.escapeshellarg($this->dpi);
1401  }
1402  ob_start();
1403  $getimagesize = GetImageSize($this->sourceFilename);
1404  $GetImageSizeError = ob_get_contents();
1405  ob_end_clean();
1406  if (is_array($getimagesize)) {
1407  $this->DebugMessage('GetImageSize('.$this->sourceFilename.') SUCCEEDED: '.print_r($getimagesize, true), __FILE__, __LINE__);
1408  } else {
1409  $this->DebugMessage('GetImageSize('.$this->sourceFilename.') FAILED with error "'.$GetImageSizeError.'"', __FILE__, __LINE__);
1410  }
1411  if (is_array($getimagesize)) {
1412  $this->DebugMessage('GetImageSize('.$this->sourceFilename.') returned [w='.$getimagesize[0].';h='.$getimagesize[1].';f='.$getimagesize[2].']', __FILE__, __LINE__);
1413  $this->source_width = $getimagesize[0];
1414  $this->source_height = $getimagesize[1];
1415  $this->DebugMessage('source dimensions set to '.$this->source_width.'x'.$this->source_height, __FILE__, __LINE__);
1417 
1418  if (!preg_match('#('.implode('|', $this->AlphaCapableFormats).')#i', $outputFormat)) {
1419  // not a transparency-capable format
1420  $commandline .= ' -background '.escapeshellarg('#'.($this->bg ? $this->bg : 'FFFFFF'));
1421  if ($getimagesize[2] == IMAGETYPE_GIF) {
1422  $commandline .= ' -flatten';
1423  }
1424  }
1425  if ($getimagesize[2] == IMAGETYPE_GIF) {
1426  $commandline .= ' -coalesce'; // may be needed for animated GIFs
1427  }
1428  if ($this->source_width || $this->source_height) {
1429  if ($this->zc) {
1430 
1431  $borderThickness = 0;
1432  if (!empty($this->fltr)) {
1433  foreach ($this->fltr as $key => $value) {
1434  if (preg_match('#^bord\|([0-9]+)#', $value, $matches)) {
1435  $borderThickness = $matches[1];
1436  break;
1437  }
1438  }
1439  }
1440  $wAll = intval(max($this->w, $this->wp, $this->wl, $this->ws)) - (2 * $borderThickness);
1441  $hAll = intval(max($this->h, $this->hp, $this->hl, $this->hs)) - (2 * $borderThickness);
1442  $imAR = $this->source_width / $this->source_height;
1443  $zcAR = (($wAll && $hAll) ? $wAll / $hAll : 1);
1444  $side = phpthumb_functions::nonempty_min($this->source_width, $this->source_height, max($wAll, $hAll));
1445  $sideX = phpthumb_functions::nonempty_min($this->source_width, $wAll, round($hAll * $zcAR));
1446  $sideY = phpthumb_functions::nonempty_min( $this->source_height, $hAll, round($wAll / $zcAR));
1447 
1448  $thumbnailH = round(max($sideY, ($sideY * $zcAR) / $imAR));
1449  $commandline .= ' -'.$IMresizeParameter.' '.escapeshellarg(($IMuseExplicitImageOutputDimensions ? $thumbnailH : '').'x'.$thumbnailH);
1450 
1451  switch (strtoupper($this->zc)) {
1452  case 'T':
1453  $commandline .= ' -gravity north';
1454  break;
1455  case 'B':
1456  $commandline .= ' -gravity south';
1457  break;
1458  case 'L':
1459  $commandline .= ' -gravity west';
1460  break;
1461  case 'R':
1462  $commandline .= ' -gravity east';
1463  break;
1464  case 'TL':
1465  $commandline .= ' -gravity northwest';
1466  break;
1467  case 'TR':
1468  $commandline .= ' -gravity northeast';
1469  break;
1470  case 'BL':
1471  $commandline .= ' -gravity southwest';
1472  break;
1473  case 'BR':
1474  $commandline .= ' -gravity southeast';
1475  break;
1476  case '1':
1477  case 'C':
1478  default:
1479  $commandline .= ' -gravity center';
1480  break;
1481  }
1482 
1483  if (($wAll > 0) && ($hAll > 0)) {
1484  $commandline .= ' -crop '.escapeshellarg($wAll.'x'.$hAll.'+0+0');
1485  } else {
1486  $commandline .= ' -crop '.escapeshellarg($side.'x'.$side.'+0+0');
1487  }
1488  if ($this->ImageMagickSwitchAvailable('repage')) {
1489  $commandline .= ' +repage';
1490  } else {
1491  $this->DebugMessage('Skipping "+repage" because ImageMagick (v'.$this->ImageMagickVersion().') does not support it', __FILE__, __LINE__);
1492  }
1493 
1494  } elseif ($this->sw || $this->sh || $this->sx || $this->sy) {
1495 
1496  $crop_param = '';
1497  $crop_param .= ($this->sw ? (($this->sw < 2) ? round($this->sw * $this->source_width) : $this->sw) : $this->source_width);
1498  $crop_param .= 'x'.($this->sh ? (($this->sh < 2) ? round($this->sh * $this->source_height) : $this->sh) : $this->source_height);
1499  $crop_param .= '+'.(($this->sx < 2) ? round($this->sx * $this->source_width) : $this->sx);
1500  $crop_param .= '+'.(($this->sy < 2) ? round($this->sy * $this->source_height) : $this->sy);
1501 // TO BE FIXED
1502 // makes 1x1 output
1503 // http://trainspotted.com/phpThumb/phpThumb.php?src=/content/CNR/47/CNR-4728-LD-L-20110723-898.jpg&w=100&h=100&far=1&f=png&fltr[]=lvl&sx=0.05&sy=0.25&sw=0.92&sh=0.42
1504 // '/usr/bin/convert' -density 150 -thumbnail 100x100 -contrast-stretch '0.1%' '/var/www/vhosts/trainspotted.com/httpdocs/content/CNR/47/CNR-4728-LD-L-20110723-898.jpg[0]' png:'/var/www/vhosts/trainspotted.com/httpdocs/phpThumb/_cache/pThumbIIUlvj'
1505 // $commandline .= ' -crop '.escapeshellarg($crop_param);
1506 
1507  // this is broken for aoe=1, but unsure how to fix. Send advice to info@silisoftware.com
1508  if ($this->w || $this->h) {
1509  //if ($this->ImageMagickSwitchAvailable('repage')) {
1510 if (false) {
1511 // TO BE FIXED
1512 // newer versions of ImageMagick require -repage <geometry>
1513  $commandline .= ' -repage';
1514  } else {
1515  $this->DebugMessage('Skipping "-repage" because ImageMagick (v'.$this->ImageMagickVersion().') does not support it', __FILE__, __LINE__);
1516  }
1517  if ($IMuseExplicitImageOutputDimensions) {
1518  if ($this->w && !$this->h) {
1519  $this->h = ceil($this->w / ($this->source_width / $this->source_height));
1520  } elseif ($this->h && !$this->w) {
1521  $this->w = ceil($this->h * ($this->source_width / $this->source_height));
1522  }
1523  }
1524  $commandline .= ' -'.$IMresizeParameter.' '.escapeshellarg($this->w.'x'.$this->h);
1525  }
1526 
1527  } else {
1528 
1529  if ($this->iar && (intval($this->w) > 0) && (intval($this->h) > 0)) {
1530  list($nw, $nh) = phpthumb_functions::TranslateWHbyAngle($this->w, $this->h, $this->ra);
1531  $nw = ((round($nw) != 0) ? round($nw) : '');
1532  $nh = ((round($nh) != 0) ? round($nh) : '');
1533  $commandline .= ' -'.$IMresizeParameter.' '.escapeshellarg($nw.'x'.$nh.'!');
1534  } else {
1535  $this->w = ((($this->aoe || $this->far) && $this->w) ? $this->w : ($this->w ? phpthumb_functions::nonempty_min($this->w, $getimagesize[0]) : ''));
1536  $this->h = ((($this->aoe || $this->far) && $this->h) ? $this->h : ($this->h ? phpthumb_functions::nonempty_min($this->h, $getimagesize[1]) : ''));
1537  if ($this->w || $this->h) {
1538  if ($IMuseExplicitImageOutputDimensions) {
1539  if ($this->w && !$this->h) {
1540  $this->h = ceil($this->w / ($this->source_width / $this->source_height));
1541  } elseif ($this->h && !$this->w) {
1542  $this->w = ceil($this->h * ($this->source_width / $this->source_height));
1543  }
1544  }
1545  list($nw, $nh) = phpthumb_functions::TranslateWHbyAngle($this->w, $this->h, $this->ra);
1546  $nw = ((round($nw) != 0) ? round($nw) : '');
1547  $nh = ((round($nh) != 0) ? round($nh) : '');
1548  $commandline .= ' -'.$IMresizeParameter.' '.escapeshellarg($nw.'x'.$nh);
1549  }
1550  }
1551  }
1552  }
1553 
1554  } else {
1555 
1556  $this->DebugMessage('GetImageSize('.$this->sourceFilename.') failed', __FILE__, __LINE__);
1557  if ($this->w || $this->h) {
1558  $exactDimensionsBang = (($this->iar && (intval($this->w) > 0) && (intval($this->h) > 0)) ? '!' : '');
1559  if ($IMuseExplicitImageOutputDimensions) {
1560  // unknown source aspect ratio, just put large number and hope IM figures it out
1561  $commandline .= ' -'.$IMresizeParameter.' '.escapeshellarg(($this->w ? $this->w : '9999').'x'.($this->h ? $this->h : '9999').$exactDimensionsBang);
1562  } else {
1563  $commandline .= ' -'.$IMresizeParameter.' '.escapeshellarg($this->w.'x'.$this->h.$exactDimensionsBang);
1564  }
1565  }
1566 
1567  }
1568 
1569  if ($this->ra) {
1570  $this->ra = intval($this->ra);
1571  if ($this->ImageMagickSwitchAvailable('rotate')) {
1572  if (!preg_match('#('.implode('|', $this->AlphaCapableFormats).')#i', $outputFormat) || phpthumb_functions::version_compare_replacement($this->ImageMagickVersion(), '6.3.7', '>=')) {
1573  $this->DebugMessage('Using ImageMagick rotate', __FILE__, __LINE__);
1574  $commandline .= ' -rotate '.escapeshellarg($this->ra);
1575  if (($this->ra % 90) != 0) {
1576  if (preg_match('#('.implode('|', $this->AlphaCapableFormats).')#i', $outputFormat)) {
1577  // alpha-capable format
1578  $commandline .= ' -background rgba(255,255,255,0)';
1579  } else {
1580  $commandline .= ' -background '.escapeshellarg('#'.($this->bg ? $this->bg : 'FFFFFF'));
1581  }
1582  }
1583  $this->ra = 0;
1584  } else {
1585  $this->DebugMessage('Not using ImageMagick rotate because alpha background buggy before v6.3.7', __FILE__, __LINE__);
1586  }
1587  } else {
1588  $this->DebugMessage('Not using ImageMagick rotate because not supported', __FILE__, __LINE__);
1589  }
1590  }
1591 
1592  $successfullyProcessedFilters = array();
1593  foreach ($this->fltr as $filterkey => $filtercommand) {
1594  @list($command, $parameter) = explode('|', $filtercommand, 2);
1595  switch ($command) {
1596  case 'brit':
1597  if ($this->ImageMagickSwitchAvailable('modulate')) {
1598  $commandline .= ' -modulate '.escapeshellarg((100 + intval($parameter)).',100,100');
1599  $successfullyProcessedFilters[] = $filterkey;
1600  }
1601  break;
1602 
1603  case 'cont':
1604  if ($this->ImageMagickSwitchAvailable('contrast')) {
1605  $contDiv10 = round(intval($parameter) / 10);
1606  if ($contDiv10 > 0) {
1607  $contDiv10 = min($contDiv10, 100);
1608  for ($i = 0; $i < $contDiv10; $i++) {
1609  $commandline .= ' -contrast'; // increase contrast by 10%
1610  }
1611  } elseif ($contDiv10 < 0) {
1612  $contDiv10 = max($contDiv10, -100);
1613  for ($i = $contDiv10; $i < 0; $i++) {
1614  $commandline .= ' +contrast'; // decrease contrast by 10%
1615  }
1616  } else {
1617  // do nothing
1618  }
1619  $successfullyProcessedFilters[] = $filterkey;
1620  }
1621  break;
1622 
1623  case 'ds':
1624  if ($this->ImageMagickSwitchAvailable(array('colorspace', 'modulate'))) {
1625  if ($parameter == 100) {
1626  $commandline .= ' -colorspace GRAY';
1627  $commandline .= ' -modulate 100,0,100';
1628  } else {
1629  $commandline .= ' -modulate '.escapeshellarg('100,'.(100 - intval($parameter)).',100');
1630  }
1631  $successfullyProcessedFilters[] = $filterkey;
1632  }
1633  break;
1634 
1635  case 'sat':
1636  if ($this->ImageMagickSwitchAvailable(array('colorspace', 'modulate'))) {
1637  if ($parameter == -100) {
1638  $commandline .= ' -colorspace GRAY';
1639  $commandline .= ' -modulate 100,0,100';
1640  } else {
1641  $commandline .= ' -modulate '.escapeshellarg('100,'.(100 + intval($parameter)).',100');
1642  }
1643  $successfullyProcessedFilters[] = $filterkey;
1644  }
1645  break;
1646 
1647  case 'gray':
1648  if ($this->ImageMagickSwitchAvailable(array('colorspace', 'modulate'))) {
1649  $commandline .= ' -colorspace GRAY';
1650  $commandline .= ' -modulate 100,0,100';
1651  $successfullyProcessedFilters[] = $filterkey;
1652  }
1653  break;
1654 
1655  case 'clr':
1656  if ($this->ImageMagickSwitchAvailable(array('fill', 'colorize'))) {
1657  @list($amount, $color) = explode('|', $parameter);
1658  $commandline .= ' -fill '.escapeshellarg('#'.preg_replace('#[^0-9A-F]#i', '', $color));
1659  $commandline .= ' -colorize '.escapeshellarg(min(max(intval($amount), 0), 100));
1660  }
1661  break;
1662 
1663  case 'sep':
1664  if ($this->ImageMagickSwitchAvailable('sepia-tone')) {
1665  @list($amount, $color) = explode('|', $parameter);
1666  $amount = ($amount ? $amount : 80);
1667  if (!$color) {
1668  $commandline .= ' -sepia-tone '.escapeshellarg(min(max(intval($amount), 0), 100).'%');
1669  $successfullyProcessedFilters[] = $filterkey;
1670  }
1671  }
1672  break;
1673 
1674  case 'gam':
1675  @list($amount) = explode('|', $parameter);
1676  $amount = min(max(floatval($amount), 0.001), 10);
1677  if (number_format($amount, 3) != '1.000') {
1678  if ($this->ImageMagickSwitchAvailable('gamma')) {
1679  $commandline .= ' -gamma '.escapeshellarg($amount);
1680  $successfullyProcessedFilters[] = $filterkey;
1681  }
1682  }
1683  break;
1684 
1685  case 'neg':
1686  if ($this->ImageMagickSwitchAvailable('negate')) {
1687  $commandline .= ' -negate';
1688  $successfullyProcessedFilters[] = $filterkey;
1689  }
1690  break;
1691 
1692  case 'th':
1693  @list($amount) = explode('|', $parameter);
1694  if ($this->ImageMagickSwitchAvailable(array('threshold', 'dither', 'monochrome'))) {
1695  $commandline .= ' -threshold '.escapeshellarg(round(min(max(intval($amount), 0), 255) / 2.55).'%');
1696  $commandline .= ' -dither';
1697  $commandline .= ' -monochrome';
1698  $successfullyProcessedFilters[] = $filterkey;
1699  }
1700  break;
1701 
1702  case 'rcd':
1703  if ($this->ImageMagickSwitchAvailable(array('colors', 'dither'))) {
1704  @list($colors, $dither) = explode('|', $parameter);
1705  $colors = ($colors ? (int) $colors : 256);
1706  $dither = ((strlen($dither) > 0) ? (bool) $dither : true);
1707  $commandline .= ' -colors '.escapeshellarg(max($colors, 8)); // ImageMagick will otherwise fail with "cannot quantize to fewer than 8 colors"
1708  $commandline .= ($dither ? ' -dither' : ' +dither');
1709  $successfullyProcessedFilters[] = $filterkey;
1710  }
1711  break;
1712 
1713  case 'flip':
1714  if ($this->ImageMagickSwitchAvailable(array('flip', 'flop'))) {
1715  if (strpos(strtolower($parameter), 'x') !== false) {
1716  $commandline .= ' -flop';
1717  }
1718  if (strpos(strtolower($parameter), 'y') !== false) {
1719  $commandline .= ' -flip';
1720  }
1721  $successfullyProcessedFilters[] = $filterkey;
1722  }
1723  break;
1724 
1725  case 'edge':
1726  if ($this->ImageMagickSwitchAvailable('edge')) {
1727  $parameter = (!empty($parameter) ? $parameter : 2);
1728  $commandline .= ' -edge '.escapeshellarg(!empty($parameter) ? intval($parameter) : 1);
1729  $successfullyProcessedFilters[] = $filterkey;
1730  }
1731  break;
1732 
1733  case 'emb':
1734  if ($this->ImageMagickSwitchAvailable(array('emboss', 'negate'))) {
1735  $parameter = (!empty($parameter) ? $parameter : 2);
1736  $commandline .= ' -emboss '.escapeshellarg(intval($parameter));
1737  if ($parameter < 2) {
1738  $commandline .= ' -negate'; // ImageMagick negates the image for some reason with '-emboss 1';
1739  }
1740  $successfullyProcessedFilters[] = $filterkey;
1741  }
1742  break;
1743 
1744  case 'lvl':
1745  @list($band, $method, $threshold) = explode('|', $parameter);
1746  $band = ($band ? preg_replace('#[^RGBA\\*]#', '', strtoupper($band)) : '*');
1747  $method = ((strlen($method) > 0) ? intval($method) : 2);
1748  $threshold = ((strlen($threshold) > 0) ? min(max(floatval($threshold), 0), 100) : 0.1);
1749 
1750  $band = preg_replace('#[^RGBA\\*]#', '', strtoupper($band));
1751 
1752  if (($method > 1) && !$this->ImageMagickSwitchAvailable(array('channel', 'contrast-stretch'))) {
1753  // Because ImageMagick processing happens before PHP-GD filters, and because some
1754  // clipping is involved in the "lvl" filter, if "lvl" happens before "wb" then the
1755  // "wb" filter will have (almost) no effect. Therefore, if "wb" is enabled then
1756  // force the "lvl" filter to be processed by GD, not ImageMagick.
1757  foreach ($this->fltr as $fltr_key => $fltr_value) {
1758  list($fltr_cmd) = explode('|', $fltr_value);
1759  if ($fltr_cmd == 'wb') {
1760  $this->DebugMessage('Setting "lvl" filter method to "0" (from "'.$method.'") because white-balance filter also enabled', __FILE__, __LINE__);
1761  $method = 0;
1762  }
1763  }
1764  }
1765 
1766  switch ($method) {
1767  case 0: // internal RGB
1768  case 1: // internal grayscale
1769  break;
1770  case 2: // ImageMagick "contrast-stretch"
1771  if ($this->ImageMagickSwitchAvailable('contrast-stretch')) {
1772  if ($band != '*') {
1773  $commandline .= ' -channel '.escapeshellarg(strtoupper($band));
1774  }
1775  $threshold = preg_replace('#[^0-9\\.]#', '', $threshold); // should be unneccesary, but just to be double-sure
1776  //$commandline .= ' -contrast-stretch '.escapeshellarg($threshold.'%');
1777  $commandline .= ' -contrast-stretch \''.$threshold.'%\'';
1778  if ($band != '*') {
1779  $commandline .= ' +channel';
1780  }
1781  $successfullyProcessedFilters[] = $filterkey;
1782  }
1783  break;
1784  case 3: // ImageMagick "normalize"
1785  if ($this->ImageMagickSwitchAvailable('normalize')) {
1786  if ($band != '*') {
1787  $commandline .= ' -channel '.escapeshellarg(strtoupper($band));
1788  }
1789  $commandline .= ' -normalize';
1790  if ($band != '*') {
1791  $commandline .= ' +channel';
1792  }
1793  $successfullyProcessedFilters[] = $filterkey;
1794  }
1795  break;
1796  default:
1797  $this->DebugMessage('unsupported method ('.$method.') for "lvl" filter', __FILE__, __LINE__);
1798  break;
1799  }
1800  if (isset($this->fltr[$filterkey]) && ($method > 1)) {
1801  $this->fltr[$filterkey] = $command.'|'.$band.'|0|'.$threshold;
1802  $this->DebugMessage('filter "lvl" remapped from method "'.$method.'" to method "0" because ImageMagick support is missing', __FILE__, __LINE__);
1803  }
1804  break;
1805 
1806  case 'wb':
1807  if ($this->ImageMagickSwitchAvailable(array('channel', 'contrast-stretch'))) {
1808  @list($threshold) = explode('|', $parameter);
1809  $threshold = (!empty($threshold) ? min(max(floatval($threshold), 0), 100) : 0.1);
1810  $threshold = preg_replace('#[^0-9\\.]#', '', $threshold); // should be unneccesary, but just to be double-sure
1811  //$commandline .= ' -channel R -contrast-stretch '.escapeshellarg($threshold.'%'); // doesn't work on Windows because most versions of PHP do not properly
1812  //$commandline .= ' -channel G -contrast-stretch '.escapeshellarg($threshold.'%'); // escape special characters (such as %) and just replace them with spaces
1813  //$commandline .= ' -channel B -contrast-stretch '.escapeshellarg($threshold.'%'); // https://bugs.php.net/bug.php?id=43261
1814  $commandline .= ' -channel R -contrast-stretch \''.$threshold.'%\'';
1815  $commandline .= ' -channel G -contrast-stretch \''.$threshold.'%\'';
1816  $commandline .= ' -channel B -contrast-stretch \''.$threshold.'%\'';
1817  $commandline .= ' +channel';
1818  $successfullyProcessedFilters[] = $filterkey;
1819  }
1820  break;
1821 
1822  case 'blur':
1823  if ($this->ImageMagickSwitchAvailable('blur')) {
1824  @list($radius) = explode('|', $parameter);
1825  $radius = (!empty($radius) ? min(max(intval($radius), 0), 25) : 1);
1826  $commandline .= ' -blur '.escapeshellarg($radius);
1827  $successfullyProcessedFilters[] = $filterkey;
1828  }
1829  break;
1830 
1831  case 'gblr':
1832  @list($radius) = explode('|', $parameter);
1833  $radius = (!empty($radius) ? min(max(intval($radius), 0), 25) : 1);
1834  // "-gaussian" changed to "-gaussian-blur" sometime around 2009
1835  if ($this->ImageMagickSwitchAvailable('gaussian-blur')) {
1836  $commandline .= ' -gaussian-blur '.escapeshellarg($radius);
1837  $successfullyProcessedFilters[] = $filterkey;
1838  } elseif ($this->ImageMagickSwitchAvailable('gaussian')) {
1839  $commandline .= ' -gaussian '.escapeshellarg($radius);
1840  $successfullyProcessedFilters[] = $filterkey;
1841  }
1842  break;
1843 
1844  case 'usm':
1845  if ($this->ImageMagickSwitchAvailable('unsharp')) {
1846  @list($amount, $radius, $threshold) = explode('|', $parameter);
1847  $amount = ($amount ? min(max(intval($radius), 0), 255) : 80);
1848  $radius = ($radius ? min(max(intval($radius), 0), 10) : 0.5);
1849  $threshold = (strlen($threshold) ? min(max(intval($radius), 0), 50) : 3);
1850  $commandline .= ' -unsharp '.escapeshellarg(number_format(($radius * 2) - 1, 2, '.', '').'x1+'.number_format($amount / 100, 2, '.', '').'+'.number_format($threshold / 100, 2, '.', ''));
1851  $successfullyProcessedFilters[] = $filterkey;
1852  }
1853  break;
1854 
1855  case 'bord':
1856  if ($this->ImageMagickSwitchAvailable(array('border', 'bordercolor', 'thumbnail', 'crop'))) {
1857  if (!$this->zc) {
1858  @list($width, $rX, $rY, $color) = explode('|', $parameter);
1859  $width = intval($width);
1860  $rX = intval($rX);
1861  $rY = intval($rY);
1862  if ($width && !$rX && !$rY) {
1863  if (!phpthumb_functions::IsHexColor($color)) {
1864  $color = ((!empty($this->bc) && phpthumb_functions::IsHexColor($this->bc)) ? $this->bc : '000000');
1865  }
1866  $commandline .= ' -border '.escapeshellarg(intval($width));
1867  $commandline .= ' -bordercolor '.escapeshellarg('#'.$color);
1868 
1869  if (preg_match('# \\-crop "([0-9]+)x([0-9]+)\\+0\\+0" #', $commandline, $matches)) {
1870  $commandline = str_replace(' -crop "'.$matches[1].'x'.$matches[2].'+0+0" ', ' -crop '.escapeshellarg(($matches[1] - (2 * $width)).'x'.($matches[2] - (2 * $width)).'+0+0').' ', $commandline);
1871  } elseif (preg_match('# \\-'.$IMresizeParameter.' "([0-9]+)x([0-9]+)" #', $commandline, $matches)) {
1872  $commandline = str_replace(' -'.$IMresizeParameter.' "'.$matches[1].'x'.$matches[2].'" ', ' -'.$IMresizeParameter.' '.escapeshellarg(($matches[1] - (2 * $width)).'x'.($matches[2] - (2 * $width))).' ', $commandline);
1873  }
1874  $successfullyProcessedFilters[] = $filterkey;
1875  }
1876  }
1877  }
1878  break;
1879 
1880  case 'crop':
1881  break;
1882 
1883  case 'sblr':
1884  break;
1885 
1886  case 'mean':
1887  break;
1888 
1889  case 'smth':
1890  break;
1891 
1892  case 'bvl':
1893  break;
1894 
1895  case 'wmi':
1896  break;
1897 
1898  case 'wmt':
1899  break;
1900 
1901  case 'over':
1902  break;
1903 
1904  case 'hist':
1905  break;
1906 
1907  case 'fram':
1908  break;
1909 
1910  case 'drop':
1911  break;
1912 
1913  case 'mask':
1914  break;
1915 
1916  case 'elip':
1917  break;
1918 
1919  case 'ric':
1920  break;
1921 
1922  case 'stc':
1923  break;
1924 
1925  case 'size':
1926  break;
1927 
1928  default:
1929  $this->DebugMessage('Unknown $this->fltr['.$filterkey.'] ('.$filtercommand.') -- deleting filter command', __FILE__, __LINE__);
1930  $successfullyProcessedFilters[] = $filterkey;
1931  break;
1932  }
1933  if (!isset($this->fltr[$filterkey])) {
1934  $this->DebugMessage('Processed $this->fltr['.$filterkey.'] ('.$filtercommand.') with ImageMagick', __FILE__, __LINE__);
1935  } else {
1936  $this->DebugMessage('Skipping $this->fltr['.$filterkey.'] ('.$filtercommand.') with ImageMagick', __FILE__, __LINE__);
1937  }
1938  }
1939  $this->DebugMessage('Remaining $this->fltr after ImageMagick: ('.$this->phpThumbDebugVarDump($this->fltr).')', __FILE__, __LINE__);
1940  if (count($this->fltr) > 0) {
1941  $this->useRawIMoutput = false;
1942  }
1943 
1944  if (preg_match('#jpe?g#i', $outputFormat) && $this->q) {
1945  if ($this->ImageMagickSwitchAvailable(array('quality', 'interlace'))) {
1946  $commandline .= ' -quality '.escapeshellarg($this->thumbnailQuality);
1947  if ($this->config_output_interlace) {
1948  // causes weird things with animated GIF... leave for JPEG only
1949  $commandline .= ' -interlace line '; // Use Line or Plane to create an interlaced PNG or GIF or progressive JPEG image
1950  }
1951  }
1952  }
1953  $commandline .= ' '.escapeshellarg(preg_replace('#[/\\\\]#', DIRECTORY_SEPARATOR, $this->sourceFilename).(($outputFormat == 'gif') ? '' : '['.intval($this->sfn).']')); // [0] means first frame of (GIF) animation, can be ignored
1954  $commandline .= ' '.$outputFormat.':'.escapeshellarg($IMtempfilename);
1955  if (!$this->iswindows) {
1956  $commandline .= ' 2>&1';
1957  }
1958  $this->DebugMessage('ImageMagick called as ('.$commandline.')', __FILE__, __LINE__);
1959  $IMresult = phpthumb_functions::SafeExec($commandline);
1960  clearstatcache();
1961  if (!@file_exists($IMtempfilename) || !@filesize($IMtempfilename)) {
1962  $this->FatalError('ImageMagick failed with message ('.trim($IMresult).')');
1963  $this->DebugMessage('ImageMagick failed with message ('.trim($IMresult).')', __FILE__, __LINE__);
1964  if ($this->iswindows && !$IMresult) {
1965  $this->DebugMessage('Check to make sure that PHP has read+write permissions to "'.dirname($IMtempfilename).'"', __FILE__, __LINE__);
1966  }
1967 
1968  } else {
1969 
1970  foreach ($successfullyProcessedFilters as $dummy => $filterkey) {
1971  unset($this->fltr[$filterkey]);
1972  }
1973  $this->IMresizedData = file_get_contents($IMtempfilename);
1974  $getimagesize_imresized = @GetImageSize($IMtempfilename);
1975  $this->DebugMessage('GetImageSize('.$IMtempfilename.') returned [w='.$getimagesize_imresized[0].';h='.$getimagesize_imresized[1].';f='.$getimagesize_imresized[2].']', __FILE__, __LINE__);
1976  if (($this->config_max_source_pixels > 0) && (($getimagesize_imresized[0] * $getimagesize_imresized[1]) > $this->config_max_source_pixels)) {
1977  $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__);
1978  } elseif (function_exists(@$ImageCreateFunction) && ($this->gdimg_source = @$ImageCreateFunction($IMtempfilename))) {
1979  $this->source_width = ImageSX($this->gdimg_source);
1980  $this->source_height = ImageSY($this->gdimg_source);
1981  $this->DebugMessage('ImageMagickThumbnailToGD::'.$ImageCreateFunction.'() succeeded, $this->gdimg_source is now ('.$this->source_width.'x'.$this->source_height.')', __FILE__, __LINE__);
1982  $this->DebugMessage('ImageMagickThumbnailToGD() returning $this->IMresizedData ('.strlen($this->IMresizedData).' bytes)', __FILE__, __LINE__);
1983  } else {
1984  $this->useRawIMoutput = true;
1985  $this->DebugMessage('$this->useRawIMoutput set to TRUE because '.@$ImageCreateFunction.'('.$IMtempfilename.') failed', __FILE__, __LINE__);
1986  }
1987  return true;
1988 
1989  }
1990  if (file_exists($IMtempfilename)) {
1991  $this->DebugMessage('deleting "'.$IMtempfilename.'"', __FILE__, __LINE__);
1992  @unlink($IMtempfilename);
1993  }
1994 
1995  } elseif ($this->issafemode) {
1996  $this->DebugMessage('ImageMagickThumbnailToGD() aborting because PHP safe_mode is enabled and phpThumb_tempnam() failed', __FILE__, __LINE__);
1997  $this->useRawIMoutput = false;
1998  } else {
1999  if (file_exists($IMtempfilename)) {
2000  $this->DebugMessage('deleting "'.$IMtempfilename.'"', __FILE__, __LINE__);
2001  @unlink($IMtempfilename);
2002  }
2003  $this->DebugMessage('ImageMagickThumbnailToGD() aborting, phpThumb_tempnam() failed', __FILE__, __LINE__);
2004  }
2005  } else {
2006  $this->DebugMessage('ImageMagickThumbnailToGD() aborting because ImageMagickCommandlineBase() failed', __FILE__, __LINE__);
2007  }
2008  $this->useRawIMoutput = false;
2009  return false;
2010  }
2011 
2012 
2013  function Rotate() {
2014  if ($this->ra || $this->ar) {
2015  if (!function_exists('ImageRotate')) {
2016  $this->DebugMessage('!function_exists(ImageRotate)', __FILE__, __LINE__);
2017  return false;
2018  }
2019  if (!include_once(dirname(__FILE__).'/phpthumb.filters.php')) {
2020  $this->DebugMessage('Error including "'.dirname(__FILE__).'/phpthumb.filters.php" which is required for applying filters ('.implode(';', $this->fltr).')', __FILE__, __LINE__);
2021  return false;
2022  }
2023 
2024  $this->config_background_hexcolor = ($this->bg ? $this->bg : $this->config_background_hexcolor);
2025  if (!phpthumb_functions::IsHexColor($this->config_background_hexcolor)) {
2026  return $this->ErrorImage('Invalid hex color string "'.$this->config_background_hexcolor.'" for parameter "bg"');
2027  }
2028 
2029  $rotate_angle = 0;
2030  if ($this->ra) {
2031 
2032  $rotate_angle = floatval($this->ra);
2033 
2034  } else {
2035 
2036  if ($this->ar == 'x') {
2037  if (phpthumb_functions::version_compare_replacement(phpversion(), '4.2.0', '>=')) {
2038  if ($this->sourceFilename) {
2039  if (function_exists('exif_read_data')) {
2040  if ($exif_data = @exif_read_data($this->sourceFilename, 'IFD0')) {
2041  // http://sylvana.net/jpegcrop/exif_orientation.html
2042  switch (@$exif_data['Orientation']) {
2043  case 1:
2044  $rotate_angle = 0;
2045  break;
2046  case 3:
2047  $rotate_angle = 180;
2048  break;
2049  case 6:
2050  $rotate_angle = 270;
2051  break;
2052  case 8:
2053  $rotate_angle = 90;
2054  break;
2055 
2056  default:
2057  $this->DebugMessage('EXIF auto-rotate failed because unknown $exif_data[Orientation] "'.@$exif_data['Orientation'].'"', __FILE__, __LINE__);
2058  return false;
2059  break;
2060  }
2061  $this->DebugMessage('EXIF auto-rotate set to '.$rotate_angle.' degrees ($exif_data[Orientation] = "'.@$exif_data['Orientation'].'")', __FILE__, __LINE__);
2062  } else {
2063  $this->DebugMessage('failed: exif_read_data('.$this->sourceFilename.')', __FILE__, __LINE__);
2064  return false;
2065  }
2066  } else {
2067  $this->DebugMessage('!function_exists(exif_read_data)', __FILE__, __LINE__);
2068  return false;
2069  }
2070  } else {
2071  $this->DebugMessage('Cannot auto-rotate from EXIF data because $this->sourceFilename is empty', __FILE__, __LINE__);
2072  return false;
2073  }
2074  } else {
2075  $this->DebugMessage('Cannot auto-rotate from EXIF data because PHP is less than v4.2.0 ('.phpversion().')', __FILE__, __LINE__);
2076  return false;
2077  }
2078  } elseif (($this->ar == 'l') && ($this->source_height > $this->source_width)) {
2079  $rotate_angle = 270;
2080  } elseif (($this->ar == 'L') && ($this->source_height > $this->source_width)) {
2081  $rotate_angle = 90;
2082  } elseif (($this->ar == 'p') && ($this->source_width > $this->source_height)) {
2083  $rotate_angle = 90;
2084  } elseif (($this->ar == 'P') && ($this->source_width > $this->source_height)) {
2085  $rotate_angle = 270;
2086  }
2087 
2088  }
2089  if ($rotate_angle % 90) {
2090  $this->is_alpha = true;
2091  }
2092  phpthumb_filters::ImprovedImageRotate($this->gdimg_source, $rotate_angle, $this->config_background_hexcolor, $this->bg);
2093  $this->source_width = ImageSX($this->gdimg_source);
2094  $this->source_height = ImageSY($this->gdimg_source);
2095  }
2096  return true;
2097  }
2098 
2099 
2100  function FixedAspectRatio() {
2101  // optional fixed-dimension images (regardless of aspect ratio)
2102 
2103  if (!$this->far) {
2104  // do nothing
2105  return true;
2106  }
2107 
2108  if (!$this->w || !$this->h) {
2109  return false;
2110  }
2111  $this->thumbnail_width = $this->w;
2112  $this->thumbnail_height = $this->h;
2113  $this->is_alpha = true;
2114  if ($this->thumbnail_image_width >= $this->thumbnail_width) {
2115 
2116  if ($this->w) {
2117  $aspectratio = $this->thumbnail_image_height / $this->thumbnail_image_width;
2118  $this->thumbnail_image_height = round($this->thumbnail_image_width * $aspectratio);
2119  $this->thumbnail_height = ($this->h ? $this->h : $this->thumbnail_image_height);
2120  } elseif ($this->thumbnail_image_height < $this->thumbnail_height) {
2121  $this->thumbnail_image_height = $this->thumbnail_height;
2122  $this->thumbnail_image_width = round($this->thumbnail_image_height / $aspectratio);
2123  }
2124 
2125  } else {
2126  if ($this->h) {
2127  $aspectratio = $this->thumbnail_image_width / $this->thumbnail_image_height;
2128  $this->thumbnail_image_width = round($this->thumbnail_image_height * $aspectratio);
2129  } elseif ($this->thumbnail_image_width < $this->thumbnail_width) {
2130  $this->thumbnail_image_width = $this->thumbnail_width;
2131  $this->thumbnail_image_height = round($this->thumbnail_image_width / $aspectratio);
2132  }
2133 
2134  }
2135  return true;
2136  }
2137 
2138 
2139  function OffsiteDomainIsAllowed($hostname, $allowed_domains) {
2140  static $domain_is_allowed = array();
2141  $hostname = strtolower($hostname);
2142  if (!isset($domain_is_allowed[$hostname])) {
2143  $domain_is_allowed[$hostname] = false;
2144  foreach ($allowed_domains as $valid_domain) {
2145  $starpos = strpos($valid_domain, '*');
2146  if ($starpos !== false) {
2147  $valid_domain = substr($valid_domain, $starpos + 1);
2148  if (preg_match('#'.preg_quote($valid_domain).'$#', $hostname)) {
2149  $domain_is_allowed[$hostname] = true;
2150  break;
2151  }
2152  } else {
2153  if (strtolower($valid_domain) === $hostname) {
2154  $domain_is_allowed[$hostname] = true;
2155  break;
2156  }
2157  }
2158  }
2159  }
2160  return $domain_is_allowed[$hostname];
2161  }
2162 
2163 
2164  function AntiOffsiteLinking() {
2165  // Optional anti-offsite hijacking of the thumbnail script
2166  $allow = true;
2167  if ($allow && $this->config_nooffsitelink_enabled && (@$_SERVER['HTTP_REFERER'] || $this->config_nooffsitelink_require_refer)) {
2168  $this->DebugMessage('AntiOffsiteLinking() checking $_SERVER[HTTP_REFERER] "'.@$_SERVER['HTTP_REFERER'].'"', __FILE__, __LINE__);
2169  foreach ($this->config_nooffsitelink_valid_domains as $key => $valid_domain) {
2170  // $_SERVER['HTTP_HOST'] contains the port number, so strip it out here to make default configuration work
2171  list($clean_domain) = explode(':', $valid_domain);
2172  $this->config_nooffsitelink_valid_domains[$key] = $clean_domain;
2173  }
2174  $parsed_url = phpthumb_functions::ParseURLbetter(@$_SERVER['HTTP_REFERER']);
2175  if (!$this->OffsiteDomainIsAllowed(@$parsed_url['host'], $this->config_nooffsitelink_valid_domains)) {
2176  $allow = false;
2179 $this->ErrorImage('AntiOffsiteLinking() - "'.@$parsed_url['host'].'" is NOT in $this->config_nooffsitelink_valid_domains ('.implode(';', $this->config_nooffsitelink_valid_domains).')');
2180 exit;
2181  $this->DebugMessage('AntiOffsiteLinking() - "'.@$parsed_url['host'].'" is NOT in $this->config_nooffsitelink_valid_domains ('.implode(';', $this->config_nooffsitelink_valid_domains).')', __FILE__, __LINE__);
2182  } else {
2183  $this->DebugMessage('AntiOffsiteLinking() - "'.@$parsed_url['host'].'" is in $this->config_nooffsitelink_valid_domains ('.implode(';', $this->config_nooffsitelink_valid_domains).')', __FILE__, __LINE__);
2184  }
2185  }
2186 
2187  if ($allow && $this->config_nohotlink_enabled && preg_match('#^(f|ht)tps?\://#i', $this->src)) {
2188  $parsed_url = phpthumb_functions::ParseURLbetter($this->src);
2189  //if (!phpthumb_functions::CaseInsensitiveInArray(@$parsed_url['host'], $this->config_nohotlink_valid_domains)) {
2190  if ($this->OffsiteDomainIsAllowed(@$parsed_url['host'], $this->config_nohotlink_valid_domains)) {
2191  // This domain is not allowed
2192  $allow = false;
2195  $this->DebugMessage('AntiOffsiteLinking() - "'.$parsed_url['host'].'" is NOT in $this->config_nohotlink_valid_domains ('.implode(';', $this->config_nohotlink_valid_domains).')', __FILE__, __LINE__);
2196  } else {
2197  $this->DebugMessage('AntiOffsiteLinking() - "'.$parsed_url['host'].'" is in $this->config_nohotlink_valid_domains ('.implode(';', $this->config_nohotlink_valid_domains).')', __FILE__, __LINE__);
2198  }
2199  }
2200 
2201  if ($allow) {
2202  $this->DebugMessage('AntiOffsiteLinking() says this is allowed', __FILE__, __LINE__);
2203  return true;
2204  }
2205 
2206  if (!phpthumb_functions::IsHexColor($this->config_error_bgcolor)) {
2207  return $this->ErrorImage('Invalid hex color string "'.$this->config_error_bgcolor.'" for $this->config_error_bgcolor');
2208  }
2209  if (!phpthumb_functions::IsHexColor($this->config_error_textcolor)) {
2210  return $this->ErrorImage('Invalid hex color string "'.$this->config_error_textcolor.'" for $this->config_error_textcolor');
2211  }
2212  if ($erase) {
2213 
2214  return $this->ErrorImage($message, $this->thumbnail_width, $this->thumbnail_height, $this->config_error_bgcolor, $this->config_error_textcolor, $this->config_error_fontsize);
2215 
2216  } else {
2217 
2218  $this->config_nooffsitelink_watermark_src = $this->ResolveFilenameToAbsolute($this->config_nooffsitelink_watermark_src);
2219  if (is_file($this->config_nooffsitelink_watermark_src)) {
2220 
2221  if (!include_once(dirname(__FILE__).'/phpthumb.filters.php')) {
2222  $this->DebugMessage('Error including "'.dirname(__FILE__).'/phpthumb.filters.php" which is required for applying watermark', __FILE__, __LINE__);
2223  return false;
2224  }
2225  $watermark_img = $this->ImageCreateFromStringReplacement(file_get_contents($this->config_nooffsitelink_watermark_src));
2226  $phpthumbFilters = new phpthumb_filters();
2227  $phpthumbFilters->phpThumbObject = &$this;
2228  $opacity = 50;
2229  $margin = 5;
2230  $phpthumbFilters->WatermarkOverlay($this->gdimg_output, $watermark_img, '*', $opacity, $margin);
2231  ImageDestroy($watermark_img);
2232  unset($phpthumbFilters);
2233 
2234  } else {
2235 
2236  $nohotlink_text_array = explode("\n", wordwrap($message, floor($this->thumbnail_width / ImageFontWidth($this->config_error_fontsize)), "\n"));
2237  $nohotlink_text_color = phpthumb_functions::ImageHexColorAllocate($this->gdimg_output, $this->config_error_textcolor);
2238 
2239  $topoffset = round(($this->thumbnail_height - (count($nohotlink_text_array) * ImageFontHeight($this->config_error_fontsize))) / 2);
2240 
2241  $rowcounter = 0;
2242  $this->DebugMessage('AntiOffsiteLinking() writing '.count($nohotlink_text_array).' lines of text "'.$message.'" (in #'.$this->config_error_textcolor.') on top of image', __FILE__, __LINE__);
2243  foreach ($nohotlink_text_array as $textline) {
2244  $leftoffset = max(0, round(($this->thumbnail_width - (strlen($textline) * ImageFontWidth($this->config_error_fontsize))) / 2));
2245  ImageString($this->gdimg_output, $this->config_error_fontsize, $leftoffset, $topoffset + ($rowcounter++ * ImageFontHeight($this->config_error_fontsize)), $textline, $nohotlink_text_color);
2246  }
2247 
2248  }
2249 
2250  }
2251  return true;
2252  }
2253 
2254 
2255  function AlphaChannelFlatten() {
2256  if (!$this->is_alpha) {
2257  // image doesn't have alpha transparency, no need to flatten
2258  $this->DebugMessage('skipping AlphaChannelFlatten() because !$this->is_alpha', __FILE__, __LINE__);
2259  return false;
2260  }
2261  switch ($this->thumbnailFormat) {
2262  case 'png':
2263  case 'ico':
2264  // image has alpha transparency, but output as PNG or ICO which can handle it
2265  $this->DebugMessage('skipping AlphaChannelFlatten() because ($this->thumbnailFormat == "'.$this->thumbnailFormat.'")', __FILE__, __LINE__);
2266  return false;
2267  break;
2268 
2269  case 'gif':
2270  // image has alpha transparency, but output as GIF which can handle only single-color transparency
2271  $CurrentImageColorTransparent = ImageColorTransparent($this->gdimg_output);
2272  if ($CurrentImageColorTransparent == -1) {
2273  // no transparent color defined
2274 
2275  if (phpthumb_functions::gd_version() < 2.0) {
2276  $this->DebugMessage('AlphaChannelFlatten() failed because GD version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
2277  return false;
2278  }
2279 
2280  if ($img_alpha_mixdown_dither = @ImageCreateTrueColor(ImageSX($this->gdimg_output), ImageSY($this->gdimg_output))) {
2281 
2282  for ($i = 0; $i <= 255; $i++) {
2283  $dither_color[$i] = ImageColorAllocate($img_alpha_mixdown_dither, $i, $i, $i);
2284  }
2285 
2286  // scan through current truecolor image copy alpha channel to temp image as grayscale
2287  for ($x = 0; $x < $this->thumbnail_width; $x++) {
2288  for ($y = 0; $y < $this->thumbnail_height; $y++) {
2289  $PixelColor = phpthumb_functions::GetPixelColor($this->gdimg_output, $x, $y);
2290  ImageSetPixel($img_alpha_mixdown_dither, $x, $y, $dither_color[($PixelColor['alpha'] * 2)]);
2291  }
2292  }
2293 
2294  // dither alpha channel grayscale version down to 2 colors
2295  ImageTrueColorToPalette($img_alpha_mixdown_dither, true, 2);
2296 
2297  // reduce color palette to 256-1 colors (leave one palette position for transparent color)
2298  ImageTrueColorToPalette($this->gdimg_output, true, 255);
2299 
2300  // allocate a new color for transparent color index
2301  $TransparentColor = ImageColorAllocate($this->gdimg_output, 1, 254, 253);
2302  ImageColorTransparent($this->gdimg_output, $TransparentColor);
2303 
2304  // scan through alpha channel image and note pixels with >50% transparency
2305  $TransparentPixels = array();
2306  for ($x = 0; $x < $this->thumbnail_width; $x++) {
2307  for ($y = 0; $y < $this->thumbnail_height; $y++) {
2308  $AlphaChannelPixel = phpthumb_functions::GetPixelColor($img_alpha_mixdown_dither, $x, $y);
2309  if ($AlphaChannelPixel['red'] > 127) {
2310  ImageSetPixel($this->gdimg_output, $x, $y, $TransparentColor);
2311  }
2312  }
2313  }
2314  ImageDestroy($img_alpha_mixdown_dither);
2315 
2316  $this->DebugMessage('AlphaChannelFlatten() set image to 255+1 colors with transparency for GIF output', __FILE__, __LINE__);
2317  return true;
2318 
2319  } else {
2320  $this->DebugMessage('AlphaChannelFlatten() failed ImageCreate('.ImageSX($this->gdimg_output).', '.ImageSY($this->gdimg_output).')', __FILE__, __LINE__);
2321  return false;
2322  }
2323 
2324  } else {
2325  // a single transparent color already defined, leave as-is
2326  $this->DebugMessage('skipping AlphaChannelFlatten() because ($this->thumbnailFormat == "'.$this->thumbnailFormat.'") and ImageColorTransparent returned "'.$CurrentImageColorTransparent.'"', __FILE__, __LINE__);
2327  return true;
2328  }
2329  break;
2330  }
2331  $this->DebugMessage('continuing AlphaChannelFlatten() for output format "'.$this->thumbnailFormat.'"', __FILE__, __LINE__);
2332  // image has alpha transparency, and is being output in a format that doesn't support it -- flatten
2333  if ($gdimg_flatten_temp = phpthumb_functions::ImageCreateFunction($this->thumbnail_width, $this->thumbnail_height)) {
2334 
2335  $this->config_background_hexcolor = ($this->bg ? $this->bg : $this->config_background_hexcolor);
2336  if (!phpthumb_functions::IsHexColor($this->config_background_hexcolor)) {
2337  return $this->ErrorImage('Invalid hex color string "'.$this->config_background_hexcolor.'" for parameter "bg"');
2338  }
2339  $background_color = phpthumb_functions::ImageHexColorAllocate($this->gdimg_output, $this->config_background_hexcolor);
2340  ImageFilledRectangle($gdimg_flatten_temp, 0, 0, $this->thumbnail_width, $this->thumbnail_height, $background_color);
2341  ImageCopy($gdimg_flatten_temp, $this->gdimg_output, 0, 0, 0, 0, $this->thumbnail_width, $this->thumbnail_height);
2342 
2343  ImageAlphaBlending($this->gdimg_output, true);
2344  ImageSaveAlpha($this->gdimg_output, false);
2345  ImageColorTransparent($this->gdimg_output, -1);
2346  ImageCopy($this->gdimg_output, $gdimg_flatten_temp, 0, 0, 0, 0, $this->thumbnail_width, $this->thumbnail_height);
2347 
2348  ImageDestroy($gdimg_flatten_temp);
2349  return true;
2350 
2351  } else {
2352  $this->DebugMessage('ImageCreateFunction() failed', __FILE__, __LINE__);
2353  }
2354  return false;
2355  }
2356 
2357 
2358  function ApplyFilters() {
2359  if ($this->fltr && is_array($this->fltr)) {
2360  if (!include_once(dirname(__FILE__).'/phpthumb.filters.php')) {
2361  $this->DebugMessage('Error including "'.dirname(__FILE__).'/phpthumb.filters.php" which is required for applying filters ('.implode(';', $this->fltr).')', __FILE__, __LINE__);
2362  return false;
2363  }
2364  $phpthumbFilters = new phpthumb_filters();
2365  $phpthumbFilters->phpThumbObject = &$this;
2366  foreach ($this->fltr as $filtercommand) {
2367  @list($command, $parameter) = explode('|', $filtercommand, 2);
2368  $this->DebugMessage('Attempting to process filter command "'.$command.'('.$parameter.')"', __FILE__, __LINE__);
2369  switch ($command) {
2370  case 'brit': // Brightness
2371  $phpthumbFilters->Brightness($this->gdimg_output, $parameter);
2372  break;
2373 
2374  case 'cont': // Contrast
2375  $phpthumbFilters->Contrast($this->gdimg_output, $parameter);
2376  break;
2377 
2378  case 'ds': // Desaturation
2379  $phpthumbFilters->Desaturate($this->gdimg_output, $parameter, '');
2380  break;
2381 
2382  case 'sat': // Saturation
2383  $phpthumbFilters->Saturation($this->gdimg_output, $parameter, '');
2384  break;
2385 
2386  case 'gray': // Grayscale
2387  $phpthumbFilters->Grayscale($this->gdimg_output);
2388  break;
2389 
2390  case 'clr': // Colorize
2391  if (phpthumb_functions::gd_version() < 2) {
2392  $this->DebugMessage('Skipping Colorize() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
2393  break;
2394  }
2395  @list($amount, $color) = explode('|', $parameter, 2);
2396  $phpthumbFilters->Colorize($this->gdimg_output, $amount, $color);
2397  break;
2398 
2399  case 'sep': // Sepia
2400  if (phpthumb_functions::gd_version() < 2) {
2401  $this->DebugMessage('Skipping Sepia() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
2402  break;
2403  }
2404  @list($amount, $color) = explode('|', $parameter, 2);
2405  $phpthumbFilters->Sepia($this->gdimg_output, $amount, $color);
2406  break;
2407 
2408  case 'gam': // Gamma correction
2409  $phpthumbFilters->Gamma($this->gdimg_output, $parameter);
2410  break;
2411 
2412  case 'neg': // Negative colors
2413  $phpthumbFilters->Negative($this->gdimg_output);
2414  break;
2415 
2416  case 'th': // Threshold
2417  $phpthumbFilters->Threshold($this->gdimg_output, $parameter);
2418  break;
2419 
2420  case 'rcd': // ReduceColorDepth
2421  if (phpthumb_functions::gd_version() < 2) {
2422  $this->DebugMessage('Skipping ReduceColorDepth() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
2423  break;
2424  }
2425  @list($colors, $dither) = explode('|', $parameter, 2);
2426  $colors = ($colors ? (int) $colors : 256);
2427  $dither = ((strlen($dither) > 0) ? (bool) $dither : true);
2428  $phpthumbFilters->ReduceColorDepth($this->gdimg_output, $colors, $dither);
2429  break;
2430 
2431  case 'flip': // Flip
2432  $phpthumbFilters->Flip($this->gdimg_output, (strpos(strtolower($parameter), 'x') !== false), (strpos(strtolower($parameter), 'y') !== false));
2433  break;
2434 
2435  case 'edge': // EdgeDetect
2436  $phpthumbFilters->EdgeDetect($this->gdimg_output);
2437  break;
2438 
2439  case 'emb': // Emboss
2440  $phpthumbFilters->Emboss($this->gdimg_output);
2441  break;
2442 
2443  case 'bvl': // Bevel
2444  @list($width, $color1, $color2) = explode('|', $parameter, 3);
2445  $phpthumbFilters->Bevel($this->gdimg_output, $width, $color1, $color2);
2446  break;
2447 
2448  case 'lvl': // autoLevels
2449  @list($band, $method, $threshold) = explode('|', $parameter, 3);
2450  $band = ($band ? preg_replace('#[^RGBA\\*]#', '', strtoupper($band)) : '*');
2451  $method = ((strlen($method) > 0) ? intval($method) : 2);
2452  $threshold = ((strlen($threshold) > 0) ? floatval($threshold) : 0.1);
2453 
2454  $phpthumbFilters->HistogramStretch($this->gdimg_output, $band, $method, $threshold);
2455  break;
2456 
2457  case 'wb': // WhiteBalance
2458  $phpthumbFilters->WhiteBalance($this->gdimg_output, $parameter);
2459  break;
2460 
2461  case 'hist': // Histogram overlay
2462  if (phpthumb_functions::gd_version() < 2) {
2463  $this->DebugMessage('Skipping HistogramOverlay() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
2464  break;
2465  }
2466  @list($bands, $colors, $width, $height, $alignment, $opacity, $margin_x, $margin_y) = explode('|', $parameter, 8);
2467  $bands = ($bands ? $bands : '*');
2468  $colors = ($colors ? $colors : '');
2469  $width = ($width ? $width : 0.25);
2470  $height = ($height ? $height : 0.25);
2471  $alignment = ($alignment ? $alignment : 'BR');
2472  $opacity = ($opacity ? $opacity : 50);
2473  $margin_x = ($margin_x ? $margin_x : 5);
2474  $margin_y = $margin_y; // just to note it wasn't forgotten, but let the value always pass unchanged
2475  $phpthumbFilters->HistogramOverlay($this->gdimg_output, $bands, $colors, $width, $height, $alignment, $opacity, $margin_x, $margin_y);
2476  break;
2477 
2478  case 'fram': // Frame
2479  @list($frame_width, $edge_width, $color_frame, $color1, $color2) = explode('|', $parameter, 5);
2480  $phpthumbFilters->Frame($this->gdimg_output, $frame_width, $edge_width, $color_frame, $color1, $color2);
2481  break;
2482 
2483  case 'drop': // DropShadow
2484  if (phpthumb_functions::gd_version() < 2) {
2485  $this->DebugMessage('Skipping DropShadow() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
2486  return false;
2487  }
2488  $this->is_alpha = true;
2489  @list($distance, $width, $color, $angle, $fade) = explode('|', $parameter, 5);
2490  $phpthumbFilters->DropShadow($this->gdimg_output, $distance, $width, $color, $angle, $fade);
2491  break;
2492 
2493  case 'mask': // Mask cropping
2494  if (phpthumb_functions::gd_version() < 2) {
2495  $this->DebugMessage('Skipping Mask() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
2496  return false;
2497  }
2498  $mask_filename = $this->ResolveFilenameToAbsolute($parameter);
2499  if (@is_readable($mask_filename) && ($fp_mask = @fopen($mask_filename, 'rb'))) {
2500  $MaskImageData = '';
2501  do {
2502  $buffer = fread($fp_mask, 8192);
2503  $MaskImageData .= $buffer;
2504  } while (strlen($buffer) > 0);
2505  fclose($fp_mask);
2506  if ($gdimg_mask = $this->ImageCreateFromStringReplacement($MaskImageData)) {
2507  $this->is_alpha = true;
2508  $phpthumbFilters->ApplyMask($gdimg_mask, $this->gdimg_output);
2509  ImageDestroy($gdimg_mask);
2510  } else {
2511  $this->DebugMessage('ImageCreateFromStringReplacement() failed for "'.$mask_filename.'"', __FILE__, __LINE__);
2512  }
2513  } else {
2514  $this->DebugMessage('Cannot open mask file "'.$mask_filename.'"', __FILE__, __LINE__);
2515  }
2516  break;
2517 
2518  case 'elip': // Elipse cropping
2519  if (phpthumb_functions::gd_version() < 2) {
2520  $this->DebugMessage('Skipping Elipse() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
2521  return false;
2522  }
2523  $this->is_alpha = true;
2524  $phpthumbFilters->Elipse($this->gdimg_output);
2525  break;
2526 
2527  case 'ric': // RoundedImageCorners
2528  if (phpthumb_functions::gd_version() < 2) {
2529  $this->DebugMessage('Skipping RoundedImageCorners() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
2530  return false;
2531  }
2532  @list($radius_x, $radius_y) = explode('|', $parameter, 2);
2533  if (($radius_x < 1) || ($radius_y < 1)) {
2534  $this->DebugMessage('Skipping RoundedImageCorners('.$radius_x.', '.$radius_y.') because x/y radius is less than 1', __FILE__, __LINE__);
2535  break;
2536  }
2537  $this->is_alpha = true;
2538  $phpthumbFilters->RoundedImageCorners($this->gdimg_output, $radius_x, $radius_y);
2539  break;
2540 
2541  case 'crop': // Crop
2542  @list($left, $right, $top, $bottom) = explode('|', $parameter, 4);
2543  $phpthumbFilters->Crop($this->gdimg_output, $left, $right, $top, $bottom);
2544  break;
2545 
2546  case 'bord': // Border
2547  @list($border_width, $radius_x, $radius_y, $hexcolor_border) = explode('|', $parameter, 4);
2548  $this->is_alpha = true;
2549  $phpthumbFilters->ImageBorder($this->gdimg_output, $border_width, $radius_x, $radius_y, $hexcolor_border);
2550  break;
2551 
2552  case 'over': // Overlay
2553  @list($filename, $underlay, $margin, $opacity) = explode('|', $parameter, 4);
2554  $underlay = (bool) ($underlay ? $underlay : false);
2555  $margin = ((strlen($margin) > 0) ? $margin : ($underlay ? 0.1 : 0.0));
2556  $opacity = ((strlen($opacity) > 0) ? $opacity : 100);
2557  if (($margin > 0) && ($margin < 1)) {
2558  $margin = min(0.499, $margin);
2559  } elseif (($margin > -1) && ($margin < 0)) {
2560  $margin = max(-0.499, $margin);
2561  }
2562 
2563  $filename = $this->ResolveFilenameToAbsolute($filename);
2564  if (@is_readable($filename) && ($fp_watermark = @fopen($filename, 'rb'))) {
2565  $WatermarkImageData = '';
2566  do {
2567  $buffer = fread($fp_watermark, 8192);
2568  $WatermarkImageData .= $buffer;
2569  } while (strlen($buffer) > 0);
2570  fclose($fp_watermark);
2571  if ($img_watermark = $this->ImageCreateFromStringReplacement($WatermarkImageData)) {
2572  if ($margin < 1) {
2573  $resized_x = max(1, ImageSX($this->gdimg_output) - round(2 * (ImageSX($this->gdimg_output) * $margin)));
2574  $resized_y = max(1, ImageSY($this->gdimg_output) - round(2 * (ImageSY($this->gdimg_output) * $margin)));
2575  } else {
2576  $resized_x = max(1, ImageSX($this->gdimg_output) - round(2 * $margin));
2577  $resized_y = max(1, ImageSY($this->gdimg_output) - round(2 * $margin));
2578  }
2579 
2580  if ($underlay) {
2581 
2582  if ($img_watermark_resized = phpthumb_functions::ImageCreateFunction(ImageSX($this->gdimg_output), ImageSY($this->gdimg_output))) {
2583  ImageAlphaBlending($img_watermark_resized, false);
2584  ImageSaveAlpha($img_watermark_resized, true);
2585  $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));
2586  if ($img_source_resized = phpthumb_functions::ImageCreateFunction($resized_x, $resized_y)) {
2587  ImageAlphaBlending($img_source_resized, false);
2588  ImageSaveAlpha($img_source_resized, true);
2589  $this->ImageResizeFunction($img_source_resized, $this->gdimg_output, 0, 0, 0, 0, ImageSX($img_source_resized), ImageSY($img_source_resized), ImageSX($this->gdimg_output), ImageSY($this->gdimg_output));
2590  $phpthumbFilters->WatermarkOverlay($img_watermark_resized, $img_source_resized, 'C', $opacity, $margin);
2591  ImageCopy($this->gdimg_output, $img_watermark_resized, 0, 0, 0, 0, ImageSX($this->gdimg_output), ImageSY($this->gdimg_output));
2592  } else {
2593  $this->DebugMessage('phpthumb_functions::ImageCreateFunction('.$resized_x.', '.$resized_y.')', __FILE__, __LINE__);
2594  }
2595  ImageDestroy($img_watermark_resized);
2596  } else {
2597  $this->DebugMessage('phpthumb_functions::ImageCreateFunction('.ImageSX($this->gdimg_output).', '.ImageSY($this->gdimg_output).')', __FILE__, __LINE__);
2598  }
2599 
2600  } else { // overlay
2601 
2602  if ($img_watermark_resized = phpthumb_functions::ImageCreateFunction($resized_x, $resized_y)) {
2603  ImageAlphaBlending($img_watermark_resized, false);
2604  ImageSaveAlpha($img_watermark_resized, true);
2605  $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));
2606  $phpthumbFilters->WatermarkOverlay($this->gdimg_output, $img_watermark_resized, 'C', $opacity, $margin);
2607  ImageDestroy($img_watermark_resized);
2608  } else {
2609  $this->DebugMessage('phpthumb_functions::ImageCreateFunction('.$resized_x.', '.$resized_y.')', __FILE__, __LINE__);
2610  }
2611 
2612  }
2613  ImageDestroy($img_watermark);
2614 
2615  } else {
2616  $this->DebugMessage('ImageCreateFromStringReplacement() failed for "'.$filename.'"', __FILE__, __LINE__);
2617  }
2618  } else {
2619  $this->DebugMessage('Cannot open overlay file "'.$filename.'"', __FILE__, __LINE__);
2620  }
2621  break;
2622 
2623  case 'wmi': // WaterMarkImage
2624  @list($filename, $alignment, $opacity, $margin['x'], $margin['y'], $rotate_angle) = explode('|', $parameter, 6);
2625  // $margin can be pixel margin or percent margin if $alignment is text, or max width/height if $alignment is position like "50x75"
2626  $alignment = ($alignment ? $alignment : 'BR');
2627  $opacity = (strlen($opacity) ? intval($opacity) : 50);
2628  $rotate_angle = (strlen($rotate_angle) ? intval($rotate_angle) : 0);
2629  if (!preg_match('#^([0-9\\.\\-]*)x([0-9\\.\\-]*)$#i', $alignment, $matches)) {
2630  $margins = array('x', 'y');
2631  foreach ($margins as $xy) {
2632  $margin[$xy] = (strlen($margin[$xy]) ? $margin[$xy] : 5);
2633  if (($margin[$xy] > 0) && ($margin[$xy] < 1)) {
2634  $margin[$xy] = min(0.499, $margin[$xy]);
2635  } elseif (($margin[$xy] > -1) && ($margin[$xy] < 0)) {
2636  $margin[$xy] = max(-0.499, $margin[$xy]);
2637  }
2638  }
2639  }
2640 
2641  $filename = $this->ResolveFilenameToAbsolute($filename);
2642  if (@is_readable($filename)) {
2643  if ($img_watermark = $this->ImageCreateFromFilename($filename)) {
2644  if ($rotate_angle !== 0) {
2645  $phpthumbFilters->ImprovedImageRotate($img_watermark, $rotate_angle);
2646  }
2647  if (preg_match('#^([0-9\\.\\-]*)x([0-9\\.\\-]*)$#i', $alignment, $matches)) {
2648  $watermark_max_width = intval($margin['x'] ? $margin['x'] : ImageSX($img_watermark));
2649  $watermark_max_height = intval($margin['y'] ? $margin['y'] : ImageSY($img_watermark));
2650  $scale = phpthumb_functions::ScaleToFitInBox(ImageSX($img_watermark), ImageSY($img_watermark), $watermark_max_width, $watermark_max_height, true, true);
2651  $this->DebugMessage('Scaling watermark by a factor of '.number_format($scale, 4), __FILE__, __LINE__);
2652  if (($scale > 1) || ($scale < 1)) {
2653  if ($img_watermark2 = phpthumb_functions::ImageCreateFunction($scale * ImageSX($img_watermark), $scale * ImageSY($img_watermark))) {
2654  ImageAlphaBlending($img_watermark2, false);
2655  ImageSaveAlpha($img_watermark2, true);
2656  $this->ImageResizeFunction($img_watermark2, $img_watermark, 0, 0, 0, 0, ImageSX($img_watermark2), ImageSY($img_watermark2), ImageSX($img_watermark), ImageSY($img_watermark));
2657  $img_watermark = $img_watermark2;
2658  } else {
2659  $this->DebugMessage('ImageCreateFunction('.($scale * ImageSX($img_watermark)).', '.($scale * ImageSX($img_watermark)).') failed', __FILE__, __LINE__);
2660  }
2661  }
2662  $watermark_dest_x = round($matches[1] - (ImageSX($img_watermark) / 2));
2663  $watermark_dest_y = round($matches[2] - (ImageSY($img_watermark) / 2));
2664  $alignment = $watermark_dest_x.'x'.$watermark_dest_y;
2665  }
2666  $phpthumbFilters->WatermarkOverlay($this->gdimg_output, $img_watermark, $alignment, $opacity, $margin['x'], $margin['y']);
2667  ImageDestroy($img_watermark);
2668  if (isset($img_watermark2) && is_resource($img_watermark2)) {
2669  ImageDestroy($img_watermark2);
2670  }
2671  } else {
2672  $this->DebugMessage('ImageCreateFromFilename() failed for "'.$filename.'"', __FILE__, __LINE__);
2673  }
2674  } else {
2675  $this->DebugMessage('!is_readable('.$filename.')', __FILE__, __LINE__);
2676  }
2677  break;
2678 
2679  case 'wmt': // WaterMarkText
2680  @list($text, $size, $alignment, $hex_color, $ttffont, $opacity, $margin, $angle, $bg_color, $bg_opacity, $fillextend) = explode('|', $parameter, 11);
2681  $text = ($text ? $text : '');
2682  $size = ($size ? $size : 3);
2683  $alignment = ($alignment ? $alignment : 'BR');
2684  $hex_color = ($hex_color ? $hex_color : '000000');
2685  $ttffont = ($ttffont ? $ttffont : '');
2686  $opacity = (strlen($opacity) ? $opacity : 50);
2687  $margin = (strlen($margin) ? $margin : 5);
2688  $angle = (strlen($angle) ? $angle : 0);
2689  $bg_color = ($bg_color ? $bg_color : false);
2690  $bg_opacity = ($bg_opacity ? $bg_opacity : 0);
2691  $fillextend = ($fillextend ? $fillextend : '');
2692 
2693  if (basename($ttffont) == $ttffont) {
2694  $ttffont = realpath($this->config_ttf_directory.DIRECTORY_SEPARATOR.$ttffont);
2695  } else {
2696  $ttffont = $this->ResolveFilenameToAbsolute($ttffont);
2697  }
2698  $phpthumbFilters->WatermarkText($this->gdimg_output, $text, $size, $alignment, $hex_color, $ttffont, $opacity, $margin, $angle, $bg_color, $bg_opacity, $fillextend);
2699  break;
2700 
2701  case 'blur': // Blur
2702  @list($radius) = explode('|', $parameter, 1);
2703  $radius = ($radius ? $radius : 1);
2704  if (phpthumb_functions::gd_version() >= 2) {
2705  $phpthumbFilters->Blur($this->gdimg_output, $radius);
2706  } else {
2707  $this->DebugMessage('Skipping Blur() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
2708  }
2709  break;
2710 
2711  case 'gblr': // Gaussian Blur
2712  $phpthumbFilters->BlurGaussian($this->gdimg_output);
2713  break;
2714 
2715  case 'sblr': // Selective Blur
2716  $phpthumbFilters->BlurSelective($this->gdimg_output);
2717  break;
2718 
2719  case 'mean': // MeanRemoval blur
2720  $phpthumbFilters->MeanRemoval($this->gdimg_output);
2721  break;
2722 
2723  case 'smth': // Smooth blur
2724  $phpthumbFilters->Smooth($this->gdimg_output, $parameter);
2725  break;
2726 
2727  case 'usm': // UnSharpMask sharpening
2728  @list($amount, $radius, $threshold) = explode('|', $parameter, 3);
2729  $amount = ($amount ? $amount : 80);
2730  $radius = ($radius ? $radius : 0.5);
2731  $threshold = (strlen($threshold) ? $threshold : 3);
2732  if (phpthumb_functions::gd_version() >= 2.0) {
2733  ob_start();
2734  if (!@include_once(dirname(__FILE__).'/phpthumb.unsharp.php')) {
2735  $include_error = ob_get_contents();
2736  if ($include_error) {
2737  $this->DebugMessage('include_once("'.dirname(__FILE__).'/phpthumb.unsharp.php") generated message: "'.$include_error.'"', __FILE__, __LINE__);
2738  }
2739  $this->DebugMessage('Error including "'.dirname(__FILE__).'/phpthumb.unsharp.php" which is required for unsharp masking', __FILE__, __LINE__);
2740  ob_end_clean();
2741  return false;
2742  }
2743  ob_end_clean();
2744  phpUnsharpMask::applyUnsharpMask($this->gdimg_output, $amount, $radius, $threshold);
2745  } else {
2746  $this->DebugMessage('Skipping unsharp mask because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
2747  return false;
2748  }
2749  break;
2750 
2751  case 'size': // Resize
2752  @list($newwidth, $newheight, $stretch) = explode('|', $parameter);
2753  $newwidth = (!$newwidth ? ImageSX($this->gdimg_output) : ((($newwidth > 0) && ($newwidth < 1)) ? round($newwidth * ImageSX($this->gdimg_output)) : round($newwidth)));
2754  $newheight = (!$newheight ? ImageSY($this->gdimg_output) : ((($newheight > 0) && ($newheight < 1)) ? round($newheight * ImageSY($this->gdimg_output)) : round($newheight)));
2755  $stretch = ($stretch ? true : false);
2756  if ($stretch) {
2757  $scale_x = phpthumb_functions::ScaleToFitInBox(ImageSX($this->gdimg_output), ImageSX($this->gdimg_output), $newwidth, $newwidth, true, true);
2758  $scale_y = phpthumb_functions::ScaleToFitInBox(ImageSY($this->gdimg_output), ImageSY($this->gdimg_output), $newheight, $newheight, true, true);
2759  } else {
2760  $scale_x = phpthumb_functions::ScaleToFitInBox(ImageSX($this->gdimg_output), ImageSY($this->gdimg_output), $newwidth, $newheight, true, true);
2761  $scale_y = $scale_x;
2762  }
2763  $this->DebugMessage('Scaling watermark ('.($stretch ? 'with' : 'without').' stretch) by a factor of "'.number_format($scale_x, 4).' x '.number_format($scale_y, 4).'"', __FILE__, __LINE__);
2764  if (($scale_x > 1) || ($scale_x < 1) || ($scale_y > 1) || ($scale_y < 1)) {
2765  if ($img_temp = phpthumb_functions::ImageCreateFunction(ImageSX($this->gdimg_output), ImageSY($this->gdimg_output))) {
2766  ImageCopy($img_temp, $this->gdimg_output, 0, 0, 0, 0, ImageSX($this->gdimg_output), ImageSY($this->gdimg_output));
2767  //ImageDestroy($this->gdimg_output);
2768  if ($this->gdimg_output = phpthumb_functions::ImageCreateFunction($scale_x * ImageSX($img_temp), $scale_y * ImageSY($img_temp))) {
2769  ImageAlphaBlending($this->gdimg_output, false);
2770  ImageSaveAlpha($this->gdimg_output, true);
2771  $this->ImageResizeFunction($this->gdimg_output, $img_temp, 0, 0, 0, 0, ImageSX($this->gdimg_output), ImageSY($this->gdimg_output), ImageSX($img_temp), ImageSY($img_temp));
2772  } else {
2773  $this->DebugMessage('ImageCreateFunction('.($scale_x * ImageSX($img_temp)).', '.($scale_y * ImageSY($img_temp)).') failed', __FILE__, __LINE__);
2774  }
2775  ImageDestroy($img_temp);
2776  } else {
2777  $this->DebugMessage('ImageCreateFunction('.ImageSX($this->gdimg_output).', '.ImageSY($this->gdimg_output).') failed', __FILE__, __LINE__);
2778  }
2779  }
2780  break;
2781 
2782  case 'rot': // ROTate
2783  @list($angle, $bgcolor) = explode('|', $parameter, 2);
2784  $phpthumbFilters->ImprovedImageRotate($this->gdimg_output, $angle, $bgcolor);
2785  break;
2786 
2787  case 'stc': // Source Transparent Color
2788  @list($hexcolor, $min_limit, $max_limit) = explode('|', $parameter, 3);
2789  if (!phpthumb_functions::IsHexColor($hexcolor)) {
2790  $this->DebugMessage('Skipping SourceTransparentColor hex color is invalid ('.$hexcolor.')', __FILE__, __LINE__);
2791  return false;
2792  }
2793  $min_limit = (strlen($min_limit) ? $min_limit : 5);
2794  $max_limit = (strlen($max_limit) ? $max_limit : 10);
2795  if ($gdimg_mask = $phpthumbFilters->SourceTransparentColorMask($this->gdimg_output, $hexcolor, $min_limit, $max_limit)) {
2796  $this->is_alpha = true;
2797  $phpthumbFilters->ApplyMask($gdimg_mask, $this->gdimg_output);
2798  ImageDestroy($gdimg_mask);
2799  } else {
2800  $this->DebugMessage('SourceTransparentColorMask() failed for "'.$mask_filename.'"', __FILE__, __LINE__);
2801  }
2802  break;
2803  }
2804  $this->DebugMessage('Finished processing filter command "'.$command.'('.$parameter.')"', __FILE__, __LINE__);
2805  }
2806  }
2807  return true;
2808  }
2809 
2810 
2811  function MaxFileSize() {
2812  if (phpthumb_functions::gd_version() < 2) {
2813  $this->DebugMessage('Skipping MaxFileSize() because gd_version is "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
2814  return false;
2815  }
2816  if ($this->maxb > 0) {
2817  switch ($this->thumbnailFormat) {
2818  case 'png':
2819  case 'gif':
2820  $imgRenderFunction = 'image'.$this->thumbnailFormat;
2821 
2822  ob_start();
2823  $imgRenderFunction($this->gdimg_output);
2824  $imgdata = ob_get_contents();
2825  ob_end_clean();
2826 
2827  if (strlen($imgdata) > $this->maxb) {
2828  for ($i = 8; $i >= 1; $i--) {
2829  $tempIMG = ImageCreateTrueColor(ImageSX($this->gdimg_output), ImageSY($this->gdimg_output));
2830  ImageCopy($tempIMG, $this->gdimg_output, 0, 0, 0, 0, ImageSX($this->gdimg_output), ImageSY($this->gdimg_output));
2831  ImageTrueColorToPalette($tempIMG, true, pow(2, $i));
2832  ob_start();
2833  $imgRenderFunction($tempIMG);
2834  $imgdata = ob_get_contents();
2835  ob_end_clean();
2836 
2837  if (strlen($imgdata) <= $this->maxb) {
2838  ImageTrueColorToPalette($this->gdimg_output, true, pow(2, $i));
2839  break;
2840  }
2841  }
2842  }
2843  if (strlen($imgdata) > $this->maxb) {
2844  ImageTrueColorToPalette($this->gdimg_output, true, pow(2, $i));
2845  return false;
2846  }
2847  break;
2848 
2849  case 'jpeg':
2850  ob_start();
2851  ImageJPEG($this->gdimg_output);
2852  $imgdata = ob_get_contents();
2853  ob_end_clean();
2854 
2855  $OriginalJPEGquality = $this->thumbnailQuality;
2856  if (strlen($imgdata) > $this->maxb) {
2857  for ($i = 3; $i < 20; $i++) {
2858  $q = round(100 * (1 - log10($i / 2)));
2859  ob_start();
2860  ImageJPEG($this->gdimg_output, '', $q);
2861  $imgdata = ob_get_contents();
2862  ob_end_clean();
2863 
2864  $this->thumbnailQuality = $q;
2865  if (strlen($imgdata) <= $this->maxb) {
2866  break;
2867  }
2868  }
2869  }
2870  if (strlen($imgdata) > $this->maxb) {
2871  return false;
2872  }
2873  break;
2874 
2875  default:
2876  return false;
2877  break;
2878  }
2879  }
2880  return true;
2881  }
2882 
2883 
2885  $this->DebugMessage('CalculateThumbnailDimensions() starting with [W,H,sx,sy,sw,sh] initially set to ['.$this->source_width.','.$this->source_height.','.$this->sx.','.$this->sy.','.$this->sw.','.$this->sh.']', __FILE__, __LINE__);
2886 //echo $this->source_width.'x'.$this->source_height.'<hr>';
2887  $this->thumbnailCropX = ($this->sx ? (($this->sx >= 2) ? $this->sx : round($this->sx * $this->source_width)) : 0);
2888 //echo $this->thumbnailCropX.'<br>';
2889  $this->thumbnailCropY = ($this->sy ? (($this->sy >= 2) ? $this->sy : round($this->sy * $this->source_height)) : 0);
2890 //echo $this->thumbnailCropY.'<br>';
2891  $this->thumbnailCropW = ($this->sw ? (($this->sw >= 2) ? $this->sw : round($this->sw * $this->source_width)) : $this->source_width);
2892 //echo $this->thumbnailCropW.'<br>';
2893  $this->thumbnailCropH = ($this->sh ? (($this->sh >= 2) ? $this->sh : round($this->sh * $this->source_height)) : $this->source_height);
2894 //echo $this->thumbnailCropH.'<hr>';
2895 
2896  // limit source area to original image area
2897  $this->thumbnailCropW = max(1, min($this->thumbnailCropW, $this->source_width - $this->thumbnailCropX));
2898  $this->thumbnailCropH = max(1, min($this->thumbnailCropH, $this->source_height - $this->thumbnailCropY));
2899 
2900  $this->DebugMessage('CalculateThumbnailDimensions() starting with [x,y,w,h] initially set to ['.$this->thumbnailCropX.','.$this->thumbnailCropY.','.$this->thumbnailCropW.','.$this->thumbnailCropH.']', __FILE__, __LINE__);
2901 
2902 
2903  if ($this->zc && $this->w && $this->h) {
2904  // Zoom Crop
2905  // retain proportional resizing we did above, but crop off larger dimension so smaller
2906  // dimension fully fits available space
2907 
2908  $scaling_X = $this->source_width / $this->w;
2909  $scaling_Y = $this->source_height / $this->h;
2910  if ($scaling_X > $scaling_Y) {
2911  // some of the width will need to be cropped
2912  $allowable_width = $this->source_width / $scaling_X * $scaling_Y;
2913  $this->thumbnailCropW = round($allowable_width);
2914  $this->thumbnailCropX = round(($this->source_width - $allowable_width) / 2);
2915 
2916  } elseif ($scaling_Y > $scaling_X) {
2917  // some of the height will need to be cropped
2918  $allowable_height = $this->source_height / $scaling_Y * $scaling_X;
2919  $this->thumbnailCropH = round($allowable_height);
2920  $this->thumbnailCropY = round(($this->source_height - $allowable_height) / 2);
2921 
2922  } else {
2923  // image fits perfectly, no cropping needed
2924  }
2925  $this->thumbnail_width = $this->w;
2926  $this->thumbnail_height = $this->h;
2927  $this->thumbnail_image_width = $this->thumbnail_width;
2928  $this->thumbnail_image_height = $this->thumbnail_height;
2929 
2930  } elseif ($this->iar && $this->w && $this->h) {
2931 
2932  // Ignore Aspect Ratio
2933  // stretch image to fit exactly 'w' x 'h'
2934  $this->thumbnail_width = $this->w;
2935  $this->thumbnail_height = $this->h;
2936  $this->thumbnail_image_width = $this->thumbnail_width;
2937  $this->thumbnail_image_height = $this->thumbnail_height;
2938 
2939  } else {
2940 
2941  $original_aspect_ratio = $this->thumbnailCropW / $this->thumbnailCropH;
2942  if ($this->aoe) {
2943  if ($this->w && $this->h) {
2944  $maxwidth = min($this->w, $this->h * $original_aspect_ratio);
2945  $maxheight = min($this->h, $this->w / $original_aspect_ratio);
2946  } elseif ($this->w) {
2947  $maxwidth = $this->w;
2948  $maxheight = $this->w / $original_aspect_ratio;
2949  } elseif ($this->h) {
2950  $maxwidth = $this->h * $original_aspect_ratio;
2951  $maxheight = $this->h;
2952  } else {
2953  $maxwidth = $this->thumbnailCropW;
2954  $maxheight = $this->thumbnailCropH;
2955  }
2956  } else {
2957  $maxwidth = phpthumb_functions::nonempty_min($this->w, $this->thumbnailCropW, $this->config_output_maxwidth);
2958  $maxheight = phpthumb_functions::nonempty_min($this->h, $this->thumbnailCropH, $this->config_output_maxheight);
2959 //echo $maxwidth.'x'.$maxheight.'<br>';
2960  $maxwidth = min($maxwidth, $maxheight * $original_aspect_ratio);
2961  $maxheight = min($maxheight, $maxwidth / $original_aspect_ratio);
2962 //echo $maxwidth.'x'.$maxheight.'<hr>';
2963  }
2964 
2965  $this->thumbnail_image_width = $maxwidth;
2966  $this->thumbnail_image_height = $maxheight;
2967  $this->thumbnail_width = $maxwidth;
2968  $this->thumbnail_height = $maxheight;
2969 
2970  $this->FixedAspectRatio();
2971  }
2972 
2973  $this->thumbnail_width = max(1, floor($this->thumbnail_width));
2974  $this->thumbnail_height = max(1, floor($this->thumbnail_height));
2975  return true;
2976  }
2977 
2978 
2979  function CreateGDoutput() {
2981 
2982  // Create the GD image (either true-color or 256-color, depending on GD version)
2983  $this->gdimg_output = phpthumb_functions::ImageCreateFunction($this->thumbnail_width, $this->thumbnail_height);
2984 
2985  // Images that have transparency must have the background filled with the configured 'bg' color
2986  // otherwise the transparent color will appear as black
2987  ImageSaveAlpha($this->gdimg_output, true);
2988  if ($this->is_alpha && phpthumb_functions::gd_version() >= 2) {
2989 
2990  ImageAlphaBlending($this->gdimg_output, false);
2991  $output_full_alpha = phpthumb_functions::ImageColorAllocateAlphaSafe($this->gdimg_output, 255, 255, 255, 127);
2992  ImageFilledRectangle($this->gdimg_output, 0, 0, $this->thumbnail_width, $this->thumbnail_height, $output_full_alpha);
2993 
2994  } else {
2995 
2996  $current_transparent_color = ImageColorTransparent($this->gdimg_source);
2997  if ($this->bg || (@$current_transparent_color >= 0)) {
2998 
2999  $this->config_background_hexcolor = ($this->bg ? $this->bg : $this->config_background_hexcolor);
3000  if (!phpthumb_functions::IsHexColor($this->config_background_hexcolor)) {
3001  return $this->ErrorImage('Invalid hex color string "'.$this->config_background_hexcolor.'" for parameter "bg"');
3002  }
3003  $background_color = phpthumb_functions::ImageHexColorAllocate($this->gdimg_output, $this->config_background_hexcolor);
3004  ImageFilledRectangle($this->gdimg_output, 0, 0, $this->thumbnail_width, $this->thumbnail_height, $background_color);
3005 
3006  }
3007 
3008  }
3009  $this->DebugMessage('CreateGDoutput() returning canvas "'.$this->thumbnail_width.'x'.$this->thumbnail_height.'"', __FILE__, __LINE__);
3010  return true;
3011  }
3012 
3014  $this->DebugMessage('SetOrientationDependantWidthHeight() starting with "'.$this->source_width.'"x"'.$this->source_height.'"', __FILE__, __LINE__);
3015  if ($this->source_height > $this->source_width) {
3016  // portrait
3017  $this->w = phpthumb_functions::OneOfThese($this->wp, $this->w, $this->ws, $this->wl);
3018  $this->h = phpthumb_functions::OneOfThese($this->hp, $this->h, $this->hs, $this->hl);
3019  } elseif ($this->source_height < $this->source_width) {
3020  // landscape
3021  $this->w = phpthumb_functions::OneOfThese($this->wl, $this->w, $this->ws, $this->wp);
3022  $this->h = phpthumb_functions::OneOfThese($this->hl, $this->h, $this->hs, $this->hp);
3023  } else {
3024  // square
3025  $this->w = phpthumb_functions::OneOfThese($this->ws, $this->w, $this->wl, $this->wp);
3026  $this->h = phpthumb_functions::OneOfThese($this->hs, $this->h, $this->hl, $this->hp);
3027  }
3028  //$this->w = round($this->w ? $this->w : (($this->h && $this->source_height) ? $this->h * $this->source_width / $this->source_height : $this->w));
3029  //$this->h = round($this->h ? $this->h : (($this->w && $this->source_width) ? $this->w * $this->source_height / $this->source_width : $this->h));
3030  $this->DebugMessage('SetOrientationDependantWidthHeight() setting w="'.intval($this->w).'", h="'.intval($this->h).'"', __FILE__, __LINE__);
3031  return true;
3032  }
3033 
3035  $this->DebugMessage('starting ExtractEXIFgetImageSize()', __FILE__, __LINE__);
3036 
3037  if (preg_match('#^http:#i', $this->src) && !$this->sourceFilename && $this->rawImageData) {
3038  !$this->SourceDataToTempFile();
3039  }
3040  if (is_null($this->getimagesizeinfo)) {
3041  if ($this->sourceFilename) {
3042  $this->getimagesizeinfo = @GetImageSize($this->sourceFilename);
3043  $this->source_width = $this->getimagesizeinfo[0];
3044  $this->source_height = $this->getimagesizeinfo[1];
3045  $this->DebugMessage('GetImageSize('.$this->sourceFilename.') says image is '.$this->source_width.'x'.$this->source_height, __FILE__, __LINE__);
3046  } else {
3047  $this->DebugMessage('skipping GetImageSize() because $this->sourceFilename is empty', __FILE__, __LINE__);
3048  }
3049  } else {
3050  $this->DebugMessage('skipping GetImageSize() because !is_null($this->getimagesizeinfo)', __FILE__, __LINE__);
3051  }
3052 
3053  if (is_resource($this->gdimg_source)) {
3054 
3055  $this->source_width = ImageSX($this->gdimg_source);
3056  $this->source_height = ImageSY($this->gdimg_source);
3057 
3059 
3060  } elseif ($this->rawImageData && !$this->sourceFilename) {
3061 
3062  if ($this->SourceImageIsTooLarge($this->source_width, $this->source_height)) {
3063  $this->DebugMessage('NOT bypassing EXIF and GetImageSize sections because source image is too large for GD ('.$this->source_width.'x'.$this->source_width.'='.($this->source_width * $this->source_height * 5).'MB)', __FILE__, __LINE__);
3064  } else {
3065  $this->DebugMessage('bypassing EXIF and GetImageSize sections because $this->rawImageData is set, and $this->sourceFilename is not set, and source image is not too large for GD ('.$this->source_width.'x'.$this->source_width.'='.($this->source_width * $this->source_height * 5).'MB)', __FILE__, __LINE__);
3066  }
3067 
3068  }
3069 
3070  if (is_null($this->getimagesizeinfo)) {
3071  $this->getimagesizeinfo = @GetImageSize($this->sourceFilename);
3072  }
3073 
3074  if (!empty($this->getimagesizeinfo)) {
3075  // great
3076  $this->getimagesizeinfo['filesize'] = @filesize($this->sourceFilename);
3077  } elseif (!$this->rawImageData) {
3078  $this->DebugMessage('GetImageSize("'.$this->sourceFilename.'") failed', __FILE__, __LINE__);
3079  }
3080 
3081  if ($this->config_prefer_imagemagick) {
3082  if ($this->ImageMagickThumbnailToGD()) {
3083  return true;
3084  }
3085  $this->DebugMessage('ImageMagickThumbnailToGD() failed', __FILE__, __LINE__);
3086  }
3087 
3088  $this->source_width = $this->getimagesizeinfo[0];
3089  $this->source_height = $this->getimagesizeinfo[1];
3090 
3092 
3093  if (phpthumb_functions::version_compare_replacement(phpversion(), '4.2.0', '>=') && function_exists('exif_read_data')) {
3094  switch ($this->getimagesizeinfo[2]) {
3095  case IMAGETYPE_JPEG:
3096  case IMAGETYPE_TIFF_II:
3097  case IMAGETYPE_TIFF_MM:
3098  $this->exif_raw_data = @exif_read_data($this->sourceFilename, 0, true);
3099  break;
3100  }
3101  }
3102  if (function_exists('exif_thumbnail') && ($this->getimagesizeinfo[2] == IMAGETYPE_JPEG)) {
3103  // Extract EXIF info from JPEGs
3104 
3105  $this->exif_thumbnail_width = '';
3106  $this->exif_thumbnail_height = '';
3107  $this->exif_thumbnail_type = '';
3108 
3109  // The parameters width, height and imagetype are available since PHP v4.3.0
3110  if (phpthumb_functions::version_compare_replacement(phpversion(), '4.3.0', '>=')) {
3111 
3112  $this->exif_thumbnail_data = @exif_thumbnail($this->sourceFilename, $this->exif_thumbnail_width, $this->exif_thumbnail_height, $this->exif_thumbnail_type);
3113 
3114  } else {
3115 
3116  // older versions of exif_thumbnail output an error message but NOT return false on failure
3117  ob_start();
3118  $this->exif_thumbnail_data = exif_thumbnail($this->sourceFilename);
3119  $exit_thumbnail_error = ob_get_contents();
3120  ob_end_clean();
3121  if (!$exit_thumbnail_error && $this->exif_thumbnail_data) {
3122 
3123  if ($gdimg_exif_temp = $this->ImageCreateFromStringReplacement($this->exif_thumbnail_data, false)) {
3124  $this->exif_thumbnail_width = ImageSX($gdimg_exif_temp);
3125  $this->exif_thumbnail_height = ImageSY($gdimg_exif_temp);
3126  $this->exif_thumbnail_type = 2; // (2 == JPEG) before PHP v4.3.0 only JPEG format EXIF thumbnails are returned
3127  unset($gdimg_exif_temp);
3128  } else {
3129  return $this->ErrorImage('Failed - $this->ImageCreateFromStringReplacement($this->exif_thumbnail_data) in '.__FILE__.' on line '.__LINE__);
3130  }
3131 
3132  }
3133 
3134  }
3135 
3136  } elseif (!function_exists('exif_thumbnail')) {
3137 
3138  $this->DebugMessage('exif_thumbnail() does not exist, cannot extract EXIF thumbnail', __FILE__, __LINE__);
3139 
3140  }
3141 
3142  $this->DebugMessage('EXIF thumbnail extraction: (size='.strlen($this->exif_thumbnail_data).'; type="'.$this->exif_thumbnail_type.'"; '.intval($this->exif_thumbnail_width).'x'.intval($this->exif_thumbnail_height).')', __FILE__, __LINE__);
3143 
3144  // see if EXIF thumbnail can be used directly with no processing
3145  if ($this->config_use_exif_thumbnail_for_speed && $this->exif_thumbnail_data) {
3146  while (true) {
3147  if (!$this->xto) {
3148  $source_ar = $this->source_width / $this->source_height;
3149  $exif_ar = $this->exif_thumbnail_width / $this->exif_thumbnail_height;
3150  if (number_format($source_ar, 2) != number_format($exif_ar, 2)) {
3151  $this->DebugMessage('not using EXIF thumbnail because $source_ar != $exif_ar ('.$source_ar.' != '.$exif_ar.')', __FILE__, __LINE__);
3152  break;
3153  }
3154  if ($this->w && ($this->w != $this->exif_thumbnail_width)) {
3155  $this->DebugMessage('not using EXIF thumbnail because $this->w != $this->exif_thumbnail_width ('.$this->w.' != '.$this->exif_thumbnail_width.')', __FILE__, __LINE__);
3156  break;
3157  }
3158  if ($this->h && ($this->h != $this->exif_thumbnail_height)) {
3159  $this->DebugMessage('not using EXIF thumbnail because $this->h != $this->exif_thumbnail_height ('.$this->h.' != '.$this->exif_thumbnail_height.')', __FILE__, __LINE__);
3160  break;
3161  }
3162  $CannotBeSetParameters = array('sx', 'sy', 'sh', 'sw', 'far', 'bg', 'bc', 'fltr', 'phpThumbDebug');
3163  foreach ($CannotBeSetParameters as $parameter) {
3164  if ($this->$parameter) {
3165  break 2;
3166  }
3167  }
3168  }
3169 
3170  $this->DebugMessage('setting $this->gdimg_source = $this->ImageCreateFromStringReplacement($this->exif_thumbnail_data)', __FILE__, __LINE__);
3171  $this->gdimg_source = $this->ImageCreateFromStringReplacement($this->exif_thumbnail_data);
3172  $this->source_width = ImageSX($this->gdimg_source);
3173  $this->source_height = ImageSY($this->gdimg_source);
3174  return true;
3175  }
3176  }
3177 
3178  if (($this->config_max_source_pixels > 0) && (($this->source_width * $this->source_height) > $this->config_max_source_pixels)) {
3179 
3180  // Source image is larger than would fit in available PHP memory.
3181  // If ImageMagick is installed, use it to generate the thumbnail.
3182  // Else, if an EXIF thumbnail is available, use that as the source image.
3183  // Otherwise, no choice but to fail with an error message
3184  $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__);
3185  if (!$this->config_prefer_imagemagick && $this->ImageMagickThumbnailToGD()) {
3186  // excellent, we have a thumbnailed source image
3187  return true;
3188  }
3189 
3190  }
3191  return true;
3192  }
3193 
3194 
3195  function SetCacheFilename() {
3196  if (!is_null($this->cache_filename)) {
3197  $this->DebugMessage('$this->cache_filename already set, skipping SetCacheFilename()', __FILE__, __LINE__);
3198  return true;
3199  }
3200  $this->setOutputFormat();
3201  $this->setCacheDirectory();
3202  if (!$this->config_cache_directory) {
3203  $this->DebugMessage('SetCacheFilename() failed because $this->config_cache_directory is empty', __FILE__, __LINE__);
3204  return false;
3205  }
3206 
3207  if (!$this->sourceFilename && !$this->rawImageData && $this->src) {
3208  $this->sourceFilename = $this->ResolveFilenameToAbsolute($this->src);
3209  }
3210 
3211  if ($this->config_cache_default_only_suffix && $this->sourceFilename) {
3212  // simplified cache filenames:
3213  // only use default parameters in phpThumb.config.php
3214  // substitute source filename into * in $this->config_cache_default_only_suffix
3215  // (eg: '*_thumb' becomes 'picture_thumb.jpg')
3216  if (strpos($this->config_cache_default_only_suffix, '*') === false) {
3217  $this->DebugMessage('aborting simplified caching filename because no * in "'.$this->config_cache_default_only_suffix.'"', __FILE__, __LINE__);
3218  } else {
3219  preg_match('#(.+)(\\.[a-z0-9]+)?$#i', basename($this->sourceFilename), $matches);
3220  $this->cache_filename = $this->config_cache_directory.DIRECTORY_SEPARATOR.rawurlencode(str_replace('*', @$matches[1], $this->config_cache_default_only_suffix)).'.'.strtolower($this->thumbnailFormat);
3221  return true;
3222  }
3223  }
3224 
3225  $this->cache_filename = '';
3226  $broad_directory_name = '';
3227  if ($this->new) {
3228  $broad_directory_name = strtolower(md5($this->new));
3229  $this->cache_filename .= '_new'.$broad_directory_name;
3230  } elseif ($this->md5s) {
3231  // source image MD5 hash provided
3232  $this->DebugMessage('SetCacheFilename() _raw set from $this->md5s = "'.$this->md5s.'"', __FILE__, __LINE__);
3233  $broad_directory_name = $this->md5s;
3234  $this->cache_filename .= '_raw'.$this->md5s;
3235  } elseif (!$this->src && $this->rawImageData) {
3236  $this->DebugMessage('SetCacheFilename() _raw set from md5($this->rawImageData) = "'.md5($this->rawImageData).'"', __FILE__, __LINE__);
3237  $broad_directory_name = strtolower(md5($this->rawImageData));
3238  $this->cache_filename .= '_raw'.$broad_directory_name;
3239  } else {
3240  $this->DebugMessage('SetCacheFilename() _src set from md5($this->sourceFilename) "'.$this->sourceFilename.'" = "'.md5($this->sourceFilename).'"', __FILE__, __LINE__);
3241  $broad_directory_name = strtolower(md5($this->sourceFilename));
3242  $this->cache_filename .= '_src'.$broad_directory_name;
3243  }
3244  if (@$_SERVER['HTTP_REFERER'] && $this->config_nooffsitelink_enabled) {
3245  $parsed_url1 = @phpthumb_functions::ParseURLbetter(@$_SERVER['HTTP_REFERER']);
3246  $parsed_url2 = @phpthumb_functions::ParseURLbetter('http://'.@$_SERVER['HTTP_HOST']);
3247  if (@$parsed_url1['host'] && @$parsed_url2['host'] && ($parsed_url1['host'] != $parsed_url2['host'])) {
3248  // include "_offsite" only if nooffsitelink_enabled and if referrer doesn't match the domain of the current server
3249  $this->cache_filename .= '_offsite';
3250  }
3251  }
3252 
3253  $ParametersString = '';
3254  if ($this->fltr && is_array($this->fltr)) {
3255  $ParametersString .= '_fltr'.implode('_fltr', $this->fltr);
3256  }
3257  $FilenameParameters1 = array('ar', 'bg', 'bc', 'far', 'sx', 'sy', 'sw', 'sh', 'zc');
3258  foreach ($FilenameParameters1 as $key) {
3259  if ($this->$key) {
3260  $ParametersString .= '_'.$key.$this->$key;
3261  }
3262  }
3263  $FilenameParameters2 = array('h', 'w', 'wl', 'wp', 'ws', 'hp', 'hs', 'xto', 'ra', 'iar', 'aoe', 'maxb', 'sfn', 'dpi');
3264  foreach ($FilenameParameters2 as $key) {
3265  if ($this->$key) {
3266  $ParametersString .= '_'.$key.intval($this->$key);
3267  }
3268  }
3269  if ($this->thumbnailFormat == 'jpeg') {
3270  // only JPEG output has variable quality option
3271  $ParametersString .= '_q'.intval($this->thumbnailQuality);
3272  }
3273  $this->DebugMessage('SetCacheFilename() _par set from md5('.$ParametersString.')', __FILE__, __LINE__);
3274  $this->cache_filename .= '_par'.strtolower(md5($ParametersString));
3275 
3276  if ($this->md5s) {
3277  // source image MD5 hash provided
3278  // do not source image modification date --
3279  // cached image will be used even if file was modified or removed
3280  } elseif (!$this->config_cache_source_filemtime_ignore_remote && preg_match('#^(f|ht)tps?\://#i', $this->src)) {
3281  $this->cache_filename .= '_dat'.intval(phpthumb_functions::filedate_remote($this->src));
3282  } elseif (!$this->config_cache_source_filemtime_ignore_local && $this->src && !$this->rawImageData) {
3283  $this->cache_filename .= '_dat'.intval(@filemtime($this->sourceFilename));
3284  }
3285 
3286  $this->cache_filename .= '.'.strtolower($this->thumbnailFormat);
3287  $broad_directories = '';
3288  for ($i = 0; $i < $this->config_cache_directory_depth; $i++) {
3289  $broad_directories .= DIRECTORY_SEPARATOR.substr($broad_directory_name, 0, $i + 1);
3290  }
3291 
3292  $this->cache_filename = $this->config_cache_directory.$broad_directories.DIRECTORY_SEPARATOR.$this->config_cache_prefix.rawurlencode($this->cache_filename);
3293  return true;
3294  }
3295 
3296 
3297  function SourceImageIsTooLarge($width, $height) {
3298  if (!$this->config_max_source_pixels) {
3299  return false;
3300  }
3301  if (function_exists('memory_get_usage')) {
3302  $available_memory = max(intval(ini_get('memory_limit')), intval(get_cfg_var('memory_limit'))) * 1048576;
3303  $available_memory -= memory_get_usage();
3304  return (bool) (($width * $height * 5) > $available_memory);
3305  }
3306  return (bool) (($width * $height) > $this->config_max_source_pixels);
3307  }
3308 
3309  function ImageCreateFromFilename($filename) {
3310  // try to create GD image source directly via GD, if possible,
3311  // rather than buffering to memory and creating with ImageCreateFromString
3312  $ImageCreateWasAttempted = false;
3313  $gd_image = false;
3314 
3315  $this->DebugMessage('starting ImageCreateFromFilename('.$filename.')', __FILE__, __LINE__);
3316  if ($filename && ($getimagesizeinfo = @GetImageSize($filename))) {
3318  $ImageCreateFromFunction = array(
3319  1 => 'ImageCreateFromGIF',
3320  2 => 'ImageCreateFromJPEG',
3321  3 => 'ImageCreateFromPNG',
3322  15 => 'ImageCreateFromWBMP',
3323  );
3324  $this->DebugMessage('ImageCreateFromFilename found ($getimagesizeinfo[2]=='.@$getimagesizeinfo[2].')', __FILE__, __LINE__);
3325  switch (@$getimagesizeinfo[2]) {
3326  case 1: // GIF
3327  case 2: // JPEG
3328  case 3: // PNG
3329  case 15: // WBMP
3330  $ImageCreateFromFunctionName = $ImageCreateFromFunction[$getimagesizeinfo[2]];
3331  if (function_exists($ImageCreateFromFunctionName)) {
3332  $this->DebugMessage('Calling '.$ImageCreateFromFunctionName.'('.$filename.')', __FILE__, __LINE__);
3333  $ImageCreateWasAttempted = true;
3334  $gd_image = $ImageCreateFromFunctionName($filename);
3335  } else {
3336  $this->DebugMessage('NOT calling '.$ImageCreateFromFunctionName.'('.$filename.') because !function_exists('.$ImageCreateFromFunctionName.')', __FILE__, __LINE__);
3337  }
3338  break;
3339 
3340  case 4: // SWF
3341  case 5: // PSD
3342  case 6: // BMP
3343  case 7: // TIFF (LE)
3344  case 8: // TIFF (BE)
3345  case 9: // JPC
3346  case 10: // JP2
3347  case 11: // JPX
3348  case 12: // JB2
3349  case 13: // SWC
3350  case 14: // IFF
3351  case 16: // XBM
3352  $this->DebugMessage('No built-in image creation function for image type "'.@$getimagesizeinfo[2].'" ($getimagesizeinfo[2])', __FILE__, __LINE__);
3353  break;
3354 
3355  default:
3356  $this->DebugMessage('Unknown value for $getimagesizeinfo[2]: "'.@$getimagesizeinfo[2].'"', __FILE__, __LINE__);
3357  break;
3358  }
3359  } else {
3360  $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__);
3361  return false;
3362  }
3363  } else {
3364  $this->DebugMessage('empty $filename or GetImageSize('.$filename.') failed', __FILE__, __LINE__);
3365  }
3366 
3367  if (!$gd_image) {
3368  // cannot create from filename, attempt to create source image with ImageCreateFromString, if possible
3369  if ($ImageCreateWasAttempted) {
3370  $this->DebugMessage(@$ImageCreateFromFunctionName.'() was attempted but FAILED', __FILE__, __LINE__);
3371  }
3372  $this->DebugMessage('Populating $rawimagedata', __FILE__, __LINE__);
3373  $rawimagedata = '';
3374  if ($fp = @fopen($filename, 'rb')) {
3375  $filesize = filesize($filename);
3376  $blocksize = 8192;
3377  $blockreads = ceil($filesize / $blocksize);
3378  for ($i = 0; $i < $blockreads; $i++) {
3379  $rawimagedata .= fread($fp, $blocksize);
3380  }
3381  fclose($fp);
3382  } else {
3383  $this->DebugMessage('cannot fopen('.$filename.')', __FILE__, __LINE__);
3384  }
3385  if ($rawimagedata) {
3386  $this->DebugMessage('attempting ImageCreateFromStringReplacement($rawimagedata ('.strlen($rawimagedata).' bytes), true)', __FILE__, __LINE__);
3387  $gd_image = $this->ImageCreateFromStringReplacement($rawimagedata, true);
3388  }
3389  }
3390  return $gd_image;
3391  }
3392 
3393  function SourceImageToGD() {
3394  if (is_resource($this->gdimg_source)) {
3395  $this->source_width = ImageSX($this->gdimg_source);
3396  $this->source_height = ImageSY($this->gdimg_source);
3397  $this->DebugMessage('skipping SourceImageToGD() because $this->gdimg_source is already a resource ('.$this->source_width.'x'.$this->source_height.')', __FILE__, __LINE__);
3398  return true;
3399  }
3400  $this->DebugMessage('starting SourceImageToGD()', __FILE__, __LINE__);
3401 
3402  if ($this->config_prefer_imagemagick) {
3403  if (empty($this->sourceFilename) && !empty($this->rawImageData)) {
3404  $this->DebugMessage('Copying raw image data to temp file and trying again with ImageMagick', __FILE__, __LINE__);
3405  if ($tempnam = $this->phpThumb_tempnam()) {
3406  if (file_put_contents($tempname, $this->rawImageData)) {
3407  $this->sourceFilename = $tempnam;
3408  if ($this->ImageMagickThumbnailToGD()) {
3409  // excellent, we have a thumbnailed source image
3410  $this->DebugMessage('ImageMagickThumbnailToGD() succeeded', __FILE__, __LINE__);
3411  } else {
3412  $this->DebugMessage('ImageMagickThumbnailToGD() failed', __FILE__, __LINE__);
3413  }
3414  } else {
3415  $this->DebugMessage('failed to put $this->rawImageData into temp file "'.$tempnam.'"', __FILE__, __LINE__);
3416  }
3417  } else {
3418  $this->DebugMessage('failed to generate temp file name', __FILE__, __LINE__);
3419  }
3420  }
3421  }
3422  if (!$this->gdimg_source && $this->rawImageData) {
3423 
3424  if ($this->SourceImageIsTooLarge($this->source_width, $this->source_height)) {
3425  $memory_get_usage = (function_exists('memory_get_usage') ? memory_get_usage() : 0);
3426  return $this->ErrorImage('Source image is too large ('.$this->source_width.'x'.$this->source_height.' = '.number_format($this->source_width * $this->source_height / 1000000, 1).'Mpx, max='.number_format($this->config_max_source_pixels / 1000000, 1).'Mpx) for GD creation (either install ImageMagick or increase PHP memory_limit to at least '.ceil(($memory_get_usage + (5 * $this->source_width * $this->source_height)) / 1048576).'M).');
3427  }
3428  if ($this->md5s && ($this->md5s != md5($this->rawImageData))) {
3429  return $this->ErrorImage('$this->md5s != md5($this->rawImageData)'."\n".'"'.$this->md5s.'" != '."\n".'"'.md5($this->rawImageData).'"');
3430  }
3431  //if ($this->issafemode) {
3432  // return $this->ErrorImage('Cannot generate thumbnails from raw image data when PHP SAFE_MODE enabled');
3433  //}
3434  $this->gdimg_source = $this->ImageCreateFromStringReplacement($this->rawImageData);
3435  if (!$this->gdimg_source) {
3436  if (substr($this->rawImageData, 0, 2) === 'BM') {
3437  $this->getimagesizeinfo[2] = 6; // BMP
3438  } elseif (substr($this->rawImageData, 0, 4) === 'II'."\x2A\x00") {
3439  $this->getimagesizeinfo[2] = 7; // TIFF (littlendian)
3440  } elseif (substr($this->rawImageData, 0, 4) === 'MM'."\x00\x2A") {
3441  $this->getimagesizeinfo[2] = 8; // TIFF (bigendian)
3442  }
3443  $this->DebugMessage('SourceImageToGD.ImageCreateFromStringReplacement() failed with unknown image type "'.substr($this->rawImageData, 0, 4).'" ('.phpthumb_functions::HexCharDisplay(substr($this->rawImageData, 0, 4)).')', __FILE__, __LINE__);
3444 // return $this->ErrorImage('Unknown image type identified by "'.substr($this->rawImageData, 0, 4).'" ('.phpthumb_functions::HexCharDisplay(substr($this->rawImageData, 0, 4)).') in SourceImageToGD()['.__LINE__.']');
3445  }
3446 
3447  } elseif (!$this->gdimg_source && $this->sourceFilename) {
3448 
3449  if ($this->md5s && ($this->md5s != phpthumb_functions::md5_file_safe($this->sourceFilename))) {
3450  return $this->ErrorImage('$this->md5s != md5(sourceFilename)'."\n".'"'.$this->md5s.'" != '."\n".'"'.phpthumb_functions::md5_file_safe($this->sourceFilename).'"');
3451  }
3452  switch (@$this->getimagesizeinfo[2]) {
3453  case 1:
3454  case 3:
3455  // GIF or PNG input file may have transparency
3456  $this->is_alpha = true;
3457  break;
3458  }
3459  if (!$this->SourceImageIsTooLarge($this->source_width, $this->source_height)) {
3460  $this->gdimg_source = $this->ImageCreateFromFilename($this->sourceFilename);
3461  }
3462 
3463  }
3464 
3465  while (true) {
3466  if ($this->gdimg_source) {
3467  $this->DebugMessage('Not using EXIF thumbnail data because $this->gdimg_source is already set', __FILE__, __LINE__);
3468  break;
3469  }
3470  if (!$this->exif_thumbnail_data) {
3471  $this->DebugMessage('Not using EXIF thumbnail data because $this->exif_thumbnail_data is empty', __FILE__, __LINE__);
3472  break;
3473  }
3474  if (ini_get('safe_mode')) {
3475  if (!$this->SourceImageIsTooLarge($this->source_width, $this->source_height)) {
3476  $this->DebugMessage('Using EXIF thumbnail data because source image too large and safe_mode enabled', __FILE__, __LINE__);
3477  $this->aoe = true;
3478  } else {
3479  break;
3480  }
3481  } else {
3482  if (!$this->config_use_exif_thumbnail_for_speed) {
3483  $this->DebugMessage('Not using EXIF thumbnail data because $this->config_use_exif_thumbnail_for_speed is FALSE', __FILE__, __LINE__);
3484  break;
3485  }
3486  if (($this->thumbnailCropX != 0) || ($this->thumbnailCropY != 0)) {
3487  $this->DebugMessage('Not using EXIF thumbnail data because source cropping is enabled ('.$this->thumbnailCropX.','.$this->thumbnailCropY.')', __FILE__, __LINE__);
3488  break;
3489  }
3490  if (($this->w > $this->exif_thumbnail_width) || ($this->h > $this->exif_thumbnail_height)) {
3491  $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__);
3492  break;
3493  }
3494  $source_ar = $this->source_width / $this->source_height;
3495  $exif_ar = $this->exif_thumbnail_width / $this->exif_thumbnail_height;
3496  if (number_format($source_ar, 2) != number_format($exif_ar, 2)) {
3497  $this->DebugMessage('not using EXIF thumbnail because $source_ar != $exif_ar ('.$source_ar.' != '.$exif_ar.')', __FILE__, __LINE__);
3498  break;
3499  }
3500  }
3501 
3502  // EXIF thumbnail exists, and is equal to or larger than destination thumbnail, and will be use as source image
3503  $this->DebugMessage('Trying to use EXIF thumbnail as source image', __FILE__, __LINE__);
3504 
3505  if ($gdimg_exif_temp = $this->ImageCreateFromStringReplacement($this->exif_thumbnail_data, false)) {
3506 
3507  $this->DebugMessage('Successfully using EXIF thumbnail as source image', __FILE__, __LINE__);
3508  $this->gdimg_source = $gdimg_exif_temp;
3509  $this->source_width = $this->exif_thumbnail_width;
3510  $this->source_height = $this->exif_thumbnail_height;
3511  $this->thumbnailCropW = $this->source_width;
3512  $this->thumbnailCropH = $this->source_height;
3513  return true;
3514 
3515  } else {
3516  $this->DebugMessage('$this->ImageCreateFromStringReplacement($this->exif_thumbnail_data, false) failed', __FILE__, __LINE__);
3517  }
3518 
3519  break;
3520  }
3521 
3522  if (!$this->gdimg_source) {
3523  $this->DebugMessage('$this->gdimg_source is still empty', __FILE__, __LINE__);
3524 
3525  $this->DebugMessage('ImageMagickThumbnailToGD() failed', __FILE__, __LINE__);
3526 
3527  $imageHeader = '';
3528  $gd_info = gd_info();
3529  $GDreadSupport = false;
3530  switch (@$this->getimagesizeinfo[2]) {
3531  case 1:
3532  $imageHeader = 'Content-Type: image/gif';
3533  $GDreadSupport = (bool) @$gd_info['GIF Read Support'];
3534  break;
3535  case 2:
3536  $imageHeader = 'Content-Type: image/jpeg';
3537  $GDreadSupport = (bool) @$gd_info['JPG Support'];
3538  break;
3539  case 3:
3540  $imageHeader = 'Content-Type: image/png';
3541  $GDreadSupport = (bool) @$gd_info['PNG Support'];
3542  break;
3543  }
3544  if ($imageHeader) {
3545  // cannot create image for whatever reason (maybe ImageCreateFromJPEG et al are not available?)
3546  // and ImageMagick is not available either, no choice but to output original (not resized/modified) data and exit
3547  if ($this->config_error_die_on_source_failure) {
3548  $errormessages = array();
3549  $errormessages[] = 'All attempts to create GD image source failed.';
3550  if ($this->fatalerror) {
3551  $errormessages[] = $this->fatalerror;
3552  }
3553  if ($this->issafemode) {
3554  $errormessages[] = 'Safe Mode enabled, therefore ImageMagick is unavailable. (disable Safe Mode if possible)';
3555  } elseif (!$this->ImageMagickVersion()) {
3556  $errormessages[] = 'ImageMagick is not installed (it is highly recommended that you install it).';
3557  }
3558  if ($this->SourceImageIsTooLarge($this->getimagesizeinfo[0], $this->getimagesizeinfo[1])) {
3559  $memory_get_usage = (function_exists('memory_get_usage') ? memory_get_usage() : 0);
3560  $errormessages[] = 'Source image is too large ('.$this->getimagesizeinfo[0].'x'.$this->getimagesizeinfo[1].' = '.number_format($this->getimagesizeinfo[0] * $this->getimagesizeinfo[1] / 1000000, 1).'Mpx, max='.number_format($this->config_max_source_pixels / 1000000, 1).'Mpx) for GD creation (either install ImageMagick or increase PHP memory_limit to at least '.ceil(($memory_get_usage + (5 * $this->getimagesizeinfo[0] * $this->getimagesizeinfo[1])) / 1048576).'M).';
3561  } elseif (!$GDreadSupport) {
3562  $errormessages[] = 'GD does not have read support for "'.$imageHeader.'".';
3563  } else {
3564  $errormessages[] = 'Source image probably corrupt.';
3565  }
3566  $this->ErrorImage(implode("\n", $errormessages));
3567 
3568  } else {
3569  $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');
3570  //$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__);
3571  //if (!$this->phpThumbDebug) {
3572  // header($imageHeader);
3573  // echo $this->rawImageData;
3574  // exit;
3575  //}
3576  return false;
3577  }
3578  }
3579 
3580  //switch (substr($this->rawImageData, 0, 2)) {
3581  // case 'BM':
3582  switch (@$this->getimagesizeinfo[2]) {
3583  case 6:
3584  ob_start();
3585  if (!@include_once(dirname(__FILE__).'/phpthumb.bmp.php')) {
3586  ob_end_clean();
3587  return $this->ErrorImage('include_once('.dirname(__FILE__).'/phpthumb.bmp.php) failed');
3588  }
3589  ob_end_clean();
3590  if ($fp = @fopen($this->sourceFilename, 'rb')) {
3591  $this->rawImageData = '';
3592  while (!feof($fp)) {
3593  $this->rawImageData .= fread($fp, 32768);
3594  }
3595  fclose($fp);
3596  }
3597  $phpthumb_bmp = new phpthumb_bmp();
3598  $this->gdimg_source = $phpthumb_bmp->phpthumb_bmp2gd($this->rawImageData, (phpthumb_functions::gd_version() >= 2.0));
3599  unset($phpthumb_bmp);
3600  if ($this->gdimg_source) {
3601  $this->DebugMessage('$phpthumb_bmp->phpthumb_bmp2gd() succeeded', __FILE__, __LINE__);
3602  } else {
3603  return $this->ErrorImage($this->ImageMagickVersion() ? 'ImageMagick failed on BMP source conversion' : 'phpthumb_bmp2gd() failed');
3604  }
3605  break;
3606  //}
3607  //switch (substr($this->rawImageData, 0, 4)) {
3608  // case 'II'."\x2A\x00":
3609  // case 'MM'."\x00\x2A":
3610  case 7:
3611  case 8:
3612  return $this->ErrorImage($this->ImageMagickVersion() ? 'ImageMagick failed on TIFF source conversion' : 'ImageMagick is unavailable and phpThumb() does not support TIFF source images without it');
3613  break;
3614 
3615  //case "\xD7\xCD\xC6\x9A":
3616  // return $this->ErrorImage($this->ImageMagickVersion() ? 'ImageMagick failed on WMF source conversion' : 'ImageMagick is unavailable and phpThumb() does not support WMF source images without it');
3617  // break;
3618  }
3619 
3620  if (!$this->gdimg_source) {
3621  $HeaderFourBytes = '';
3622  if ($this->rawImageData) {
3623  $HeaderFourBytes = substr($this->rawImageData, 0, 4);
3624  } elseif ($this->sourceFilename) {
3625  if ($fp = @fopen($this->sourceFilename, 'rb')) {
3626  $HeaderFourBytes = fread($fp, 4);
3627  fclose($fp);
3628  } else {
3629  return $this->ErrorImage('failed to open "'.$this->sourceFilename.'" SourceImageToGD() ['.__LINE__.']');
3630  }
3631  } else {
3632  return $this->ErrorImage('Unable to create image, neither filename nor image data suppplied in SourceImageToGD() ['.__LINE__.']');
3633  }
3634  if (!$this->ImageMagickVersion() && !phpthumb_functions::gd_version()) {
3635  return $this->ErrorImage('Neither GD nor ImageMagick seem to be installed on this server. At least one (preferably GD), or better both, MUST be installed for phpThumb to work.');
3636  } elseif ($HeaderFourBytes == "\xD7\xCD\xC6\x9A") { // WMF
3637  return $this->ErrorImage($this->ImageMagickVersion() ? 'ImageMagick failed on WMF source conversion' : 'ImageMagick is unavailable and phpThumb() does not support WMF source images without it');
3638  } elseif ($HeaderFourBytes == '%PDF') { // "%PDF"
3639  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');
3640  } elseif (substr($HeaderFourBytes, 0, 3) == "\xFF\xD8\xFF") { // JPEG
3641  return $this->ErrorImage('Image (JPEG) is too large for PHP-GD memory_limit, please install ImageMagick or increase php.ini memory_limit setting');
3642  } elseif ($HeaderFourBytes == '%PNG') { // "%PNG"
3643  return $this->ErrorImage('Image (PNG) is too large for PHP-GD memory_limit, please install ImageMagick or increase php.ini memory_limit setting');
3644  } elseif (substr($HeaderFourBytes, 0, 3) == 'GIF') { // GIF
3645  return $this->ErrorImage('Image (GIF) is too large for PHP-GD memory_limit, please install ImageMagick or increase php.ini memory_limit setting');
3646  }
3647  return $this->ErrorImage('Unknown image type identified by "'.$HeaderFourBytes.'" ('.phpthumb_functions::HexCharDisplay($HeaderFourBytes).') in SourceImageToGD() ['.__LINE__.']');
3648  }
3649  }
3650 
3651  if (!$this->gdimg_source) {
3652  if ($gdimg_exif_temp = $this->ImageCreateFromStringReplacement($this->exif_thumbnail_data, false)) {
3653  $this->DebugMessage('All other attempts failed, but successfully using EXIF thumbnail as source image', __FILE__, __LINE__);
3654  $this->gdimg_source = $gdimg_exif_temp;
3655  // override allow-enlarging setting if EXIF thumbnail is the only source available
3656  // otherwise thumbnails larger than the EXIF thumbnail will be created at EXIF size
3657  $this->aoe = true;
3658  return true;
3659  }
3660  return false;
3661  }
3662 
3663  $this->source_width = ImageSX($this->gdimg_source);
3664  $this->source_height = ImageSY($this->gdimg_source);
3665  return true;
3666  }
3667 
3668 
3670  if (is_null($var)) {
3671  return 'NULL';
3672  } elseif (is_bool($var)) {
3673  return ($var ? 'TRUE' : 'FALSE');
3674  } elseif (is_string($var)) {
3675  return 'string('.strlen($var).')'.str_repeat(' ', max(0, 3 - strlen(strlen($var)))).' "'.$var.'"';
3676  } elseif (is_int($var)) {
3677  return 'integer '.$var;
3678  } elseif (is_float($var)) {
3679  return 'float '.$var;
3680  } elseif (is_array($var)) {
3681  ob_start();
3682  var_dump($var);
3683  $vardumpoutput = ob_get_contents();
3684  ob_end_clean();
3685  return strtr($vardumpoutput, "\n\r\t", ' ');
3686  }
3687  return gettype($var);
3688  }
3689 
3690  function phpThumbDebug($level='') {
3691  if ($level && ($this->phpThumbDebug !== $level)) {
3692  return true;
3693  }
3694  if ($this->config_disable_debug) {
3695  return $this->ErrorImage('phpThumbDebug disabled');
3696  }
3697 
3698  $FunctionsExistance = array('exif_thumbnail', 'gd_info', 'image_type_to_mime_type', 'GetImageSize', 'ImageCopyResampled', 'ImageCopyResized', 'ImageCreate', 'ImageCreateFromString', 'ImageCreateTrueColor', 'ImageIsTrueColor', 'ImageRotate', 'ImageTypes', 'version_compare', 'ImageCreateFromGIF', 'ImageCreateFromJPEG', 'ImageCreateFromPNG', 'ImageCreateFromWBMP', 'ImageCreateFromXBM', 'ImageCreateFromXPM', 'ImageCreateFromString', 'ImageCreateFromGD', 'ImageCreateFromGD2', 'ImageCreateFromGD2Part', 'ImageJPEG', 'ImageGIF', 'ImagePNG', 'ImageWBMP');
3699  $ParameterNames = array('src', 'new', 'w', 'h', 'f', 'q', 'sx', 'sy', 'sw', 'sh', 'far', 'bg', 'bc', 'file', 'goto', 'err', 'xto', 'ra', 'ar', 'aoe', 'iar', 'maxb');
3700  $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', 'max_source_pixels', 'use_exif_thumbnail_for_speed', 'border_hexcolor', 'background_hexcolor', 'ttf_directory', 'disable_pathinfo_parsing', 'disable_imagecopyresampled');
3701  $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');
3702 
3703  $DebugOutput = array();
3704  $DebugOutput[] = 'phpThumb() version = '.$this->phpthumb_version;
3705  $DebugOutput[] = 'phpversion() = '.@phpversion();
3706  $DebugOutput[] = 'PHP_OS = '.PHP_OS;
3707  $DebugOutput[] = '$_SERVER[SERVER_SOFTWARE] = '.@$_SERVER['SERVER_SOFTWARE'];
3708  $DebugOutput[] = '__FILE__ = '.__FILE__;
3709  $DebugOutput[] = 'realpath(.) = '.@realpath('.');
3710  $DebugOutput[] = '$_SERVER[PHP_SELF] = '.@$_SERVER['PHP_SELF'];
3711  $DebugOutput[] = '$_SERVER[HOST_NAME] = '.@$_SERVER['HOST_NAME'];
3712  $DebugOutput[] = '$_SERVER[HTTP_REFERER] = '.@$_SERVER['HTTP_REFERER'];
3713  $DebugOutput[] = '$_SERVER[QUERY_STRING] = '.@$_SERVER['QUERY_STRING'];
3714  $DebugOutput[] = '$_SERVER[PATH_INFO] = '.@$_SERVER['PATH_INFO'];
3715  $DebugOutput[] = '$_SERVER[DOCUMENT_ROOT] = '.@$_SERVER['DOCUMENT_ROOT'];
3716  $DebugOutput[] = 'getenv(DOCUMENT_ROOT) = '.@getenv('DOCUMENT_ROOT');
3717  $DebugOutput[] = '';
3718 
3719  $DebugOutput[] = 'get_magic_quotes_gpc() = '.$this->phpThumbDebugVarDump(@get_magic_quotes_gpc());
3720  $DebugOutput[] = 'get_magic_quotes_runtime() = '.$this->phpThumbDebugVarDump(@get_magic_quotes_runtime());
3721  $DebugOutput[] = 'error_reporting() = '.$this->phpThumbDebugVarDump(error_reporting());
3722  $DebugOutput[] = 'ini_get(error_reporting) = '.$this->phpThumbDebugVarDump(@ini_get('error_reporting'));
3723  $DebugOutput[] = 'ini_get(display_errors) = '.$this->phpThumbDebugVarDump(@ini_get('display_errors'));
3724  $DebugOutput[] = 'ini_get(allow_url_fopen) = '.$this->phpThumbDebugVarDump(@ini_get('allow_url_fopen'));
3725  $DebugOutput[] = 'ini_get(disable_functions) = '.$this->phpThumbDebugVarDump(@ini_get('disable_functions'));
3726  $DebugOutput[] = 'get_cfg_var(disable_functions) = '.$this->phpThumbDebugVarDump(@get_cfg_var('disable_functions'));
3727  $DebugOutput[] = 'ini_get(safe_mode) = '.$this->phpThumbDebugVarDump(@ini_get('safe_mode'));
3728  $DebugOutput[] = 'ini_get(open_basedir) = '.$this->phpThumbDebugVarDump(@ini_get('open_basedir'));
3729  $DebugOutput[] = 'ini_get(max_execution_time) = '.$this->phpThumbDebugVarDump(@ini_get('max_execution_time'));
3730  $DebugOutput[] = 'ini_get(memory_limit) = '.$this->phpThumbDebugVarDump(@ini_get('memory_limit'));
3731  $DebugOutput[] = 'get_cfg_var(memory_limit) = '.$this->phpThumbDebugVarDump(@get_cfg_var('memory_limit'));
3732  $DebugOutput[] = 'memory_get_usage() = '.(function_exists('memory_get_usage') ? $this->phpThumbDebugVarDump(@memory_get_usage()) : 'n/a');
3733  $DebugOutput[] = '';
3734 
3735  $DebugOutput[] = '$this->config_prefer_imagemagick = '.$this->phpThumbDebugVarDump($this->config_prefer_imagemagick);
3736  $DebugOutput[] = '$this->config_imagemagick_path = '.$this->phpThumbDebugVarDump($this->config_imagemagick_path);
3737  $DebugOutput[] = '$this->ImageMagickWhichConvert() = '.$this->ImageMagickWhichConvert();
3738  $IMpathUsed = ($this->config_imagemagick_path ? $this->config_imagemagick_path : $this->ImageMagickWhichConvert());
3739  $DebugOutput[] = '[actual ImageMagick path used] = '.$this->phpThumbDebugVarDump($IMpathUsed);
3740  $DebugOutput[] = 'file_exists([actual ImageMagick path used]) = '.$this->phpThumbDebugVarDump(@file_exists($IMpathUsed));
3741  $DebugOutput[] = 'ImageMagickVersion(false) = '.$this->ImageMagickVersion(false);
3742  $DebugOutput[] = 'ImageMagickVersion(true) = '.$this->ImageMagickVersion(true);
3743  $DebugOutput[] = '';
3744 
3745  $DebugOutput[] = '$this->config_cache_directory = '.$this->phpThumbDebugVarDump($this->config_cache_directory);
3746  $DebugOutput[] = '$this->config_cache_directory_depth = '.$this->phpThumbDebugVarDump($this->config_cache_directory_depth);
3747  $DebugOutput[] = '$this->config_cache_disable_warning = '.$this->phpThumbDebugVarDump($this->config_cache_disable_warning);
3748  $DebugOutput[] = '$this->config_cache_maxage = '.$this->phpThumbDebugVarDump($this->config_cache_maxage);
3749  $DebugOutput[] = '$this->config_cache_maxsize = '.$this->phpThumbDebugVarDump($this->config_cache_maxsize);
3750  $DebugOutput[] = '$this->config_cache_maxfiles = '.$this->phpThumbDebugVarDump($this->config_cache_maxfiles);
3751  $DebugOutput[] = '$this->config_cache_force_passthru = '.$this->phpThumbDebugVarDump($this->config_cache_force_passthru);
3752  $DebugOutput[] = '$this->cache_filename = '.$this->phpThumbDebugVarDump($this->cache_filename);
3753  $DebugOutput[] = 'is_readable($this->config_cache_directory) = '.$this->phpThumbDebugVarDump(@is_readable($this->config_cache_directory));
3754  $DebugOutput[] = 'is_writable($this->config_cache_directory) = '.$this->phpThumbDebugVarDump(@is_writable($this->config_cache_directory));
3755  $DebugOutput[] = 'is_readable($this->cache_filename) = '.$this->phpThumbDebugVarDump(@is_readable($this->cache_filename));
3756  $DebugOutput[] = 'is_writable($this->cache_filename) = '.(@file_exists($this->cache_filename) ? $this->phpThumbDebugVarDump(@is_writable($this->cache_filename)) : 'n/a');
3757  $DebugOutput[] = '';
3758 
3759  foreach ($ConfigVariableNames as $varname) {
3760  $varname = 'config_'.$varname;
3761  $value = $this->$varname;
3762  $DebugOutput[] = '$this->'.str_pad($varname, 37, ' ', STR_PAD_RIGHT).' = '.$this->phpThumbDebugVarDump($value);
3763  }
3764  $DebugOutput[] = '';
3765  foreach ($OtherVariableNames as $varname) {
3766  $value = $this->$varname;
3767  $DebugOutput[] = '$this->'.str_pad($varname, 27, ' ', STR_PAD_RIGHT).' = '.$this->phpThumbDebugVarDump($value);
3768  }
3769  $DebugOutput[] = 'strlen($this->rawImageData) = '.strlen(@$this->rawImageData);
3770  $DebugOutput[] = 'strlen($this->exif_thumbnail_data) = '.strlen(@$this->exif_thumbnail_data);
3771  $DebugOutput[] = '';
3772 
3773  foreach ($ParameterNames as $varname) {
3774  $value = $this->$varname;
3775  $DebugOutput[] = '$this->'.str_pad($varname, 4, ' ', STR_PAD_RIGHT).' = '.$this->phpThumbDebugVarDump($value);
3776  }
3777  $DebugOutput[] = '';
3778 
3779  foreach ($FunctionsExistance as $functionname) {
3780  $DebugOutput[] = 'builtin_function_exists('.$functionname.')'.str_repeat(' ', 23 - strlen($functionname)).' = '.$this->phpThumbDebugVarDump(phpthumb_functions::builtin_function_exists($functionname));
3781  }
3782  $DebugOutput[] = '';
3783 
3784  $gd_info = gd_info();
3785  foreach ($gd_info as $key => $value) {
3786  $DebugOutput[] = 'gd_info.'.str_pad($key, 34, ' ', STR_PAD_RIGHT).' = '.$this->phpThumbDebugVarDump($value);
3787  }
3788  $DebugOutput[] = '';
3789 
3790  $exif_info = phpthumb_functions::exif_info();
3791  foreach ($exif_info as $key => $value) {
3792  $DebugOutput[] = 'exif_info.'.str_pad($key, 26, ' ', STR_PAD_RIGHT).' = '.$this->phpThumbDebugVarDump($value);
3793  }
3794  $DebugOutput[] = '';
3795 
3796  if ($ApacheLookupURIarray = phpthumb_functions::ApacheLookupURIarray(dirname(@$_SERVER['PHP_SELF']))) {
3797  foreach ($ApacheLookupURIarray as $key => $value) {
3798  $DebugOutput[] = 'ApacheLookupURIarray.'.str_pad($key, 15, ' ', STR_PAD_RIGHT).' = '.$this->phpThumbDebugVarDump($value);
3799  }
3800  } else {
3801  $DebugOutput[] = 'ApacheLookupURIarray() -- FAILED';
3802  }
3803  $DebugOutput[] = '';
3804 
3805  if (isset($_GET) && is_array($_GET)) {
3806  foreach ($_GET as $key => $value) {
3807  $DebugOutput[] = '$_GET['.$key.']'.str_repeat(' ', 30 - strlen($key)).'= '.$this->phpThumbDebugVarDump($value);
3808  }
3809  }
3810  if (isset($_POST) && is_array($_POST)) {
3811  foreach ($_POST as $key => $value) {
3812  $DebugOutput[] = '$_POST['.$key.']'.str_repeat(' ', 29 - strlen($key)).'= '.$this->phpThumbDebugVarDump($value);
3813  }
3814  }
3815  $DebugOutput[] = '';
3816 
3817  $DebugOutput[] = '$this->debugmessages:';
3818  foreach ($this->debugmessages as $errorstring) {
3819  $DebugOutput[] = ' * '.$errorstring;
3820  }
3821  $DebugOutput[] = '';
3822 
3823  $DebugOutput[] = '$this->debugtiming:';
3824  foreach ($this->debugtiming as $timestamp => $timingstring) {
3825  $DebugOutput[] = ' * '.$timestamp.' '.$timingstring;
3826  }
3827  $DebugOutput[] = ' * Total processing time: '.number_format(max(array_keys($this->debugtiming)) - min(array_keys($this->debugtiming)), 6);
3828 
3829  $this->f = (isset($_GET['f']) ? $_GET['f'] : $this->f); // debug modes 0-2 don't recognize text mode otherwise
3830  return $this->ErrorImage(implode("\n", $DebugOutput), 700, 500, true);
3831  }
3832 
3833  function FatalError($text) {
3834  if (is_null($this->fatalerror)) {
3835  $this->fatalerror = $text;
3836  }
3837  return true;
3838  }
3839 
3840  function ErrorImage($text, $width=0, $height=0, $forcedisplay=false) {
3841  $width = ($width ? $width : $this->config_error_image_width);
3842  $height = ($height ? $height : $this->config_error_image_height);
3843 
3844  $text = 'phpThumb() v'.$this->phpthumb_version."\n".'http://phpthumb.sourceforge.net'."\n\n".($this->config_disable_debug ? 'Error messages disabled' : $text);
3845 
3846  $this->FatalError($text);
3847  $this->DebugMessage($text, __FILE__, __LINE__);
3848  $this->purgeTempFiles();
3849  if ($this->phpThumbDebug && !$forcedisplay) {
3850  return false;
3851  }
3852  if (!$this->config_error_die_on_error && !$forcedisplay) {
3853  return false;
3854  }
3855  if ($this->config_error_silent_die_on_error) {
3856  exit;
3857  }
3858  if ($this->err || $this->config_error_message_image_default) {
3859  // Show generic custom error image instead of error message
3860  // for use on production sites where you don't want debug messages
3861  if (($this->err == 'showerror') || $this->phpThumbDebug) {
3862  // fall through and actually show error message even if default error image is set
3863  } else {
3864  header('Location: '.($this->err ? $this->err : $this->config_error_message_image_default));
3865  exit;
3866  }
3867  }
3868  $this->setOutputFormat();
3869  if (!$this->thumbnailFormat || (phpthumb_functions::gd_version() < 1)) {
3870  $this->thumbnailFormat = 'text';
3871  }
3872  if (@$this->thumbnailFormat == 'text') {
3873  // bypass all GD functions and output text error message
3874  if (!headers_sent()) {
3875  header('Content-type: text/plain');
3876  echo $text;
3877  } else {
3878  echo '<pre>'.htmlspecialchars($text).'</pre>';
3879  }
3880  exit;
3881  }
3882 
3883  $FontWidth = ImageFontWidth($this->config_error_fontsize);
3884  $FontHeight = ImageFontHeight($this->config_error_fontsize);
3885 
3886  $LinesOfText = explode("\n", @wordwrap($text, floor($width / $FontWidth), "\n", true));
3887  $height = max($height, count($LinesOfText) * $FontHeight);
3888 
3889  $headers_file = '';
3890  $headers_line = '';
3891  if (phpthumb_functions::version_compare_replacement(phpversion(), '4.3.0', '>=') && headers_sent($headers_file, $headers_line)) {
3892 
3893  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>';
3894 
3895  } elseif (headers_sent()) {
3896 
3897  echo "\n".'**Headers already sent, dumping error message as text:**<br><pre>'."\n\n".$text."\n".'</pre>';
3898 
3899  } elseif ($gdimg_error = ImageCreate($width, $height)) {
3900 
3901  $background_color = phpthumb_functions::ImageHexColorAllocate($gdimg_error, $this->config_error_bgcolor, true);
3902  $text_color = phpthumb_functions::ImageHexColorAllocate($gdimg_error, $this->config_error_textcolor, true);
3903  ImageFilledRectangle($gdimg_error, 0, 0, $width, $height, $background_color);
3904  $lineYoffset = 0;
3905  foreach ($LinesOfText as $line) {
3906  ImageString($gdimg_error, $this->config_error_fontsize, 2, $lineYoffset, $line, $text_color);
3907  $lineYoffset += $FontHeight;
3908  }
3909  if (function_exists('ImageTypes')) {
3910  $imagetypes = ImageTypes();
3911  if ($imagetypes & IMG_PNG) {
3912  header('Content-Type: image/png');
3913  ImagePNG($gdimg_error);
3914  } elseif ($imagetypes & IMG_GIF) {
3915  header('Content-Type: image/gif');
3916  ImageGIF($gdimg_error);
3917  } elseif ($imagetypes & IMG_JPG) {
3918  header('Content-Type: image/jpeg');
3919  ImageJPEG($gdimg_error);
3920  } elseif ($imagetypes & IMG_WBMP) {
3921  header('Content-Type: image/vnd.wap.wbmp');
3922  ImageWBMP($gdimg_error);
3923  }
3924  }
3925  ImageDestroy($gdimg_error);
3926 
3927  }
3928  if (!headers_sent()) {
3929  echo "\n".'**Failed to send graphical error image, dumping error message as text:**<br>'."\n\n".$text;
3930  }
3931  exit;
3932  return true;
3933  }
3934 
3935  function ImageCreateFromStringReplacement(&$RawImageData, $DieOnErrors=false) {
3936  // there are serious bugs in the non-bundled versions of GD which may cause
3937  // PHP to segfault when calling ImageCreateFromString() - avoid if at all possible
3938  // when not using a bundled version of GD2
3940  if ($DieOnErrors) {
3941  if (!headers_sent()) {
3942  // base64-encoded error image in GIF format
3943  $ERROR_NOGD = 'R0lGODlhIAAgALMAAAAAABQUFCQkJDY2NkZGRldXV2ZmZnJycoaGhpSUlKWlpbe3t8XFxdXV1eTk5P7+/iwAAAAAIAAgAAAE/vDJSau9WILtTAACUinDNijZtAHfCojS4W5H+qxD8xibIDE9h0OwWaRWDIljJSkUJYsN4bihMB8th3IToAKs1VtYM75cyV8sZ8vygtOE5yMKmGbO4jRdICQCjHdlZzwzNW4qZSQmKDaNjhUMBX4BBAlmMywFSRWEmAI6b5gAlhNxokGhooAIK5o/pi9vEw4Lfj4OLTAUpj6IabMtCwlSFw0DCKBoFqwAB04AjI54PyZ+yY3TD0ss2YcVmN/gvpcu4TOyFivWqYJlbAHPpOntvxNAACcmGHjZzAZqzSzcq5fNjxFmAFw9iFRunD1epU6tsIPmFCAJnWYE0FURk7wJDA0MTKpEzoWAAskiAAA7';
3944  header('Content-Type: image/gif');
3945  echo base64_decode($ERROR_NOGD);
3946  } else {
3947  echo '*** ERROR: No PHP-GD support available ***';
3948  }
3949  exit;
3950  } else {
3951  $this->DebugMessage('ImageCreateFromStringReplacement() failed: gd_version says "'.phpthumb_functions::gd_version().'"', __FILE__, __LINE__);
3952  return false;
3953  }
3954  }
3956  $this->DebugMessage('ImageCreateFromStringReplacement() calling built-in ImageCreateFromString()', __FILE__, __LINE__);
3957  return @ImageCreateFromString($RawImageData);
3958  }
3959  if ($this->issafemode) {
3960  $this->DebugMessage('ImageCreateFromStringReplacement() failed: cannot create temp file in SAFE_MODE', __FILE__, __LINE__);
3961  return false;
3962  }
3963 
3964  switch (substr($RawImageData, 0, 3)) {
3965  case 'GIF':
3966  $ICFSreplacementFunctionName = 'ImageCreateFromGIF';
3967  break;
3968  case "\xFF\xD8\xFF":
3969  $ICFSreplacementFunctionName = 'ImageCreateFromJPEG';
3970  break;
3971  case "\x89".'PN':
3972  $ICFSreplacementFunctionName = 'ImageCreateFromPNG';
3973  break;
3974  default:
3975  $this->DebugMessage('ImageCreateFromStringReplacement() failed: unknown fileformat signature "'.phpthumb_functions::HexCharDisplay(substr($RawImageData, 0, 3)).'"', __FILE__, __LINE__);
3976  return false;
3977  break;
3978  }
3979  if ($tempnam = $this->phpThumb_tempnam()) {
3980  if ($fp_tempnam = @fopen($tempnam, 'wb')) {
3981  fwrite($fp_tempnam, $RawImageData);
3982  fclose($fp_tempnam);
3983  if (($ICFSreplacementFunctionName == 'ImageCreateFromGIF') && !function_exists($ICFSreplacementFunctionName)) {
3984 
3985  // Need to create from GIF file, but ImageCreateFromGIF does not exist
3986  ob_start();
3987  if (!@include_once(dirname(__FILE__).'/phpthumb.gif.php')) {
3988  $ErrorMessage = 'Failed to include required file "'.dirname(__FILE__).'/phpthumb.gif.php" in '.__FILE__.' on line '.__LINE__;
3989  $this->DebugMessage($ErrorMessage, __FILE__, __LINE__);
3990  }
3991  ob_end_clean();
3992  // gif_loadFileToGDimageResource() cannot read from raw data, write to file first
3993  if ($tempfilename = $this->phpThumb_tempnam()) {
3994  if ($fp_tempfile = @fopen($tempfilename, 'wb')) {
3995  fwrite($fp_tempfile, $RawImageData);
3996  fclose($fp_tempfile);
3998  $this->DebugMessage('gif_loadFileToGDimageResource('.$tempfilename.') completed', __FILE__, __LINE__);
3999  $this->DebugMessage('deleting "'.$tempfilename.'"', __FILE__, __LINE__);
4000  unlink($tempfilename);
4001  return $gdimg_source;
4002  break;
4003  } else {
4004  $ErrorMessage = 'Failed to open tempfile in '.__FILE__.' on line '.__LINE__;
4005  $this->DebugMessage($ErrorMessage, __FILE__, __LINE__);
4006  }
4007  } else {
4008  $ErrorMessage = 'Failed to open generate tempfile name in '.__FILE__.' on line '.__LINE__;
4009  $this->DebugMessage($ErrorMessage, __FILE__, __LINE__);
4010  }
4011 
4012  } elseif (function_exists($ICFSreplacementFunctionName) && ($gdimg_source = @$ICFSreplacementFunctionName($tempnam))) {
4013 
4014  // great
4015  $this->DebugMessage($ICFSreplacementFunctionName.'('.$tempnam.') succeeded', __FILE__, __LINE__);
4016  $this->DebugMessage('deleting "'.$tempnam.'"', __FILE__, __LINE__);
4017  unlink($tempnam);
4018  return $gdimg_source;
4019 
4020  } else {
4021 
4022  // GD functions not available, or failed to create image
4023  $this->DebugMessage($ICFSreplacementFunctionName.'('.$tempnam.') '.(function_exists($ICFSreplacementFunctionName) ? 'failed' : 'does not exist'), __FILE__, __LINE__);
4024  if (isset($_GET['phpThumbDebug'])) {
4025  $this->phpThumbDebug();
4026  }
4027 
4028  }
4029  } else {
4030  $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';
4031  if ($this->issafemode) {
4032  $ErrorMessage = 'ImageCreateFromStringReplacement() failed in '.__FILE__.' on line '.__LINE__.': cannot create temp file in SAFE_MODE';
4033  }
4034  $this->DebugMessage($ErrorMessage, __FILE__, __LINE__);
4035  }
4036  $this->DebugMessage('deleting "'.$tempnam.'"', __FILE__, __LINE__);
4037  @unlink($tempnam);
4038  } else {
4039  $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';
4040  if ($this->issafemode) {
4041  $ErrorMessage = 'ImageCreateFromStringReplacement() failed in '.__FILE__.' on line '.__LINE__.': cannot create temp file in SAFE_MODE';
4042  }
4043  }
4044  if ($DieOnErrors && $ErrorMessage) {
4045  return $this->ErrorImage($ErrorMessage);
4046  }
4047  return false;
4048  }
4049 
4050  function ImageResizeFunction(&$dst_im, &$src_im, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH) {
4051  $this->DebugMessage('ImageResizeFunction($o, $s, '.$dstX.', '.$dstY.', '.$srcX.', '.$srcY.', '.$dstW.', '.$dstH.', '.$srcW.', '.$srcH.')', __FILE__, __LINE__);
4052  if (($dstW == $srcW) && ($dstH == $srcH)) {
4053  return ImageCopy($dst_im, $src_im, $dstX, $dstY, $srcX, $srcY, $srcW, $srcH);
4054  }
4055  if (phpthumb_functions::gd_version() >= 2.0) {
4056  if ($this->config_disable_imagecopyresampled) {
4057  return phpthumb_functions::ImageCopyResampleBicubic($dst_im, $src_im, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH);
4058  }
4059  return ImageCopyResampled($dst_im, $src_im, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH);
4060  }
4061  return ImageCopyResized($dst_im, $src_im, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH);
4062  }
4063 
4065  $this->config_temp_directory = realpath($this->config_temp_directory ? $this->config_temp_directory : (getenv('TMPDIR') ? getenv('TMPDIR') : getenv('TMP')));
4066  return true;
4067  }
4068 
4069  function phpThumb_tempnam() {
4070  $this->InitializeTempDirSetting();
4071  $tempnam = realpath(tempnam($this->config_temp_directory, 'pThumb'));
4072  $this->tempFilesToDelete[$tempnam] = $tempnam;
4073  $this->DebugMessage('phpThumb_tempnam() returning "'.$tempnam.'"', __FILE__, __LINE__);
4074  return $tempnam;
4075  }
4076 
4077  function DebugMessage($message, $file='', $line='') {
4078  $this->debugmessages[] = $message.($file ? ' in file "'.(basename($file) ? basename($file) : $file).'"' : '').($line ? ' on line '.$line : '');
4079  return true;
4080  }
4081 
4082  function DebugTimingMessage($message, $file='', $line='', $timestamp=0) {
4083  if (!$timestamp) {
4084  $timestamp = array_sum(explode(' ', microtime()));
4085  }
4086  $this->debugtiming[number_format($timestamp, 6, '.', '')] = ': '.$message.($file ? ' in file "'.(basename($file) ? basename($file) : $file).'"' : '').($line ? ' on line '.$line : '');
4087  return true;
4088  }
4089 
4090 }
4091 
4092 ?>