captcha.class.php 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. <?php
  2. defined('IN_IA') or exit('Access Denied');
  3. class Captcha {
  4. public $maxAngle = 15;
  5. public $maxOffset = 5;
  6. public $phrase = '';
  7. public function build($width, $height) {
  8. $image = @imagecreatetruecolor($width, $height);
  9. if (empty($image)) {
  10. return error('1', 'Not supplied GD');
  11. }
  12. $bg = imagecolorallocate($image, $this->rand(200, 255), $this->rand(200, 255), $this->rand(200, 255));
  13. imagefill($image, 0, 0, $bg);
  14. $square = $width * $height * 3;
  15. $effects = $this->rand($square / 2000, $square / 1000);
  16. for ($e = 0; $e < $effects; ++$e) {
  17. $this->drawLine($image, $width, $height);
  18. }
  19. $this->phrase = $this->phrase();
  20. $color = $this->writePhrase($image, $this->phrase, $this->font(), $width, $height);
  21. $square = $width * $height;
  22. $effects = $this->rand($square / 3000, $square / 2000);
  23. if (0 !== $this->maxFrontLines) {
  24. for ($e = 0; $e < $effects; ++$e) {
  25. $this->drawLine($image, $width, $height, $color);
  26. }
  27. }
  28. $image = $this->distort($image, $width, $height, $bg);
  29. $this->image = $image;
  30. return $this;
  31. }
  32. public function output($quality = 90) {
  33. header('content-type: image/png');
  34. imagepng($this->image);
  35. imagedestroy($this->image);
  36. }
  37. protected function phrase() {
  38. return random(4, true);
  39. }
  40. protected function rand($min, $max) {
  41. mt_srand((float) microtime() * 1000000);
  42. return mt_rand($min, $max);
  43. }
  44. protected function drawLine($image, $width, $height, $tcol = null) {
  45. if (null === $tcol) {
  46. $tcol = imagecolorallocate($image, $this->rand(100, 255), $this->rand(100, 255), $this->rand(100, 255));
  47. }
  48. if ($this->rand(0, 1)) {
  49. $Xa = $this->rand(0, $width / 2);
  50. $Ya = $this->rand(0, $height);
  51. $Xb = $this->rand($width / 2, $width);
  52. $Yb = $this->rand(0, $height);
  53. } else {
  54. $Xa = $this->rand(0, $width);
  55. $Ya = $this->rand(0, $height / 2);
  56. $Xb = $this->rand(0, $width);
  57. $Yb = $this->rand($height / 2, $height);
  58. }
  59. imagesetthickness($image, $this->rand(1, 3));
  60. imageline($image, $Xa, $Ya, $Xb, $Yb, $tcol);
  61. }
  62. protected function writePhrase($image, $phrase, $font, $width, $height) {
  63. $size = $width / strlen($phrase) - $this->rand(0, 3) - 1;
  64. $box = imagettfbbox($size, 0, $font, $phrase);
  65. $textWidth = $box[2] - $box[0];
  66. $textHeight = $box[1] - $box[7];
  67. $x = ($width - $textWidth) / 2;
  68. $y = ($height - $textHeight) / 2 + $size;
  69. $textColor = array($this->rand(0, 150), $this->rand(0, 150), $this->rand(0, 150));
  70. $col = imagecolorallocate($image, $textColor[0], $textColor[1], $textColor[2]);
  71. $length = strlen($phrase);
  72. for ($i = 0; $i < $length; ++$i) {
  73. $box = imagettfbbox($size, 0, $font, $phrase[$i]);
  74. $w = $box[2] - $box[0];
  75. $angle = $this->rand(-$this->maxAngle, $this->maxAngle);
  76. $offset = $this->rand(-$this->maxOffset, $this->maxOffset);
  77. imagettftext($image, $size, $angle, $x, $y + $offset, $col, $font, $phrase[$i]);
  78. $x += $w;
  79. }
  80. return $col;
  81. }
  82. public function distort($image, $width, $height, $bg) {
  83. $contents = imagecreatetruecolor($width, $height);
  84. $X = $this->rand(0, $width);
  85. $Y = $this->rand(0, $height);
  86. $phase = $this->rand(0, 10);
  87. $scale = 1.1 + $this->rand(0, 10000) / 30000;
  88. for ($x = 0; $x < $width; ++$x) {
  89. for ($y = 0; $y < $height; ++$y) {
  90. $Vx = $x - $X;
  91. $Vy = $y - $Y;
  92. $Vn = sqrt($Vx * $Vx + $Vy * $Vy);
  93. if (0 != $Vn) {
  94. $Vn2 = $Vn + 4 * sin($Vn / 30);
  95. $nX = $X + ($Vx * $Vn2 / $Vn);
  96. $nY = $Y + ($Vy * $Vn2 / $Vn);
  97. } else {
  98. $nX = $X;
  99. $nY = $Y;
  100. }
  101. $nY = $nY + $scale * sin($phase + $nX * 0.2);
  102. $p = $this->interpolate(
  103. $nX - floor($nX),
  104. $nY - floor($nY),
  105. $this->getCol($image, floor($nX), floor($nY), $bg),
  106. $this->getCol($image, ceil($nX), floor($nY), $bg),
  107. $this->getCol($image, floor($nX), ceil($nY), $bg),
  108. $this->getCol($image, ceil($nX), ceil($nY), $bg)
  109. );
  110. if (0 == $p) {
  111. $p = $bg;
  112. }
  113. imagesetpixel($contents, $x, $y, $p);
  114. }
  115. }
  116. return $contents;
  117. }
  118. protected function interpolate($x, $y, $nw, $ne, $sw, $se) {
  119. list($r0, $g0, $b0) = $this->getRGB($nw);
  120. list($r1, $g1, $b1) = $this->getRGB($ne);
  121. list($r2, $g2, $b2) = $this->getRGB($sw);
  122. list($r3, $g3, $b3) = $this->getRGB($se);
  123. $cx = 1.0 - $x;
  124. $cy = 1.0 - $y;
  125. $m0 = $cx * $r0 + $x * $r1;
  126. $m1 = $cx * $r2 + $x * $r3;
  127. $r = (int) ($cy * $m0 + $y * $m1);
  128. $m0 = $cx * $g0 + $x * $g1;
  129. $m1 = $cx * $g2 + $x * $g3;
  130. $g = (int) ($cy * $m0 + $y * $m1);
  131. $m0 = $cx * $b0 + $x * $b1;
  132. $m1 = $cx * $b2 + $x * $b3;
  133. $b = (int) ($cy * $m0 + $y * $m1);
  134. return ($r << 16) | ($g << 8) | $b;
  135. }
  136. protected function getRGB($col) {
  137. return array(
  138. (int) ($col >> 16) & 0xff,
  139. (int) ($col >> 8) & 0xff,
  140. (int) ($col) & 0xff,
  141. );
  142. }
  143. protected function getCol($image, $x, $y, $background) {
  144. $L = imagesx($image);
  145. $H = imagesy($image);
  146. if ($x < 0 || $x >= $L || $y < 0 || $y >= $H) {
  147. return $background;
  148. }
  149. return imagecolorat($image, $x, $y);
  150. }
  151. protected function font() {
  152. return IA_ROOT . '/web/resource/fonts/captcha.ttf';
  153. }
  154. }