root/releases/elgg0.8rc2/lib/phpthumb/phpThumb.php

Revision 421, 28.0 kB (checked in by sven, 3 years ago)

icons: upgrade phpthumb to 1.7.2 and move it to lib/
change icons to be output through a function rather than the bundled phpThumb.php, to allow greater control over security

  • Property svn:eol-style set to native
Line 
1 <?php
2
3 die("no");
4
5 //////////////////////////////////////////////////////////////
6 ///  phpThumb() by James Heinrich <info@silisoftware.com>   //
7 //        available at http://phpthumb.sourceforge.net     ///
8 //////////////////////////////////////////////////////////////
9 ///                                                         //
10 // See: phpthumb.changelog.txt for recent changes           //
11 // See: phpthumb.readme.txt for usage instructions          //
12 //                                                         ///
13 //////////////////////////////////////////////////////////////
14
15 error_reporting(E_ALL);
16 ini_set('display_errors', '1');
17 if (!@ini_get('safe_mode')) {
18     set_time_limit(60);  // shouldn't take nearly this long in most cases, but with many filter and/or a slow server...
19 }
20 ini_set('magic_quotes_runtime', '0');
21 if (@ini_get('magic_quotes_runtime')) {
22     die('"magic_quotes_runtime" is set in php.ini, cannot run phpThumb with this enabled');
23 }
24 $starttime = array_sum(explode(' ', microtime()));
25
26 // this script relies on the superglobal arrays, fake it here for old PHP versions
27 if (phpversion() < '4.1.0') {
28     $_SERVER = $HTTP_SERVER_VARS;
29     $_GET    = $HTTP_GET_VARS;
30 }
31
32 // instantiate a new phpThumb() object
33 ob_start();
34 if (!include_once(dirname(__FILE__).'/phpthumb.class.php')) {
35     ob_end_flush();
36     die('failed to include_once("'.realpath(dirname(__FILE__).'/phpthumb.class.php').'")');
37 }
38 ob_end_clean();
39 $phpThumb = new phpThumb();
40 $phpThumb->DebugTimingMessage('phpThumb.php start', __FILE__, __LINE__, $starttime);
41
42 // phpThumbDebug[0] used to be here, but may reveal too much
43 // info when high_security_mode should be enabled (not set yet)
44
45 if (file_exists(dirname(__FILE__).'/phpThumb.config.php')) {
46     ob_start();
47     if (include_once(dirname(__FILE__).'/phpThumb.config.php')) {
48         // great
49     } else {
50         ob_end_flush();
51         $phpThumb->ErrorImage('failed to include_once('.dirname(__FILE__).'/phpThumb.config.php) - realpath="'.realpath(dirname(__FILE__).'/phpThumb.config.php').'"');
52     }
53     ob_end_clean();
54 } elseif (file_exists(dirname(__FILE__).'/phpThumb.config.php.default')) {
55     $phpThumb->ErrorImage('Please rename "phpThumb.config.php.default" to "phpThumb.config.php"');
56 } else {
57     $phpThumb->ErrorImage('failed to include_once('.dirname(__FILE__).'/phpThumb.config.php) - realpath="'.realpath(dirname(__FILE__).'/phpThumb.config.php').'"');
58 }
59
60 if (!@$PHPTHUMB_CONFIG['disable_pathinfo_parsing'] && (empty($_GET) || isset($_GET['phpThumbDebug'])) && !empty($_SERVER['PATH_INFO'])) {
61     $_SERVER['PHP_SELF'] = str_replace($_SERVER['PATH_INFO'], '', @$_SERVER['PHP_SELF']);
62
63     $args = explode(';', substr($_SERVER['PATH_INFO'], 1));
64     $phpThumb->DebugMessage('PATH_INFO.$args set to ('.implode(')(', $args).')', __FILE__, __LINE__);
65     if (!empty($args)) {
66         $_GET['src'] = @$args[count($args) - 1];
67         if (eregi('^new\=([a-z0-9]+)', $_GET['src'], $matches)) {
68             unset($_GET['src']);
69             $_GET['new'] = $matches[1];
70         }
71     }
72     if (eregi('^([0-9]*)x?([0-9]*)$', @$args[count($args) - 2], $matches)) {
73         $_GET['w'] = $matches[1];
74         $_GET['h'] = $matches[2];
75         $phpThumb->DebugMessage('PATH_INFO."w"x"h" set to "'.$_GET['w'].'"x"'.$_GET['h'].'"', __FILE__, __LINE__);
76     }
77     for ($i = 0; $i < count($args) - 2; $i++) {
78         @list($key, $value) = explode('=', @$args[$i]);
79         if (substr($key, -2) == '[]') {
80             $array_key_name = substr($key, 0, -2);
81             $_GET[$array_key_name][] = $value;
82             $phpThumb->DebugMessage('PATH_INFO."'.$array_key_name.'[]" = "'.$value.'"', __FILE__, __LINE__);
83         } else {
84             $_GET[$key] = $value;
85             $phpThumb->DebugMessage('PATH_INFO."'.$key.'" = "'.$value.'"', __FILE__, __LINE__);
86         }
87     }
88 }
89
90 if (@$PHPTHUMB_CONFIG['high_security_enabled']) {
91     if (!@$_GET['hash']) {
92         $phpThumb->ErrorImage('ERROR: missing hash');
93     } elseif (strlen($PHPTHUMB_CONFIG['high_security_password']) < 5) {
94         $phpThumb->ErrorImage('ERROR: strlen($PHPTHUMB_CONFIG[high_security_password]) < 5');
95     } elseif ($_GET['hash'] != md5(str_replace('&hash='.$_GET['hash'], '', $_SERVER['QUERY_STRING']).$PHPTHUMB_CONFIG['high_security_password'])) {
96         $phpThumb->ErrorImage('ERROR: invalid hash');
97     }
98 }
99
100 ////////////////////////////////////////////////////////////////
101 // Debug output, to try and help me diagnose problems
102 $phpThumb->DebugTimingMessage('phpThumbDebug[0]', __FILE__, __LINE__);
103 if (@$_GET['phpThumbDebug'] == '0') {
104     $phpThumb->phpThumbDebug();
105 }
106 ////////////////////////////////////////////////////////////////
107
108 // returned the fixed string if the evil "magic_quotes_gpc" setting is on
109 if (get_magic_quotes_gpc()) {
110     $RequestVarsToStripSlashes = array('src', 'wmf', 'file', 'err', 'goto', 'down');
111     foreach ($RequestVarsToStripSlashes as $dummy => $key) {
112         if (isset($_GET[$key])) {
113             $_GET[$key] = stripslashes($_GET[$key]);
114         }
115     }
116 }
117
118 if (!@$_SERVER['PATH_INFO'] && !@$_SERVER['QUERY_STRING']) {
119     echo 'phpThumb() v'.$phpThumb->phpthumb_version.'<br><a href="http://phpthumb.sourceforge.net">http://phpthumb.sourceforge.net</a><br><br>ERROR: no parameters specified';
120     unset($phpThumb);
121     exit;
122 }
123
124 if (@$_GET['src'] && isset($_GET['md5s']) && empty($_GET['md5s'])) {
125     if (eregi('^(f|ht)tps?://', $_GET['src'])) {
126         if ($rawImageData = phpthumb_functions::SafeURLread($_GET['src'], $error)) {
127             $md5s = md5($rawImageData);
128         }
129     } else {
130         $SourceFilename = $phpThumb->ResolveFilenameToAbsolute($_GET['src']);
131         if (is_readable($SourceFilename)) {
132             $md5s = phpthumb_functions::md5_file_safe($SourceFilename);
133         } else {
134             $phpThumb->ErrorImage('ERROR: "'.$SourceFilename.'" cannot be read');
135         }
136     }
137     if (@$_SERVER['HTTP_REFERER']) {
138         $phpThumb->ErrorImage('&md5s='.$md5s);
139     } else {
140         die('&md5s='.$md5s);
141     }
142 }
143
144 if (!empty($PHPTHUMB_CONFIG)) {
145     foreach ($PHPTHUMB_CONFIG as $key => $value) {
146         $keyname = 'config_'.$key;
147         $phpThumb->setParameter($keyname, $value);
148         if (!eregi('password', $key)) {
149             $phpThumb->DebugMessage('setParameter('.$keyname.', '.$phpThumb->phpThumbDebugVarDump($value).')', __FILE__, __LINE__);
150         }
151     }
152 } else {
153     $phpThumb->DebugMessage('$PHPTHUMB_CONFIG is empty', __FILE__, __LINE__);
154 }
155
156 if (@$_GET['src'] && !@$PHPTHUMB_CONFIG['allow_local_http_src'] && eregi('^http://'.@$_SERVER['HTTP_HOST'].'(.+)', @$_GET['src'], $matches)) {
157     $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');
158 }
159
160 ////////////////////////////////////////////////////////////////
161 // Debug output, to try and help me diagnose problems
162 $phpThumb->DebugTimingMessage('phpThumbDebug[1]', __FILE__, __LINE__);
163 if (@$_GET['phpThumbDebug'] == '1') {
164     $phpThumb->phpThumbDebug();
165 }
166 ////////////////////////////////////////////////////////////////
167
168 $parsed_url_referer = parse_url(@$_SERVER['HTTP_REFERER']);
169 if ($phpThumb->config_nooffsitelink_require_refer && !in_array(@$parsed_url_referer['host'], $phpThumb->config_nohotlink_valid_domains)) {
170     $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'));
171 }
172 $parsed_url_src = parse_url(@$_GET['src']);
173 if ($phpThumb->config_nohotlink_enabled && $phpThumb->config_nohotlink_erase_image && eregi('^(f|ht)tps?://', @$_GET['src']) && !in_array(@$parsed_url_src['host'], $phpThumb->config_nohotlink_valid_domains)) {
174     $phpThumb->ErrorImage($phpThumb->config_nohotlink_text_message);
175 }
176
177 if ($phpThumb->config_mysql_query) {
178     if ($cid = @mysql_connect($phpThumb->config_mysql_hostname, $phpThumb->config_mysql_username, $phpThumb->config_mysql_password)) {
179         if (@mysql_select_db($phpThumb->config_mysql_database, $cid)) {
180             if ($result = @mysql_query($phpThumb->config_mysql_query, $cid)) {
181                 if ($row = @mysql_fetch_array($result)) {
182
183                     mysql_free_result($result);
184                     mysql_close($cid);
185                     $phpThumb->setSourceData($row[0]);
186                     unset($row);
187
188                 } else {
189                     mysql_free_result($result);
190                     mysql_close($cid);
191                     $phpThumb->ErrorImage('no matching data in database.');
192                 }
193             } else {
194                 mysql_close($cid);
195                 $phpThumb->ErrorImage('Error in MySQL query: "'.mysql_error($cid).'"');
196             }
197         } else {
198             mysql_close($cid);
199             $phpThumb->ErrorImage('cannot select MySQL database: "'.mysql_error($cid).'"');
200         }
201     } else {
202         $phpThumb->ErrorImage('cannot connect to MySQL server');
203     }
204     unset($_GET['id']);
205 }
206
207 ////////////////////////////////////////////////////////////////
208 // Debug output, to try and help me diagnose problems
209 $phpThumb->DebugTimingMessage('phpThumbDebug[2]', __FILE__, __LINE__);
210 if (@$_GET['phpThumbDebug'] == '2') {
211     $phpThumb->phpThumbDebug();
212 }
213 ////////////////////////////////////////////////////////////////
214
215 if (@$PHPTHUMB_CONFIG['cache_default_only_suffix'] && (strpos($PHPTHUMB_CONFIG['cache_default_only_suffix'], '*') !== false)) {
216     $PHPTHUMB_DEFAULTS_DISABLEGETPARAMS = true;
217 }
218 $allowedGETparameters = array('src', 'new', 'w', 'h', 'wp', 'hp', 'wl', 'hl', 'ws', 'hs', 'f', 'q', 'sx', 'sy', 'sw', 'sh', 'zc', 'bc', 'bg', 'bgt', 'fltr', 'file', 'goto', 'err', 'xto', 'ra', 'ar', 'aoe', 'far', 'iar', 'maxb', 'down', 'phpThumbDebug', 'hash', 'md5s');
219 if (!empty($PHPTHUMB_DEFAULTS) && is_array($PHPTHUMB_DEFAULTS)) {
220     $phpThumb->DebugMessage('setting $PHPTHUMB_DEFAULTS['.implode(';', array_keys($PHPTHUMB_DEFAULTS)).']', __FILE__, __LINE__);
221     foreach ($PHPTHUMB_DEFAULTS as $key => $value) {
222         if ($PHPTHUMB_DEFAULTS_GETSTRINGOVERRIDE || !isset($_GET[$key])) {
223             $_GET[$key] = $value;
224             $phpThumb->DebugMessage('PHPTHUMB_DEFAULTS assigning ('.$value.') to $_GET['.$key.']', __FILE__, __LINE__);
225             //$phpThumb->DebugMessage('PHPTHUMB_DEFAULTS.setParameter('.$key.', '.$phpThumb->phpThumbDebugVarDump($value).')', __FILE__, __LINE__);
226             //$phpThumb->setParameter($key, $value);
227         }
228     }
229 }
230 foreach ($_GET as $key => $value) {
231     if (@$PHPTHUMB_DEFAULTS_DISABLEGETPARAMS && ($key != 'src')) {
232         // disabled, do not set parameter
233         $phpThumb->DebugMessage('ignoring $_GET['.$key.'] because of $PHPTHUMB_DEFAULTS_DISABLEGETPARAMS', __FILE__, __LINE__);
234     } elseif (in_array($key, $allowedGETparameters)) {
235         $phpThumb->DebugMessage('setParameter('.$key.', '.$phpThumb->phpThumbDebugVarDump($value).')', __FILE__, __LINE__);
236         $phpThumb->setParameter($key, $value);
237     } else {
238         $phpThumb->ErrorImage('Forbidden parameter: '.$key);
239     }
240 }
241
242 ////////////////////////////////////////////////////////////////
243 // Debug output, to try and help me diagnose problems
244 $phpThumb->DebugTimingMessage('phpThumbDebug[3]', __FILE__, __LINE__);
245 if (@$_GET['phpThumbDebug'] == '3') {
246     $phpThumb->phpThumbDebug();
247 }
248 ////////////////////////////////////////////////////////////////
249
250 //if (!@$_GET['phpThumbDebug'] && !$phpThumb->sourceFilename && !function_exists('ImageJPEG') && !function_exists('ImagePNG') && !function_exists('ImageGIF')) {
251 if (!@$_GET['phpThumbDebug'] && !is_file($phpThumb->sourceFilename) && !phpthumb_functions::gd_version()) {
252     if (!headers_sent()) {
253         // base64-encoded error image in GIF format
254         $ERROR_NOGD = 'R0lGODlhIAAgALMAAAAAABQUFCQkJDY2NkZGRldXV2ZmZnJycoaGhpSUlKWlpbe3t8XFxdXV1eTk5P7+/iwAAAAAIAAgAAAE/vDJSau9WILtTAACUinDNijZtAHfCojS4W5H+qxD8xibIDE9h0OwWaRWDIljJSkUJYsN4bihMB8th3IToAKs1VtYM75cyV8sZ8vygtOE5yMKmGbO4jRdICQCjHdlZzwzNW4qZSQmKDaNjhUMBX4BBAlmMywFSRWEmAI6b5gAlhNxokGhooAIK5o/pi9vEw4Lfj4OLTAUpj6IabMtCwlSFw0DCKBoFqwAB04AjI54PyZ+yY3TD0ss2YcVmN/gvpcu4TOyFivWqYJlbAHPpOntvxNAACcmGHjZzAZqzSzcq5fNjxFmAFw9iFRunD1epU6tsIPmFCAJnWYE0FURk7wJDA0MTKpEzoWAAskiAAA7';
255         header('Content-Type: image/gif');
256         echo base64_decode($ERROR_NOGD);
257     } else {
258         echo '*** ERROR: No PHP-GD support available ***';
259     }
260     exit;
261 }
262
263 // check to see if file can be output from source with no processing or caching
264 $CanPassThroughDirectly = true;
265 if ($phpThumb->rawImageData) {
266     // data from SQL, should be fine
267 } elseif (eregi('^(f|ht)tp\://', $phpThumb->src)) {
268     $phpThumb->DebugMessage('$CanPassThroughDirectly=false because eregi("^(f|ht)tp\://", '.$phpThumb->src.')', __FILE__, __LINE__);
269     $CanPassThroughDirectly = false;
270 } elseif (!@is_file($phpThumb->sourceFilename)) {
271     $phpThumb->DebugMessage('$CanPassThroughDirectly=false because !@is_file('.$phpThumb->sourceFilename.')', __FILE__, __LINE__);
272     $CanPassThroughDirectly = false;
273 } elseif (!@is_readable($phpThumb->sourceFilename)) {
274     $phpThumb->DebugMessage('$CanPassThroughDirectly=false because !@is_readable('.$phpThumb->sourceFilename.')', __FILE__, __LINE__);
275     $CanPassThroughDirectly = false;
276 }
277 foreach ($_GET as $key => $value) {
278     switch ($key) {
279         case 'src':
280             // allowed
281             break;
282
283         case 'w':
284         case 'h':
285             // might be OK if exactly matches original
286             break;
287
288         case 'phpThumbDebug':
289             // handled in direct-passthru code
290             break;
291
292         default:
293             // all other parameters will cause some processing,
294             // therefore cannot pass through original image unmodified
295             $CanPassThroughDirectly = false;
296             $UnAllowedGET[] = $key;
297             break;
298     }
299 }
300 if (!empty($UnAllowedGET)) {
301     $phpThumb->DebugMessage('$CanPassThroughDirectly=false because $_GET['.implode(';', array_unique($UnAllowedGET)).'] are set', __FILE__, __LINE__);
302 }
303
304 ////////////////////////////////////////////////////////////////
305 // Debug output, to try and help me diagnose problems
306 $phpThumb->DebugTimingMessage('phpThumbDebug[4]', __FILE__, __LINE__);
307 if (@$_GET['phpThumbDebug'] == '4') {
308     $phpThumb->phpThumbDebug();
309 }
310 ////////////////////////////////////////////////////////////////
311
312 function SendSaveAsFileHeaderIfNeeded() {
313     if (headers_sent()) {
314         return false;
315     }
316     global $phpThumb;
317     if (@$_GET['down']) {
318         $downloadfilename = ereg_replace('[/\\:\*\?"<>|]', '_', $_GET['down']);
319         if (phpthumb_functions::version_compare_replacement(phpversion(), '4.1.0', '>=')) {
320             $downloadfilename = trim($downloadfilename, '.');
321         }
322         if (@$downloadfilename) {
323             $phpThumb->DebugMessage('SendSaveAsFileHeaderIfNeeded() sending header: Content-Disposition: attachment; filename="'.$downloadfilename.'"', __FILE__, __LINE__);
324             header('Content-Disposition: attachment; filename="'.$downloadfilename.'"');
325             return true;
326         }
327     }
328     $phpThumb->DebugMessage('SendSaveAsFileHeaderIfNeeded() sending header: Content-Disposition: inline', __FILE__, __LINE__);
329     header('Content-Disposition: inline');
330     return true;
331 }
332
333 $phpThumb->DebugMessage('$CanPassThroughDirectly="'.intval($CanPassThroughDirectly).'" && $phpThumb->src="'.$phpThumb->src.'"', __FILE__, __LINE__);
334 while ($CanPassThroughDirectly && $phpThumb->src) {
335     // no parameters set, passthru
336     $SourceFilename = $phpThumb->ResolveFilenameToAbsolute($phpThumb->src);
337
338     // security and size checks
339     if ($phpThumb->getimagesizeinfo = @GetImageSize($SourceFilename)) {
340         $phpThumb->DebugMessage('Direct passthru GetImageSize() returned [w='.$phpThumb->getimagesizeinfo[0].';h='.$phpThumb->getimagesizeinfo[1].';t='.$phpThumb->getimagesizeinfo[2].']', __FILE__, __LINE__);
341
342         if (!@$_GET['w'] && !@$_GET['wp'] && !@$_GET['wl'] && !@$_GET['ws'] && !@$_GET['h'] && !@$_GET['hp'] && !@$_GET['hl'] && !@$_GET['hs']) {
343             // no resizing needed
344             $phpThumb->DebugMessage('Passing "'.$SourceFilename.'" through directly, no resizing required ("'.$phpThumb->getimagesizeinfo[0].'"x"'.$phpThumb->getimagesizeinfo[1].'")', __FILE__, __LINE__);
345         } elseif (($phpThumb->getimagesizeinfo[0] <= @$_GET['w']) && ($phpThumb->getimagesizeinfo[1] <= @$_GET['h']) && ((@$_GET['w'] == $phpThumb->getimagesizeinfo[0]) || (@$_GET['h'] == $phpThumb->getimagesizeinfo[1]))) {
346             // image fits into 'w'x'h' box, and at least one dimension matches exactly, therefore no resizing needed
347             $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__);
348         } else {
349             $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__);
350             break;
351         }
352         switch ($phpThumb->getimagesizeinfo[2]) {
353             case 1: // GIF
354             case 2: // JPG
355             case 3: // PNG
356                 // great, let it through
357                 break;
358             default:
359                 // browser probably can't handle format, remangle it to JPEG/PNG/GIF
360                 $phpThumb->DebugMessage('Not passing "'.$SourceFilename.'" through directly because $phpThumb->getimagesizeinfo[2] = "'.$phpThumb->getimagesizeinfo[2].'"', __FILE__, __LINE__);
361                 break 2;
362         }
363
364         $ImageCreateFunctions = array(1=>'ImageCreateFromGIF', 2=>'ImageCreateFromJPEG', 3=>'ImageCreateFromPNG');
365         $theImageCreateFunction = @$ImageCreateFunctions[$phpThumb->getimagesizeinfo[2]];
366         if ($phpThumb->config_disable_onlycreateable_passthru || (function_exists($theImageCreateFunction) && ($dummyImage = @$theImageCreateFunction($SourceFilename)))) {
367
368             // great
369             if (@is_resource($dummyImage)) {
370                 unset($dummyImage);
371             }
372
373             if (headers_sent()) {
374                 $phpThumb->ErrorImage('Headers already sent ('.basename(__FILE__).' line '.__LINE__.')');
375                 exit;
376             }
377             if (@$_GET['phpThumbDebug']) {
378                 $phpThumb->DebugTimingMessage('skipped direct $SourceFilename passthru', __FILE__, __LINE__);
379                 $phpThumb->DebugMessage('Would have passed "'.$SourceFilename.'" through directly, but skipping due to phpThumbDebug', __FILE__, __LINE__);
380                 break;
381             }
382
383             SendSaveAsFileHeaderIfNeeded();
384             header('Last-Modified: '.gmdate('D, d M Y H:i:s', @filemtime($SourceFilename)).' GMT');
385             if ($contentType = phpthumb_functions::ImageTypeToMIMEtype(@$phpThumb->getimagesizeinfo[2])) {
386                 header('Content-Type: '.$contentType);
387             }
388             @readfile($SourceFilename);
389             exit;
390
391         } else {
392             $phpThumb->