PageRenderTime 46ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/cool-php-captcha-0.3.1/captcha.php

https://bitbucket.org/marekmurawski/social_login
PHP | 478 lines | 221 code | 146 blank | 111 comment | 34 complexity | bd8f14db1e936f231492b39092ca20fd MD5 | raw file
  1. <?php
  2. /**
  3. * Script para la generacion de CAPTCHAS
  4. *
  5. * @author Jose Rodriguez <jose.rodriguez@exec.cl>
  6. * @license GPLv3
  7. * @link http://code.google.com/p/cool-php-captcha
  8. * @package captcha
  9. * @version 0.3
  10. *
  11. */
  12. /**
  13. * SimpleCaptcha class
  14. *
  15. */
  16. class SimpleCaptcha {
  17. /** Width of the image */
  18. public $width = 200;
  19. /** Height of the image */
  20. public $height = 70;
  21. /** Dictionary word file (empty for random text) */
  22. public $wordsFile = 'words/en.php';
  23. /**
  24. * Path for resource files (fonts, words, etc.)
  25. *
  26. * "resources" by default. For security reasons, is better move this
  27. * directory to another location outise the web server
  28. *
  29. */
  30. public $resourcesPath = 'resources';
  31. /** Min word length (for non-dictionary random text generation) */
  32. public $minWordLength = 5;
  33. /**
  34. * Max word length (for non-dictionary random text generation)
  35. *
  36. * Used for dictionary words indicating the word-length
  37. * for font-size modification purposes
  38. */
  39. public $maxWordLength = 8;
  40. /** Sessionname to store the original text */
  41. public $session_var = 'captcha';
  42. /** Background color in RGB-array */
  43. public $backgroundColor = array(255, 255, 255);
  44. /** Foreground colors in RGB-array */
  45. public $colors = array(
  46. array(27,78,181), // blue
  47. array(22,163,35), // green
  48. array(214,36,7), // red
  49. );
  50. /** Shadow color in RGB-array or null */
  51. public $shadowColor = null; //array(0, 0, 0);
  52. /** Horizontal line through the text */
  53. public $lineWidth = 0;
  54. /**
  55. * Font configuration
  56. *
  57. * - font: TTF file
  58. * - spacing: relative pixel space between character
  59. * - minSize: min font size
  60. * - maxSize: max font size
  61. */
  62. public $fonts = array(
  63. 'Antykwa' => array('spacing' => -3, 'minSize' => 27, 'maxSize' => 30, 'font' => 'AntykwaBold.ttf'),
  64. 'Candice' => array('spacing' =>-1.5,'minSize' => 28, 'maxSize' => 31, 'font' => 'Candice.ttf'),
  65. 'DingDong' => array('spacing' => -2, 'minSize' => 24, 'maxSize' => 30, 'font' => 'Ding-DongDaddyO.ttf'),
  66. 'Duality' => array('spacing' => -2, 'minSize' => 30, 'maxSize' => 38, 'font' => 'Duality.ttf'),
  67. 'Heineken' => array('spacing' => -2, 'minSize' => 24, 'maxSize' => 34, 'font' => 'Heineken.ttf'),
  68. 'Jura' => array('spacing' => -2, 'minSize' => 28, 'maxSize' => 32, 'font' => 'Jura.ttf'),
  69. 'StayPuft' => array('spacing' =>-1.5,'minSize' => 28, 'maxSize' => 32, 'font' => 'StayPuft.ttf'),
  70. 'Times' => array('spacing' => -2, 'minSize' => 28, 'maxSize' => 34, 'font' => 'TimesNewRomanBold.ttf'),
  71. 'VeraSans' => array('spacing' => -1, 'minSize' => 20, 'maxSize' => 28, 'font' => 'VeraSansBold.ttf'),
  72. );
  73. /** Wave configuracion in X and Y axes */
  74. public $Yperiod = 12;
  75. public $Yamplitude = 14;
  76. public $Xperiod = 11;
  77. public $Xamplitude = 5;
  78. /** letter rotation clockwise */
  79. public $maxRotation = 8;
  80. /**
  81. * Internal image size factor (for better image quality)
  82. * 1: low, 2: medium, 3: high
  83. */
  84. public $scale = 2;
  85. /**
  86. * Blur effect for better image quality (but slower image processing).
  87. * Better image results with scale=3
  88. */
  89. public $blur = false;
  90. /** Debug? */
  91. public $debug = false;
  92. /** Image format: jpeg or png */
  93. public $imageFormat = 'jpeg';
  94. /** GD image */
  95. public $im;
  96. public function __construct($config = array()) {
  97. }
  98. public function CreateImage() {
  99. $ini = microtime(true);
  100. /** Initialization */
  101. $this->ImageAllocate();
  102. /** Text insertion */
  103. $text = $this->GetCaptchaText();
  104. $fontcfg = $this->fonts[array_rand($this->fonts)];
  105. $this->WriteText($text, $fontcfg);
  106. $_SESSION[$this->session_var] = $text;
  107. /** Transformations */
  108. if (!empty($this->lineWidth)) {
  109. $this->WriteLine();
  110. }
  111. $this->WaveImage();
  112. if ($this->blur && function_exists('imagefilter')) {
  113. imagefilter($this->im, IMG_FILTER_GAUSSIAN_BLUR);
  114. }
  115. $this->ReduceImage();
  116. if ($this->debug) {
  117. imagestring($this->im, 1, 1, $this->height-8,
  118. "$text {$fontcfg['font']} ".round((microtime(true)-$ini)*1000)."ms",
  119. $this->GdFgColor
  120. );
  121. }
  122. /** Output */
  123. $this->WriteImage();
  124. $this->Cleanup();
  125. }
  126. /**
  127. * Creates the image resources
  128. */
  129. protected function ImageAllocate() {
  130. // Cleanup
  131. if (!empty($this->im)) {
  132. imagedestroy($this->im);
  133. }
  134. $this->im = imagecreatetruecolor($this->width*$this->scale, $this->height*$this->scale);
  135. // Background color
  136. $this->GdBgColor = imagecolorallocate($this->im,
  137. $this->backgroundColor[0],
  138. $this->backgroundColor[1],
  139. $this->backgroundColor[2]
  140. );
  141. imagefilledrectangle($this->im, 0, 0, $this->width*$this->scale, $this->height*$this->scale, $this->GdBgColor);
  142. // Foreground color
  143. $color = $this->colors[mt_rand(0, sizeof($this->colors)-1)];
  144. $this->GdFgColor = imagecolorallocate($this->im, $color[0], $color[1], $color[2]);
  145. // Shadow color
  146. if (!empty($this->shadowColor) && is_array($this->shadowColor) && sizeof($this->shadowColor) >= 3) {
  147. $this->GdShadowColor = imagecolorallocate($this->im,
  148. $this->shadowColor[0],
  149. $this->shadowColor[1],
  150. $this->shadowColor[2]
  151. );
  152. }
  153. }
  154. /**
  155. * Text generation
  156. *
  157. * @return string Text
  158. */
  159. protected function GetCaptchaText() {
  160. $text = $this->GetDictionaryCaptchaText();
  161. if (!$text) {
  162. $text = $this->GetRandomCaptchaText();
  163. }
  164. return $text;
  165. }
  166. /**
  167. * Random text generation
  168. *
  169. * @return string Text
  170. */
  171. protected function GetRandomCaptchaText($length = null) {
  172. if (empty($length)) {
  173. $length = rand($this->minWordLength, $this->maxWordLength);
  174. }
  175. $words = "abcdefghijlmnopqrstvwyz";
  176. $vocals = "aeiou";
  177. $text = "";
  178. $vocal = rand(0, 1);
  179. for ($i=0; $i<$length; $i++) {
  180. if ($vocal) {
  181. $text .= substr($vocals, mt_rand(0, 4), 1);
  182. } else {
  183. $text .= substr($words, mt_rand(0, 22), 1);
  184. }
  185. $vocal = !$vocal;
  186. }
  187. return $text;
  188. }
  189. /**
  190. * Random dictionary word generation
  191. *
  192. * @param boolean $extended Add extended "fake" words
  193. * @return string Word
  194. */
  195. function GetDictionaryCaptchaText($extended = false) {
  196. if (empty($this->wordsFile)) {
  197. return false;
  198. }
  199. // Full path of words file
  200. if (substr($this->wordsFile, 0, 1) == '/') {
  201. $wordsfile = $this->wordsFile;
  202. } else {
  203. $wordsfile = $this->resourcesPath.'/'.$this->wordsFile;
  204. }
  205. if (!file_exists($wordsfile)) {
  206. return false;
  207. }
  208. $fp = fopen($wordsfile, "r");
  209. $length = strlen(fgets($fp));
  210. if (!$length) {
  211. return false;
  212. }
  213. $line = rand(1, (filesize($wordsfile)/$length)-2);
  214. if (fseek($fp, $length*$line) == -1) {
  215. return false;
  216. }
  217. $text = trim(fgets($fp));
  218. fclose($fp);
  219. /** Change ramdom volcals */
  220. if ($extended) {
  221. $text = preg_split('//', $text, -1, PREG_SPLIT_NO_EMPTY);
  222. $vocals = array('a', 'e', 'i', 'o', 'u');
  223. foreach ($text as $i => $char) {
  224. if (mt_rand(0, 1) && in_array($char, $vocals)) {
  225. $text[$i] = $vocals[mt_rand(0, 4)];
  226. }
  227. }
  228. $text = implode('', $text);
  229. }
  230. return $text;
  231. }
  232. /**
  233. * Horizontal line insertion
  234. */
  235. protected function WriteLine() {
  236. $x1 = $this->width*$this->scale*.15;
  237. $x2 = $this->textFinalX;
  238. $y1 = rand($this->height*$this->scale*.40, $this->height*$this->scale*.65);
  239. $y2 = rand($this->height*$this->scale*.40, $this->height*$this->scale*.65);
  240. $width = $this->lineWidth/2*$this->scale;
  241. for ($i = $width*-1; $i <= $width; $i++) {
  242. imageline($this->im, $x1, $y1+$i, $x2, $y2+$i, $this->GdFgColor);
  243. }
  244. }
  245. /**
  246. * Text insertion
  247. */
  248. protected function WriteText($text, $fontcfg = array()) {
  249. if (empty($fontcfg)) {
  250. // Select the font configuration
  251. $fontcfg = $this->fonts[array_rand($this->fonts)];
  252. }
  253. // Full path of font file
  254. $fontfile = $this->resourcesPath.'/fonts/'.$fontcfg['font'];
  255. /** Increase font-size for shortest words: 9% for each glyp missing */
  256. $lettersMissing = $this->maxWordLength-strlen($text);
  257. $fontSizefactor = 1+($lettersMissing*0.09);
  258. // Text generation (char by char)
  259. $x = 20*$this->scale;
  260. $y = round(($this->height*27/40)*$this->scale);
  261. $length = strlen($text);
  262. for ($i=0; $i<$length; $i++) {
  263. $degree = rand($this->maxRotation*-1, $this->maxRotation);
  264. $fontsize = rand($fontcfg['minSize'], $fontcfg['maxSize'])*$this->scale*$fontSizefactor;
  265. $letter = substr($text, $i, 1);
  266. if ($this->shadowColor) {
  267. $coords = imagettftext($this->im, $fontsize, $degree,
  268. $x+$this->scale, $y+$this->scale,
  269. $this->GdShadowColor, $fontfile, $letter);
  270. }
  271. $coords = imagettftext($this->im, $fontsize, $degree,
  272. $x, $y,
  273. $this->GdFgColor, $fontfile, $letter);
  274. $x += ($coords[2]-$x) + ($fontcfg['spacing']*$this->scale);
  275. }
  276. $this->textFinalX = $x;
  277. }
  278. /**
  279. * Wave filter
  280. */
  281. protected function WaveImage() {
  282. // X-axis wave generation
  283. $xp = $this->scale*$this->Xperiod*rand(1,3);
  284. $k = rand(0, 100);
  285. for ($i = 0; $i < ($this->width*$this->scale); $i++) {
  286. imagecopy($this->im, $this->im,
  287. $i-1, sin($k+$i/$xp) * ($this->scale*$this->Xamplitude),
  288. $i, 0, 1, $this->height*$this->scale);
  289. }
  290. // Y-axis wave generation
  291. $k = rand(0, 100);
  292. $yp = $this->scale*$this->Yperiod*rand(1,2);
  293. for ($i = 0; $i < ($this->height*$this->scale); $i++) {
  294. imagecopy($this->im, $this->im,
  295. sin($k+$i/$yp) * ($this->scale*$this->Yamplitude), $i-1,
  296. 0, $i, $this->width*$this->scale, 1);
  297. }
  298. }
  299. /**
  300. * Reduce the image to the final size
  301. */
  302. protected function ReduceImage() {
  303. // Reduzco el tama�o de la imagen
  304. $imResampled = imagecreatetruecolor($this->width, $this->height);
  305. imagecopyresampled($imResampled, $this->im,
  306. 0, 0, 0, 0,
  307. $this->width, $this->height,
  308. $this->width*$this->scale, $this->height*$this->scale
  309. );
  310. imagedestroy($this->im);
  311. $this->im = $imResampled;
  312. }
  313. /**
  314. * File generation
  315. */
  316. protected function WriteImage() {
  317. if ($this->imageFormat == 'png' && function_exists('imagepng')) {
  318. header("Content-type: image/png");
  319. imagepng($this->im);
  320. } else {
  321. header("Content-type: image/jpeg");
  322. imagejpeg($this->im, null, 80);
  323. }
  324. }
  325. /**
  326. * Cleanup
  327. */
  328. protected function Cleanup() {
  329. imagedestroy($this->im);
  330. }
  331. }
  332. ?>