captcha.class.inc.php 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. <?php
  2. class captcha {
  3. private $randString = '';
  4. private $stringLength = 10;
  5. private $imageWidth = false;
  6. private $imageHeight = false;
  7. private $background = true;
  8. private $backgroundColor = array('R'=>255, 'V'=>255, 'B'=>255);
  9. private $borderColor = array('R'=>226, 'V'=>113, 'B'=>59);
  10. private $borderWidth = 0;
  11. private $textColor = array('R'=>0, 'V'=>0, 'B'=>0);
  12. private $forbiddenChars= array(1,0,'l','0');
  13. private $font = '';
  14. private $fontSize = 15;
  15. private $fromBorder = 10;
  16. private $type = '';
  17. private $shadow = false;
  18. private $shadowColor = array('R'=>128, 'V'=>128, 'B'=>128);
  19. private $shadowX = 2;
  20. private $shadowY = 2;
  21. private $backgroundImage = false;
  22. private $textAngle = 0;
  23. private $roundedCorners = false;
  24. private $roundedCornersRadius = 5;
  25. /**
  26. * Constructeur - fixe le type d'image : PNG,GIF,JPEG
  27. *
  28. * @param string $type type de l'image
  29. */
  30. public function __construct($type='PNG') {
  31. $this->setImageType($type);
  32. }
  33. /**
  34. * Fixe la longueur de la chaîne aléatoire générée
  35. *
  36. * @param int $lenght longueur de la chaîne
  37. */
  38. public function setStringLenght($lenght) {
  39. $this->stringLength = $lenght;
  40. }
  41. /**
  42. * Fixe la couleur de fond de l'image
  43. *
  44. * @param int $R rouge
  45. * @param int $V vert
  46. * @param int $B bleu
  47. */
  48. public function setBackgroundColor($R,$V,$B) {
  49. $this->backgroundColor['R'] = $R;
  50. $this->backgroundColor['V'] = $V;
  51. $this->backgroundColor['B'] = $B;
  52. }
  53. /**
  54. * Fixe la couleur de la bordure
  55. *
  56. * @param int $R rouge
  57. * @param int $V vert
  58. * @param int $B bleu
  59. */
  60. public function setBorderColor($R,$V,$B) {
  61. $this->borderColor['R'] = $R;
  62. $this->borderColor['V'] = $V;
  63. $this->borderColor['B'] = $B;
  64. }
  65. /**
  66. * Fixe la taille de la bordure
  67. *
  68. * @param int $width taille en pixel de la bordure
  69. */
  70. public function setBorderWidth($width) {
  71. $this->borderWidth = (int)$width;
  72. }
  73. /**
  74. * Fixe la couleur du texte
  75. *
  76. * @param int $R rouge
  77. * @param int $V vert
  78. * @param int $B bleu
  79. */
  80. public function setTextColor($R,$V,$B) {
  81. $this->textColor['R'] = $R;
  82. $this->textColor['V'] = $V;
  83. $this->textColor['B'] = $B;
  84. }
  85. /**
  86. * Fixe la largeur de l'image
  87. *
  88. * @param int $width largeur en pixel de l'image
  89. */
  90. public function setImageWidth($width) {
  91. $this->imageWidth = $width;
  92. }
  93. /**
  94. * Fixe la hauteur de l'image
  95. *
  96. * @param int $height hauteur en pixel de l'image
  97. */
  98. public function setImageHeight($height) {
  99. $this->imageHeight = $height;
  100. }
  101. /**
  102. * Fixe la police True Type et sa taille
  103. *
  104. * @param string $font chemin vers la police
  105. * @param int $size taille de la police
  106. */
  107. public function setFont($font, $size) {
  108. if(!is_readable($font)) {
  109. throw new Exception('La police est introuvable');
  110. }
  111. $this->font = $font;
  112. $this->fontSize = $size;
  113. }
  114. /**
  115. * Fixe si une ombre doit être appliquée au texte
  116. *
  117. * @param int $x décalage de l'ombre en absisse
  118. * @param int $y décalage de l'ombre en ordonné
  119. */
  120. public function setShadow($x=false,$y=false) {
  121. $this->shadow = true;
  122. if($x) {
  123. $this->shadowX = (int)$x;
  124. }
  125. if($y) {
  126. $this->shadowY = (int)$y;
  127. }
  128. }
  129. /**
  130. * Fixe la couleur de l'ombre
  131. *
  132. * @param int $R rouge
  133. * @param int $V vert
  134. * @param int $B bleu
  135. */
  136. public function setShadowColor($R,$V,$B) {
  137. $this->shadow = true;
  138. $this->shadowColor['R'] = $R;
  139. $this->shadowColor['V'] = $V;
  140. $this->shadowColor['B'] = $B;
  141. }
  142. /**
  143. * Définie si une image de fond doit être appliquée
  144. *
  145. * @param string $image chemin vers l'image
  146. */
  147. public function setBackgroundImage($image) {
  148. if(!is_readable($image)) {
  149. throw new Exception('Image de fond introuvable');
  150. }
  151. $this->backgroundImage = $image;
  152. }
  153. /**
  154. * Fixe l'angle du texte
  155. *
  156. * @param int $angle angle en degrés
  157. */
  158. public function setTextAngle($angle) {
  159. $this->textAngle = (int)$angle;
  160. }
  161. /**
  162. * Fixe la taille de la marge par rapport à la bordure
  163. *
  164. * @param int $margin taille en pixel de la marge
  165. */
  166. public function setMarginFromBorder($margin) {
  167. $this->fromBorder = (int)$margin;
  168. }
  169. public function setRoundedCorners($radius=false) {
  170. $this->roundedCorners = true;
  171. if($radius) {
  172. $this->roundedCornersRadius = (int)$radius;
  173. }
  174. }
  175. /**
  176. * Construit l'image
  177. *
  178. */
  179. public function getImage() {
  180. if(!$this->font) {
  181. throw new Exception('Il faut charger une police');
  182. }
  183. $text = $this->getRandString();
  184. $text = trim(preg_replace('`(\w)`', '$1 ', $text));
  185. $box = imagettfbbox($this->fontSize,$this->textAngle,$this->font,$text);
  186. if(!$this->imageHeight) {
  187. $boxHeight = max($box[1],$box[3]) - min($box[7],$box[5]);
  188. $this->imageHeight = $boxHeight + $this->borderWidth*2 + $this->fromBorder*2;
  189. }
  190. if(!$this->imageWidth) {
  191. $boxWidth = max($box[4],$box[2]) - min($box[6],$box[0]);
  192. $this->imageWidth = $boxWidth + $this->borderWidth*2 + $this->fromBorder*2;
  193. }
  194. if(function_exists('imagecreatetruecolor')) {
  195. $im = imagecreatetruecolor($this->imageWidth, $this->imageHeight);
  196. } else {
  197. $im = imagecreate($this->imageWidth, $this->imageHeight);
  198. }
  199. // border
  200. if($this->borderWidth > 0) {
  201. $border = imagecolorallocate(
  202. $im,
  203. $this->borderColor['R'],
  204. $this->borderColor['V'],
  205. $this->borderColor['B']
  206. );
  207. if(!$this->roundedCorners) {
  208. imagefilledrectangle(
  209. $im,
  210. 0,
  211. 0,
  212. $this->imageWidth,
  213. $this->imageHeight,
  214. $border
  215. );
  216. } else {
  217. $this->ImageRectangleWithRoundedCorners(
  218. $im,
  219. 0,
  220. 0,
  221. $this->imageWidth,
  222. $this->imageHeight,
  223. $border,
  224. $this->roundedCornersRadius
  225. );
  226. }
  227. }
  228. // background
  229. $background = imagecolorallocate(
  230. $im,
  231. $this->backgroundColor['R'],
  232. $this->backgroundColor['V'],
  233. $this->backgroundColor['B']
  234. );
  235. imagefilledrectangle(
  236. $im,
  237. $this->borderWidth,
  238. $this->borderWidth,
  239. $this->imageWidth-$this->borderWidth,
  240. $this->imageHeight-$this->borderWidth,
  241. $background
  242. );
  243. if($this->backgroundImage) {
  244. // Calcul des nouvelles dimensions
  245. list($width, $height,$type) = getimagesize($this->backgroundImage);
  246. $new_width = $this->imageWidth-$this->borderWidth*2;
  247. $new_height = $this->imageHeight-$this->borderWidth*2;
  248. if($type === 1) {
  249. $type_ = 'gif';
  250. } elseif($type === 2) {
  251. $type_ = 'jpeg';
  252. } elseif($type === 3) {
  253. $type_ = 'png';
  254. } else {
  255. throw new Exception('Mauvais type pour l\'image de fond');
  256. }
  257. $fct = 'imagecreatefrom' . $type_;
  258. $imb = $fct($this->backgroundImage);
  259. imagecopyresampled(
  260. $im,
  261. $imb,
  262. $this->borderWidth,
  263. $this->borderWidth,
  264. 0,
  265. 0,
  266. $new_width,
  267. $new_height,
  268. $width,
  269. $height
  270. );
  271. imagedestroy($imb);
  272. }
  273. // couleur du texte
  274. $textColor = imagecolorallocate (
  275. $im,
  276. $this->textColor['R'],
  277. $this->textColor['V'],
  278. $this->textColor['B']
  279. );
  280. // centrage horizontal
  281. $x = ($this->imageWidth - $boxWidth)/2;
  282. // centrage vertical
  283. $y = $this->imageHeight - $this->borderWidth - $this->fromBorder;
  284. // ombre
  285. if($this->shadow) {
  286. $shadow = imagecolorallocate(
  287. $im,
  288. $this->shadowColor['R'],
  289. $this->shadowColor['V'],
  290. $this->shadowColor['B']
  291. );
  292. imagettftext(
  293. $im,
  294. $this->fontSize,
  295. $this->textAngle,
  296. $x+$this->shadowX,
  297. $y+$this->shadowY,
  298. $shadow,
  299. $this->font,
  300. $text
  301. );
  302. }
  303. // le texte
  304. imagettftext(
  305. $im,
  306. $this->fontSize,
  307. $this->textAngle,
  308. $x,
  309. $y,
  310. $textColor,
  311. $this->font,
  312. $text
  313. );
  314. $this->makeHeaders();
  315. $image_function = 'image' . $this->type;
  316. $image_function($im);
  317. imagedestroy($im);
  318. }
  319. /**
  320. * Récupère la chaîne aléatoire générée
  321. *
  322. * @return string chaîne aléatoire générée
  323. */
  324. public function getRandString() {
  325. if(!$this->randString) {
  326. $T = array_merge(range('a','z') , range('A', 'Z') , range(1,9));
  327. shuffle($T);
  328. //$TT = array_filter($T, array($this, 'forbiddenCharsFilter'));
  329. $TT = array_chunk($T, $this->stringLength);
  330. $this->randString = implode('', $TT[0]);
  331. }
  332. return $this->randString;
  333. }
  334. private function ImageRectangleWithRoundedCorners(&$im, $x1, $y1, $x2, $y2, $color, $radius) {
  335. // transparence
  336. $trans = imageColorAllocate ($im, 255, 255, 255);
  337. $color_ = imagecolortransparent($im, $trans);
  338. // rectangle sans coins
  339. imagefilledrectangle($im, $x1, $y1, $x2, $y2, $color_);
  340. imagefilledrectangle($im, $x1+$radius, $y1, $x2-$radius, $y2, $color);
  341. imagefilledrectangle($im, $x1, $y1+$radius, $x2, $y2-$radius, $color);
  342. // coins arrondis
  343. imagefilledellipse($im, $x1+$radius, $y1+$radius, $radius*2, $radius*2, $color);
  344. imagefilledellipse($im, $x2-$radius, $y1+$radius, $radius*2, $radius*2, $color);
  345. imagefilledellipse($im, $x1+$radius, $y2-$radius, $radius*2, $radius*2, $color);
  346. imagefilledellipse($im, $x2-$radius, $y2-$radius, $radius*2, $radius*2, $color);
  347. }
  348. private function forbiddenCharsFilter($in) {
  349. return in_array($in, $this->forbiddenChars);
  350. }
  351. private function setImageType($type) {
  352. switch(strtolower($type)) {
  353. case 'gif' :
  354. case 'png' :
  355. case 'jpeg' :
  356. $this->type = $type;
  357. break;
  358. case 'jpg' :
  359. $this->type = 'jpeg';
  360. break;
  361. default :
  362. $this->type = 'png';
  363. }
  364. if(!function_exists('image'.$this->type)) {
  365. throw new Exception('La fonction n\'est pas disponible');
  366. }
  367. }
  368. private function makeHeaders() {
  369. header('Expires: Mon, 01 Jan 2000 00:00:00 GMT');
  370. header('Last-Modified: ' . gmdate("D, d M Y H:i:s") . ' GMT');
  371. header('Cache-Control: no-store, no-cache, must-revalidate');
  372. header('Cache-Control: post-check=0, pre-check=0', false);
  373. header('Pragma: no-cache');
  374. header('Content-Type: image/' . $this->type);
  375. }
  376. }
  377. ?>