Guest User

thumb.php

a guest
Aug 30th, 2019
318
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 44.18 KB | None | 0 0
  1. <?php
  2. require_once('./includes/config.php');
  3.  
  4. if(!empty($_GET['t'])) {
  5.     if($_GET['t'] == 'a') {
  6.         $type = 'uploads/avatars';
  7.         $width_list = array(25, 48, 50, 112, 150, 200);
  8.         $height_list = array(25, 48, 50, 112, 150, 200);
  9.         $quality_list = array(50, 75, 100);
  10.     } elseif($_GET['t'] == 'm') {
  11.         $type = 'uploads/media';
  12.         $width_list = array(100, 200, 300, 435, 500, 650, 700, 800, 900, 1000);
  13.         $height_list = array(100, 200, 300, 435, 500, 650, 700, 800, 900, 1000);
  14.         $quality_list = array(50, 75, 100);
  15.     } elseif($_GET['t'] == 'c') {
  16.         $type = 'uploads/covers';
  17.         $width_list = array(48, 300, 800, 900, 1000);
  18.         $height_list = array(48, 100, 200, 300);
  19.         $quality_list = array(50, 75, 100);
  20.     } else {
  21.         exit('Invalid parameter value');
  22.     }
  23. } else {
  24.     exit('The \'t\' parameter is not set.');
  25. }
  26.  
  27. // Build up the src query
  28. $_GET['src'] = $CONF['url'].'/'.$type.'/'.$_GET['src'];
  29.  
  30. if(!empty($_GET['w'])) {
  31.     if(!in_array($_GET['w'], $width_list)) {
  32.         exit('Invalid width value.');
  33.     }
  34. }
  35.  
  36. if(!empty($_GET['h'])) {
  37.     if(!in_array($_GET['h'], $height_list)) {
  38.         exit('Invalid height value.');
  39.     }
  40. }
  41.  
  42. if(!empty($_GET['q'])) {
  43.     if(!in_array($_GET['q'], $quality_list)) {
  44.         exit('Invalid quality value.');
  45.     }
  46. }
  47.  
  48. define ('VERSION', '2.8.11');                                                                       // Version of this script
  49.  
  50. if(! defined('DEBUG_ON') )                  define ('DEBUG_ON', false);                             // Enable debug logging to web server error log (STDERR)
  51. if(! defined('DEBUG_LEVEL') )               define ('DEBUG_LEVEL', 1);                              // Debug level 1 is less noisy and 3 is the most noisy
  52. if(! defined('MEMORY_LIMIT') )              define ('MEMORY_LIMIT', '30M');                         // Set PHP memory limit
  53. if(! defined('BLOCK_EXTERNAL_LEECHERS') )   define ('BLOCK_EXTERNAL_LEECHERS', false);              // If the image or webshot is being loaded on an external site, display a red "No Hotlinking" gif.
  54.  
  55. //Image fetching and caching
  56. if(! defined('ALLOW_EXTERNAL') )            define ('ALLOW_EXTERNAL', TRUE);                        // Allow image fetching from external websites. Will check against ALLOWED_SITES if ALLOW_ALL_EXTERNAL_SITES is false
  57. if(! defined('ALLOW_ALL_EXTERNAL_SITES') )  define ('ALLOW_ALL_EXTERNAL_SITES', false);             // Less secure.
  58. if(! defined('FILE_CACHE_ENABLED') )        define ('FILE_CACHE_ENABLED', TRUE);                    // Should we store resized/modified images on disk to speed things up?
  59. if(! defined('FILE_CACHE_TIME_BETWEEN_CLEANS')) define ('FILE_CACHE_TIME_BETWEEN_CLEANS', 2592000000);  // How often the cache is cleaned
  60.  
  61. if(! defined('FILE_CACHE_MAX_FILE_AGE') )   define ('FILE_CACHE_MAX_FILE_AGE', 2592000000);             // How old does a file have to be to be deleted from the cache
  62. if(! defined('FILE_CACHE_SUFFIX') )         define ('FILE_CACHE_SUFFIX', '.thumb.txt');         // What to put at the end of all files in the cache directory so we can identify them
  63. if(! defined('FILE_CACHE_PREFIX') )         define ('FILE_CACHE_PREFIX', 'cache');              // What to put at the beg of all files in the cache directory so we can identify them
  64. if(! defined('FILE_CACHE_DIRECTORY') )      define ('FILE_CACHE_DIRECTORY', './cache');             // Directory where images are cached. Left blank it will use the system temporary directory (which is better for security)
  65. if(! defined('MAX_FILE_SIZE') )             define ('MAX_FILE_SIZE', 20485760);                     // 10 Megs is 10485760. This is the max internal or external file size that we'll process.  
  66. if(! defined('CURL_TIMEOUT') )              define ('CURL_TIMEOUT', 20);                            // Timeout duration for Curl. This only applies if you have Curl installed and aren't using PHP's default URL fetching mechanism.
  67. if(! defined('WAIT_BETWEEN_FETCH_ERRORS') ) define ('WAIT_BETWEEN_FETCH_ERRORS', 3600);             // Time to wait between errors fetching remote file
  68.  
  69. //Browser caching
  70. if(! defined('BROWSER_CACHE_MAX_AGE') )     define ('BROWSER_CACHE_MAX_AGE', 864000000);                // Time to cache in the browser
  71. if(! defined('BROWSER_CACHE_DISABLE') )     define ('BROWSER_CACHE_DISABLE', false);                // Use for testing if you want to disable all browser caching
  72.  
  73. //Image size and defaults
  74. if(! defined('MAX_WIDTH') )             define ('MAX_WIDTH', 1000);                                 // Maximum image width
  75. if(! defined('MAX_HEIGHT') )            define ('MAX_HEIGHT', 1000);                                // Maximum image height
  76. if(! defined('NOT_FOUND_IMAGE') )       define ('NOT_FOUND_IMAGE', '');                             // Image to serve if any 404 occurs
  77. if(! defined('ERROR_IMAGE') )           define ('ERROR_IMAGE', '');                                 // Image to serve if an error occurs instead of showing error message
  78. if(! defined('PNG_IS_TRANSPARENT') )    define ('PNG_IS_TRANSPARENT', FALSE);                       // Define if a png image should have a transparent background color. Use False value if you want to display a custom coloured canvas_colour
  79. if(! defined('DEFAULT_Q') )             define ('DEFAULT_Q', 90);                                   // Default image quality. Allows overrid in timthumb-config.php
  80. if(! defined('DEFAULT_ZC') )            define ('DEFAULT_ZC', 1);                                   // Default zoom/crop setting. Allows overrid in timthumb-config.php
  81. if(! defined('DEFAULT_F') )             define ('DEFAULT_F', '');                                   // Default image filters. Allows overrid in timthumb-config.php
  82. if(! defined('DEFAULT_S') )             define ('DEFAULT_S', 0);                                    // Default sharpen value. Allows overrid in timthumb-config.php
  83. if(! defined('DEFAULT_CC') )            define ('DEFAULT_CC', 'ffffff');                            // Default canvas colour. Allows overrid in timthumb-config.php
  84.  
  85.  
  86. //Image compression is enabled if either of these point to valid paths
  87.  
  88. //These are now disabled by default because the file sizes of PNGs (and GIFs) are much smaller than we used to generate.
  89. //They only work for PNGs. GIFs and JPEGs are not affected.
  90. if(! defined('OPTIPNG_ENABLED') )       define ('OPTIPNG_ENABLED', false);  
  91. if(! defined('OPTIPNG_PATH') )          define ('OPTIPNG_PATH', '/usr/bin/optipng'); //This will run first because it gives better compression than pngcrush.
  92. if(! defined('PNGCRUSH_ENABLED') )      define ('PNGCRUSH_ENABLED', false);
  93. if(! defined('PNGCRUSH_PATH') )         define ('PNGCRUSH_PATH', '/usr/bin/pngcrush'); //This will only run if OPTIPNG_PATH is not set or is not valid
  94.  
  95. // If ALLOW_EXTERNAL is true and ALLOW_ALL_EXTERNAL_SITES is false, then external images will only be fetched from these domains and their subdomains.
  96. if(! isset($ALLOWED_SITES)){
  97.     $ALLOWED_SITES = array (
  98.         'facebook.com',
  99.         'img.youtube.com',
  100.         'upload.wikimedia.org',
  101.         'imgur.com'
  102.     );
  103. }
  104. // -------------------------------------------------------------
  105. // -------------- STOP EDITING CONFIGURATION HERE --------------
  106. // -------------------------------------------------------------
  107.  
  108. timthumb::start();
  109.  
  110. class timthumb {
  111.     protected $src = "";
  112.     protected $is404 = false;
  113.     protected $docRoot = "";
  114.     protected $lastURLError = false;
  115.     protected $localImage = "";
  116.     protected $localImageMTime = 0;
  117.     protected $url = false;
  118.     protected $myHost = "";
  119.     protected $isURL = false;
  120.     protected $cachefile = '';
  121.     protected $errors = array();
  122.     protected $toDeletes = array();
  123.     protected $cacheDirectory = '';
  124.     protected $startTime = 0;
  125.     protected $lastBenchTime = 0;
  126.     protected $cropTop = false;
  127.     protected $salt = "";
  128.     protected $fileCacheVersion = 1; //Generally if timthumb.php is modifed (upgraded) then the salt changes and all cache files are recreated. This is a backup mechanism to force regen.
  129.     protected $filePrependSecurityBlock = "<?php die('Execution denied!'); //"; //Designed to have three letter mime type, space, question mark and greater than symbol appended. 6 bytes total.
  130.     protected static $curlDataWritten = 0;
  131.     protected static $curlFH = false;
  132.     public static function start(){
  133.         $tim = new timthumb();
  134.         $tim->handleErrors();
  135.         $tim->securityChecks();
  136.         if($tim->tryBrowserCache()){
  137.             exit(0);
  138.         }
  139.         $tim->handleErrors();
  140.         if(FILE_CACHE_ENABLED && $tim->tryServerCache()){
  141.             exit(0);
  142.         }
  143.         $tim->handleErrors();
  144.         $tim->run();
  145.         $tim->handleErrors();
  146.         exit(0);
  147.     }
  148.     public function __construct(){
  149.         global $ALLOWED_SITES;
  150.         $this->startTime = microtime(true);
  151.         date_default_timezone_set('UTC');
  152.         $this->debug(1, "Starting new request from " . $this->getIP() . " to " . $_SERVER['REQUEST_URI']);
  153.         $this->calcDocRoot();
  154.         //On windows systems I'm assuming fileinode returns an empty string or a number that doesn't change. Check this.
  155.         $this->salt = @filemtime(__FILE__) . '-' . @fileinode(__FILE__);
  156.         $this->debug(3, "Salt is: " . $this->salt);
  157.         if(FILE_CACHE_DIRECTORY){
  158.             if(! is_dir(FILE_CACHE_DIRECTORY)){
  159.                 @mkdir(FILE_CACHE_DIRECTORY);
  160.                 if(! is_dir(FILE_CACHE_DIRECTORY)){
  161.                     $this->error("Could not create the file cache directory.");
  162.                     return false;
  163.                 }
  164.             }
  165.             $this->cacheDirectory = FILE_CACHE_DIRECTORY;
  166.             if (!touch($this->cacheDirectory . '/index.html')) {
  167.                 $this->error("Could not create the index.html file - to fix this create an empty file named index.html file in the cache directory.");
  168.             }
  169.         } else {
  170.             $this->cacheDirectory = sys_get_temp_dir();
  171.         }
  172.         //Clean the cache before we do anything because we don't want the first visitor after FILE_CACHE_TIME_BETWEEN_CLEANS expires to get a stale image.
  173.         $this->cleanCache();
  174.        
  175.         $this->myHost = preg_replace('/^www\./i', '', $_SERVER['HTTP_HOST']);
  176.         $this->src = $this->param('src');
  177.         $this->url = parse_url($this->src);
  178.         $this->src = preg_replace('/https?:\/\/(?:www\.)?' . $this->myHost . '/i', '', $this->src);
  179.        
  180.         if(strlen($this->src) <= 3){
  181.             $this->error("No image specified");
  182.             return false;
  183.         }
  184.         if(BLOCK_EXTERNAL_LEECHERS && array_key_exists('HTTP_REFERER', $_SERVER) && (! preg_match('/^https?:\/\/(?:www\.)?' . $this->myHost . '(?:$|\/)/i', $_SERVER['HTTP_REFERER']))){
  185.             // base64 encoded red image that says 'no hotlinkers'
  186.             // nothing to worry about! :)
  187.             $imgData = base64_decode("R0lGODlhUAAMAIAAAP8AAP///yH5BAAHAP8ALAAAAABQAAwAAAJpjI+py+0Po5y0OgAMjjv01YUZ\nOGplhWXfNa6JCLnWkXplrcBmW+spbwvaVr/cDyg7IoFC2KbYVC2NQ5MQ4ZNao9Ynzjl9ScNYpneb\nDULB3RP6JuPuaGfuuV4fumf8PuvqFyhYtjdoeFgAADs=");
  188.             header('Content-Type: image/gif');
  189.             header('Content-Length: ' . sizeof($imgData));
  190.             header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
  191.             header("Pragma: no-cache");
  192.             header('Expires: ' . gmdate ('D, d M Y H:i:s', time()));
  193.             echo $imgData;
  194.             return false;
  195.             exit(0);
  196.         }
  197.         if(preg_match('/^https?:\/\/[^\/]+/i', $this->src)){
  198.             $this->debug(2, "Is a request for an external URL: " . $this->src);
  199.             $this->isURL = true;
  200.         } else {
  201.             $this->debug(2, "Is a request for an internal file: " . $this->src);
  202.         }
  203.         if($this->isURL && (! ALLOW_EXTERNAL)){
  204.             $this->error("You are not allowed to fetch images from an external website.");
  205.             return false;
  206.         }
  207.         if($this->isURL){
  208.             if(ALLOW_ALL_EXTERNAL_SITES){
  209.                 $this->debug(2, "Fetching from all external sites is enabled.");
  210.             } else {
  211.                 $this->debug(2, "Fetching only from selected external sites is enabled.");
  212.                 $allowed = false;
  213.                 foreach($ALLOWED_SITES as $site){
  214.                     if ((strtolower(substr($this->url['host'],-strlen($site)-1)) === strtolower(".$site")) || (strtolower($this->url['host'])===strtolower($site))) {
  215.                         $this->debug(3, "URL hostname {$this->url['host']} matches $site so allowing.");
  216.                         $allowed = true;
  217.                     }
  218.                 }
  219.                 if(! $allowed){
  220.                     return $this->error("You may not fetch images from that site. To enable this site in timthumb, you can either add it to \$ALLOWED_SITES and set ALLOW_EXTERNAL=true. Or you can set ALLOW_ALL_EXTERNAL_SITES=true, depending on your security needs.");
  221.                 }
  222.             }
  223.         }
  224.  
  225.         $cachePrefix = ($this->isURL ? '_ext_' : '_int_');
  226.         if($this->isURL){
  227.             $arr = explode('&', $_SERVER ['QUERY_STRING']);
  228.             asort($arr);
  229.             $this->cachefile = $this->cacheDirectory . '/' . FILE_CACHE_PREFIX . $cachePrefix . md5($this->salt . implode('', $arr) . $this->fileCacheVersion) . FILE_CACHE_SUFFIX;
  230.         } else {
  231.             $this->localImage = $this->getLocalImagePath($this->src);
  232.             if(! $this->localImage){
  233.                 $this->debug(1, "Could not find the local image: {$this->localImage}");
  234.                 $this->error("Could not find the internal image you specified.");
  235.                 $this->set404();
  236.                 return false;
  237.             }
  238.             $this->debug(1, "Local image path is {$this->localImage}");
  239.             $this->localImageMTime = @filemtime($this->localImage);
  240.             //We include the mtime of the local file in case in changes on disk.
  241.             $this->cachefile = $this->cacheDirectory . '/' . FILE_CACHE_PREFIX . $cachePrefix . md5($this->salt . $this->localImageMTime . $_SERVER ['QUERY_STRING'] . $this->fileCacheVersion) . FILE_CACHE_SUFFIX;
  242.         }
  243.         $this->debug(2, "Cache file is: " . $this->cachefile);
  244.  
  245.         return true;
  246.     }
  247.     public function __destruct(){
  248.         foreach($this->toDeletes as $del){
  249.             $this->debug(2, "Deleting temp file $del");
  250.             @unlink($del);
  251.         }
  252.     }
  253.     public function run(){
  254.         if($this->isURL){
  255.             if(! ALLOW_EXTERNAL){
  256.                 $this->debug(1, "Got a request for an external image but ALLOW_EXTERNAL is disabled so returning error msg.");
  257.                 $this->error("You are not allowed to fetch images from an external website.");
  258.                 return false;
  259.             }
  260.             $this->debug(3, "Got request for external image. Starting serveExternalImage.");
  261.             $this->serveExternalImage();
  262.         } else {
  263.             $this->debug(3, "Got request for internal image. Starting serveInternalImage()");
  264.             $this->serveInternalImage();
  265.         }
  266.         return true;
  267.     }
  268.     protected function handleErrors(){
  269.         if($this->haveErrors()){
  270.             if(NOT_FOUND_IMAGE && $this->is404()){
  271.                 if($this->serveImg(NOT_FOUND_IMAGE)){
  272.                     exit(0);
  273.                 } else {
  274.                     $this->error("Additionally, the 404 image that is configured could not be found or there was an error serving it.");
  275.                 }
  276.             }
  277.             if(ERROR_IMAGE){
  278.                 if($this->serveImg(ERROR_IMAGE)){
  279.                     exit(0);
  280.                 } else {
  281.                     $this->error("Additionally, the error image that is configured could not be found or there was an error serving it.");
  282.                 }
  283.             }
  284.             $this->serveErrors();
  285.             exit(0);
  286.         }
  287.         return false;
  288.     }
  289.     protected function tryBrowserCache(){
  290.         if(BROWSER_CACHE_DISABLE){ $this->debug(3, "Browser caching is disabled"); return false; }
  291.         if(!empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) ){
  292.             $this->debug(3, "Got a conditional get");
  293.             $mtime = false;
  294.             //We've already checked if the real file exists in the constructor
  295.             if(! is_file($this->cachefile)){
  296.                 //If we don't have something cached, regenerate the cached image.
  297.                 return false;
  298.             }
  299.             if($this->localImageMTime){
  300.                 $mtime = $this->localImageMTime;
  301.                 $this->debug(3, "Local real file's modification time is $mtime");
  302.             } else if(is_file($this->cachefile)){ //If it's not a local request then use the mtime of the cached file to determine the 304
  303.                 $mtime = @filemtime($this->cachefile);
  304.                 $this->debug(3, "Cached file's modification time is $mtime");
  305.             }
  306.             if(! $mtime){ return false; }
  307.  
  308.             $iftime = strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']);
  309.             $this->debug(3, "The conditional get's if-modified-since unixtime is $iftime");
  310.             if($iftime < 1){
  311.                 $this->debug(3, "Got an invalid conditional get modified since time. Returning false.");
  312.                 return false;
  313.             }
  314.             if($iftime < $mtime){ //Real file or cache file has been modified since last request, so force refetch.
  315.                 $this->debug(3, "File has been modified since last fetch.");
  316.                 return false;
  317.             } else { //Otherwise serve a 304
  318.                 $this->debug(3, "File has not been modified since last get, so serving a 304.");
  319.                 header ($_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified');
  320.                 $this->debug(1, "Returning 304 not modified");
  321.                 return true;
  322.             }
  323.         }
  324.         return false;
  325.     }
  326.     protected function tryServerCache(){
  327.         $this->debug(3, "Trying server cache");
  328.         if(file_exists($this->cachefile)){
  329.             $this->debug(3, "Cachefile {$this->cachefile} exists");
  330.             if($this->isURL){
  331.                 $this->debug(3, "This is an external request, so checking if the cachefile is empty which means the request failed previously.");
  332.                 if(filesize($this->cachefile) < 1){
  333.                     $this->debug(3, "Found an empty cachefile indicating a failed earlier request. Checking how old it is.");
  334.                     //Fetching error occured previously
  335.                     if(time() - @filemtime($this->cachefile) > WAIT_BETWEEN_FETCH_ERRORS){
  336.                         $this->debug(3, "File is older than " . WAIT_BETWEEN_FETCH_ERRORS . " seconds. Deleting and returning false so app can try and load file.");
  337.                         @unlink($this->cachefile);
  338.                         return false; //to indicate we didn't serve from cache and app should try and load
  339.                     } else {
  340.                         $this->debug(3, "Empty cachefile is still fresh so returning message saying we had an error fetching this image from remote host.");
  341.                         $this->set404();
  342.                         $this->error("An error occured fetching image.");
  343.                         return false;
  344.                     }
  345.                 }
  346.             } else {
  347.                 $this->debug(3, "Trying to serve cachefile {$this->cachefile}");
  348.             }
  349.             if($this->serveCacheFile()){
  350.                 $this->debug(3, "Succesfully served cachefile {$this->cachefile}");
  351.                 return true;
  352.             } else {
  353.                 $this->debug(3, "Failed to serve cachefile {$this->cachefile} - Deleting it from cache.");
  354.                 //Image serving failed. We can't retry at this point, but lets remove it from cache so the next request recreates it
  355.                 @unlink($this->cachefile);
  356.                 return true;
  357.             }
  358.         }
  359.     }
  360.     protected function error($err){
  361.         $this->debug(3, "Adding error message: $err");
  362.         $this->errors[] = $err;
  363.         return false;
  364.  
  365.     }
  366.     protected function haveErrors(){
  367.         if(sizeof($this->errors) > 0){
  368.             return true;
  369.         }
  370.         return false;
  371.     }
  372.     protected function serveErrors(){
  373.         header ($_SERVER['SERVER_PROTOCOL'] . ' 400 Bad Request');
  374.         $html = '<ul>';
  375.         foreach($this->errors as $err){
  376.             $html .= '<li>' . htmlentities($err) . '</li>';
  377.         }
  378.         $html .= '</ul>';
  379.         echo '<h1>An error has occured</h1>The following error(s) occured:<br />' . $html . '<br />';
  380.         echo '<br />Query String : ' . htmlentities ($_SERVER['QUERY_STRING']);
  381.         echo '<br />Cache Version : ' . VERSION . '</pre>';
  382.     }
  383.     protected function serveInternalImage(){
  384.         $this->debug(3, "Local image path is $this->localImage");
  385.         if(! $this->localImage){
  386.             $this->sanityFail("localImage not set after verifying it earlier in the code.");
  387.             return false;
  388.         }
  389.         $fileSize = filesize($this->localImage);
  390.         if($fileSize > MAX_FILE_SIZE){
  391.             $this->error("The file you specified is greater than the maximum allowed file size.");
  392.             return false;
  393.         }
  394.         if($fileSize <= 0){
  395.             $this->error("The file you specified is <= 0 bytes.");
  396.             return false;
  397.         }
  398.         $this->debug(3, "Calling processImageAndWriteToCache() for local image.");
  399.         if($this->processImageAndWriteToCache($this->localImage)){
  400.             $this->serveCacheFile();
  401.             return true;
  402.         } else {
  403.             return false;
  404.         }
  405.     }
  406.     protected function cleanCache(){
  407.         if (FILE_CACHE_TIME_BETWEEN_CLEANS < 0) {
  408.             return;
  409.         }
  410.         $this->debug(3, "cleanCache() called");
  411.         $lastCleanFile = $this->cacheDirectory . '/'. FILE_CACHE_PREFIX .'_lastCleanTime.touch';
  412.        
  413.         //If this is a new timthumb installation we need to create the file
  414.         if(! is_file($lastCleanFile)){
  415.             $this->debug(1, "File tracking last clean doesn't exist. Creating $lastCleanFile");
  416.             if (!touch($lastCleanFile)) {
  417.                 $this->error("Could not create cache clean timestamp file.");
  418.             }
  419.             return;
  420.         }
  421.         if(@filemtime($lastCleanFile) < (time() - FILE_CACHE_TIME_BETWEEN_CLEANS) ){ //Cache was last cleaned more than 1 day ago
  422.             $this->debug(1, "Cache was last cleaned more than " . FILE_CACHE_TIME_BETWEEN_CLEANS . " seconds ago. Cleaning now.");
  423.             // Very slight race condition here, but worst case we'll have 2 or 3 servers cleaning the cache simultaneously once a day.
  424.             if (!touch($lastCleanFile)) {
  425.                 $this->error("Could not create cache clean timestamp file.");
  426.             }
  427.             $files = glob($this->cacheDirectory . '/*' . FILE_CACHE_SUFFIX);
  428.             if ($files) {
  429.                 $timeAgo = time() - FILE_CACHE_MAX_FILE_AGE;
  430.                 foreach($files as $file){
  431.                     if(@filemtime($file) < $timeAgo){
  432.                         $this->debug(3, "Deleting cache file $file older than max age: " . FILE_CACHE_MAX_FILE_AGE . " seconds");
  433.                         @unlink($file);
  434.                     }
  435.                 }
  436.             }
  437.             return true;
  438.         } else {
  439.             $this->debug(3, "Cache was cleaned less than " . FILE_CACHE_TIME_BETWEEN_CLEANS . " seconds ago so no cleaning needed.");
  440.         }
  441.         return false;
  442.     }
  443.     protected function processImageAndWriteToCache($localImage){
  444.         $sData = getimagesize($localImage);
  445.         $origType = $sData[2];
  446.         $mimeType = $sData['mime'];
  447.  
  448.         $this->debug(3, "Mime type of image is $mimeType");
  449.         if(! preg_match('/^image\/(?:gif|jpg|jpeg|png)$/i', $mimeType)){
  450.             return $this->error("The image being resized is not a valid gif, jpg or png.");
  451.         }
  452.  
  453.         if (!function_exists ('imagecreatetruecolor')) {
  454.             return $this->error('GD Library Error: imagecreatetruecolor does not exist - please contact your webhost and ask them to install the GD library');
  455.         }
  456.  
  457.         if (function_exists ('imagefilter') && defined ('IMG_FILTER_NEGATE')) {
  458.             $imageFilters = array (
  459.                 1 => array (IMG_FILTER_NEGATE, 0),
  460.                 2 => array (IMG_FILTER_GRAYSCALE, 0),
  461.                 3 => array (IMG_FILTER_BRIGHTNESS, 1),
  462.                 4 => array (IMG_FILTER_CONTRAST, 1),
  463.                 5 => array (IMG_FILTER_COLORIZE, 4),
  464.                 6 => array (IMG_FILTER_EDGEDETECT, 0),
  465.                 7 => array (IMG_FILTER_EMBOSS, 0),
  466.                 8 => array (IMG_FILTER_GAUSSIAN_BLUR, 0),
  467.                 9 => array (IMG_FILTER_SELECTIVE_BLUR, 0),
  468.                 10 => array (IMG_FILTER_MEAN_REMOVAL, 0),
  469.                 11 => array (IMG_FILTER_SMOOTH, 0),
  470.             );
  471.         }
  472.  
  473.         // get standard input properties       
  474.         $new_width =  (int) abs ($this->param('w', 0));
  475.         $new_height = (int) abs ($this->param('h', 0));
  476.         $zoom_crop = (int) $this->param('zc', DEFAULT_ZC);
  477.         $quality = (int) abs ($this->param('q', DEFAULT_Q));
  478.         $align = $this->cropTop ? 't' : $this->param('a', 'c');
  479.         $filters = $this->param('f', DEFAULT_F);
  480.         $sharpen = (bool) $this->param('s', DEFAULT_S);
  481.         $canvas_color = $this->param('cc', DEFAULT_CC);
  482.         $canvas_trans = (bool) $this->param('ct', '1');
  483.  
  484.         // set default width and height if neither are set already
  485.         if ($new_width == 0 && $new_height == 0) {
  486.             $new_width = 1000;
  487.             $new_height = 1000;
  488.         }
  489.  
  490.         // ensure size limits can not be abused
  491.         $new_width = min ($new_width, MAX_WIDTH);
  492.         $new_height = min ($new_height, MAX_HEIGHT);
  493.  
  494.         // set memory limit to be able to have enough space to resize larger images
  495.         $this->setMemoryLimit();
  496.  
  497.         // open the existing image
  498.         $image = $this->openImage ($mimeType, $localImage);
  499.         if ($image === false) {
  500.             return $this->error('Unable to open image.');
  501.         }
  502.  
  503.         // Get original width and height
  504.         $width = imagesx ($image);
  505.         $height = imagesy ($image);
  506.         $origin_x = 0;
  507.         $origin_y = 0;
  508.  
  509.         // generate new w/h if not provided
  510.         if ($new_width && !$new_height) {
  511.             $new_height = floor ($height * ($new_width / $width));
  512.         } else if ($new_height && !$new_width) {
  513.             $new_width = floor ($width * ($new_height / $height));
  514.         }
  515.  
  516.         // scale down and add borders
  517.         if ($zoom_crop == 3) {
  518.  
  519.             $final_height = $height * ($new_width / $width);
  520.  
  521.             if ($final_height > $new_height) {
  522.                 $new_width = $width * ($new_height / $height);
  523.             } else {
  524.                 $new_height = $final_height;
  525.             }
  526.  
  527.         }
  528.  
  529.         // create a new true color image
  530.         $canvas = imagecreatetruecolor ($new_width, $new_height);
  531.         imagealphablending ($canvas, false);
  532.  
  533.         if (strlen($canvas_color) == 3) { //if is 3-char notation, edit string into 6-char notation
  534.             $canvas_color =  str_repeat(substr($canvas_color, 0, 1), 2) . str_repeat(substr($canvas_color, 1, 1), 2) . str_repeat(substr($canvas_color, 2, 1), 2);
  535.         } else if (strlen($canvas_color) != 6) {
  536.             $canvas_color = DEFAULT_CC; // on error return default canvas color
  537.         }
  538.  
  539.         $canvas_color_R = hexdec (substr ($canvas_color, 0, 2));
  540.         $canvas_color_G = hexdec (substr ($canvas_color, 2, 2));
  541.         $canvas_color_B = hexdec (substr ($canvas_color, 4, 2));
  542.  
  543.         // Create a new transparent color for image
  544.         // If is a png and PNG_IS_TRANSPARENT is false then remove the alpha transparency
  545.         // (and if is set a canvas color show it in the background)
  546.         if(preg_match('/^image\/png$/i', $mimeType) && !PNG_IS_TRANSPARENT && $canvas_trans){
  547.             $color = imagecolorallocatealpha ($canvas, $canvas_color_R, $canvas_color_G, $canvas_color_B, 127);    
  548.         }else{
  549.             $color = imagecolorallocatealpha ($canvas, $canvas_color_R, $canvas_color_G, $canvas_color_B, 0);
  550.         }
  551.  
  552.  
  553.         // Completely fill the background of the new image with allocated color.
  554.         imagefill ($canvas, 0, 0, $color);
  555.  
  556.         // scale down and add borders
  557.         if ($zoom_crop == 2) {
  558.  
  559.             $final_height = $height * ($new_width / $width);
  560.  
  561.             if ($final_height > $new_height) {
  562.  
  563.                 $origin_x = $new_width / 2;
  564.                 $new_width = $width * ($new_height / $height);
  565.                 $origin_x = round ($origin_x - ($new_width / 2));
  566.  
  567.             } else {
  568.  
  569.                 $origin_y = $new_height / 2;
  570.                 $new_height = $final_height;
  571.                 $origin_y = round ($origin_y - ($new_height / 2));
  572.  
  573.             }
  574.  
  575.         }
  576.  
  577.         // Restore transparency blending
  578.         imagesavealpha ($canvas, true);
  579.  
  580.         if ($zoom_crop > 0) {
  581.  
  582.             $src_x = $src_y = 0;
  583.             $src_w = $width;
  584.             $src_h = $height;
  585.  
  586.             $cmp_x = $width / $new_width;
  587.             $cmp_y = $height / $new_height;
  588.  
  589.             // calculate x or y coordinate and width or height of source
  590.             if ($cmp_x > $cmp_y) {
  591.  
  592.                 $src_w = round ($width / $cmp_x * $cmp_y);
  593.                 $src_x = round (($width - ($width / $cmp_x * $cmp_y)) / 2);
  594.  
  595.             } else if ($cmp_y > $cmp_x) {
  596.  
  597.                 $src_h = round ($height / $cmp_y * $cmp_x);
  598.                 $src_y = round (($height - ($height / $cmp_y * $cmp_x)) / 2);
  599.  
  600.             }
  601.  
  602.             // positional cropping!
  603.             if ($align) {
  604.                 if (strpos ($align, 't') !== false) {
  605.                     $src_y = 0;
  606.                 }
  607.                 if (strpos ($align, 'b') !== false) {
  608.                     $src_y = $height - $src_h;
  609.                 }
  610.                 if (strpos ($align, 'l') !== false) {
  611.                     $src_x = 0;
  612.                 }
  613.                 if (strpos ($align, 'r') !== false) {
  614.                     $src_x = $width - $src_w;
  615.                 }
  616.             }
  617.  
  618.             imagecopyresampled ($canvas, $image, $origin_x, $origin_y, $src_x, $src_y, $new_width, $new_height, $src_w, $src_h);
  619.  
  620.         } else {
  621.  
  622.             // copy and resize part of an image with resampling
  623.             imagecopyresampled ($canvas, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
  624.  
  625.         }
  626.  
  627.         if ($filters != '' && function_exists ('imagefilter') && defined ('IMG_FILTER_NEGATE')) {
  628.             // apply filters to image
  629.             $filterList = explode ('|', $filters);
  630.             foreach ($filterList as $fl) {
  631.  
  632.                 $filterSettings = explode (',', $fl);
  633.                 if (isset ($imageFilters[$filterSettings[0]])) {
  634.  
  635.                     for ($i = 0; $i < 4; $i ++) {
  636.                         if (!isset ($filterSettings[$i])) {
  637.                             $filterSettings[$i] = null;
  638.                         } else {
  639.                             $filterSettings[$i] = (int) $filterSettings[$i];
  640.                         }
  641.                     }
  642.  
  643.                     switch ($imageFilters[$filterSettings[0]][1]) {
  644.  
  645.                         case 1:
  646.  
  647.                             imagefilter ($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1]);
  648.                             break;
  649.  
  650.                         case 2:
  651.  
  652.                             imagefilter ($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1], $filterSettings[2]);
  653.                             break;
  654.  
  655.                         case 3:
  656.  
  657.                             imagefilter ($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1], $filterSettings[2], $filterSettings[3]);
  658.                             break;
  659.  
  660.                         case 4:
  661.  
  662.                             imagefilter ($canvas, $imageFilters[$filterSettings[0]][0], $filterSettings[1], $filterSettings[2], $filterSettings[3], $filterSettings[4]);
  663.                             break;
  664.  
  665.                         default:
  666.  
  667.                             imagefilter ($canvas, $imageFilters[$filterSettings[0]][0]);
  668.                             break;
  669.  
  670.                     }
  671.                 }
  672.             }
  673.         }
  674.  
  675.         // sharpen image
  676.         if ($sharpen && function_exists ('imageconvolution')) {
  677.  
  678.             $sharpenMatrix = array (
  679.                     array (-1,-1,-1),
  680.                     array (-1,16,-1),
  681.                     array (-1,-1,-1),
  682.                     );
  683.  
  684.             $divisor = 8;
  685.             $offset = 0;
  686.  
  687.             imageconvolution ($canvas, $sharpenMatrix, $divisor, $offset);
  688.  
  689.         }
  690.         //Straight from Wordpress core code. Reduces filesize by up to 70% for PNG's
  691.         if ( (IMAGETYPE_PNG == $origType || IMAGETYPE_GIF == $origType) && function_exists('imageistruecolor') && !imageistruecolor( $image ) && imagecolortransparent( $image ) > 0 ){
  692.             imagetruecolortopalette( $canvas, false, imagecolorstotal( $image ) );
  693.         }
  694.  
  695.         $imgType = "";
  696.         $tempfile = tempnam($this->cacheDirectory, 'timthumb_tmpimg_');
  697.         if(preg_match('/^image\/(?:jpg|jpeg)$/i', $mimeType)){
  698.             $imgType = 'jpg';
  699.             imagejpeg($canvas, $tempfile, $quality);
  700.         } else if(preg_match('/^image\/png$/i', $mimeType)){
  701.             $imgType = 'png';
  702.             imagepng($canvas, $tempfile, floor($quality * 0.09));
  703.         } else if(preg_match('/^image\/gif$/i', $mimeType)){
  704.             $imgType = 'gif';
  705.             imagegif($canvas, $tempfile);
  706.         } else {
  707.             return $this->sanityFail("Could not match mime type after verifying it previously.");
  708.         }
  709.  
  710.         if($imgType == 'png' && OPTIPNG_ENABLED && OPTIPNG_PATH && @is_file(OPTIPNG_PATH)){
  711.             $exec = OPTIPNG_PATH;
  712.             $this->debug(3, "optipng'ing $tempfile");
  713.             $presize = filesize($tempfile);
  714.             $out = `$exec -o1 $tempfile`; //you can use up to -o7 but it really slows things down
  715.             clearstatcache();
  716.             $aftersize = filesize($tempfile);
  717.             $sizeDrop = $presize - $aftersize;
  718.             if($sizeDrop > 0){
  719.                 $this->debug(1, "optipng reduced size by $sizeDrop");
  720.             } else if($sizeDrop < 0){
  721.                 $this->debug(1, "optipng increased size! Difference was: $sizeDrop");
  722.             } else {
  723.                 $this->debug(1, "optipng did not change image size.");
  724.             }
  725.         } else if($imgType == 'png' && PNGCRUSH_ENABLED && PNGCRUSH_PATH && @is_file(PNGCRUSH_PATH)){
  726.             $exec = PNGCRUSH_PATH;
  727.             $tempfile2 = tempnam($this->cacheDirectory, 'timthumb_tmpimg_');
  728.             $this->debug(3, "pngcrush'ing $tempfile to $tempfile2");
  729.             $out = `$exec $tempfile $tempfile2`;
  730.             $todel = "";
  731.             if(is_file($tempfile2)){
  732.                 $sizeDrop = filesize($tempfile) - filesize($tempfile2);
  733.                 if($sizeDrop > 0){
  734.                     $this->debug(1, "pngcrush was succesful and gave a $sizeDrop byte size reduction");
  735.                     $todel = $tempfile;
  736.                     $tempfile = $tempfile2;
  737.                 } else {
  738.                     $this->debug(1, "pngcrush did not reduce file size. Difference was $sizeDrop bytes.");
  739.                     $todel = $tempfile2;
  740.                 }
  741.             } else {
  742.                 $this->debug(3, "pngcrush failed with output: $out");
  743.                 $todel = $tempfile2;
  744.             }
  745.             @unlink($todel);
  746.         }
  747.  
  748.         $this->debug(3, "Rewriting image with security header.");
  749.         $tempfile4 = tempnam($this->cacheDirectory, 'timthumb_tmpimg_');
  750.         $context = stream_context_create ();
  751.         $fp = fopen($tempfile,'r',0,$context);
  752.         file_put_contents($tempfile4, $this->filePrependSecurityBlock . $imgType . ' ?' . '>'); //6 extra bytes, first 3 being image type
  753.         file_put_contents($tempfile4, $fp, FILE_APPEND);
  754.         fclose($fp);
  755.         @unlink($tempfile);
  756.         $this->debug(3, "Locking and replacing cache file.");
  757.         $lockFile = $this->cachefile . '.lock';
  758.         $fh = fopen($lockFile, 'w');
  759.         if(! $fh){
  760.             return $this->error("Could not open the lockfile for writing an image.");
  761.         }
  762.         if(flock($fh, LOCK_EX)){
  763.             @unlink($this->cachefile); //rename generally overwrites, but doing this in case of platform specific quirks. File might not exist yet.
  764.             rename($tempfile4, $this->cachefile);
  765.             flock($fh, LOCK_UN);
  766.             fclose($fh);
  767.             @unlink($lockFile);
  768.         } else {
  769.             fclose($fh);
  770.             @unlink($lockFile);
  771.             @unlink($tempfile4);
  772.             return $this->error("Could not get a lock for writing.");
  773.         }
  774.         $this->debug(3, "Done image replace with security header. Cleaning up and running cleanCache()");
  775.         imagedestroy($canvas);
  776.         imagedestroy($image);
  777.         return true;
  778.     }
  779.     protected function calcDocRoot(){
  780.         $docRoot = @$_SERVER['DOCUMENT_ROOT'];
  781.         if (defined('LOCAL_FILE_BASE_DIRECTORY')) {
  782.             $docRoot = LOCAL_FILE_BASE_DIRECTORY;  
  783.         }
  784.         if(!isset($docRoot)){
  785.             $this->debug(3, "DOCUMENT_ROOT is not set. This is probably windows. Starting search 1.");
  786.             if(isset($_SERVER['SCRIPT_FILENAME'])){
  787.                 $docRoot = str_replace( '\\', '/', substr($_SERVER['SCRIPT_FILENAME'], 0, 0-strlen($_SERVER['PHP_SELF'])));
  788.                 $this->debug(3, "Generated docRoot using SCRIPT_FILENAME and PHP_SELF as: $docRoot");
  789.             }
  790.         }
  791.         if(!isset($docRoot)){
  792.             $this->debug(3, "DOCUMENT_ROOT still is not set. Starting search 2.");
  793.             if(isset($_SERVER['PATH_TRANSLATED'])){
  794.                 $docRoot = str_replace( '\\', '/', substr(str_replace('\\\\', '\\', $_SERVER['PATH_TRANSLATED']), 0, 0-strlen($_SERVER['PHP_SELF'])));
  795.                 $this->debug(3, "Generated docRoot using PATH_TRANSLATED and PHP_SELF as: $docRoot");
  796.             }
  797.         }
  798.         if($docRoot && $_SERVER['DOCUMENT_ROOT'] != '/'){ $docRoot = preg_replace('/\/$/', '', $docRoot); }
  799.         $this->debug(3, "Doc root is: " . $docRoot);
  800.         $this->docRoot = $docRoot;
  801.  
  802.     }
  803.     protected function getLocalImagePath($src){
  804.         $src = ltrim($src, '/'); //strip off the leading '/'
  805.         if(! $this->docRoot){
  806.             $this->debug(3, "We have no document root set, so as a last resort, lets check if the image is in the current dir and serve that.");
  807.             //We don't support serving images outside the current dir if we don't have a doc root for security reasons.
  808.             $file = preg_replace('/^.*?([^\/\\\\]+)$/', '$1', $src); //strip off any path info and just leave the filename.
  809.             if(is_file($file)){
  810.                 return $this->realpath($file);
  811.             }
  812.             return $this->error("Could not find your website document root and the file specified doesn't exist in timthumbs directory. We don't support serving files outside timthumb's directory without a document root for security reasons.");
  813.         } //Do not go past this point without docRoot set
  814.  
  815.         //Try src under docRoot
  816.         if(file_exists ($this->docRoot . '/' . $src)) {
  817.             $this->debug(3, "Found file as " . $this->docRoot . '/' . $src);
  818.             $real = $this->realpath($this->docRoot . '/' . $src);
  819.             if(stripos($real, $this->docRoot) === 0){
  820.                 return $real;
  821.             } else {
  822.                 $this->debug(1, "Security block: The file specified occurs outside the document root.");
  823.                 //allow search to continue
  824.             }
  825.         }
  826.         //Check absolute paths and then verify the real path is under doc root
  827.         $absolute = $this->realpath('/' . $src);
  828.         if($absolute && file_exists($absolute)){ //realpath does file_exists check, so can probably skip the exists check here
  829.             $this->debug(3, "Found absolute path: $absolute");
  830.             if(! $this->docRoot){ $this->sanityFail("docRoot not set when checking absolute path."); }
  831.             if(stripos($absolute, $this->docRoot) === 0){
  832.                 return $absolute;
  833.             } else {
  834.                 $this->debug(1, "Security block: The file specified occurs outside the document root.");
  835.                 //and continue search
  836.             }
  837.         }
  838.        
  839.         $base = $this->docRoot;
  840.        
  841.         // account for Windows directory structure
  842.         if (strstr($_SERVER['SCRIPT_FILENAME'],':')) {
  843.             $sub_directories = explode('\\', str_replace($this->docRoot, '', $_SERVER['SCRIPT_FILENAME']));
  844.         } else {
  845.             $sub_directories = explode('/', str_replace($this->docRoot, '', $_SERVER['SCRIPT_FILENAME']));
  846.         }
  847.  
  848.         foreach ($sub_directories as $sub){
  849.             $base .= $sub . '/';
  850.             $this->debug(3, "Trying file as: " . $base . $src);
  851.             if(file_exists($base . $src)){
  852.                 $this->debug(3, "Found file as: " . $base . $src);
  853.                 $real = $this->realpath($base . $src);
  854.                 if(stripos($real, $this->realpath($this->docRoot)) === 0){
  855.                     return $real;
  856.                 } else {
  857.                     $this->debug(1, "Security block: The file specified occurs outside the document root.");
  858.                     //And continue search
  859.                 }
  860.             }
  861.         }
  862.         return false;
  863.     }
  864.     protected function realpath($path){
  865.         //try to remove any relative paths
  866.         $remove_relatives = '/\w+\/\.\.\//';
  867.         while(preg_match($remove_relatives,$path)){
  868.             $path = preg_replace($remove_relatives, '', $path);
  869.         }
  870.         //if any remain use PHP realpath to strip them out, otherwise return $path
  871.         //if using realpath, any symlinks will also be resolved
  872.         return preg_match('#^\.\./|/\.\./#', $path) ? realpath($path) : $path;
  873.     }
  874.     protected function toDelete($name){
  875.         $this->debug(3, "Scheduling file $name to delete on destruct.");
  876.         $this->toDeletes[] = $name;
  877.     }
  878.     protected function serveExternalImage(){
  879.         if(! preg_match('/^https?:\/\/[a-zA-Z0-9\-\.]+/i', $this->src)){
  880.             $this->error("Invalid URL supplied.");
  881.             return false;
  882.         }
  883.         $tempfile = tempnam($this->cacheDirectory, 'timthumb');
  884.         $this->debug(3, "Fetching external image into temporary file $tempfile");
  885.         $this->toDelete($tempfile);
  886.         #fetch file here
  887.         if(! $this->getURL($this->src, $tempfile)){
  888.             @unlink($this->cachefile);
  889.             touch($this->cachefile);
  890.             $this->debug(3, "Error fetching URL: " . $this->lastURLError);
  891.             $this->error("Error reading the URL you specified from remote host." . $this->lastURLError);
  892.             return false;
  893.         }
  894.  
  895.         $mimeType = $this->getMimeType($tempfile);
  896.         if(! preg_match("/^image\/(?:jpg|jpeg|gif|png)$/i", $mimeType)){
  897.             $this->debug(3, "Remote file has invalid mime type: $mimeType");
  898.             @unlink($this->cachefile);
  899.             touch($this->cachefile);
  900.             $this->error("The remote file is not a valid image. Mimetype = '" . $mimeType . "'" . $tempfile);
  901.             return false;
  902.         }
  903.         if($this->processImageAndWriteToCache($tempfile)){
  904.             $this->debug(3, "Image processed succesfully. Serving from cache");
  905.             return $this->serveCacheFile();
  906.         } else {
  907.             return false;
  908.         }
  909.     }
  910.     public static function curlWrite($h, $d){
  911.         fwrite(self::$curlFH, $d);
  912.         self::$curlDataWritten += strlen($d);
  913.         if(self::$curlDataWritten > MAX_FILE_SIZE){
  914.             return 0;
  915.         } else {
  916.             return strlen($d);
  917.         }
  918.     }
  919.     protected function serveCacheFile(){
  920.         $this->debug(3, "Serving {$this->cachefile}");
  921.         if(! is_file($this->cachefile)){
  922.             $this->error("serveCacheFile called in timthumb but we couldn't find the cached file.");
  923.             return false;
  924.         }
  925.         $fp = fopen($this->cachefile, 'rb');
  926.         if(! $fp){ return $this->error("Could not open cachefile."); }
  927.         fseek($fp, strlen($this->filePrependSecurityBlock), SEEK_SET);
  928.         $imgType = fread($fp, 3);
  929.         fseek($fp, 3, SEEK_CUR);
  930.         if(ftell($fp) != strlen($this->filePrependSecurityBlock) + 6){
  931.             @unlink($this->cachefile);
  932.             return $this->error("The cached image file seems to be corrupt.");
  933.         }
  934.         $imageDataSize = filesize($this->cachefile) - (strlen($this->filePrependSecurityBlock) + 6);
  935.         $this->sendImageHeaders($imgType, $imageDataSize);
  936.         $bytesSent = @fpassthru($fp);
  937.         fclose($fp);
  938.         if($bytesSent > 0){
  939.             return true;
  940.         }
  941.         $content = file_get_contents ($this->cachefile);
  942.         if ($content != FALSE) {
  943.             $content = substr($content, strlen($this->filePrependSecurityBlock) + 6);
  944.             echo $content;
  945.             $this->debug(3, "Served using file_get_contents and echo");
  946.             return true;
  947.         } else {
  948.             $this->error("Cache file could not be loaded.");
  949.             return false;
  950.         }
  951.     }
  952.     protected function sendImageHeaders($mimeType, $dataSize){
  953.         if(! preg_match('/^image\//i', $mimeType)){
  954.             $mimeType = 'image/' . $mimeType;
  955.         }
  956.         if(strtolower($mimeType) == 'image/jpg'){
  957.             $mimeType = 'image/jpeg';
  958.         }
  959.         $gmdate_expires = gmdate ('D, d M Y H:i:s', strtotime ('now +10 days')) . ' GMT';
  960.         $gmdate_modified = gmdate ('D, d M Y H:i:s') . ' GMT';
  961.         // send content headers then display image
  962.         header ('Content-Type: ' . $mimeType);
  963.         header ('Accept-Ranges: none'); //Changed this because we don't accept range requests
  964.         header ('Last-Modified: ' . $gmdate_modified);
  965.         header ('Content-Length: ' . $dataSize);
  966.         if(BROWSER_CACHE_DISABLE){
  967.             $this->debug(3, "Browser cache is disabled so setting non-caching headers.");
  968.             header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
  969.             header("Pragma: no-cache");
  970.             header('Expires: ' . gmdate ('D, d M Y H:i:s', time()));
  971.         } else {
  972.             $this->debug(3, "Browser caching is enabled");
  973.             header('Cache-Control: max-age=' . BROWSER_CACHE_MAX_AGE . ', must-revalidate');
  974.             header('Expires: ' . $gmdate_expires);
  975.         }
  976.         return true;
  977.     }
  978.     protected function securityChecks(){
  979.     }
  980.     protected function param($property, $default = ''){
  981.         if (isset ($_GET[$property])) {
  982.             return $_GET[$property];
  983.         } else {
  984.             return $default;
  985.         }
  986.     }
  987.     protected function openImage($mimeType, $src){
  988.         switch ($mimeType) {
  989.             case 'image/jpeg':
  990.                 $image = imagecreatefromjpeg ($src);
  991.                 break;
  992.  
  993.             case 'image/png':
  994.                 $image = imagecreatefrompng ($src);
  995.                 imagealphablending( $image, true );
  996.                 imagesavealpha( $image, true );
  997.                 break;
  998.  
  999.             case 'image/gif':
  1000.                 $image = imagecreatefromgif ($src);
  1001.                 break;
  1002.            
  1003.             default:
  1004.                 $this->error("Unrecognised mimeType");
  1005.         }
  1006.  
  1007.         return $image;
  1008.     }
  1009.     protected function getIP(){
  1010.         $rem = @$_SERVER["REMOTE_ADDR"];
  1011.         $ff = @$_SERVER["HTTP_X_FORWARDED_FOR"];
  1012.         $ci = @$_SERVER["HTTP_CLIENT_IP"];
  1013.         if(preg_match('/^(?:192\.168|172\.16|10\.|127\.)/', $rem)){
  1014.             if($ff){ return $ff; }
  1015.             if($ci){ return $ci; }
  1016.             return $rem;
  1017.         } else {
  1018.             if($rem){ return $rem; }
  1019.             if($ff){ return $ff; }
  1020.             if($ci){ return $ci; }
  1021.             return "UNKNOWN";
  1022.         }
  1023.     }
  1024.     protected function debug($level, $msg){
  1025.         if(DEBUG_ON && $level <= DEBUG_LEVEL){
  1026.             $execTime = sprintf('%.6f', microtime(true) - $this->startTime);
  1027.             $tick = sprintf('%.6f', 0);
  1028.             if($this->lastBenchTime > 0){
  1029.                 $tick = sprintf('%.6f', microtime(true) - $this->lastBenchTime);
  1030.             }
  1031.             $this->lastBenchTime = microtime(true);
  1032.             error_log("TimThumb Debug line " . __LINE__ . " [$execTime : $tick]: $msg");
  1033.         }
  1034.     }
  1035.     protected function sanityFail($msg){
  1036.         return $this->error("There is a problem in the timthumb code. Message: Please report this error at <a href='http://code.google.com/p/timthumb/issues/list'>timthumb's bug tracking page</a>: $msg");
  1037.     }
  1038.     protected function getMimeType($file){
  1039.         $info = getimagesize($file);
  1040.         if(is_array($info) && $info['mime']){
  1041.             return $info['mime'];
  1042.         }
  1043.         return '';
  1044.     }
  1045.     protected function setMemoryLimit(){
  1046.         $inimem = ini_get('memory_limit');
  1047.         $inibytes = timthumb::returnBytes($inimem);
  1048.         $ourbytes = timthumb::returnBytes(MEMORY_LIMIT);
  1049.         if($inibytes < $ourbytes){
  1050.             ini_set ('memory_limit', MEMORY_LIMIT);
  1051.             $this->debug(3, "Increased memory from $inimem to " . MEMORY_LIMIT);
  1052.         } else {
  1053.             $this->debug(3, "Not adjusting memory size because the current setting is " . $inimem . " and our size of " . MEMORY_LIMIT . " is smaller.");
  1054.         }
  1055.     }
  1056.     protected static function returnBytes($size_str){
  1057.         switch (substr ($size_str, -1))
  1058.         {
  1059.             case 'M': case 'm': return (int)$size_str * 1048576;
  1060.             case 'K': case 'k': return (int)$size_str * 1024;
  1061.             case 'G': case 'g': return (int)$size_str * 1073741824;
  1062.             default: return $size_str;
  1063.         }
  1064.     }
  1065.    
  1066.     protected function getURL($url, $tempfile){
  1067.         $this->lastURLError = false;
  1068.         $url = preg_replace('/ /', '%20', $url);
  1069.         if(function_exists('curl_init')){
  1070.             $this->debug(3, "Curl is installed so using it to fetch URL.");
  1071.             self::$curlFH = fopen($tempfile, 'w');
  1072.             if(! self::$curlFH){
  1073.                 $this->error("Could not open $tempfile for writing.");
  1074.                 return false;
  1075.             }
  1076.             self::$curlDataWritten = 0;
  1077.             $this->debug(3, "Fetching url with curl: $url");
  1078.             $curl = curl_init($url);
  1079.             curl_setopt ($curl, CURLOPT_TIMEOUT, CURL_TIMEOUT);
  1080.             curl_setopt ($curl, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.122 Safari/534.30");
  1081.             curl_setopt ($curl, CURLOPT_RETURNTRANSFER, TRUE);
  1082.             curl_setopt ($curl, CURLOPT_HEADER, 0);
  1083.             curl_setopt ($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
  1084.             curl_setopt ($curl, CURLOPT_WRITEFUNCTION, 'timthumb::curlWrite');
  1085.             @curl_setopt ($curl, CURLOPT_FOLLOWLOCATION, true);
  1086.             @curl_setopt ($curl, CURLOPT_MAXREDIRS, 10);
  1087.            
  1088.             $curlResult = curl_exec($curl);
  1089.             fclose(self::$curlFH);
  1090.             $httpStatus = curl_getinfo($curl, CURLINFO_HTTP_CODE);
  1091.             if($httpStatus == 404){
  1092.                 $this->set404();
  1093.             }
  1094.             if($httpStatus == 302){
  1095.                 $this->error("External Image is Redirecting. Try alternate image url");
  1096.                 return false;
  1097.             }
  1098.             if($curlResult){
  1099.                 curl_close($curl);
  1100.                 return true;
  1101.             } else {
  1102.                 $this->lastURLError = curl_error($curl);
  1103.                 curl_close($curl);
  1104.                 return false;
  1105.             }
  1106.         } else {
  1107.             $img = @file_get_contents ($url);
  1108.             if($img === false){
  1109.                 $err = error_get_last();
  1110.                 if(is_array($err) && $err['message']){
  1111.                     $this->lastURLError = $err['message'];
  1112.                 } else {
  1113.                     $this->lastURLError = $err;
  1114.                 }
  1115.                 if(preg_match('/404/', $this->lastURLError)){
  1116.                     $this->set404();
  1117.                 }
  1118.  
  1119.                 return false;
  1120.             }
  1121.             if(! file_put_contents($tempfile, $img)){
  1122.                 $this->error("Could not write to $tempfile.");
  1123.                 return false;
  1124.             }
  1125.             return true;
  1126.         }
  1127.  
  1128.     }
  1129.     protected function serveImg($file){
  1130.         $s = getimagesize($file);
  1131.         if(! ($s && $s['mime'])){
  1132.             return false;
  1133.         }
  1134.         header ('Content-Type: ' . $s['mime']);
  1135.         header ('Content-Length: ' . filesize($file) );
  1136.         header ('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
  1137.         header ("Pragma: no-cache");
  1138.         $bytes = @readfile($file);
  1139.         if($bytes > 0){
  1140.             return true;
  1141.         }
  1142.         $content = @file_get_contents ($file);
  1143.         if ($content != FALSE){
  1144.             echo $content;
  1145.             return true;
  1146.         }
  1147.         return false;
  1148.  
  1149.     }
  1150.     protected function set404(){
  1151.         $this->is404 = true;
  1152.     }
  1153.     protected function is404(){
  1154.         return $this->is404;
  1155.     }
  1156. }
Add Comment
Please, Sign In to add comment