|
1 <?php |
|
2 |
|
3 /* |
|
4 * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between |
|
5 * Version 1.1.1 (Caoineag alpha 1) |
|
6 * Copyright (C) 2006-2007 Dan Fuhry |
|
7 * captcha.php - visual confirmation system used during registration |
|
8 * |
|
9 * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License |
|
10 * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. |
|
11 * |
|
12 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied |
|
13 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. |
|
14 */ |
|
15 |
|
16 /** |
|
17 * A more complex captcha engine that relies on GD. |
|
18 * @package Enano |
|
19 * @subpackage User management |
|
20 * @copyright 2007-2008 Dan Fuhry |
|
21 * @copyright 2002-2008 phpBB Group |
|
22 */ |
|
23 |
|
24 class captcha_engine_potpourri extends captcha_base |
|
25 { |
|
26 var $captcha_config; |
|
27 |
|
28 function __construct($sid, $r = false) |
|
29 { |
|
30 parent::__construct($sid, $r); |
|
31 |
|
32 $hex = Array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'); |
|
33 $latticecolor = '#'; |
|
34 for ( $i = 0; $i < 6; $i++ ) |
|
35 $latticecolor .= $hex[mt_rand(0, 15)]; |
|
36 |
|
37 $this->captcha_config = array ( |
|
38 'width' => '350', |
|
39 'height' => '90', |
|
40 'background_color' => '#E5ECF9', |
|
41 'jpeg' => '0', |
|
42 'jpeg_quality' => '95', |
|
43 'pre_letters' => '1', |
|
44 'pre_letters_great' => '0', |
|
45 'font' => '1', |
|
46 'chess' => '2', |
|
47 'ellipses' => '2', |
|
48 'arcs' => '2', |
|
49 'lines' => '2', |
|
50 'image' => '0', |
|
51 'gammacorrect' => '0.8', |
|
52 'foreground_lattice_x' => (string)mt_rand(25, 30), |
|
53 'foreground_lattice_y' => (string)mt_rand(25, 30), |
|
54 'lattice_color' => $latticecolor, |
|
55 ); |
|
56 } |
|
57 |
|
58 function make_image() |
|
59 { |
|
60 $code = $this->get_code(); |
|
61 |
|
62 // Prefs |
|
63 $total_width = $this->captcha_config['width']; |
|
64 $total_height = $this->captcha_config['height']; |
|
65 |
|
66 $hex_bg_color = $this->get_rgb($this->captcha_config['background_color']); |
|
67 $bg_color = array(); |
|
68 $bg_color = explode(",", $hex_bg_color); |
|
69 |
|
70 $jpeg = $this->captcha_config['jpeg']; |
|
71 $img_quality = $this->captcha_config['jpeg_quality']; |
|
72 // Max quality is 95 |
|
73 |
|
74 $pre_letters = $this->captcha_config['pre_letters']; |
|
75 $pre_letter_great = $this->captcha_config['pre_letters_great']; |
|
76 $rnd_font = $this->captcha_config['font']; |
|
77 $chess = $this->captcha_config['chess']; |
|
78 $ellipses = $this->captcha_config['ellipses']; |
|
79 $arcs = $this->captcha_config['arcs']; |
|
80 $lines = $this->captcha_config['lines']; |
|
81 $image = $this->captcha_config['image']; |
|
82 |
|
83 $gammacorrect = $this->captcha_config['gammacorrect']; |
|
84 |
|
85 $foreground_lattice_y = $this->captcha_config['foreground_lattice_y']; |
|
86 $foreground_lattice_x = $this->captcha_config['foreground_lattice_x']; |
|
87 $hex_lattice_color = $this->get_rgb($this->captcha_config['lattice_color']); |
|
88 $rgb_lattice_color = array(); |
|
89 $rgb_lattice_color = explode(",", $hex_lattice_color); |
|
90 |
|
91 $font_debug = false; |
|
92 |
|
93 // Fonts and images init |
|
94 if ($image) |
|
95 { |
|
96 $bg_imgs = array(); |
|
97 if ($img_dir = opendir(ENANO_ROOT.'/includes/captcha/pics/')) |
|
98 { |
|
99 while (true == ($file = @readdir($img_dir))) |
|
100 { |
|
101 if ((substr(strtolower($file), -3) == 'jpg') || (substr(strtolower($file), -3) == 'gif')) |
|
102 { |
|
103 $bg_imgs[] = $file; |
|
104 } |
|
105 } |
|
106 closedir($img_dir); |
|
107 } |
|
108 // Grab a random Background Image or set FALSE if none was found |
|
109 $bg_img = ( count($bg_imgs) ) ? rand(0, (count($bg_imgs)-1)) : false; |
|
110 } |
|
111 |
|
112 $fonts = array(); |
|
113 if ($fonts_dir = opendir(ENANO_ROOT . '/includes/captcha/fonts/')) |
|
114 { |
|
115 while (true == ($file = @readdir($fonts_dir))) |
|
116 { |
|
117 if ((substr(strtolower($file), strlen($file)-3, strlen($file)) == 'ttf')) |
|
118 { |
|
119 $fonts[] = $file; |
|
120 } |
|
121 } |
|
122 closedir($fonts_dir); |
|
123 } else { |
|
124 die('Error reading directory: '.ENANO_ROOT.'/includes/captcha/fonts/'); |
|
125 } |
|
126 $font = mt_rand(0, (count($fonts)-1)); |
|
127 |
|
128 // Generate |
|
129 $image = ($this->gdVersion() >= 2) ? imagecreatetruecolor($total_width, $total_height) : imagecreate($total_width, $total_height); |
|
130 $background_color = imagecolorallocate($image, $bg_color[0], $bg_color[1], $bg_color[2]); |
|
131 imagefill($image, 0, 0, $background_color); |
|
132 |
|
133 // Generate backgrund |
|
134 if ($chess == '1' || $chess == '2' && rand(0,1)) |
|
135 { |
|
136 // Draw rectangles |
|
137 for($i = 0; $i <= 8; $i++) |
|
138 { |
|
139 $rectanglecolor = imagecolorallocate($image, rand(100,200),rand(100,200),rand(100,200)); |
|
140 imagefilledrectangle($image, 0, 0, round($total_width-($total_width/8*$i)), round($total_height), $rectanglecolor); |
|
141 $rectanglecolor = imagecolorallocate($image, rand(100,200),rand(100,200),rand(100,200)); |
|
142 imagefilledrectangle($image, 0, 0, round($total_width-($total_width/8*$i)), round($total_height/2), $rectanglecolor); |
|
143 } |
|
144 } |
|
145 if ($ellipses == '1' || $ellipses == '2' && rand(0,1)) |
|
146 { |
|
147 // Draw random ellipses |
|
148 for ($i = 1; $i <= 60; $i++) |
|
149 { |
|
150 $ellipsecolor = imagecolorallocate($image, rand(100,250),rand(100,250),rand(100,250)); |
|
151 imagefilledellipse($image, round(rand(0, $total_width)), round(rand(0, $total_height)), round(rand(0, $total_width/8)), round(rand(0, $total_height/4)), $ellipsecolor); |
|
152 } |
|
153 } |
|
154 if ($arcs == '1' || $arcs == '2' && rand(0,1)) |
|
155 { |
|
156 // Draw random partial ellipses |
|
157 for ($i = 0; $i <= 30; $i++) |
|
158 { |
|
159 $linecolor = imagecolorallocate($image, rand(120,255),rand(120,255),rand(120,255)); |
|
160 $cx = round(rand(1, $total_width)); |
|
161 $cy = round(rand(1, $total_height)); |
|
162 $int_w = round(rand(1, $total_width/2)); |
|
163 $int_h = round(rand(1, $total_height)); |
|
164 imagearc($image, $cx, $cy, $int_w, $int_h, round(rand(0, 190)), round(rand(191, 360)), $linecolor); |
|
165 imagearc($image, $cx-1, $cy-1, $int_w, $int_h, round(rand(0, 190)), round(rand(191, 360)), $linecolor); |
|
166 } |
|
167 } |
|
168 if ($lines == '1' || $lines == '2' && rand(0,1)) |
|
169 { |
|
170 // Draw random lines |
|
171 for ($i = 0; $i <= 50; $i++) |
|
172 { |
|
173 $linecolor = imagecolorallocate($image, rand(120,255),rand(120,255),rand(120,255)); |
|
174 imageline($image, round(rand(1, $total_width*3)), round(rand(1, $total_height*5)), round(rand(1, $total_width/2)), round(rand(1, $total_height*2)), $linecolor); |
|
175 } |
|
176 } |
|
177 |
|
178 $text_color_array = array('255,51,0', '51,77,255', '204,51,102', '0,153,0', '255,166,2', '255,0,255', '255,0,0', '0,255,0', '0,0,255', '0,255,255'); |
|
179 shuffle($text_color_array); |
|
180 $pre_text_color_array = array('255,71,20', '71,20,224', '224,71,122', '20,173,20', '255,186,22', '25,25,25'); |
|
181 shuffle($pre_text_color_array); |
|
182 $white = imagecolorallocate($image, 255, 255, 255); |
|
183 $gray = imagecolorallocate($image, 100, 100, 100); |
|
184 $black = imagecolorallocate($image, 0, 0, 0); |
|
185 $lattice_color = imagecolorallocate($image, $rgb_lattice_color[0], $rgb_lattice_color[1], $rgb_lattice_color[2]); |
|
186 |
|
187 $x_char_position = (round(($total_width - 12) / strlen($code)) + mt_rand(-3, 5)); |
|
188 |
|
189 for ($i = 0; $i < strlen($code); $i++) |
|
190 { |
|
191 mt_srand((double)microtime()*1000000); |
|
192 |
|
193 $char = $code{$i}; |
|
194 $size = mt_rand(floor($total_height / 3.5), ceil($total_height / 2.8)); |
|
195 $font = ($rnd_font) ? rand(0, (count($fonts)-1)) : $font; |
|
196 $angle = mt_rand(-30, 30); |
|
197 |
|
198 $char_pos = array(); |
|
199 $char_pos = imagettfbbox($size, $angle, ENANO_ROOT.'/includes/captcha/fonts/'.$fonts[$font], $char); |
|
200 $letter_width = abs($char_pos[0]) + abs($char_pos[4]); |
|
201 $letter_height = abs($char_pos[1]) + abs($char_pos[5]); |
|
202 |
|
203 $x_pos = ($x_char_position / 4) + ($i * $x_char_position); |
|
204 ($i == strlen($code)-1 && $x_pos >= ($total_width - ($letter_width + 5))) ? $x_pos = ($total_width - ($letter_width + 5)) : ''; |
|
205 $y_pos = mt_rand(($size * 1.4 ), $total_height - ($size * 0.4)); |
|
206 |
|
207 // Pre letters |
|
208 $size = ($pre_letter_great) ? $size + (2 * $pre_letters) : $size - (2 * $pre_letters); |
|
209 for ($count = 1; $count <= $pre_letters; $count++) |
|
210 { |
|
211 $pre_angle = $angle + mt_rand(-20, 20); |
|
212 |
|
213 $text_color = $pre_text_color_array[mt_rand(0,count($pre_text_color_array)-1)]; |
|
214 $text_color = explode(",", $text_color); |
|
215 $textcolor = imagecolorallocate($image, $text_color[0], $text_color[1], $text_color[2]); |
|
216 |
|
217 imagettftext($image, $size, $pre_angle, $x_pos, $y_pos-2, $white, ENANO_ROOT.'/includes/captcha/fonts/'.$fonts[$font], $char); |
|
218 imagettftext($image, $size, $pre_angle, $x_pos+2, $y_pos, $black, ENANO_ROOT.'/includes/captcha/fonts/'.$fonts[$font], $char); |
|
219 imagettftext($image, $size, $pre_angle, $x_pos+1, $y_pos-1, $textcolor, ENANO_ROOT.'/includes/captcha/fonts/'.$fonts[$font], $char); |
|
220 |
|
221 $size = ($pre_letter_great) ? $size - 2 : $size + 2; |
|
222 } |
|
223 |
|
224 // Final letters |
|
225 $text_color = $text_color_array[mt_rand(0,count($text_color_array)-1)]; |
|
226 $text_color = explode(",", $text_color); |
|
227 $textcolor = imagecolorallocate($image, $text_color[0], $text_color[1], $text_color[2]); |
|
228 |
|
229 imagettftext($image, $size, $angle, $x_pos, $y_pos-2, $white, ENANO_ROOT.'/includes/captcha/fonts/'.$fonts[$font], $char); |
|
230 imagettftext($image, $size, $angle, $x_pos+2, $y_pos, $black, ENANO_ROOT.'/includes/captcha/fonts/'.$fonts[$font], $char); |
|
231 imagettftext($image, $size, $angle, $x_pos+1, $y_pos-1, $textcolor, ENANO_ROOT.'/includes/captcha/fonts/'.$fonts[$font], $char); |
|
232 } |
|
233 |
|
234 |
|
235 ($gammacorrect) ? imagegammacorrect($image, 1.0, $gammacorrect) : ''; |
|
236 |
|
237 // Generate a white lattice in foreground |
|
238 if ($foreground_lattice_y) |
|
239 { |
|
240 // x lines |
|
241 $ih = round($total_height / $foreground_lattice_y); |
|
242 for ($i = 0; $i <= $ih; $i++) |
|
243 { |
|
244 imageline($image, 0, $i*$foreground_lattice_y, $total_width, $i*$foreground_lattice_y, $lattice_color); |
|
245 } |
|
246 } |
|
247 if ($foreground_lattice_x) |
|
248 { |
|
249 // y lines |
|
250 $iw = round($total_width / $foreground_lattice_x); |
|
251 for ($i = 0; $i <= $iw; $i++) |
|
252 { |
|
253 imageline($image, $i*$foreground_lattice_x, 0, $i*$foreground_lattice_x, $total_height, $lattice_color); |
|
254 } |
|
255 } |
|
256 |
|
257 // Font debug |
|
258 if ($font_debug && !$rnd_font) |
|
259 { |
|
260 imagestring($image, 5, 2, 0, $fonts[$font], $white); |
|
261 imagestring($image, 5, 5, 0, $fonts[$font], $white); |
|
262 imagestring($image, 5, 4, 2, $fonts[$font], $gray); |
|
263 imagestring($image, 5, 3, 1, $fonts[$font], $black); |
|
264 } |
|
265 |
|
266 // Display |
|
267 header("Last-Modified: " . gmdate("D, d M Y H:i:s") ." GMT"); |
|
268 header("Pragma: no-cache"); |
|
269 header("Cache-Control: no-store, no-cache, max-age=0, must-revalidate"); |
|
270 (!$jpeg) ? header("Content-Type: image/png") : header("Content-Type: image/jpeg"); |
|
271 |
|
272 (!$jpeg) ? imagepng($image) : imagejpeg($image, '', $img_quality); |
|
273 imagedestroy($image); |
|
274 } |
|
275 |
|
276 // Function get_rgb by Frank Burian |
|
277 // http://www.phpfuncs.org/?content=show&id=46 |
|
278 function get_rgb($hex) { |
|
279 $hex_array = array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, |
|
280 'A' => 10, 'B' => 11, 'C' => 12, 'D' => 13, 'E' => 14, |
|
281 'F' => 15); |
|
282 $hex = str_replace('#', '', strtoupper($hex)); |
|
283 if (($length = strlen($hex)) == 3) { |
|
284 $hex = $hex{0}.$hex{0}.$hex{1}.$hex{1}.$hex{2}.$hex{2}; |
|
285 $length = 6; |
|
286 } |
|
287 if ($length != 6 or strlen(str_replace(array_keys($hex_array), '', $hex))) |
|
288 return NULL; |
|
289 $rgb['r'] = $hex_array[$hex{0}] * 16 + $hex_array[$hex{1}]; |
|
290 $rgb['g'] = $hex_array[$hex{2}] * 16 + $hex_array[$hex{3}]; |
|
291 $rgb['b']= $hex_array[$hex{4}] * 16 + $hex_array[$hex{5}]; |
|
292 return $rgb['r'].','.$rgb['g'].','.$rgb['b']; |
|
293 } |
|
294 |
|
295 // Function gdVersion by Hagan Fox |
|
296 // http://de3.php.net/manual/en/function.gd-info.php#52481 |
|
297 function gdVersion($user_ver = 0) |
|
298 { |
|
299 if (! extension_loaded('gd')) { return; } |
|
300 static $gd_ver = 0; |
|
301 // Just accept the specified setting if it's 1. |
|
302 if ($user_ver == 1) { $gd_ver = 1; return 1; } |
|
303 // Use the static variable if function was called previously. |
|
304 if ($user_ver !=2 && $gd_ver > 0 ) { return $gd_ver; } |
|
305 // Use the gd_info() function if possible. |
|
306 if (function_exists('gd_info')) { |
|
307 $ver_info = gd_info(); |
|
308 preg_match('/\d/', $ver_info['GD Version'], $match); |
|
309 $gd_ver = $match[0]; |
|
310 return $match[0]; |
|
311 } |
|
312 // If phpinfo() is disabled use a specified / fail-safe choice... |
|
313 if (preg_match('/phpinfo/', ini_get('disable_functions'))) { |
|
314 if ($user_ver == 2) { |
|
315 $gd_ver = 2; |
|
316 return 2; |
|
317 } else { |
|
318 $gd_ver = 1; |
|
319 return 1; |
|
320 } |
|
321 } |
|
322 // ...otherwise use phpinfo(). |
|
323 ob_start(); |
|
324 phpinfo(8); |
|
325 $info = ob_get_contents(); |
|
326 ob_end_clean(); |
|
327 $info = stristr($info, 'gd version'); |
|
328 preg_match('/\d/', $info, $match); |
|
329 $gd_ver = $match[0]; |
|
330 return $match[0]; |
|
331 } |
|
332 } |