Mercurial > hg > vamp-website
comparison forum/Sources/Subs-Graphics.php @ 76:e3e11437ecea website
Add forum code
author | Chris Cannam |
---|---|
date | Sun, 07 Jul 2013 11:25:48 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
75:72f59aa7e503 | 76:e3e11437ecea |
---|---|
1 <?php | |
2 | |
3 /** | |
4 * Simple Machines Forum (SMF) | |
5 * | |
6 * @package SMF | |
7 * @author Simple Machines http://www.simplemachines.org | |
8 * @copyright 2011 Simple Machines | |
9 * @license http://www.simplemachines.org/about/smf/license.php BSD | |
10 * | |
11 * @version 2.0 | |
12 */ | |
13 | |
14 // TrueType fonts supplied by www.LarabieFonts.com | |
15 | |
16 if (!defined('SMF')) | |
17 die('Hacking attempt...'); | |
18 | |
19 /* This whole file deals almost exclusively with handling avatars, | |
20 specifically uploaded ones. It uses, for gifs at least, Gif Util... for | |
21 more information on that, please see its website, shown above. The other | |
22 functions are as follows: | |
23 | |
24 bool downloadAvatar(string url, int id_member, int max_width, | |
25 int max_height) | |
26 - downloads file from url and stores it locally for avatar use | |
27 by id_member. | |
28 - supports GIF, JPG, PNG, BMP and WBMP formats. | |
29 - detects if GD2 is available. | |
30 - if GIF support isn't present in GD, handles GIFs with gif_loadFile() | |
31 and gif_outputAsPng(). | |
32 - uses resizeImageFile() to resize to max_width by max_height, | |
33 and saves the result to a file. | |
34 - updates the database info for the member's avatar. | |
35 - returns whether the download and resize was successful. | |
36 | |
37 bool createThumbnail(string source, int max_width, int max_height) | |
38 - create a thumbnail of the given source. | |
39 - uses the resizeImageFile function to achieve the resize. | |
40 - returns whether the thumbnail creation was successful. | |
41 | |
42 bool reencodeImage(string fileName, int preferred_format = 0) | |
43 - creates a copy of the file at the same location as fileName. | |
44 - the file would have the format preferred_format if possible, | |
45 otherwise the default format is jpeg. | |
46 - makes sure that all non-essential image contents are disposed. | |
47 - returns true on success, false on failure. | |
48 | |
49 bool checkImageContents(string fileName, bool extensiveCheck = false) | |
50 - searches through the file to see if there's non-binary content. | |
51 - if extensiveCheck is true, searches for asp/php short tags as well. | |
52 - returns true on success, false on failure. | |
53 | |
54 bool checkGD() | |
55 - sets a global $gd2 variable needed by some functions to determine | |
56 whetehr the GD2 library is present. | |
57 - returns whether or not GD1 is available. | |
58 | |
59 void resizeImageFile(string source, string destination, | |
60 int max_width, int max_height, int preferred_format = 0) | |
61 - resizes an image from a remote location or a local file. | |
62 - puts the resized image at the destination location. | |
63 - the file would have the format preferred_format if possible, | |
64 otherwise the default format is jpeg. | |
65 - returns whether it succeeded. | |
66 | |
67 void resizeImage(resource src_img, string destination_filename, | |
68 int src_width, int src_height, int max_width, int max_height, | |
69 int preferred_format) | |
70 - resizes src_img proportionally to fit within max_width and | |
71 max_height limits if it is too large. | |
72 - if GD2 is present, it'll use it to achieve better quality. | |
73 - saves the new image to destination_filename. | |
74 - saves as preferred_format if possible, default is jpeg. | |
75 | |
76 void imagecopyresamplebicubic(resource dest_img, resource src_img, | |
77 int dest_x, int dest_y, int src_x, int src_y, int dest_w, | |
78 int dest_h, int src_w, int src_h) | |
79 - used when imagecopyresample() is not available. | |
80 | |
81 resource gif_loadFile(string filename, int animation_index) | |
82 - loads a gif file with the Yamasoft GIF utility class. | |
83 - returns a new GD image. | |
84 | |
85 bool gif_outputAsPng(resource gif, string destination_filename, | |
86 int bgColor = -1) | |
87 - writes a gif file to disk as a png file. | |
88 - returns whether it was successful or not. | |
89 | |
90 bool imagecreatefrombmp(string filename) | |
91 - is set only if it doesn't already exist (for forwards compatiblity.) | |
92 - only supports uncompressed bitmaps. | |
93 - returns an image identifier representing the bitmap image obtained | |
94 from the given filename. | |
95 | |
96 bool showCodeImage(string code) | |
97 - show an image containing the visual verification code for registration. | |
98 - requires the GD extension. | |
99 - uses a random font for each letter from default_theme_dir/fonts. | |
100 - outputs a gif or a png (depending on whether gif ix supported). | |
101 - returns false if something goes wrong. | |
102 | |
103 bool showLetterImage(string letter) | |
104 - show a letter for the visual verification code. | |
105 - alternative function for showCodeImage() in case GD is missing. | |
106 - includes an image from a random sub directory of | |
107 default_theme_dir/fonts. | |
108 */ | |
109 | |
110 function downloadAvatar($url, $memID, $max_width, $max_height) | |
111 { | |
112 global $modSettings, $sourcedir, $smcFunc; | |
113 | |
114 $ext = !empty($modSettings['avatar_download_png']) ? 'png' : 'jpeg'; | |
115 $destName = 'avatar_' . $memID . '_' . time() . '.' . $ext; | |
116 | |
117 // Just making sure there is a non-zero member. | |
118 if (empty($memID)) | |
119 return false; | |
120 | |
121 require_once($sourcedir . '/ManageAttachments.php'); | |
122 removeAttachments(array('id_member' => $memID)); | |
123 | |
124 $id_folder = !empty($modSettings['currentAttachmentUploadDir']) ? $modSettings['currentAttachmentUploadDir'] : 1; | |
125 $avatar_hash = empty($modSettings['custom_avatar_enabled']) ? getAttachmentFilename($destName, false, null, true) : ''; | |
126 $smcFunc['db_insert']('', | |
127 '{db_prefix}attachments', | |
128 array( | |
129 'id_member' => 'int', 'attachment_type' => 'int', 'filename' => 'string-255', 'file_hash' => 'string-255', 'fileext' => 'string-8', 'size' => 'int', | |
130 'id_folder' => 'int', | |
131 ), | |
132 array( | |
133 $memID, empty($modSettings['custom_avatar_enabled']) ? 0 : 1, $destName, $avatar_hash, $ext, 1, | |
134 $id_folder, | |
135 ), | |
136 array('id_attach') | |
137 ); | |
138 $attachID = $smcFunc['db_insert_id']('{db_prefix}attachments', 'id_attach'); | |
139 // Retain this globally in case the script wants it. | |
140 $modSettings['new_avatar_data'] = array( | |
141 'id' => $attachID, | |
142 'filename' => $destName, | |
143 'type' => empty($modSettings['custom_avatar_enabled']) ? 0 : 1, | |
144 ); | |
145 | |
146 $destName = (empty($modSettings['custom_avatar_enabled']) ? (is_array($modSettings['attachmentUploadDir']) ? $modSettings['attachmentUploadDir'][$modSettings['currentAttachmentUploadDir']] : $modSettings['attachmentUploadDir']) : $modSettings['custom_avatar_dir']) . '/' . $destName . '.tmp'; | |
147 | |
148 // Resize it. | |
149 if (!empty($modSettings['avatar_download_png'])) | |
150 $success = resizeImageFile($url, $destName, $max_width, $max_height, 3); | |
151 else | |
152 $success = resizeImageFile($url, $destName, $max_width, $max_height); | |
153 | |
154 // Remove the .tmp extension. | |
155 $destName = substr($destName, 0, -4); | |
156 | |
157 if ($success) | |
158 { | |
159 // Walk the right path. | |
160 if (!empty($modSettings['currentAttachmentUploadDir'])) | |
161 { | |
162 if (!is_array($modSettings['attachmentUploadDir'])) | |
163 $modSettings['attachmentUploadDir'] = unserialize($modSettings['attachmentUploadDir']); | |
164 $path = $modSettings['attachmentUploadDir'][$modSettings['currentAttachmentUploadDir']]; | |
165 } | |
166 else | |
167 $path = $modSettings['attachmentUploadDir']; | |
168 | |
169 // Remove the .tmp extension from the attachment. | |
170 if (rename($destName . '.tmp', empty($avatar_hash) ? $destName : $path . '/' . $attachID . '_' . $avatar_hash)) | |
171 { | |
172 $destName = empty($avatar_hash) ? $destName : $path . '/' . $attachID . '_' . $avatar_hash; | |
173 list ($width, $height) = getimagesize($destName); | |
174 $mime_type = 'image/' . $ext; | |
175 | |
176 // Write filesize in the database. | |
177 $smcFunc['db_query']('', ' | |
178 UPDATE {db_prefix}attachments | |
179 SET size = {int:filesize}, width = {int:width}, height = {int:height}, | |
180 mime_type = {string:mime_type} | |
181 WHERE id_attach = {int:current_attachment}', | |
182 array( | |
183 'filesize' => filesize($destName), | |
184 'width' => (int) $width, | |
185 'height' => (int) $height, | |
186 'current_attachment' => $attachID, | |
187 'mime_type' => $mime_type, | |
188 ) | |
189 ); | |
190 return true; | |
191 } | |
192 else | |
193 return false; | |
194 } | |
195 else | |
196 { | |
197 $smcFunc['db_query']('', ' | |
198 DELETE FROM {db_prefix}attachments | |
199 WHERE id_attach = {int:current_attachment}', | |
200 array( | |
201 'current_attachment' => $attachID, | |
202 ) | |
203 ); | |
204 | |
205 @unlink($destName . '.tmp'); | |
206 return false; | |
207 } | |
208 } | |
209 | |
210 function createThumbnail($source, $max_width, $max_height) | |
211 { | |
212 global $modSettings; | |
213 | |
214 $destName = $source . '_thumb.tmp'; | |
215 | |
216 // Do the actual resize. | |
217 if (!empty($modSettings['attachment_thumb_png'])) | |
218 $success = resizeImageFile($source, $destName, $max_width, $max_height, 3); | |
219 else | |
220 $success = resizeImageFile($source, $destName, $max_width, $max_height); | |
221 | |
222 // Okay, we're done with the temporary stuff. | |
223 $destName = substr($destName, 0, -4); | |
224 | |
225 if ($success && @rename($destName . '.tmp', $destName)) | |
226 return true; | |
227 else | |
228 { | |
229 @unlink($destName . '.tmp'); | |
230 @touch($destName); | |
231 return false; | |
232 } | |
233 } | |
234 | |
235 function reencodeImage($fileName, $preferred_format = 0) | |
236 { | |
237 // There is nothing we can do without GD, sorry! | |
238 if (!checkGD()) | |
239 return false; | |
240 | |
241 if (!resizeImageFile($fileName, $fileName . '.tmp', null, null, $preferred_format)) | |
242 { | |
243 if (file_exists($fileName . '.tmp')) | |
244 unlink($fileName . '.tmp'); | |
245 | |
246 return false; | |
247 } | |
248 | |
249 if (!unlink($fileName)) | |
250 return false; | |
251 | |
252 if (!rename($fileName . '.tmp', $fileName)) | |
253 return false; | |
254 | |
255 return true; | |
256 } | |
257 | |
258 function checkImageContents($fileName, $extensiveCheck = false) | |
259 { | |
260 $fp = fopen($fileName, 'rb'); | |
261 if (!$fp) | |
262 fatal_lang_error('attach_timeout'); | |
263 | |
264 $prev_chunk = ''; | |
265 while (!feof($fp)) | |
266 { | |
267 $cur_chunk = fread($fp, 8192); | |
268 | |
269 // Though not exhaustive lists, better safe than sorry. | |
270 if (!empty($extensiveCheck)) | |
271 { | |
272 // Paranoid check. Some like it that way. | |
273 if (preg_match('~(iframe|\\<\\?|\\<%|html|eval|body|script\W|[CF]WS[\x01-\x0C])~i', $prev_chunk . $cur_chunk) === 1) | |
274 { | |
275 fclose($fp); | |
276 return false; | |
277 } | |
278 } | |
279 else | |
280 { | |
281 // Check for potential infection | |
282 if (preg_match('~(iframe|html|eval|body|script\W|[CF]WS[\x01-\x0C])~i', $prev_chunk . $cur_chunk) === 1) | |
283 { | |
284 fclose($fp); | |
285 return false; | |
286 } | |
287 } | |
288 $prev_chunk = $cur_chunk; | |
289 } | |
290 fclose($fp); | |
291 | |
292 return true; | |
293 } | |
294 | |
295 function checkGD() | |
296 { | |
297 global $gd2; | |
298 | |
299 // Check to see if GD is installed and what version. | |
300 if (($extensionFunctions = get_extension_funcs('gd')) === false) | |
301 return false; | |
302 | |
303 // Also determine if GD2 is installed and store it in a global. | |
304 $gd2 = in_array('imagecreatetruecolor', $extensionFunctions) && function_exists('imagecreatetruecolor'); | |
305 | |
306 return true; | |
307 } | |
308 | |
309 function resizeImageFile($source, $destination, $max_width, $max_height, $preferred_format = 0) | |
310 { | |
311 global $sourcedir; | |
312 | |
313 // Nothing to do without GD | |
314 if (!checkGD()) | |
315 return false; | |
316 | |
317 static $default_formats = array( | |
318 '1' => 'gif', | |
319 '2' => 'jpeg', | |
320 '3' => 'png', | |
321 '6' => 'bmp', | |
322 '15' => 'wbmp' | |
323 ); | |
324 | |
325 require_once($sourcedir . '/Subs-Package.php'); | |
326 @ini_set('memory_limit', '90M'); | |
327 | |
328 $success = false; | |
329 | |
330 // Get the image file, we have to work with something after all | |
331 $fp_destination = fopen($destination, 'wb'); | |
332 if ($fp_destination && substr($source, 0, 7) == 'http://') | |
333 { | |
334 $fileContents = fetch_web_data($source); | |
335 | |
336 fwrite($fp_destination, $fileContents); | |
337 fclose($fp_destination); | |
338 | |
339 $sizes = @getimagesize($destination); | |
340 } | |
341 elseif ($fp_destination) | |
342 { | |
343 $sizes = @getimagesize($source); | |
344 | |
345 $fp_source = fopen($source, 'rb'); | |
346 if ($fp_source !== false) | |
347 { | |
348 while (!feof($fp_source)) | |
349 fwrite($fp_destination, fread($fp_source, 8192)); | |
350 fclose($fp_source); | |
351 } | |
352 else | |
353 $sizes = array(-1, -1, -1); | |
354 fclose($fp_destination); | |
355 } | |
356 // We can't get to the file. | |
357 else | |
358 $sizes = array(-1, -1, -1); | |
359 | |
360 // Gif? That might mean trouble if gif support is not available. | |
361 if ($sizes[2] == 1 && !function_exists('imagecreatefromgif') && function_exists('imagecreatefrompng')) | |
362 { | |
363 // Download it to the temporary file... use the special gif library... and save as png. | |
364 if ($img = @gif_loadFile($destination) && gif_outputAsPng($img, $destination)) | |
365 $sizes[2] = 3; | |
366 } | |
367 | |
368 // A known and supported format? | |
369 if (isset($default_formats[$sizes[2]]) && function_exists('imagecreatefrom' . $default_formats[$sizes[2]])) | |
370 { | |
371 $imagecreatefrom = 'imagecreatefrom' . $default_formats[$sizes[2]]; | |
372 if ($src_img = @$imagecreatefrom($destination)) | |
373 { | |
374 resizeImage($src_img, $destination, imagesx($src_img), imagesy($src_img), $max_width === null ? imagesx($src_img) : $max_width, $max_height === null ? imagesy($src_img) : $max_height, true, $preferred_format); | |
375 $success = true; | |
376 } | |
377 } | |
378 | |
379 return $success; | |
380 } | |
381 | |
382 function resizeImage($src_img, $destName, $src_width, $src_height, $max_width, $max_height, $force_resize = false, $preferred_format = 0) | |
383 { | |
384 global $gd2, $modSettings; | |
385 | |
386 // Without GD, no image resizing at all. | |
387 if (!checkGD()) | |
388 return false; | |
389 | |
390 $success = false; | |
391 | |
392 // Determine whether to resize to max width or to max height (depending on the limits.) | |
393 if (!empty($max_width) || !empty($max_height)) | |
394 { | |
395 if (!empty($max_width) && (empty($max_height) || $src_height * $max_width / $src_width <= $max_height)) | |
396 { | |
397 $dst_width = $max_width; | |
398 $dst_height = floor($src_height * $max_width / $src_width); | |
399 } | |
400 elseif (!empty($max_height)) | |
401 { | |
402 $dst_width = floor($src_width * $max_height / $src_height); | |
403 $dst_height = $max_height; | |
404 } | |
405 | |
406 // Don't bother resizing if it's already smaller... | |
407 if (!empty($dst_width) && !empty($dst_height) && ($dst_width < $src_width || $dst_height < $src_height || $force_resize)) | |
408 { | |
409 // (make a true color image, because it just looks better for resizing.) | |
410 if ($gd2) | |
411 { | |
412 $dst_img = imagecreatetruecolor($dst_width, $dst_height); | |
413 | |
414 // Deal nicely with a PNG - because we can. | |
415 if ((!empty($preferred_format)) && ($preferred_format == 3)) | |
416 { | |
417 imagealphablending($dst_img, false); | |
418 if (function_exists('imagesavealpha')) | |
419 imagesavealpha($dst_img, true); | |
420 } | |
421 } | |
422 else | |
423 $dst_img = imagecreate($dst_width, $dst_height); | |
424 | |
425 // Resize it! | |
426 if ($gd2) | |
427 imagecopyresampled($dst_img, $src_img, 0, 0, 0, 0, $dst_width, $dst_height, $src_width, $src_height); | |
428 else | |
429 imagecopyresamplebicubic($dst_img, $src_img, 0, 0, 0, 0, $dst_width, $dst_height, $src_width, $src_height); | |
430 } | |
431 else | |
432 $dst_img = $src_img; | |
433 } | |
434 else | |
435 $dst_img = $src_img; | |
436 | |
437 // Save the image as ... | |
438 if (!empty($preferred_format) && ($preferred_format == 3) && function_exists('imagepng')) | |
439 $success = imagepng($dst_img, $destName); | |
440 elseif (!empty($preferred_format) && ($preferred_format == 1) && function_exists('imagegif')) | |
441 $success = imagegif($dst_img, $destName); | |
442 elseif (function_exists('imagejpeg')) | |
443 $success = imagejpeg($dst_img, $destName); | |
444 | |
445 // Free the memory. | |
446 imagedestroy($src_img); | |
447 if ($dst_img != $src_img) | |
448 imagedestroy($dst_img); | |
449 | |
450 return $success; | |
451 } | |
452 | |
453 function imagecopyresamplebicubic($dst_img, $src_img, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h) | |
454 { | |
455 $palsize = imagecolorstotal($src_img); | |
456 for ($i = 0; $i < $palsize; $i++) | |
457 { | |
458 $colors = imagecolorsforindex($src_img, $i); | |
459 imagecolorallocate($dst_img, $colors['red'], $colors['green'], $colors['blue']); | |
460 } | |
461 | |
462 $scaleX = ($src_w - 1) / $dst_w; | |
463 $scaleY = ($src_h - 1) / $dst_h; | |
464 | |
465 $scaleX2 = (int) $scaleX / 2; | |
466 $scaleY2 = (int) $scaleY / 2; | |
467 | |
468 for ($j = $src_y; $j < $dst_h; $j++) | |
469 { | |
470 $sY = (int) $j * $scaleY; | |
471 $y13 = $sY + $scaleY2; | |
472 | |
473 for ($i = $src_x; $i < $dst_w; $i++) | |
474 { | |
475 $sX = (int) $i * $scaleX; | |
476 $x34 = $sX + $scaleX2; | |
477 | |
478 $color1 = imagecolorsforindex($src_img, imagecolorat($src_img, $sX, $y13)); | |
479 $color2 = imagecolorsforindex($src_img, imagecolorat($src_img, $sX, $sY)); | |
480 $color3 = imagecolorsforindex($src_img, imagecolorat($src_img, $x34, $y13)); | |
481 $color4 = imagecolorsforindex($src_img, imagecolorat($src_img, $x34, $sY)); | |
482 | |
483 $red = ($color1['red'] + $color2['red'] + $color3['red'] + $color4['red']) / 4; | |
484 $green = ($color1['green'] + $color2['green'] + $color3['green'] + $color4['green']) / 4; | |
485 $blue = ($color1['blue'] + $color2['blue'] + $color3['blue'] + $color4['blue']) / 4; | |
486 | |
487 $color = imagecolorresolve($dst_img, $red, $green, $blue); | |
488 if ($color == -1) | |
489 { | |
490 if ($palsize++ < 256) | |
491 imagecolorallocate($dst_img, $red, $green, $blue); | |
492 $color = imagecolorclosest($dst_img, $red, $green, $blue); | |
493 } | |
494 | |
495 imagesetpixel($dst_img, $i + $dst_x - $src_x, $j + $dst_y - $src_y, $color); | |
496 } | |
497 } | |
498 } | |
499 | |
500 if (!function_exists('imagecreatefrombmp')) | |
501 { | |
502 function imagecreatefrombmp($filename) | |
503 { | |
504 global $gd2; | |
505 | |
506 $fp = fopen($filename, 'rb'); | |
507 | |
508 $errors = error_reporting(0); | |
509 | |
510 $header = unpack('vtype/Vsize/Vreserved/Voffset', fread($fp, 14)); | |
511 $info = unpack('Vsize/Vwidth/Vheight/vplanes/vbits/Vcompression/Vimagesize/Vxres/Vyres/Vncolor/Vcolorimportant', fread($fp, 40)); | |
512 | |
513 if ($header['type'] != 0x4D42) | |
514 false; | |
515 | |
516 if ($gd2) | |
517 $dst_img = imagecreatetruecolor($info['width'], $info['height']); | |
518 else | |
519 $dst_img = imagecreate($info['width'], $info['height']); | |
520 | |
521 $palette_size = $header['offset'] - 54; | |
522 $info['ncolor'] = $palette_size / 4; | |
523 | |
524 $palette = array(); | |
525 | |
526 $palettedata = fread($fp, $palette_size); | |
527 $n = 0; | |
528 for ($j = 0; $j < $palette_size; $j++) | |
529 { | |
530 $b = ord($palettedata{$j++}); | |
531 $g = ord($palettedata{$j++}); | |
532 $r = ord($palettedata{$j++}); | |
533 | |
534 $palette[$n++] = imagecolorallocate($dst_img, $r, $g, $b); | |
535 } | |
536 | |
537 $scan_line_size = ($info['bits'] * $info['width'] + 7) >> 3; | |
538 $scan_line_align = $scan_line_size & 3 ? 4 - ($scan_line_size & 3) : 0; | |
539 | |
540 for ($y = 0, $l = $info['height'] - 1; $y < $info['height']; $y++, $l--) | |
541 { | |
542 fseek($fp, $header['offset'] + ($scan_line_size + $scan_line_align) * $l); | |
543 $scan_line = fread($fp, $scan_line_size); | |
544 | |
545 if (strlen($scan_line) < $scan_line_size) | |
546 continue; | |
547 | |
548 if ($info['bits'] == 32) | |
549 { | |
550 $x = 0; | |
551 for ($j = 0; $j < $scan_line_size; $x++) | |
552 { | |
553 $b = ord($scan_line{$j++}); | |
554 $g = ord($scan_line{$j++}); | |
555 $r = ord($scan_line{$j++}); | |
556 $j++; | |
557 | |
558 $color = imagecolorexact($dst_img, $r, $g, $b); | |
559 if ($color == -1) | |
560 { | |
561 $color = imagecolorallocate($dst_img, $r, $g, $b); | |
562 | |
563 // Gah! Out of colors? Stupid GD 1... try anyhow. | |
564 if ($color == -1) | |
565 $color = imagecolorclosest($dst_img, $r, $g, $b); | |
566 } | |
567 | |
568 imagesetpixel($dst_img, $x, $y, $color); | |
569 } | |
570 } | |
571 elseif ($info['bits'] == 24) | |
572 { | |
573 $x = 0; | |
574 for ($j = 0; $j < $scan_line_size; $x++) | |
575 { | |
576 $b = ord($scan_line{$j++}); | |
577 $g = ord($scan_line{$j++}); | |
578 $r = ord($scan_line{$j++}); | |
579 | |
580 $color = imagecolorexact($dst_img, $r, $g, $b); | |
581 if ($color == -1) | |
582 { | |
583 $color = imagecolorallocate($dst_img, $r, $g, $b); | |
584 | |
585 // Gah! Out of colors? Stupid GD 1... try anyhow. | |
586 if ($color == -1) | |
587 $color = imagecolorclosest($dst_img, $r, $g, $b); | |
588 } | |
589 | |
590 imagesetpixel($dst_img, $x, $y, $color); | |
591 } | |
592 } | |
593 elseif ($info['bits'] == 16) | |
594 { | |
595 $x = 0; | |
596 for ($j = 0; $j < $scan_line_size; $x++) | |
597 { | |
598 $b1 = ord($scan_line{$j++}); | |
599 $b2 = ord($scan_line{$j++}); | |
600 | |
601 $word = $b2 * 256 + $b1; | |
602 | |
603 $b = (($word & 31) * 255) / 31; | |
604 $g = ((($word >> 5) & 31) * 255) / 31; | |
605 $r = ((($word >> 10) & 31) * 255) / 31; | |
606 | |
607 // Scale the image colors up properly. | |
608 $color = imagecolorexact($dst_img, $r, $g, $b); | |
609 if ($color == -1) | |
610 { | |
611 $color = imagecolorallocate($dst_img, $r, $g, $b); | |
612 | |
613 // Gah! Out of colors? Stupid GD 1... try anyhow. | |
614 if ($color == -1) | |
615 $color = imagecolorclosest($dst_img, $r, $g, $b); | |
616 } | |
617 | |
618 imagesetpixel($dst_img, $x, $y, $color); | |
619 } | |
620 } | |
621 elseif ($info['bits'] == 8) | |
622 { | |
623 $x = 0; | |
624 for ($j = 0; $j < $scan_line_size; $x++) | |
625 imagesetpixel($dst_img, $x, $y, $palette[ord($scan_line{$j++})]); | |
626 } | |
627 elseif ($info['bits'] == 4) | |
628 { | |
629 $x = 0; | |
630 for ($j = 0; $j < $scan_line_size; $x++) | |
631 { | |
632 $byte = ord($scan_line{$j++}); | |
633 | |
634 imagesetpixel($dst_img, $x, $y, $palette[(int) ($byte / 16)]); | |
635 if (++$x < $info['width']) | |
636 imagesetpixel($dst_img, $x, $y, $palette[$byte & 15]); | |
637 } | |
638 } | |
639 else | |
640 { | |
641 // Sorry, I'm just not going to do monochrome :P. | |
642 } | |
643 } | |
644 | |
645 fclose($fp); | |
646 | |
647 error_reporting($errors); | |
648 | |
649 return $dst_img; | |
650 } | |
651 } | |
652 | |
653 function gif_loadFile($lpszFileName, $iIndex = 0) | |
654 { | |
655 // The classes needed are in this file. | |
656 loadClassFile('Class-Graphics.php'); | |
657 $gif = new gif_file(); | |
658 | |
659 if (!$gif->loadFile($lpszFileName, $iIndex)) | |
660 return false; | |
661 | |
662 return $gif; | |
663 } | |
664 | |
665 function gif_outputAsPng($gif, $lpszFileName, $background_color = -1) | |
666 { | |
667 if (!isset($gif) || @get_class($gif) != 'cgif' || !$gif->loaded || $lpszFileName == '') | |
668 return false; | |
669 | |
670 $fd = $gif->get_png_data($background_color); | |
671 if (strlen($fd) <= 0) | |
672 return false; | |
673 | |
674 if (!($fh = @fopen($lpszFileName, 'wb'))) | |
675 return false; | |
676 | |
677 @fwrite($fh, $fd, strlen($fd)); | |
678 @fflush($fh); | |
679 @fclose($fh); | |
680 | |
681 return true; | |
682 } | |
683 | |
684 // Create the image for the visual verification code. | |
685 function showCodeImage($code) | |
686 { | |
687 global $settings, $user_info, $modSettings; | |
688 | |
689 /* | |
690 Note: The higher the value of visual_verification_type the harder the verification is - from 0 as disabled through to 4 as "Very hard". | |
691 */ | |
692 | |
693 // What type are we going to be doing? | |
694 $imageType = $modSettings['visual_verification_type']; | |
695 // Special case to allow the admin center to show samples. | |
696 if ($user_info['is_admin'] && isset($_GET['type'])) | |
697 $imageType = (int) $_GET['type']; | |
698 | |
699 // Some quick references for what we do. | |
700 // Do we show no, low or high noise? | |
701 $noiseType = $imageType == 3 ? 'low' : ($imageType == 4 ? 'high' : ($imageType == 5 ? 'extreme' : 'none')); | |
702 // Can we have more than one font in use? | |
703 $varyFonts = $imageType > 3 ? true : false; | |
704 // Just a plain white background? | |
705 $simpleBGColor = $imageType < 3 ? true : false; | |
706 // Plain black foreground? | |
707 $simpleFGColor = $imageType == 0 ? true : false; | |
708 // High much to rotate each character. | |
709 $rotationType = $imageType == 1 ? 'none' : ($imageType > 3 ? 'low' : 'high'); | |
710 // Do we show some characters inversed? | |
711 $showReverseChars = $imageType > 3 ? true : false; | |
712 // Special case for not showing any characters. | |
713 $disableChars = $imageType == 0 ? true : false; | |
714 // What do we do with the font colors. Are they one color, close to one color or random? | |
715 $fontColorType = $imageType == 1 ? 'plain' : ($imageType > 3 ? 'random' : 'cyclic'); | |
716 // Are the fonts random sizes? | |
717 $fontSizeRandom = $imageType > 3 ? true : false; | |
718 // How much space between characters? | |
719 $fontHorSpace = $imageType > 3 ? 'high' : ($imageType == 1 ? 'medium' : 'minus'); | |
720 // Where do characters sit on the image? (Fixed position or random/very random) | |
721 $fontVerPos = $imageType == 1 ? 'fixed' : ($imageType > 3 ? 'vrandom' : 'random'); | |
722 // Make font semi-transparent? | |
723 $fontTrans = $imageType == 2 || $imageType == 3 ? true : false; | |
724 // Give the image a border? | |
725 $hasBorder = $simpleBGColor; | |
726 | |
727 // Is this GD2? Needed for pixel size. | |
728 $testGD = get_extension_funcs('gd'); | |
729 $gd2 = in_array('imagecreatetruecolor', $testGD) && function_exists('imagecreatetruecolor'); | |
730 unset($testGD); | |
731 | |
732 // The amount of pixels inbetween characters. | |
733 $character_spacing = 1; | |
734 | |
735 // What color is the background - generally white unless we're on "hard". | |
736 if ($simpleBGColor) | |
737 $background_color = array(255, 255, 255); | |
738 else | |
739 $background_color = isset($settings['verification_background']) ? $settings['verification_background'] : array(236, 237, 243); | |
740 | |
741 // The color of the characters shown (red, green, blue). | |
742 if ($simpleFGColor) | |
743 $foreground_color = array(0, 0, 0); | |
744 else | |
745 { | |
746 $foreground_color = array(64, 101, 136); | |
747 | |
748 // Has the theme author requested a custom color? | |
749 if (isset($settings['verification_foreground'])) | |
750 $foreground_color = $settings['verification_foreground']; | |
751 } | |
752 | |
753 if (!is_dir($settings['default_theme_dir'] . '/fonts')) | |
754 return false; | |
755 | |
756 // Get a list of the available fonts. | |
757 $font_dir = dir($settings['default_theme_dir'] . '/fonts'); | |
758 $font_list = array(); | |
759 $ttfont_list = array(); | |
760 while ($entry = $font_dir->read()) | |
761 { | |
762 if (preg_match('~^(.+)\.gdf$~', $entry, $matches) === 1) | |
763 $font_list[] = $entry; | |
764 elseif (preg_match('~^(.+)\.ttf$~', $entry, $matches) === 1) | |
765 $ttfont_list[] = $entry; | |
766 } | |
767 | |
768 if (empty($font_list)) | |
769 return false; | |
770 | |
771 // For non-hard things don't even change fonts. | |
772 if (!$varyFonts) | |
773 { | |
774 $font_list = array($font_list[0]); | |
775 // Try use Screenge if we can - it looks good! | |
776 if (in_array('Screenge.ttf', $ttfont_list)) | |
777 $ttfont_list = array('Screenge.ttf'); | |
778 else | |
779 $ttfont_list = empty($ttfont_list) ? array() : array($ttfont_list[0]); | |
780 | |
781 } | |
782 | |
783 // Create a list of characters to be shown. | |
784 $characters = array(); | |
785 $loaded_fonts = array(); | |
786 for ($i = 0; $i < strlen($code); $i++) | |
787 { | |
788 $characters[$i] = array( | |
789 'id' => $code{$i}, | |
790 'font' => array_rand($font_list), | |
791 ); | |
792 | |
793 $loaded_fonts[$characters[$i]['font']] = null; | |
794 } | |
795 | |
796 // Load all fonts and determine the maximum font height. | |
797 foreach ($loaded_fonts as $font_index => $dummy) | |
798 $loaded_fonts[$font_index] = imageloadfont($settings['default_theme_dir'] . '/fonts/' . $font_list[$font_index]); | |
799 | |
800 // Determine the dimensions of each character. | |
801 $total_width = $character_spacing * strlen($code) + 20; | |
802 $max_height = 0; | |
803 foreach ($characters as $char_index => $character) | |
804 { | |
805 $characters[$char_index]['width'] = imagefontwidth($loaded_fonts[$character['font']]); | |
806 $characters[$char_index]['height'] = imagefontheight($loaded_fonts[$character['font']]); | |
807 | |
808 $max_height = max($characters[$char_index]['height'] + 5, $max_height); | |
809 $total_width += $characters[$char_index]['width']; | |
810 } | |
811 | |
812 // Create an image. | |
813 $code_image = $gd2 ? imagecreatetruecolor($total_width, $max_height) : imagecreate($total_width, $max_height); | |
814 | |
815 // Draw the background. | |
816 $bg_color = imagecolorallocate($code_image, $background_color[0], $background_color[1], $background_color[2]); | |
817 imagefilledrectangle($code_image, 0, 0, $total_width - 1, $max_height - 1, $bg_color); | |
818 | |
819 // Randomize the foreground color a little. | |
820 for ($i = 0; $i < 3; $i++) | |
821 $foreground_color[$i] = mt_rand(max($foreground_color[$i] - 3, 0), min($foreground_color[$i] + 3, 255)); | |
822 $fg_color = imagecolorallocate($code_image, $foreground_color[0], $foreground_color[1], $foreground_color[2]); | |
823 | |
824 // Color for the dots. | |
825 for ($i = 0; $i < 3; $i++) | |
826 $dotbgcolor[$i] = $background_color[$i] < $foreground_color[$i] ? mt_rand(0, max($foreground_color[$i] - 20, 0)) : mt_rand(min($foreground_color[$i] + 20, 255), 255); | |
827 $randomness_color = imagecolorallocate($code_image, $dotbgcolor[0], $dotbgcolor[1], $dotbgcolor[2]); | |
828 | |
829 // Some squares/rectanges for new extreme level | |
830 if ($noiseType == 'extreme') | |
831 { | |
832 for ($i = 0; $i < rand(1, 5); $i++) | |
833 { | |
834 $x1 = rand(0, $total_width / 4); | |
835 $x2 = $x1 + round(rand($total_width / 4, $total_width)); | |
836 $y1 = rand(0, $max_height); | |
837 $y2 = $y1 + round(rand(0, $max_height / 3)); | |
838 imagefilledrectangle($code_image, $x1, $y1, $x2, $y2, mt_rand(0, 1) ? $fg_color : $randomness_color); | |
839 } | |
840 } | |
841 | |
842 // Fill in the characters. | |
843 if (!$disableChars) | |
844 { | |
845 $cur_x = 0; | |
846 foreach ($characters as $char_index => $character) | |
847 { | |
848 // Can we use true type fonts? | |
849 $can_do_ttf = function_exists('imagettftext'); | |
850 | |
851 // How much rotation will we give? | |
852 if ($rotationType == 'none') | |
853 $angle = 0; | |
854 else | |
855 $angle = mt_rand(-100, 100) / ($rotationType == 'high' ? 6 : 10); | |
856 | |
857 // What color shall we do it? | |
858 if ($fontColorType == 'cyclic') | |
859 { | |
860 // Here we'll pick from a set of acceptance types. | |
861 $colors = array( | |
862 array(10, 120, 95), | |
863 array(46, 81, 29), | |
864 array(4, 22, 154), | |
865 array(131, 9, 130), | |
866 array(0, 0, 0), | |
867 array(143, 39, 31), | |
868 ); | |
869 if (!isset($last_index)) | |
870 $last_index = -1; | |
871 $new_index = $last_index; | |
872 while ($last_index == $new_index) | |
873 $new_index = mt_rand(0, count($colors) - 1); | |
874 $char_fg_color = $colors[$new_index]; | |
875 $last_index = $new_index; | |
876 } | |
877 elseif ($fontColorType == 'random') | |
878 $char_fg_color = array(mt_rand(max($foreground_color[0] - 2, 0), $foreground_color[0]), mt_rand(max($foreground_color[1] - 2, 0), $foreground_color[1]), mt_rand(max($foreground_color[2] - 2, 0), $foreground_color[2])); | |
879 else | |
880 $char_fg_color = array($foreground_color[0], $foreground_color[1], $foreground_color[2]); | |
881 | |
882 if (!empty($can_do_ttf)) | |
883 { | |
884 // GD2 handles font size differently. | |
885 if ($fontSizeRandom) | |
886 $font_size = $gd2 ? mt_rand(17, 19) : mt_rand(18, 25); | |
887 else | |
888 $font_size = $gd2 ? 18 : 24; | |
889 | |
890 // Work out the sizes - also fix the character width cause TTF not quite so wide! | |
891 $font_x = $fontHorSpace == 'minus' && $cur_x > 0 ? $cur_x - 3 : $cur_x + 5; | |
892 $font_y = $max_height - ($fontVerPos == 'vrandom' ? mt_rand(2, 8) : ($fontVerPos == 'random' ? mt_rand(3, 5) : 5)); | |
893 | |
894 // What font face? | |
895 if (!empty($ttfont_list)) | |
896 $fontface = $settings['default_theme_dir'] . '/fonts/' . $ttfont_list[mt_rand(0, count($ttfont_list) - 1)]; | |
897 | |
898 // What color are we to do it in? | |
899 $is_reverse = $showReverseChars ? mt_rand(0, 1) : false; | |
900 $char_color = function_exists('imagecolorallocatealpha') && $fontTrans ? imagecolorallocatealpha($code_image, $char_fg_color[0], $char_fg_color[1], $char_fg_color[2], 50) : imagecolorallocate($code_image, $char_fg_color[0], $char_fg_color[1], $char_fg_color[2]); | |
901 | |
902 $fontcord = @imagettftext($code_image, $font_size, $angle, $font_x, $font_y, $char_color, $fontface, $character['id']); | |
903 if (empty($fontcord)) | |
904 $can_do_ttf = false; | |
905 elseif ($is_reverse) | |
906 { | |
907 imagefilledpolygon($code_image, $fontcord, 4, $fg_color); | |
908 // Put the character back! | |
909 imagettftext($code_image, $font_size, $angle, $font_x, $font_y, $randomness_color, $fontface, $character['id']); | |
910 } | |
911 | |
912 if ($can_do_ttf) | |
913 $cur_x = max($fontcord[2], $fontcord[4]) + ($angle == 0 ? 0 : 3); | |
914 } | |
915 | |
916 if (!$can_do_ttf) | |
917 { | |
918 // Rotating the characters a little... | |
919 if (function_exists('imagerotate')) | |
920 { | |
921 $char_image = $gd2 ? imagecreatetruecolor($character['width'], $character['height']) : imagecreate($character['width'], $character['height']); | |
922 $char_bgcolor = imagecolorallocate($char_image, $background_color[0], $background_color[1], $background_color[2]); | |
923 imagefilledrectangle($char_image, 0, 0, $character['width'] - 1, $character['height'] - 1, $char_bgcolor); | |
924 imagechar($char_image, $loaded_fonts[$character['font']], 0, 0, $character['id'], imagecolorallocate($char_image, $char_fg_color[0], $char_fg_color[1], $char_fg_color[2])); | |
925 $rotated_char = imagerotate($char_image, mt_rand(-100, 100) / 10, $char_bgcolor); | |
926 imagecopy($code_image, $rotated_char, $cur_x, 0, 0, 0, $character['width'], $character['height']); | |
927 imagedestroy($rotated_char); | |
928 imagedestroy($char_image); | |
929 } | |
930 | |
931 // Sorry, no rotation available. | |
932 else | |
933 imagechar($code_image, $loaded_fonts[$character['font']], $cur_x, floor(($max_height - $character['height']) / 2), $character['id'], imagecolorallocate($code_image, $char_fg_color[0], $char_fg_color[1], $char_fg_color[2])); | |
934 $cur_x += $character['width'] + $character_spacing; | |
935 } | |
936 } | |
937 } | |
938 // If disabled just show a cross. | |
939 else | |
940 { | |
941 imageline($code_image, 0, 0, $total_width, $max_height, $fg_color); | |
942 imageline($code_image, 0, $max_height, $total_width, 0, $fg_color); | |
943 } | |
944 | |
945 // Make the background color transparent on the hard image. | |
946 if (!$simpleBGColor) | |
947 imagecolortransparent($code_image, $bg_color); | |
948 if ($hasBorder) | |
949 imagerectangle($code_image, 0, 0, $total_width - 1, $max_height - 1, $fg_color); | |
950 | |
951 // Add some noise to the background? | |
952 if ($noiseType != 'none') | |
953 { | |
954 for ($i = mt_rand(0, 2); $i < $max_height; $i += mt_rand(1, 2)) | |
955 for ($j = mt_rand(0, 10); $j < $total_width; $j += mt_rand(1, 10)) | |
956 imagesetpixel($code_image, $j, $i, mt_rand(0, 1) ? $fg_color : $randomness_color); | |
957 | |
958 // Put in some lines too? | |
959 if ($noiseType != 'extreme') | |
960 { | |
961 $num_lines = $noiseType == 'high' ? mt_rand(3, 7) : mt_rand(2, 5); | |
962 for ($i = 0; $i < $num_lines; $i++) | |
963 { | |
964 if (mt_rand(0, 1)) | |
965 { | |
966 $x1 = mt_rand(0, $total_width); | |
967 $x2 = mt_rand(0, $total_width); | |
968 $y1 = 0; $y2 = $max_height; | |
969 } | |
970 else | |
971 { | |
972 $y1 = mt_rand(0, $max_height); | |
973 $y2 = mt_rand(0, $max_height); | |
974 $x1 = 0; $x2 = $total_width; | |
975 } | |
976 imagesetthickness($code_image, mt_rand(1, 2)); | |
977 imageline($code_image, $x1, $y1, $x2, $y2, mt_rand(0, 1) ? $fg_color : $randomness_color); | |
978 } | |
979 } | |
980 else | |
981 { | |
982 // Put in some ellipse | |
983 $num_ellipse = $noiseType == 'extreme' ? mt_rand(6, 12) : mt_rand(2, 6); | |
984 for ($i = 0; $i < $num_ellipse; $i++) | |
985 { | |
986 $x1 = round(rand(($total_width / 4) * -1, $total_width + ($total_width / 4))); | |
987 $x2 = round(rand($total_width / 2, 2 * $total_width)); | |
988 $y1 = round(rand(($max_height / 4) * -1, $max_height + ($max_height / 4))); | |
989 $y2 = round(rand($max_height / 2, 2 * $max_height)); | |
990 imageellipse($code_image, $x1, $y1, $x2, $y2, mt_rand(0, 1) ? $fg_color : $randomness_color); | |
991 } | |
992 } | |
993 } | |
994 | |
995 // Show the image. | |
996 if (function_exists('imagegif')) | |
997 { | |
998 header('Content-type: image/gif'); | |
999 imagegif($code_image); | |
1000 } | |
1001 else | |
1002 { | |
1003 header('Content-type: image/png'); | |
1004 imagepng($code_image); | |
1005 } | |
1006 | |
1007 // Bail out. | |
1008 imagedestroy($code_image); | |
1009 die(); | |
1010 } | |
1011 | |
1012 // Create a letter for the visual verification code. | |
1013 function showLetterImage($letter) | |
1014 { | |
1015 global $settings; | |
1016 | |
1017 if (!is_dir($settings['default_theme_dir'] . '/fonts')) | |
1018 return false; | |
1019 | |
1020 // Get a list of the available font directories. | |
1021 $font_dir = dir($settings['default_theme_dir'] . '/fonts'); | |
1022 $font_list = array(); | |
1023 while ($entry = $font_dir->read()) | |
1024 if ($entry[0] !== '.' && is_dir($settings['default_theme_dir'] . '/fonts/' . $entry) && file_exists($settings['default_theme_dir'] . '/fonts/' . $entry . '.gdf')) | |
1025 $font_list[] = $entry; | |
1026 | |
1027 if (empty($font_list)) | |
1028 return false; | |
1029 | |
1030 // Pick a random font. | |
1031 $random_font = $font_list[array_rand($font_list)]; | |
1032 | |
1033 // Check if the given letter exists. | |
1034 if (!file_exists($settings['default_theme_dir'] . '/fonts/' . $random_font . '/' . $letter . '.gif')) | |
1035 return false; | |
1036 | |
1037 // Include it! | |
1038 header('Content-type: image/gif'); | |
1039 include($settings['default_theme_dir'] . '/fonts/' . $random_font . '/' . $letter . '.gif'); | |
1040 | |
1041 // Nothing more to come. | |
1042 die(); | |
1043 } | |
1044 | |
1045 ?> |