📜 ⬆️ ⬇️

Creating a graphic captcha with a choice of extra

image

At work, it was necessary to solve the spam problem, since the old captcha easily avoided spam bots. Googling and not finding the right options, I decided to write my own, and for a long time I wanted, to be honest.

And so, the essence of a captcha is that the user displays several icons and it is necessary to choose the one that does not logically fit into the general row. I think there is a sea of ​​such options on the Internet, but I did not find it (well, to be honest, I didn’t really look for that).

Let's start


')
The principle of operation is as follows: two groups of icons are assembled, one is an array with the correct options, the other with the wrong one. It is assembled into a common array, with the key of an incorrect picture (the sequence number of the array element) being written to the session.
From all the icons we collect one image, which we will then cut with the help of background-position.
The form is a radio button with a value from 1 to the number of icons. We send a form with the clicked value using POST and check it with the number we put in the session, everything is quite simple.

And so, there is a directory where there are groups of icons:



All functionality is implemented in one class. Let us examine in more detail:

1. Several private variables for storing values ​​that are written in the constructor.


private $icon_dir; //,      private $icon_size; //  private $first_group_num; //    private $second_group_num; //    private $icon_count; //     private $group_count; //   private $address; //,      


2. Actually the constructor itself, which is passed 4 parameters.


 function __construct($icons_count, $icon_dir, $icon_size, $address) { $this->icon_dir = $icon_dir; $this->icon_size = $icon_size; $this->group_count = scandir($this->icon_dir); $this->group_count = count($this->group_count) - 2; $this->first_group_num = rand(1, $this->group_count); $this->second_group_num = rand(1, $this->group_count); $this->icon_count = $icons_count; while ($this->first_group_num == $this->second_group_num) { $this->second_group_num = rand(1, $this->group_count); } $this->address = $address; } 


3. With a set of right and wrong options, everything is simple, the usual scandir () and writing to the array, except that writing to the session of the desired option occurs as follows:


 $_SESSION['iconcaptcha'] = array_search($true_icon, $array_of_icons) + 1; 


where $ true_icon is the icon we are looking for, and $ array_of_icons is the final array with icons.

4. Creating the final image of the icons.


 private function makeSprite() { //     $icons = array(); $array_of_icons = $this->getArrayOfIcons(); for ($i = 0; $i < $this->icon_count; ++$i) { $icons[] = imagecreatefrompng($array_of_icons[$i]); } //  png $tmp_sprite = imagecreatetruecolor($this->icon_count * $this->icon_size, $this->icon_size); imagealphablending($tmp_sprite, false); imagesavealpha($tmp_sprite, true); $tmp_icon = imagecreatetruecolor($this->icon_size, $this->icon_size); imagealphablending($tmp_icon, false); imagesavealpha($tmp_icon, true); foreach ($icons as $key => $val) { imagecopyresampled($tmp_icon, $val, 0, 0, 0, 0, $this->icon_size, $this->icon_size, $this->icon_size, $this->icon_size); imagecopy($tmp_sprite, $tmp_icon, $key * $this->icon_size, 0, 0, 0, imagesx($tmp_icon), imagesy($tmp_icon)); } header("Content-type: image/png"); imagepng($tmp_sprite); imagedestroy($tmp_sprite); exit; } 


5. Get the address at which we will call the creation of a full-fledged image.


 private function getCaptchaAddress($address) { //    $address $req = end(explode('/', $_SERVER['REQUEST_URI'])); $req = explode('?', $req); if ($req[0] == $address) $this->makeSprite(); } 


6. And finally, the final method, which displays the form itself and everything, everything, everything. It would be necessary, of course, to remove styles here, but since here the background-image is set, which provokes the makeSprite () call and the captcha is actually created (as well as solving the caching problem with this curved method), then I decided to leave it.


 function getCaptchaForm() { $this->getCaptchaAddress($this->address); $captcha_form = '<style> #icon_captcha label div { background-image: url(/'.$this->address.'?'.rand().'); width: '.$this->icon_size.'px; height: '.$this->icon_size.'px; } #icon_captcha { margin-bottom: 20px !important; display: table !important; } #icon_captcha div { width: '.$this->icon_size.'px; display: inline-block; margin-right: 20px; } #icon_captcha div input { width: '.$this->icon_size.'px; margin-left: 0; float: left; border: none; } #icon_captcha div label img { border: none; } </style> <div id="icon_captcha">'; for ($i = 1; $i <= $this->icon_count; ++$i) { $captcha_form .= '<div> <label for="val_'.$i.'"> <div class="i'.$i.'" style="background-position: ' .(($i - 1)*(-$this->icon_size)). 'px 0;"></div> </label> <input type="radio" name="radio_val" id="val_'.$i.'" value="'.$i.'" /> </div>'; } $captcha_form .= '</div>'; return $captcha_form; } 


This is how the call looks in one of the examples. This is the case in the configuration file:

 require(INC_DIR.'libs/IconCaptcha.class.php'); $icon_dir = $_SERVER['DOCUMENT_ROOT']."/design/site/images/captcha/"; $icon_captcha = new IconCaptcha(4, $icon_dir, 32, 'iconcaptcha'); $captcha_form = $icon_captcha->getCaptchaForm(); define('ICONCAPTCHA', $captcha_form); 


Then simply substitute ICONCAPTCHA in the form we need, and check it with a trivial comparison: $ _POST ['radio_val'] == $ _SESSION ['iconcaptcha'].

Click here for a demo: iconcaptcha.hut4.ru
See the entire class here: github.com/L1Qu0R/iconcaptcha/blob/master/IconCaptcha.class.php

Source: https://habr.com/ru/post/177805/


All Articles