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