1<?php 2////////////////////////////////////////////////////////////// 3// phpThumb() by James Heinrich <info@silisoftware.com> // 4// available at http://phpthumb.sourceforge.net // 5// and/or https://github.com/JamesHeinrich/phpThumb // 6////////////////////////////////////////////////////////////// 7/// // 8// See: phpthumb.changelog.txt for recent changes // 9// See: phpthumb.readme.txt for usage instructions // 10// /// 11////////////////////////////////////////////////////////////// 12 13error_reporting(E_ALL); 14ini_set('display_errors', '1'); 15 16// check for magic quotes in PHP < 7.4.0 (when these functions became deprecated) 17if (version_compare(PHP_VERSION, '7.4.0', '<')) { 18 ini_set('magic_quotes_runtime', '0'); 19 if (ini_get('magic_quotes_runtime')) { 20 die('"magic_quotes_runtime" is set in php.ini, cannot run phpThumb with this enabled'); 21 } 22} 23// Set a default timezone if web server has not done already in php.ini 24if (!ini_get('date.timezone') && function_exists('date_default_timezone_set')) { // PHP >= 5.1.0 25 date_default_timezone_set('UTC'); 26} 27$starttime = array_sum(explode(' ', microtime())); // could be called as microtime(true) for PHP 5.0.0+ 28 29// this script relies on the superglobal arrays, fake it here for old PHP versions 30if (PHP_VERSION < '4.1.0') { 31 $_SERVER = $HTTP_SERVER_VARS; 32 $_GET = $HTTP_GET_VARS; 33} 34 35function SendSaveAsFileHeaderIfNeeded($getimagesize=false) { 36 if (headers_sent()) { 37 return false; 38 } 39 global $phpThumb; 40 $downloadfilename = phpthumb_functions::SanitizeFilename(!empty($_GET['sia']) ? $_GET['sia'] : (!empty($_GET['down']) ? $_GET['down'] : 'phpThumb_generated_thumbnail.'.(!empty($_GET['f']) ? $_GET['f'] : 'jpg'))); 41 //if (empty($_GET['sia']) && empty($_GET['down']) && !empty($phpThumb->thumbnail_image_width) && !empty($phpThumb->thumbnail_image_height)) { 42 if (empty($_GET['sia']) && empty($_GET['down']) && !empty($getimagesize[0]) && !empty($getimagesize[1])) { 43 // if we know the output image dimensions we can generate a better default filename 44 $downloadfilename = phpthumb_functions::SanitizeFilename((!empty($phpThumb->src) ? basename($phpThumb->src) : md5($phpThumb->rawImageData)).'-'.intval($getimagesize[0]).'x'.intval($getimagesize[1]).'.'.(!empty($_GET['f']) ? $_GET['f'] : 'jpg')); 45 } 46 if (!empty($downloadfilename)) { 47 $phpThumb->DebugMessage('SendSaveAsFileHeaderIfNeeded() sending header: Content-Disposition: '.(!empty($_GET['down']) ? 'attachment' : 'inline').'; filename="'.$downloadfilename.'"', __FILE__, __LINE__); 48 header('Content-Disposition: '.(!empty($_GET['down']) ? 'attachment' : 'inline').'; filename="'.$downloadfilename.'"'); 49 } 50 return true; 51} 52 53function RedirectToCachedFile() { 54 global $phpThumb; 55 56 $nice_cachefile = str_replace(DIRECTORY_SEPARATOR, '/', $phpThumb->cache_filename); 57 $nice_docroot = str_replace(DIRECTORY_SEPARATOR, '/', rtrim($phpThumb->config_document_root, '/\\')); 58 59 $parsed_url = phpthumb_functions::ParseURLbetter(@$_SERVER['HTTP_REFERER']); 60 61 $nModified = filemtime($phpThumb->cache_filename); 62 63 if ($phpThumb->config_nooffsitelink_enabled && !empty($_SERVER['HTTP_REFERER']) && !in_array(@$parsed_url['host'], $phpThumb->config_nooffsitelink_valid_domains)) { 64 65 $phpThumb->DebugMessage('Would have used cached (image/'.$phpThumb->thumbnailFormat.') file "'.$phpThumb->cache_filename.'" (Last-Modified: '.gmdate('D, d M Y H:i:s', $nModified).' GMT), but skipping because $_SERVER[HTTP_REFERER] ('.@$_SERVER['HTTP_REFERER'].') is not in $phpThumb->config_nooffsitelink_valid_domains ('.implode(';', $phpThumb->config_nooffsitelink_valid_domains).')', __FILE__, __LINE__); 66 67 } elseif ($phpThumb->phpThumbDebug) { 68 69 $phpThumb->DebugTimingMessage('skipped using cached image', __FILE__, __LINE__); 70 $phpThumb->DebugMessage('Would have used cached file, but skipping due to phpThumbDebug', __FILE__, __LINE__); 71 $phpThumb->DebugMessage('* Would have sent headers (1): Last-Modified: '.gmdate('D, d M Y H:i:s', $nModified).' GMT', __FILE__, __LINE__); 72 if ($getimagesize = @getimagesize($phpThumb->cache_filename)) { 73 $phpThumb->DebugMessage('* Would have sent headers (2): Content-Type: '.phpthumb_functions::ImageTypeToMIMEtype($getimagesize[2]), __FILE__, __LINE__); 74 } 75 if (preg_match('#^'.preg_quote($nice_docroot).'(.*)$#', $nice_cachefile, $matches)) { 76 $phpThumb->DebugMessage('* Would have sent headers (3): Location: '.dirname($matches[1]).'/'.urlencode(basename($matches[1])), __FILE__, __LINE__); 77 } else { 78 $phpThumb->DebugMessage('* Would have sent data: file_get_contents('.$phpThumb->cache_filename.')', __FILE__, __LINE__); 79 } 80 81 } else { 82 83 if (headers_sent()) { 84 $phpThumb->ErrorImage('Headers already sent ('.basename(__FILE__).' line '.__LINE__.')'); 85 exit; 86 } 87 $getimagesize = @getimagesize($phpThumb->cache_filename); 88 SendSaveAsFileHeaderIfNeeded($getimagesize); 89 90 header('Pragma: private'); 91 header('Cache-Control: max-age='.$phpThumb->getParameter('config_cache_maxage')); 92 header('Expires: '.date(DATE_RFC1123, time() + $phpThumb->getParameter('config_cache_maxage'))); 93 if (!empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) && ($nModified == strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE'])) && !empty($_SERVER['SERVER_PROTOCOL'])) { 94 header('Last-Modified: '.gmdate('D, d M Y H:i:s', $nModified).' GMT'); 95 header($_SERVER['SERVER_PROTOCOL'].' 304 Not Modified'); 96 exit; 97 } 98 header('Last-Modified: '.gmdate('D, d M Y H:i:s', $nModified).' GMT'); 99 header('ETag: "'.md5_file($phpThumb->cache_filename).'"'); 100 if (!empty($getimagesize[2])) { 101 header('Content-Type: '.phpthumb_functions::ImageTypeToMIMEtype($getimagesize[2])); 102 } elseif (preg_match('#\\.ico$#i', $phpThumb->cache_filename)) { 103 header('Content-Type: image/x-icon'); 104 } 105 header('Content-Length: '.filesize($phpThumb->cache_filename)); 106 if (empty($phpThumb->config_cache_force_passthru) && preg_match('#^'.preg_quote($nice_docroot).'(.*)$#', $nice_cachefile, $matches)) { 107 header('Location: '.dirname($matches[1]).'/'.urlencode(basename($matches[1]))); 108 } else { 109 echo file_get_contents($phpThumb->cache_filename); 110 } 111 exit; 112 113 } 114 return true; 115} 116 117 118 119// instantiate a new phpThumb() object 120ob_start(); 121if (!include_once __DIR__ .'/phpthumb.class.php' ) { 122 ob_end_flush(); 123 die('failed to include_once("'.realpath( __DIR__ .'/phpthumb.class.php').'")'); 124} 125ob_end_clean(); 126$phpThumb = new phpThumb(); 127$phpThumb->DebugTimingMessage('phpThumb.php start', __FILE__, __LINE__, $starttime); 128$phpThumb->setParameter('config_error_die_on_error', true); 129 130if (!phpthumb_functions::FunctionIsDisabled('set_time_limit')) { 131 set_time_limit(60); // shouldn't take nearly this long in most cases, but with many filters and/or a slow server... 132} 133 134// phpThumbDebug[0] used to be here, but may reveal too much 135// info when high_security_mode should be enabled (not set yet) 136 137if (file_exists( __DIR__ .'/phpThumb.config.php')) { 138 ob_start(); 139 if (include_once __DIR__ .'/phpThumb.config.php' ) { 140 // great 141 } else { 142 ob_end_flush(); 143 $phpThumb->config_disable_debug = false; // otherwise error message won't print 144 $phpThumb->ErrorImage('failed to include_once('. __DIR__ .'/phpThumb.config.php) - realpath="'.realpath( __DIR__ .'/phpThumb.config.php').'"'); 145 } 146 ob_end_clean(); 147} elseif (file_exists( __DIR__ .'/phpThumb.config.php.default')) { 148 $phpThumb->config_disable_debug = false; // otherwise error message won't print 149 $phpThumb->ErrorImage('Please rename "phpThumb.config.php.default" to "phpThumb.config.php"'); 150} else { 151 $phpThumb->config_disable_debug = false; // otherwise error message won't print 152 $phpThumb->ErrorImage('failed to include_once('. __DIR__ .'/phpThumb.config.php) - realpath="'.realpath( __DIR__ .'/phpThumb.config.php').'"'); 153} 154 155if (!empty($PHPTHUMB_CONFIG)) { 156 foreach ($PHPTHUMB_CONFIG as $key => $value) { 157 $keyname = 'config_'.$key; 158 $phpThumb->setParameter($keyname, $value); 159 if (!preg_match('#(password|mysql)#i', $key)) { 160 $phpThumb->DebugMessage('setParameter('.$keyname.', '.$phpThumb->phpThumbDebugVarDump($value).')', __FILE__, __LINE__); 161 } 162 } 163 if (!$phpThumb->config_disable_debug) { 164 // if debug mode is enabled, force phpThumbDebug output, do not allow normal thumbnails to be generated 165 $_GET['phpThumbDebug'] = (!empty($_GET['phpThumbDebug']) ? max(1, (int) $_GET[ 'phpThumbDebug']) : 9); 166 $phpThumb->setParameter('phpThumbDebug', $_GET['phpThumbDebug']); 167 } 168} else { 169 $phpThumb->DebugMessage('$PHPTHUMB_CONFIG is empty', __FILE__, __LINE__); 170} 171 172if (empty($phpThumb->config_disable_pathinfo_parsing) && (empty($_GET) || isset($_GET['phpThumbDebug'])) && !empty($_SERVER['PATH_INFO'])) { 173 $_SERVER['PHP_SELF'] = str_replace($_SERVER['PATH_INFO'], '', @$_SERVER['PHP_SELF']); 174 175 $args = explode(';', substr($_SERVER['PATH_INFO'], 1)); 176 $phpThumb->DebugMessage('PATH_INFO.$args set to ('.implode(')(', $args).')', __FILE__, __LINE__); 177 if (!empty($args)) { 178 $_GET['src'] = @$args[count($args) - 1]; 179 $phpThumb->DebugMessage('PATH_INFO."src" = "'.$_GET['src'].'"', __FILE__, __LINE__); 180 if (preg_match('#^new\=([a-z0-9]+)#i', $_GET['src'], $matches)) { 181 unset($_GET['src']); 182 $_GET['new'] = $matches[1]; 183 } 184 } 185 if (preg_match('#^([\d]*)x?([\d]*)$#i', @$args[count($args) - 2], $matches)) { 186 $_GET['w'] = $matches[1]; 187 $_GET['h'] = $matches[2]; 188 $phpThumb->DebugMessage('PATH_INFO."w"x"h" set to "'.$_GET['w'].'"x"'.$_GET['h'].'"', __FILE__, __LINE__); 189 } 190 for ($i = 0; $i < count($args) - 2; $i++) { 191 @list($key, $value) = explode('=', @$args[$i]); 192 if (substr($key, -2) == '[]') { 193 $array_key_name = substr($key, 0, -2); 194 $_GET[$array_key_name][] = $value; 195 $phpThumb->DebugMessage('PATH_INFO."'.$array_key_name.'[]" = "'.$value.'"', __FILE__, __LINE__); 196 } else { 197 $_GET[$key] = $value; 198 $phpThumb->DebugMessage('PATH_INFO."'.$key.'" = "'.$value.'"', __FILE__, __LINE__); 199 } 200 } 201} 202 203if (!empty($phpThumb->config_high_security_enabled)) { 204 if (empty($_GET['hash'])) { 205 $phpThumb->config_disable_debug = false; // otherwise error message won't print 206 $phpThumb->ErrorImage('ERROR: missing hash'); 207 } elseif (phpthumb_functions::PasswordStrength($phpThumb->config_high_security_password) < 20) { 208 $phpThumb->config_disable_debug = false; // otherwise error message won't print 209 $phpThumb->ErrorImage('ERROR: $PHPTHUMB_CONFIG[high_security_password] is not complex enough'); 210 } elseif ($_GET['hash'] != hash_hmac('sha256', str_replace($phpThumb->config_high_security_url_separator.'hash='.$_GET['hash'], '', $_SERVER['QUERY_STRING']), $phpThumb->config_high_security_password)) { 211 header('HTTP/1.0 403 Forbidden'); 212 $phpThumb->ErrorImage('ERROR: invalid hash'); 213 } 214} 215 216//////////////////////////////////////////////////////////////// 217// Debug output, to try and help me diagnose problems 218$phpThumb->DebugTimingMessage('phpThumbDebug[0]', __FILE__, __LINE__); 219if (isset($_GET['phpThumbDebug']) && ($_GET['phpThumbDebug'] == '0')) { 220 $phpThumb->phpThumbDebug(); 221} 222//////////////////////////////////////////////////////////////// 223 224// check for magic quotes in PHP < 7.4.0 (when these functions became deprecated) 225if (version_compare(PHP_VERSION, '7.4.0', '<')) { 226 // returned the fixed string if the evil "magic_quotes_gpc" setting is on 227 if (get_magic_quotes_gpc()) { 228 // deprecated: 'err', 'file', 'goto', 229 $RequestVarsToStripSlashes = array('src', 'wmf', 'down'); 230 foreach ($RequestVarsToStripSlashes as $key) { 231 if (isset($_GET[$key])) { 232 if (is_string($_GET[$key])) { 233 $_GET[$key] = stripslashes($_GET[$key]); 234 } else { 235 unset($_GET[$key]); 236 } 237 } 238 } 239 } 240} 241 242if (empty($_SERVER['PATH_INFO']) && empty($_SERVER['QUERY_STRING'])) { 243 $phpThumb->config_disable_debug = false; // otherwise error message won't print 244 $phpThumb->ErrorImage('ERROR: no parameters specified'); 245} 246 247if (!empty($_GET['src']) && isset($_GET['md5s']) && empty($_GET['md5s'])) { 248 $md5s = ''; 249 if (preg_match('#^([a-z0-9]+)://#i', $_GET['src'], $protocol_matches)) { 250 if (preg_match('#^(f|ht)tps?://#i', $_GET['src'])) { 251 if ($rawImageData = phpthumb_functions::SafeURLread($_GET['src'], $error, $phpThumb->config_http_fopen_timeout, $phpThumb->config_http_follow_redirect)) { 252 $md5s = md5($rawImageData); 253 } 254 } else { 255 $phpThumb->ErrorImage('only FTP and HTTP/HTTPS protocols are allowed, "'.$protocol_matches[1].'" is not'); 256 } 257 } else { 258 $SourceFilename = $phpThumb->ResolveFilenameToAbsolute($_GET['src']); 259 if (is_readable($SourceFilename)) { 260 $md5s = phpthumb_functions::md5_file_safe($SourceFilename); 261 } else { 262 $phpThumb->ErrorImage('ERROR: "'.$SourceFilename.'" cannot be read'); 263 } 264 } 265 if (!empty($_SERVER['HTTP_REFERER'])) { 266 $phpThumb->ErrorImage('&md5s='.$md5s); 267 } else { 268 die('&md5s='.$md5s); 269 } 270} 271 272if (!empty($_GET['src']) && empty($phpThumb->config_allow_local_http_src) && preg_match('#^http://'.@$_SERVER['HTTP_HOST'].'(.+)#i', $_GET['src'], $matches)) { 273 $phpThumb->ErrorImage('It is MUCH better to specify the "src" parameter as "'.$matches[1].'" instead of "'.$matches[0].'".'."\n\n".'If you really must do it this way, enable "allow_local_http_src" in phpThumb.config.php'); 274} 275 276//////////////////////////////////////////////////////////////// 277// Debug output, to try and help me diagnose problems 278$phpThumb->DebugTimingMessage('phpThumbDebug[1]', __FILE__, __LINE__); 279if (isset($_GET['phpThumbDebug']) && ($_GET['phpThumbDebug'] == '1')) { 280 $phpThumb->phpThumbDebug(); 281} 282//////////////////////////////////////////////////////////////// 283 284$parsed_url_referer = phpthumb_functions::ParseURLbetter(@$_SERVER['HTTP_REFERER']); 285if ($phpThumb->config_nooffsitelink_require_refer && !in_array(@$parsed_url_referer['host'], $phpThumb->config_nohotlink_valid_domains)) { 286 $phpThumb->ErrorImage('config_nooffsitelink_require_refer enabled and '.(@$parsed_url_referer['host'] ? '"'.$parsed_url_referer['host'].'" is not an allowed referer' : 'no HTTP_REFERER exists')); 287} 288$parsed_url_src = phpthumb_functions::ParseURLbetter(@$_GET['src']); 289if ($phpThumb->config_nohotlink_enabled && $phpThumb->config_nohotlink_erase_image && preg_match('#^(f|ht)tps?://#i', @$_GET['src']) && !in_array(@$parsed_url_src['host'], $phpThumb->config_nohotlink_valid_domains)) { 290 $phpThumb->ErrorImage($phpThumb->config_nohotlink_text_message); 291} 292 293if ($phpThumb->config_mysql_query) { 294 if ($phpThumb->config_mysql_extension == 'mysqli') { 295 296 $found_missing_function = false; 297 foreach (array('mysqli_connect') as $required_mysqli_function) { 298 if (!function_exists($required_mysqli_function)) { 299 $found_missing_function = $required_mysqli_function; 300 break; 301 } 302 } 303 if ($found_missing_function) { 304 $phpThumb->ErrorImage('SQL function unavailable: '.$found_missing_function); 305 } else { 306 $mysqli = new mysqli($phpThumb->config_mysql_hostname, $phpThumb->config_mysql_username, $phpThumb->config_mysql_password, $phpThumb->config_mysql_database); 307 if ($mysqli->connect_error) { 308 $phpThumb->ErrorImage('MySQLi connect error ('.$mysqli->connect_errno.') '.$mysqli->connect_error); 309 } else { 310 if ($result = $mysqli->query($phpThumb->config_mysql_query)) { 311 if ($row = $result->fetch_array()) { 312 313 $result->free(); 314 $mysqli->close(); 315 $phpThumb->setSourceData($row[0]); 316 unset($row); 317 318 } else { 319 $result->free(); 320 $mysqli->close(); 321 $phpThumb->ErrorImage('no matching data in database.'); 322 } 323 } else { 324 $mysqli->close(); 325 $phpThumb->ErrorImage('Error in MySQL query: "'.$mysqli->error.'"'); 326 } 327 } 328 unset($_GET['id']); 329 } 330 331 } elseif ($phpThumb->config_mysql_extension == 'mysql') { 332 333 $found_missing_function = false; 334 //foreach (array('mysql_connect', 'mysql_select_db', 'mysql_query', 'mysql_fetch_array', 'mysql_free_result', 'mysql_close', 'mysql_error') as $required_mysql_function) { 335 foreach (array('mysql_connect') as $required_mysql_function) { 336 if (!function_exists($required_mysql_function)) { 337 $found_missing_function = $required_mysql_function; 338 break; 339 } 340 } 341 if ($found_missing_function) { 342 $phpThumb->ErrorImage('SQL function unavailable: '.$found_missing_function); 343 } else { 344 if ($cid = @mysql_connect($phpThumb->config_mysql_hostname, $phpThumb->config_mysql_username, $phpThumb->config_mysql_password)) { 345 if (@mysql_select_db($phpThumb->config_mysql_database, $cid)) { 346 if ($result = @mysql_query($phpThumb->config_mysql_query, $cid)) { 347 if ($row = @mysql_fetch_array($result)) { 348 349 mysql_free_result($result); 350 mysql_close($cid); 351 $phpThumb->setSourceData($row[0]); 352 unset($row); 353 354 } else { 355 mysql_free_result($result); 356 mysql_close($cid); 357 $phpThumb->ErrorImage('no matching data in database.'); 358 } 359 } else { 360 mysql_close($cid); 361 $phpThumb->ErrorImage('Error in MySQL query: "'.mysql_error($cid).'"'); 362 } 363 } else { 364 mysql_close($cid); 365 $phpThumb->ErrorImage('cannot select MySQL database: "'.mysql_error($cid).'"'); 366 } 367 } else { 368 $phpThumb->ErrorImage('cannot connect to MySQL server'); 369 } 370 unset($_GET['id']); 371 } 372 373 } else { 374 $phpThumb->ErrorImage('config_mysql_extension not supported'); 375 } 376} 377 378//////////////////////////////////////////////////////////////// 379// Debug output, to try and help me diagnose problems 380$phpThumb->DebugTimingMessage('phpThumbDebug[2]', __FILE__, __LINE__); 381if (isset($_GET['phpThumbDebug']) && ($_GET['phpThumbDebug'] == '2')) { 382 $phpThumb->phpThumbDebug(); 383} 384//////////////////////////////////////////////////////////////// 385 386$PHPTHUMB_DEFAULTS_DISABLEGETPARAMS = (bool) ($phpThumb->config_cache_default_only_suffix && (strpos($phpThumb->config_cache_default_only_suffix, '*') !== false)); 387 388// deprecated: 'err', 'file', 'goto', 389$allowedGETparameters = array('src', 'new', 'w', 'h', 'wp', 'hp', 'wl', 'hl', 'ws', 'hs', 'f', 'q', 'sx', 'sy', 'sw', 'sh', 'zc', 'ica', 'bc', 'bg', 'bgt', 'fltr', 'xto', 'ra', 'ar', 'aoe', 'far', 'iar', 'maxb', 'down', 'phpThumbDebug', 'hash', 'md5s', 'sfn', 'dpi', 'sia', 'nocache'); 390foreach ($_GET as $key => $value) { 391 if (!empty($PHPTHUMB_DEFAULTS_DISABLEGETPARAMS) && ($key != 'src')) { 392 // disabled, do not set parameter 393 $phpThumb->DebugMessage('ignoring $_GET['.$key.'] because of $PHPTHUMB_DEFAULTS_DISABLEGETPARAMS', __FILE__, __LINE__); 394 } elseif (in_array($key, $allowedGETparameters)) { 395 $phpThumb->DebugMessage('setParameter('.$key.', '.$phpThumb->phpThumbDebugVarDump($value).')', __FILE__, __LINE__); 396 $phpThumb->setParameter($key, $value); 397 } else { 398 $phpThumb->ErrorImage('Forbidden parameter: '.$key); 399 } 400} 401 402if (!empty($PHPTHUMB_DEFAULTS) && is_array($PHPTHUMB_DEFAULTS)) { 403 $phpThumb->DebugMessage('setting $PHPTHUMB_DEFAULTS['.implode(';', array_keys($PHPTHUMB_DEFAULTS)).']', __FILE__, __LINE__); 404 foreach ($PHPTHUMB_DEFAULTS as $key => $value) { 405 if (!$PHPTHUMB_DEFAULTS_GETSTRINGOVERRIDE || !isset($_GET[$key])) { // set parameter to default value if config is set to allow _GET to override default, OR if no value is passed via _GET for this parameter 406 //$_GET[$key] = $value; 407 //$phpThumb->DebugMessage('PHPTHUMB_DEFAULTS assigning ('.(is_array($value) ? print_r($value, true) : $value).') to $_GET['.$key.']', __FILE__, __LINE__); 408 $phpThumb->setParameter($key, $value); 409 $phpThumb->DebugMessage('setParameter('.$key.', '.$phpThumb->phpThumbDebugVarDump($value).') from $PHPTHUMB_DEFAULTS', __FILE__, __LINE__); 410 } 411 } 412} 413 414//////////////////////////////////////////////////////////////// 415// Debug output, to try and help me diagnose problems 416$phpThumb->DebugTimingMessage('phpThumbDebug[3]', __FILE__, __LINE__); 417if (isset($_GET['phpThumbDebug']) && ($_GET['phpThumbDebug'] == '3')) { 418 $phpThumb->phpThumbDebug(); 419} 420//////////////////////////////////////////////////////////////// 421 422//if (!@$_GET['phpThumbDebug'] && !is_file($phpThumb->sourceFilename) && !phpthumb_functions::gd_version()) { 423// if (!headers_sent()) { 424// // base64-encoded error image in GIF format 425// $ERROR_NOGD = 'R0lGODlhIAAgALMAAAAAABQUFCQkJDY2NkZGRldXV2ZmZnJycoaGhpSUlKWlpbe3t8XFxdXV1eTk5P7+/iwAAAAAIAAgAAAE/vDJSau9WILtTAACUinDNijZtAHfCojS4W5H+qxD8xibIDE9h0OwWaRWDIljJSkUJYsN4bihMB8th3IToAKs1VtYM75cyV8sZ8vygtOE5yMKmGbO4jRdICQCjHdlZzwzNW4qZSQmKDaNjhUMBX4BBAlmMywFSRWEmAI6b5gAlhNxokGhooAIK5o/pi9vEw4Lfj4OLTAUpj6IabMtCwlSFw0DCKBoFqwAB04AjI54PyZ+yY3TD0ss2YcVmN/gvpcu4TOyFivWqYJlbAHPpOntvxNAACcmGHjZzAZqzSzcq5fNjxFmAFw9iFRunD1epU6tsIPmFCAJnWYE0FURk7wJDA0MTKpEzoWAAskiAAA7'; 426// header('Content-Type: image/gif'); 427// echo base64_decode($ERROR_NOGD); 428// } else { 429// echo '*** ERROR: No PHP-GD support available ***'; 430// } 431// exit; 432//} 433 434// check to see if file can be output from source with no processing or caching 435$CanPassThroughDirectly = true; 436if ($phpThumb->rawImageData) { 437 // data from SQL, should be fine 438} elseif (preg_match('#^https?\\://[^\\?&]+\\.(jpe?g|gif|png|webp|avif)$#i', $phpThumb->src)) { 439 // assume is ok to passthru if no other parameters specified 440} elseif (preg_match('#^(f|ht)tps?\\://#i', $phpThumb->src)) { 441 $phpThumb->DebugMessage('$CanPassThroughDirectly=false because preg_match("#^(f|ht)tps?://#i", '.$phpThumb->src.')', __FILE__, __LINE__); 442 $CanPassThroughDirectly = false; 443} elseif (!@is_readable($phpThumb->sourceFilename)) { 444 $phpThumb->DebugMessage('$CanPassThroughDirectly=false because !@is_readable('.$phpThumb->sourceFilename.')', __FILE__, __LINE__); 445 $CanPassThroughDirectly = false; 446} elseif (!@is_file($phpThumb->sourceFilename)) { 447 $phpThumb->DebugMessage('$CanPassThroughDirectly=false because !@is_file('.$phpThumb->sourceFilename.')', __FILE__, __LINE__); 448 $CanPassThroughDirectly = false; 449} 450foreach ($_GET as $key => $value) { 451 switch ($key) { 452 case 'src': 453 // allowed 454 break; 455 456 case 'w': 457 case 'h': 458 // might be OK if exactly matches original 459 if (preg_match('#^https?\\://[^\\?&]+\\.(jpe?g|gif|png|webp|avif)$#i', $phpThumb->src)) { 460 // assume it is not ok for direct-passthru of remote image 461 $CanPassThroughDirectly = false; 462 } 463 break; 464 465 case 'phpThumbDebug': 466 // handled in direct-passthru code 467 break; 468 469 default: 470 // all other parameters will cause some processing, 471 // therefore cannot pass through original image unmodified 472 $CanPassThroughDirectly = false; 473 $UnAllowedGET[] = $key; 474 break; 475 } 476} 477if (!empty($UnAllowedGET)) { 478 $phpThumb->DebugMessage('$CanPassThroughDirectly=false because $_GET['.implode(';', array_unique($UnAllowedGET)).'] are set', __FILE__, __LINE__); 479} 480 481//////////////////////////////////////////////////////////////// 482// Debug output, to try and help me diagnose problems 483$phpThumb->DebugTimingMessage('phpThumbDebug[4]', __FILE__, __LINE__); 484if (isset($_GET['phpThumbDebug']) && ($_GET['phpThumbDebug'] == '4')) { 485 $phpThumb->phpThumbDebug(); 486} 487//////////////////////////////////////////////////////////////// 488 489$phpThumb->DebugMessage('$CanPassThroughDirectly="'. (int) $CanPassThroughDirectly .'" && $phpThumb->src="'.$phpThumb->src.'"', __FILE__, __LINE__); 490while ($CanPassThroughDirectly && $phpThumb->src) { 491 // no parameters set, passthru 492 493 if (preg_match('#^https?\\://[^\\?&]+\.(jpe?g|gif|png|webp|avif)$#i', $phpThumb->src)) { 494 $phpThumb->DebugMessage('Passing HTTP source through directly as Location: redirect ('.$phpThumb->src.')', __FILE__, __LINE__); 495 header('Location: '.$phpThumb->src); 496 exit; 497 } 498 499 $SourceFilename = $phpThumb->ResolveFilenameToAbsolute($phpThumb->src); 500 501 // security and size checks 502 if ($phpThumb->getimagesizeinfo = @getimagesize($SourceFilename)) { 503 $phpThumb->DebugMessage('Direct passthru getimagesize() returned [w='.$phpThumb->getimagesizeinfo[0].';h='.$phpThumb->getimagesizeinfo[1].';t='.$phpThumb->getimagesizeinfo[2].']', __FILE__, __LINE__); 504 505 if (!@$_GET['w'] && !@$_GET['wp'] && !@$_GET['wl'] && !@$_GET['ws'] && !@$_GET['h'] && !@$_GET['hp'] && !@$_GET['hl'] && !@$_GET['hs']) { 506 // no resizing needed 507 $phpThumb->DebugMessage('Passing "'.$SourceFilename.'" through directly, no resizing required ("'.$phpThumb->getimagesizeinfo[0].'"x"'.$phpThumb->getimagesizeinfo[1].'")', __FILE__, __LINE__); 508 } elseif (($phpThumb->getimagesizeinfo[0] <= @$_GET['w']) && ($phpThumb->getimagesizeinfo[1] <= @$_GET['h']) && ((@$_GET['w'] == $phpThumb->getimagesizeinfo[0]) || (@$_GET['h'] == $phpThumb->getimagesizeinfo[1]))) { 509 // image fits into 'w'x'h' box, and at least one dimension matches exactly, therefore no resizing needed 510 $phpThumb->DebugMessage('Passing "'.$SourceFilename.'" through directly, no resizing required ("'.$phpThumb->getimagesizeinfo[0].'"x"'.$phpThumb->getimagesizeinfo[1].'" fits inside "'.@$_GET['w'].'"x"'.@$_GET['h'].'")', __FILE__, __LINE__); 511 } else { 512 $phpThumb->DebugMessage('Not passing "'.$SourceFilename.'" through directly because resizing required (from "'.$phpThumb->getimagesizeinfo[0].'"x"'.$phpThumb->getimagesizeinfo[1].'" to "'.@$_GET['w'].'"x"'.@$_GET['h'].'")', __FILE__, __LINE__); 513 break; 514 } 515 switch ($phpThumb->getimagesizeinfo[2]) { 516 case IMAGETYPE_GIF: 517 case IMAGETYPE_JPEG: 518 case IMAGETYPE_PNG: 519 case IMAGETYPE_WEBP: 520 case IMAGETYPE_AVIF: 521 // great, let it through 522 break; 523 default: 524 // browser probably can't handle format, remangle it to JPEG/PNG/GIF 525 $phpThumb->DebugMessage('Not passing "'.$SourceFilename.'" through directly because $phpThumb->getimagesizeinfo[2] = "'.$phpThumb->getimagesizeinfo[2].'"', __FILE__, __LINE__); 526 break 2; 527 } 528 529 $ImageCreateFunctions = array( 530 IMAGETYPE_GIF => 'imagecreatefromgif', 531 IMAGETYPE_JPEG => 'imagecreatefromjpeg', 532 IMAGETYPE_PNG => 'imagecreatefrompng', 533 IMAGETYPE_WEBP => 'imagecreatefromwebp', 534 IMAGETYPE_AVIF => 'imagecreatefromavif', 535 ); 536 $theImageCreateFunction = @$ImageCreateFunctions[$phpThumb->getimagesizeinfo[2]]; 537 $dummyImage = false; 538 if ($phpThumb->config_disable_onlycreateable_passthru || (function_exists($theImageCreateFunction) && ($dummyImage = @$theImageCreateFunction($SourceFilename)))) { 539 540 // great 541 if (@is_resource($dummyImage) || (@is_object($dummyImage) && $dummyImage instanceOf \GdImage)) { 542 unset($dummyImage); 543 } 544 545 if (headers_sent()) { 546 $phpThumb->ErrorImage('Headers already sent ('.basename(__FILE__).' line '.__LINE__.')'); 547 exit; 548 } 549 if (!empty($_GET['phpThumbDebug'])) { 550 $phpThumb->DebugTimingMessage('skipped direct $SourceFilename passthru', __FILE__, __LINE__); 551 $phpThumb->DebugMessage('Would have passed "'.$SourceFilename.'" through directly, but skipping due to phpThumbDebug', __FILE__, __LINE__); 552 break; 553 } 554 555 SendSaveAsFileHeaderIfNeeded($phpThumb->getimagesizeinfo); 556 header('Last-Modified: '.gmdate('D, d M Y H:i:s', @filemtime($SourceFilename)).' GMT'); 557 if ($contentType = phpthumb_functions::ImageTypeToMIMEtype(@$phpThumb->getimagesizeinfo[2])) { 558 header('Content-Type: '.$contentType); 559 } 560 echo file_get_contents($SourceFilename); 561 exit; 562 563 } else { 564 $phpThumb->DebugMessage('Not passing "'.$SourceFilename.'" through directly because ($phpThumb->config_disable_onlycreateable_passthru = "'.$phpThumb->config_disable_onlycreateable_passthru.'") and '.$theImageCreateFunction.'() failed', __FILE__, __LINE__); 565 break; 566 } 567 568 } else { 569 $phpThumb->DebugMessage('Not passing "'.$SourceFilename.'" through directly because getimagesize() failed', __FILE__, __LINE__); 570 break; 571 } 572 break; 573} 574 575//////////////////////////////////////////////////////////////// 576// Debug output, to try and help me diagnose problems 577$phpThumb->DebugTimingMessage('phpThumbDebug[5]', __FILE__, __LINE__); 578if (isset($_GET['phpThumbDebug']) && ($_GET['phpThumbDebug'] == '5')) { 579 $phpThumb->phpThumbDebug(); 580} 581//////////////////////////////////////////////////////////////// 582 583// check to see if file already exists in cache, and output it with no processing if it does 584$phpThumb->SetCacheFilename(); 585if (@is_readable($phpThumb->cache_filename)) { 586 RedirectToCachedFile(); 587} else { 588 $phpThumb->DebugMessage('Cached file "'.$phpThumb->cache_filename.'" does not exist, processing as normal', __FILE__, __LINE__); 589} 590 591//////////////////////////////////////////////////////////////// 592// Debug output, to try and help me diagnose problems 593$phpThumb->DebugTimingMessage('phpThumbDebug[6]', __FILE__, __LINE__); 594if (isset($_GET['phpThumbDebug']) && ($_GET['phpThumbDebug'] == '6')) { 595 $phpThumb->phpThumbDebug(); 596} 597//////////////////////////////////////////////////////////////// 598 599if ($phpThumb->rawImageData) { 600 601 // great 602 603} elseif (!empty($_GET['new'])) { 604 605 // generate a blank image resource of the specified size/background color/opacity 606 if (($phpThumb->w <= 0) || ($phpThumb->h <= 0)) { 607 $phpThumb->ErrorImage('"w" and "h" parameters required for "new"'); 608 } 609 @list($bghexcolor, $opacity) = explode('|', $_GET['new']); 610 if (!phpthumb_functions::IsHexColor($bghexcolor)) { 611 $phpThumb->ErrorImage('BGcolor parameter for "new" is not valid'); 612 } 613 $opacity = ('' !== $opacity ? $opacity : 100); 614 if ($phpThumb->gdimg_source = phpthumb_functions::ImageCreateFunction($phpThumb->w, $phpThumb->h)) { 615 $alpha = (100 - min(100, max(0, $opacity))) * 1.27; 616 if ($alpha) { 617 $phpThumb->setParameter('is_alpha', true); 618 imagealphablending($phpThumb->gdimg_source, false); 619 imagesavealpha($phpThumb->gdimg_source, true); 620 } 621 $new_background_color = phpthumb_functions::ImageHexColorAllocate($phpThumb->gdimg_source, $bghexcolor, false, $alpha); 622 imagefilledrectangle($phpThumb->gdimg_source, 0, 0, $phpThumb->w, $phpThumb->h, $new_background_color); 623 } else { 624 $phpThumb->ErrorImage('failed to create "new" image ('.$phpThumb->w.'x'.$phpThumb->h.')'); 625 } 626 627} elseif (!$phpThumb->src) { 628 629 $phpThumb->ErrorImage('Usage: '.$_SERVER['PHP_SELF'].'?src=/path/and/filename.jpg'."\n".'read Usage comments for details'); 630 631} elseif (preg_match('#^([a-z0-9]+)://#i', $_GET['src'], $protocol_matches)) { 632 633 if (preg_match('#^(f|ht)tps?://#i', $_GET['src'])) { 634 $phpThumb->DebugMessage('$phpThumb->src ('.$phpThumb->src.') is remote image, attempting to download', __FILE__, __LINE__); 635 if ($phpThumb->config_http_user_agent) { 636 $phpThumb->DebugMessage('Setting "user_agent" to "'.$phpThumb->config_http_user_agent.'"', __FILE__, __LINE__); 637 ini_set('user_agent', $phpThumb->config_http_user_agent); 638 } 639 $cleanedupurl = phpthumb_functions::CleanUpURLencoding($phpThumb->src); 640 $phpThumb->DebugMessage('CleanUpURLencoding('.$phpThumb->src.') returned "'.$cleanedupurl.'"', __FILE__, __LINE__); 641 $phpThumb->src = $cleanedupurl; 642 unset($cleanedupurl); 643 if ($rawImageData = phpthumb_functions::SafeURLread($phpThumb->src, $error, $phpThumb->config_http_fopen_timeout, $phpThumb->config_http_follow_redirect)) { 644 $phpThumb->DebugMessage('SafeURLread('.$phpThumb->src.') succeeded'.($error ? ' with messages: "'.$error.'"' : ''), __FILE__, __LINE__); 645 $phpThumb->DebugMessage('Setting source data from URL "'.$phpThumb->src.'"', __FILE__, __LINE__); 646 $phpThumb->setSourceData($rawImageData, urlencode($phpThumb->src)); 647 } else { 648 $phpThumb->ErrorImage($error); 649 } 650 } else { 651 $phpThumb->ErrorImage('only FTP and HTTP/HTTPS protocols are allowed, "'.$protocol_matches[1].'" is not'); 652 } 653 654} 655 656//////////////////////////////////////////////////////////////// 657// Debug output, to try and help me diagnose problems 658$phpThumb->DebugTimingMessage('phpThumbDebug[7]', __FILE__, __LINE__); 659if (isset($_GET['phpThumbDebug']) && ($_GET['phpThumbDebug'] == '7')) { 660 $phpThumb->phpThumbDebug(); 661} 662//////////////////////////////////////////////////////////////// 663 664$phpThumb->GenerateThumbnail(); 665 666//////////////////////////////////////////////////////////////// 667// Debug output, to try and help me diagnose problems 668$phpThumb->DebugTimingMessage('phpThumbDebug[8]', __FILE__, __LINE__); 669if (isset($_GET['phpThumbDebug']) && ($_GET['phpThumbDebug'] == '8')) { 670 $phpThumb->phpThumbDebug(); 671} 672//////////////////////////////////////////////////////////////// 673 674if (!empty($phpThumb->config_high_security_enabled) && !empty($_GET['nocache'])) { 675 676 // cache disabled, don't write cachefile 677 678} else { 679 680 phpthumb_functions::EnsureDirectoryExists(dirname($phpThumb->cache_filename)); 681 if (is_writable(dirname($phpThumb->cache_filename)) || (file_exists($phpThumb->cache_filename) && is_writable($phpThumb->cache_filename))) { 682 683 $phpThumb->CleanUpCacheDirectory(); 684 if ($phpThumb->RenderToFile($phpThumb->cache_filename) && is_readable($phpThumb->cache_filename)) { 685 chmod($phpThumb->cache_filename, 0644); 686 RedirectToCachedFile(); 687 } else { 688 $phpThumb->DebugMessage('Failed: RenderToFile('.$phpThumb->cache_filename.')', __FILE__, __LINE__); 689 } 690 691 } else { 692 693 $phpThumb->DebugMessage('Cannot write to $phpThumb->cache_filename ('.$phpThumb->cache_filename.') because that directory ('.dirname($phpThumb->cache_filename).') is not writable', __FILE__, __LINE__); 694 695 } 696 697} 698 699//////////////////////////////////////////////////////////////// 700// Debug output, to try and help me diagnose problems 701$phpThumb->DebugTimingMessage('phpThumbDebug[9]', __FILE__, __LINE__); 702if (isset($_GET['phpThumbDebug']) && ($_GET['phpThumbDebug'] == '9')) { 703 $phpThumb->phpThumbDebug(); 704} 705//////////////////////////////////////////////////////////////// 706 707if (!$phpThumb->OutputThumbnail()) { 708 $phpThumb->ErrorImage('Error in OutputThumbnail():'."\n". $phpThumb->debugmessages[ count($phpThumb->debugmessages) - 1 ]); 709} 710 711//////////////////////////////////////////////////////////////// 712// Debug output, to try and help me diagnose problems 713$phpThumb->DebugTimingMessage('phpThumbDebug[10]', __FILE__, __LINE__); 714if (isset($_GET['phpThumbDebug']) && ($_GET['phpThumbDebug'] == '10')) { 715 $phpThumb->phpThumbDebug(); 716} 717//////////////////////////////////////////////////////////////// 718