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

/ php-ppcms/includes/classes/lib.captcha.class.php

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