1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10:
11:
12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26:
27: class XoopsCaptchaImageHandler
28: {
29: 30: 31:
32: public $config = array();
33: 34: 35:
36: public $code;
37:
38: 39: 40:
41: public $mode = 'gd';
42:
43: 44: 45:
46: public $invalid = false;
47:
48: 49: 50:
51: public $font;
52:
53: 54: 55:
56: public $spacing;
57:
58: 59: 60:
61: public $width;
62:
63: 64: 65:
66: public $height;
67:
68: 69: 70:
71: public $captcha_handler;
72:
73: 74: 75:
76: public $oImage;
77:
78: 79: 80:
81: protected $xoops_root_path;
82:
83: 84: 85:
86: public function __construct()
87: {
88: $this->captcha_handler = XoopsCaptcha::getInstance();
89: $this->config = $this->captcha_handler->loadConfig("image");
90: $this->xoops_root_path = \XoopsBaseConfig::get('root-path');
91: }
92:
93: 94: 95: 96: 97:
98: public function loadImage()
99: {
100: $this->generateCode();
101: $this->createImage();
102: }
103:
104: 105: 106: 107: 108:
109: public function generateCode()
110: {
111: if ($this->invalid) {
112: return false;
113: }
114:
115: if ($this->mode === "bmp") {
116: $this->config["num_chars"] = 4;
117: $this->code = mt_rand(pow(10, $this->config["num_chars"] - 1), (int)(str_pad("9", $this->config["num_chars"], "9")));
118: } else {
119: $raw_code = md5(uniqid(mt_rand(), 1));
120: if (!empty($this->config["skip_characters"])) {
121: $valid_code = str_replace($this->config["skip_characters"], "", $raw_code);
122: $this->code = substr($valid_code, 0, $this->config["num_chars"]);
123: } else {
124: $this->code = substr($raw_code, 0, $this->config["num_chars"]);
125: }
126: if (!$this->config["casesensitive"]) {
127: $this->code = strtoupper($this->code);
128: }
129: }
130: $this->captcha_handler->setCode($this->code);
131: return true;
132: }
133:
134: 135: 136: 137: 138:
139: public function createImage()
140: {
141: if ($this->invalid) {
142: header("Content-type: image/gif");
143: readfile($this->xoops_root_path . "/images/subject/icon2.gif");
144: return false;
145: }
146:
147: if ($this->mode === "bmp") {
148: return $this->createImageBmp();
149: } else {
150: return $this->createImageGd();
151: }
152: }
153:
154: 155: 156: 157: 158: 159: 160: 161:
162: public function getList($name, $extension = "")
163: {
164: if ($items = \Xoops\Cache::read("captcha_captcha_{$name}")) {
165: return $items;
166: }
167: ;
168: $file_path = $this->xoops_root_path . "/class/captcha/image/{$name}";
169: $files = \Xoops\Core\Lists\File::getList($file_path);
170: foreach ($files as $item) {
171: if (empty($extension) || preg_match("/(\.{$extension})$/i", $item)) {
172: $items[] = $item;
173: }
174: }
175: \Xoops\Cache::write("captcha_captcha_{$name}", $items);
176: return $items;
177: }
178:
179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190:
191: public function createImageGd()
192: {
193: $this->loadFont();
194: $this->setImageSize();
195:
196: $this->oImage = imagecreatetruecolor($this->width, $this->height);
197: $background = imagecolorallocate($this->oImage, 255, 255, 255);
198: imagefilledrectangle($this->oImage, 0, 0, $this->width, $this->height, $background);
199: switch ($this->config["background_type"]) {
200: case 0:
201: $this->drawBars();
202: break;
203: case 1:
204: $this->drawCircles();
205: break;
206: case 2:
207: $this->drawLines();
208: break;
209: case 3:
210: $this->drawRectangles();
211: break;
212: case 4:
213: $this->drawEllipses();
214: break;
215: case 5:
216: $this->drawPolygons();
217: break;
218: case 100:
219: $this->createFromFile();
220: break;
221: default:
222: }
223: $this->drawBorder();
224: $this->drawCode();
225:
226: header("Content-type: image/jpeg");
227: imagejpeg($this->oImage);
228: imagedestroy($this->oImage);
229: }
230:
231: 232: 233: 234: 235:
236: public function loadFont()
237: {
238: $fonts = $this->getList("fonts", "ttf");
239: $this->font = $this->xoops_root_path . "/class/captcha/image/fonts/" . $fonts[array_rand($fonts)];
240: }
241:
242: 243: 244: 245: 246:
247: public function setImageSize()
248: {
249: if (empty($this->font)) {
250: $this->loadFont();
251: }
252: $MaxCharWidth = 0;
253: $MaxCharHeight = 0;
254: $oImage = imagecreatetruecolor(100, 100);
255: $FontSize = $this->config["fontsize_max"];
256: for ($Angle = -30; $Angle <= 30; ++$Angle) {
257: for ($i = 65; $i <= 90; ++$i) {
258: $CharDetails = imageftbbox($FontSize, $Angle, $this->font, chr($i), array());
259: $_MaxCharWidth = abs($CharDetails[0] + $CharDetails[2]);
260: if ($_MaxCharWidth > $MaxCharWidth) {
261: $MaxCharWidth = $_MaxCharWidth;
262: }
263: $_MaxCharHeight = abs($CharDetails[1] + $CharDetails[5]);
264: if ($_MaxCharHeight > $MaxCharHeight) {
265: $MaxCharHeight = $_MaxCharHeight;
266: }
267: }
268: }
269: imagedestroy($oImage);
270:
271: $this->height = $MaxCharHeight + 2;
272: $this->spacing = (int)(($this->config["num_chars"] * $MaxCharWidth) / $this->config["num_chars"]);
273: $this->width = (int)(($this->config["num_chars"] * $MaxCharWidth) + ($this->spacing / 2));
274: }
275:
276: 277: 278: 279: 280:
281: public function loadBackground()
282: {
283: $RandBackground = null;
284: if ($backgrounds = $this->getList("backgrounds", "(gif|jpg|png)")) {
285: $RandBackground = $this->xoops_root_path . "/class/captcha/image/backgrounds/" . $backgrounds[array_rand($backgrounds)];
286: }
287: return $RandBackground;
288: }
289:
290: 291: 292: 293: 294:
295: public function createFromFile()
296: {
297: if ($RandImage = $this->loadBackground()) {
298: $ImageType = @getimagesize($RandImage);
299: switch (@$ImageType[2]) {
300: case 1:
301: $BackgroundImage = imagecreatefromgif($RandImage);
302: break;
303: case 2:
304: $BackgroundImage = imagecreatefromjpeg($RandImage);
305: break;
306: case 3:
307: $BackgroundImage = imagecreatefrompng($RandImage);
308: break;
309: }
310: }
311: if (isset($BackgroundImage) && !empty($BackgroundImage)) {
312: imagecopyresized($this->oImage, $BackgroundImage, 0, 0, 0, 0, imagesx($this->oImage), imagesy($this->oImage), imagesx($BackgroundImage), imagesy($BackgroundImage));
313: imagedestroy($BackgroundImage);
314: } else {
315: $this->drawBars();
316: }
317: }
318:
319: 320: 321: 322: 323:
324: public function drawCode()
325: {
326: for ($i = 0; $i < $this->config["num_chars"]; ++$i) {
327:
328: $text_color = imagecolorallocate($this->oImage, mt_rand(0, 100), mt_rand(0, 100), mt_rand(0, 100));
329:
330:
331: $Angle = mt_rand(10, 30);
332: if (($i % 2)) {
333: $Angle = mt_rand(-30, -10);
334: }
335:
336:
337: $FontSize = mt_rand($this->config["fontsize_min"], $this->config["fontsize_max"]);
338:
339: $CharDetails = imageftbbox($FontSize, $Angle, $this->font, $this->code[$i], array());
340: $CharHeight = abs($CharDetails[1] + $CharDetails[5]);
341:
342:
343: $posX = ($this->spacing / 2) + ($i * $this->spacing);
344: $posY = 2 + ($this->height / 2) + ($CharHeight / 4);
345:
346: imagefttext(
347: $this->oImage, $FontSize, $Angle, $posX, $posY, $text_color, $this->font, $this->code[$i], array()
348: );
349: }
350: }
351:
352: 353: 354: 355: 356:
357: public function drawBorder()
358: {
359: $rgb = mt_rand(50, 150);
360: $border_color = imagecolorallocate($this->oImage, $rgb, $rgb, $rgb);
361: imagerectangle($this->oImage, 0, 0, $this->width - 1, $this->height - 1, $border_color);
362: }
363:
364: 365: 366: 367: 368:
369: public function drawCircles()
370: {
371: for ($i = 1; $i <= $this->config["background_num"]; ++$i) {
372: $randomcolor = imagecolorallocate($this->oImage, mt_rand(190, 255), mt_rand(190, 255), mt_rand(190, 255));
373: imagefilledellipse($this->oImage, mt_rand(0, $this->width - 10), mt_rand(0, $this->height - 3), mt_rand(10, 20), mt_rand(20, 30), $randomcolor);
374: }
375: }
376:
377: 378: 379: 380: 381:
382: public function drawLines()
383: {
384: for ($i = 0; $i < $this->config["background_num"]; ++$i) {
385: $randomcolor = imagecolorallocate($this->oImage, mt_rand(190, 255), mt_rand(190, 255), mt_rand(190, 255));
386: imageline($this->oImage, mt_rand(0, $this->width), mt_rand(0, $this->height), mt_rand(0, $this->width), mt_rand(0, $this->height), $randomcolor);
387: }
388: }
389:
390: 391: 392: 393: 394:
395: public function drawRectangles()
396: {
397: for ($i = 1; $i <= $this->config["background_num"]; ++$i) {
398: $randomcolor = imagecolorallocate($this->oImage, mt_rand(190, 255), mt_rand(190, 255), mt_rand(190, 255));
399: imagefilledrectangle($this->oImage, mt_rand(0, $this->width), mt_rand(0, $this->height), mt_rand(0, $this->width), mt_rand(0, $this->height), $randomcolor);
400: }
401: }
402:
403: 404: 405: 406: 407:
408: public function drawBars()
409: {
410: for ($i = 0; $i <= $this->height;) {
411: $randomcolor = imagecolorallocate($this->oImage, mt_rand(190, 255), mt_rand(190, 255), mt_rand(190, 255));
412: imageline($this->oImage, 0, $i, $this->width, $i, $randomcolor);
413: $i = $i + 2.5;
414: }
415: for ($i = 0; $i <= $this->width;) {
416: $randomcolor = imagecolorallocate($this->oImage, mt_rand(190, 255), mt_rand(190, 255), mt_rand(190, 255));
417: imageline($this->oImage, $i, 0, $i, $this->height, $randomcolor);
418: $i = $i + 2.5;
419: }
420: }
421:
422: 423: 424: 425: 426:
427: public function drawEllipses()
428: {
429: for ($i = 1; $i <= $this->config["background_num"]; ++$i) {
430: $randomcolor = imagecolorallocate($this->oImage, mt_rand(190, 255), mt_rand(190, 255), mt_rand(190, 255));
431: imageellipse($this->oImage, mt_rand(0, $this->width), mt_rand(0, $this->height), mt_rand(0, $this->width), mt_rand(0, $this->height), $randomcolor);
432: }
433: }
434:
435: 436: 437: 438: 439:
440: public function drawPolygons()
441: {
442: for ($i = 1; $i <= $this->config["background_num"]; ++$i) {
443: $randomcolor = imagecolorallocate($this->oImage, mt_rand(190, 255), mt_rand(190, 255), mt_rand(190, 255));
444: $coords = array();
445: for ($j = 1; $j <= $this->config["polygon_point"]; ++$j) {
446: $coords[] = mt_rand(0, $this->width);
447: $coords[] = mt_rand(0, $this->height);
448: }
449: imagefilledpolygon($this->oImage, $coords, $this->config["polygon_point"], $randomcolor);
450: }
451: }
452:
453:
454:
455: 456: 457: 458: 459: 460: 461:
462: public function createImageBmp($file = "")
463: {
464: $image = "";
465:
466: if (empty($file)) {
467: header("Content-type: image/bmp");
468: echo $image;
469: exit();
470: } else {
471: return $image;
472: }
473: }
474: }
475: