PageRenderTime 52ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/Ojoo/Lib/captcha_1.php

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