PageRenderTime 55ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 1ms

/library/misc/captcha.php

https://bitbucket.org/zxcmehran/arta
PHP | 488 lines | 269 code | 47 blank | 172 comment | 33 complexity | 2bbf4a0b15fc75a3741fcb2222920c42 MD5 | raw file
Possible License(s): LGPL-2.1, GPL-3.0, Apache-2.0
  1. <?php
  2. /**
  3. * ArtaCAPTCHA Class
  4. * Generates CAPTCHA images to verify humans.
  5. *
  6. * @author Mehran Ahadi
  7. * @package Arta
  8. * @version $Revision: 1 2011/08/02 14:20 +3.5 GMT $
  9. * @link http://artaproject.com Author's homepage
  10. * @copyright Copyright (C) 2008 - 2013 Mehran Ahadi
  11. * @license GNU General Public License version 3 or later; see COPYING file.
  12. */
  13. //Check arta
  14. if(!defined('ARTA_VALID')){die('No access');}
  15. /**
  16. * ArtaCAPTCHA Class
  17. * Generates CAPTCHA images to verify humans.
  18. */
  19. class ArtaCaptcha{
  20. /**
  21. * Length of CAPTCHA string
  22. *
  23. * @var int
  24. * @access private
  25. */
  26. private $Length;
  27. /**
  28. * CAPTCHA string
  29. *
  30. * @var string
  31. * @access private
  32. */
  33. private $CaptchaString;
  34. /**
  35. * Fonts path
  36. *
  37. * @var string
  38. * @access private
  39. */
  40. private $fontpath;
  41. /**
  42. * Fonts array
  43. *
  44. * @var array
  45. * @access private
  46. */
  47. private $fonts;
  48. /**
  49. * Image Type
  50. *
  51. * @var string
  52. */
  53. var $type='png';
  54. /**
  55. * Errors
  56. *
  57. * @var array
  58. */
  59. var $errors=array();
  60. /**
  61. * Filters Usage option
  62. *
  63. * @var array
  64. */
  65. var $filters=array('blur'=>true, 'noise'=>false, 'signs'=>true);
  66. /**
  67. * Constructor
  68. *
  69. * @param int $length string length
  70. */
  71. function __construct($length=6){
  72. $this->Length=$length;
  73. }
  74. /**
  75. * Adds header that its an image
  76. */
  77. function setHeader(){
  78. header('Content-type: image/'.$this->type);
  79. }
  80. /**
  81. * Outputs image according to image type then destroys it
  82. *
  83. * @param object $res Image Resource
  84. */
  85. function Output($res){
  86. eval('image'.$this->type.'($res);');
  87. imagedestroy($res);
  88. }
  89. /**
  90. * Generates new image then outputs it.
  91. * @param string $id String ID
  92. */
  93. function genNew($id=null){
  94. $this->setHeader();
  95. $this->fontpath = ARTAPATH_MEDIA.'/fonts/';
  96. $this->fonts = $this->getFonts();
  97. if($this->type=='jpg'){$this->type='jpeg';}
  98. $this->type=strtolower($this->type);
  99. $this->stringGen($id);
  100. if($this->fonts == FALSE){
  101. $this->addError('CODE : '.$this->CaptchaString);
  102. $this->addError('No fonts available!');
  103. $this->displayError();
  104. }
  105. if(function_exists('imagettftext') == FALSE){
  106. $this->addError('CODE : '.$this->CaptchaString);
  107. $this->addError('CAPTCHA Font not supported!');
  108. $this->displayError();
  109. }
  110. $this->makeCaptcha();
  111. }
  112. /**
  113. * Returns String. It's static and should be used when generation is done.
  114. * @static
  115. * @param string $id String ID
  116. * @return string
  117. */
  118. static function toString($id=null){
  119. return ($id==null ? @$_SESSION['_ARTACAPTCHA_STRING_GLOBAL'] : @$_SESSION['_ARTACAPTCHA_STRING'][$id]);
  120. }
  121. /**
  122. * Verifies Captcha phrase. Its case-insensitive.
  123. * It's static and should be used when generation is done.
  124. * @static
  125. * @param string $code CAPTCHA code to verify
  126. * @param string $id String ID
  127. * @return bool
  128. */
  129. static function verifyCode($code, $id=null){
  130. return (ArtaCaptcha::toString($id)===strtoupper((string)$code));
  131. }
  132. /**
  133. * Adds an error
  134. */
  135. function addError ($errormsg){
  136. $this->errors[] = $errormsg;
  137. }
  138. /**
  139. * Displays error
  140. */
  141. function displayError (){
  142. $iheight = count($this->errors) * 20 + 17;
  143. // $iheight = ($iheight < 130) ? 130 : $iheight;
  144. $image = imagecreate(300, $iheight);
  145. $errorsign = imagecreatefrompng(ARTAPATH_BASEDIR.'/imagesets/default/false.png');
  146. imagecopy($image, $errorsign, 1, 1, 1, 1, 16, 16);
  147. $bgcolor = imagecolorallocate($image, 255, 255, 255);
  148. $stringcolor = imagecolorallocate($image, 0, 0, 0);
  149. for ($i = 0; $i < count($this->errors); $i++)
  150. {
  151. $imx = ($i == 0) ? $i * 20 + 5 : $i * 20;
  152. $msg = 'Error[' . $i . ']: ' . $this->errors[$i];
  153. imagestring($image, 5, 0, $imx+17, $msg, $stringcolor);
  154. }
  155. $this->Output($image);
  156. }
  157. /**
  158. * Checks that any errors happened
  159. *
  160. * @return bool
  161. */
  162. function isError (){
  163. if (count($this->errors) == 0){
  164. return FALSE;
  165. }else{
  166. return TRUE;
  167. }
  168. }
  169. /**
  170. * Gets fonts
  171. *
  172. * @return bool
  173. */
  174. function getFonts (){
  175. $fonts = array();
  176. $f=ArtaFile::listDir($this->fontpath);
  177. foreach($f as $k=>$v){
  178. $extension = ArtaFile::getExt($v);
  179. if(strtolower($extension) =='ttf'){
  180. $fonts[]=$v;
  181. }
  182. }
  183. if (count($fonts) == 0){
  184. return FALSE;
  185. }else{
  186. return $fonts;
  187. }
  188. }
  189. /**
  190. * Gets random font
  191. *
  192. * @return string font name
  193. */
  194. function getRandFont(){
  195. $l=count($this->fonts)-1;
  196. return $this->fontpath . $this->fonts[mt_rand(0, $l)];
  197. }
  198. /**
  199. * Generates Strings
  200. * @param string $id String ID
  201. */
  202. function stringGen($id=null){
  203. //if(!count($this->errors)){
  204. $CharPool = range('A', 'Z');
  205. $PoolLength = count($CharPool) - 1;
  206. for($i = 0; $i < $this->Length; $i++){
  207. $this->CaptchaString .= $CharPool[mt_rand(0, $PoolLength)];
  208. }
  209. //}else{
  210. // $this->CaptchaString='ABCDEF';
  211. //}
  212. if($id==null){
  213. @$_SESSION['_ARTACAPTCHA_STRING_GLOBAL']=$this->CaptchaString;
  214. }else{
  215. @$_SESSION['_ARTACAPTCHA_STRING'][$id]=$this->CaptchaString;
  216. }
  217. }
  218. /**
  219. * Makes CAPTCHA
  220. */
  221. function makeCaptcha ()
  222. {
  223. if(count($this->errors)==0){
  224. $imagelength = $this->Length * 32 + 16;
  225. $imageheight = 75;
  226. $image=imagecreate($imagelength, $imageheight);
  227. $fc=array(
  228. array(122,20,100),
  229. array(243,157,21),
  230. array(193,54,146),
  231. array(54,193,90),
  232. array(193,54,55),
  233. array(119,207,191),
  234. array(70,102,63),
  235. array(34,85,187),
  236. array(193,54,186),
  237. array(50,50,50),
  238. array(127,113,215),
  239. array(204,210,49)
  240. );
  241. $bc=array(
  242. array(172,199,255),
  243. array(186,255,181),
  244. array(254,255,181),
  245. array(255,219,181),
  246. array(211,251,255),
  247. array(255,181,181),
  248. array(210,230,250),
  249. );
  250. $r=$bc[mt_rand(0,(count($bc)-1))];
  251. $r=$this->lighten($r,mt_rand(30,55));
  252. /* foreach($fc as $v){
  253. echo '<div style="font-size:100px;color:rgb('.$v[0].', '.$v[1].', '.$v[2].');">'.$v[0].','.$v[1].','.$v[2].'</div>';
  254. }
  255. foreach($bc as $v){
  256. echo '<div style="font-size:100px;background-color:rgb('.$v[0].', '.$v[1].', '.$v[2].');">'.$v[0].','.$v[1].','.$v[2].'</div>';
  257. }
  258. header('Content-Type: text/html');
  259. die();*/
  260. $bgcolor = imagecolorallocate($image, $r[0], $r[1], $r[2]);
  261. if($this->filters['signs']){
  262. $this->signs($image, $this->getRandFont(), 8, $r);
  263. }
  264. for ($i = 0; $i < strlen($this->CaptchaString); $i++){
  265. $r=$fc[mt_rand(0,(count($fc)-1))];
  266. $r=$this->change($r,60);
  267. $r=$this->darken($r, mt_rand(50,80));
  268. $stringcolor = imagecolorallocate($image, $r[0], $r[1], $r[2]);
  269. imagettftext($image, 30, mt_rand(-20, 20), $i * 32 + 10,
  270. mt_rand(30, 60),
  271. $stringcolor,
  272. $this->getRandFont(),
  273. $this->CaptchaString{$i});
  274. }
  275. if($this->filters['noise']){
  276. $this->noise($image, mt_rand(0,20));
  277. }
  278. if($this->filters['blur']){
  279. $this->blur($image, (mt_rand(1,7)*(.1)));
  280. }
  281. $this->Output($image);
  282. }
  283. }
  284. function getCaptchaString (){
  285. return $this->CaptchaString;
  286. }
  287. ##############################################
  288. # FILTERS
  289. /**
  290. * Adds noise
  291. *
  292. * @param object $image image resource
  293. * @param int $runs noise amount
  294. */
  295. function noise (&$image, $runs = 30){
  296. $w = imagesx($image);
  297. $h = imagesy($image);
  298. for ($n = 0; $n < $runs; $n++){
  299. for ($i = 1; $i <= $h; $i++){
  300. $randcolor = imagecolorallocate($image,
  301. mt_rand(0, 255),
  302. mt_rand(0, 255),
  303. mt_rand(0, 255));
  304. imagesetpixel($image,
  305. mt_rand(1, $w),
  306. mt_rand(1, $h),
  307. $randcolor);
  308. }
  309. }
  310. }
  311. /**
  312. * Adds character signs
  313. *
  314. * @param object $image image resource
  315. * @param string $font font name
  316. * @param int $cells cell count
  317. * @param string $c bg color
  318. */
  319. function signs (&$image, $font, $cells = 3, $c){
  320. $w = imagesx($image);
  321. $h = imagesy($image);
  322. for ($i = 0; $i < $cells; $i++){
  323. $centerX = mt_rand(1, $w);
  324. $centerY = mt_rand(1, $h);
  325. $amount = mt_rand(1, 15);
  326. $stringcolor = imagecolorallocate($image, $c[0]-75, $c[1]-75, $c[2]-75);
  327. for ($n = 0; $n < $amount; $n++){
  328. $signs = range('A', 'Z');
  329. $sign = $signs[mt_rand(0, count($signs) - 1)];
  330. imagettftext($image, 25,
  331. mt_rand(-15, 15),
  332. $centerX + mt_rand(-50, 50),
  333. $centerY + mt_rand(-50, 50),
  334. $stringcolor, $font, $sign);
  335. }
  336. }
  337. }
  338. /**
  339. * Rnadomly changes color values
  340. *
  341. * @param array $arr color array
  342. * @param int $am amount
  343. * @return array
  344. */
  345. function change($arr, $am=50){
  346. if($arr[0] < $am){
  347. $a[0]=$arr[0];
  348. }else{
  349. $a[0]=$am;
  350. }
  351. if($arr[0]> (255-$am)){
  352. $arr[0]=255;
  353. $a[0]=0;
  354. }
  355. if($arr[1] < $am){
  356. $a[1]=$arr[1];
  357. }else{
  358. $a[1]=$am;
  359. }
  360. if($arr[1]> (255-$am)){
  361. $arr[1]=255;
  362. $a[1]=0;
  363. }
  364. if($arr[2] < $am){
  365. $a[2]=$arr[2];
  366. }else{
  367. $a[2]=$am;
  368. }
  369. if($arr[2]> (255-$am)){
  370. $arr[2]=255;
  371. $a[2]=0;
  372. }
  373. return array($arr[0]+mt_rand( ($a[0]*(-1)), $a[0] ),
  374. $arr[1]+mt_rand( ($a[1]*(-1)), $a[1] ),
  375. $arr[2]+mt_rand( ($a[2]*(-1)), $a[2] )
  376. );
  377. }
  378. /**
  379. * Darkens color values
  380. *
  381. * @param array $r color array
  382. * @param int $a amount
  383. * @return array
  384. */
  385. function darken($r, $a){
  386. //$a is amount
  387. foreach($r as $k=>$v){
  388. if($v> $a){
  389. $r[$k]=$v-$a;
  390. }else{
  391. $r[$k]=0;
  392. }
  393. }
  394. return $r;
  395. }
  396. /**
  397. * Lightens color values
  398. *
  399. * @param array $r color array
  400. * @param int $a amount
  401. * @return array
  402. */
  403. function lighten($r, $a){
  404. //$a is amount
  405. foreach($r as $k=>$v){
  406. if($v+$a <= 255){
  407. $r[$k]=$v+$a;
  408. }else{
  409. $r[$k]=255;
  410. }
  411. }
  412. return $r;
  413. }
  414. /**
  415. * Adds blur
  416. *
  417. * @param object $image image resource
  418. * @param int $radius amount of blur
  419. */
  420. function blur (&$image, $radius = 3)
  421. {
  422. $radius = round(max(0, min($radius, 50)) * 2);
  423. $w= imagesx($image);
  424. $h= imagesy($image);
  425. $imgBlur = imagecreate($w, $h);
  426. for ($i = 0; $i < $radius; $i++){
  427. imagecopy ($imgBlur, $image, 0, 0, 1, 1, $w - 1, $h - 1);
  428. imagecopymerge($imgBlur, $image, 1, 1, 0, 0, $w, $h, 50.0000);
  429. imagecopymerge($imgBlur, $image, 0, 1, 1, 0, $w - 1, $h, 33.3333);
  430. imagecopymerge($imgBlur, $image, 1, 0, 0, 1, $w, $h - 1, 25.0000);
  431. imagecopymerge($imgBlur, $image, 0, 0, 1, 0, $w - 1, $h, 33.3333);
  432. imagecopymerge($imgBlur, $image, 1, 0, 0, 0, $w, $h, 25.0000);
  433. imagecopymerge($imgBlur, $image, 0, 0, 0, 1, $w, $h - 1, 20.0000);
  434. imagecopymerge($imgBlur, $image, 0, 1, 0, 0, $w, $h, 16.6667);
  435. imagecopymerge($imgBlur, $image, 0, 0, 0, 0, $w, $h, 50.0000);
  436. imagecopy ($image , $imgBlur, 0, 0, 0, 0, $w, $h);
  437. }
  438. imagedestroy($imgBlur);
  439. }
  440. }
  441. ?>