• strict warning: Only variables should be passed by reference in /home/www/web/websitetutorials.net/sites/all/modules/memcache/memcache.inc on line 319.
  • strict warning: Only variables should be passed by reference in /home/www/web/websitetutorials.net/sites/all/modules/memcache/memcache.inc on line 319.
  • strict warning: Only variables should be passed by reference in /home/www/web/websitetutorials.net/sites/all/modules/memcache/memcache.inc on line 319.
  • strict warning: Only variables should be passed by reference in /home/www/web/websitetutorials.net/sites/all/modules/memcache/memcache.inc on line 319.
  • strict warning: Only variables should be passed by reference in /home/www/web/websitetutorials.net/sites/all/modules/memcache/memcache.inc on line 319.
  • strict warning: Only variables should be passed by reference in /home/www/web/websitetutorials.net/sites/all/modules/memcache/memcache.inc on line 319.
  • strict warning: Non-static method view::load() should not be called statically in /home/www/web/websitetutorials.net/sites/all/modules/views/views.module on line 879.
  • strict warning: Declaration of views_handler_argument::init() should be compatible with views_handler::init(&$view, $options) in /home/www/web/websitetutorials.net/sites/all/modules/views/includes/handlers.inc on line 77.
  • strict warning: Declaration of views_handler_filter::options_validate() should be compatible with views_handler::options_validate($form, &$form_state) in /home/www/web/websitetutorials.net/sites/all/modules/views/includes/handlers.inc on line 77.
  • strict warning: Declaration of views_handler_filter::options_submit() should be compatible with views_handler::options_submit($form, &$form_state) in /home/www/web/websitetutorials.net/sites/all/modules/views/includes/handlers.inc on line 77.
  • strict warning: Declaration of views_handler_filter_boolean_operator::value_validate() should be compatible with views_handler_filter::value_validate($form, &$form_state) in /home/www/web/websitetutorials.net/sites/all/modules/views/includes/handlers.inc on line 77.
Sep 30

Click-In that Captcha

Wed, 09/30/2009 - 05:39 — julie

Tired of the old Type-In Captcha? If so, learn how to build a unique type of “click-in” captcha in this tutorial.

Download the Source

Introduction

This tutorial is inspired by Zac Vineyard’s “Build Your Own Captcha and Contact Form” on Nettuts+, although what we’ll accomplish here is a very unique way of implementing a captcha. One of the advantages of this kind of implementation is that it gets rid of the need to retain several hundreds or even thousands of images in your server.

Objective

In this tutorial, the objective is to make a ‘click-in’ captcha.

We’ll be needing two images:

The captcha image:

The captcha mask image:

The captcha image is displayed on the form, while the mask will be stored in the server session. The mask image is simply a copy of the captcha image without the pattern. The reason for this is that it allows us to easily identify the color of each pixel. You will understand it better as we go along.

Step 1 : Build your captcha.php

First off, we will not use any font for this tutorial; we will just be using the GD library to render the captcha.

Ok let’s create captcha.php.

In our script, we open a server session using session_start(), we also declare settings variables such as $width and $height.

<?php
  // start a session session_start();
  // settings variables $width = 180; $height = 90; $blob_width = 40; $blob_height = 40;
 
?>

Step 2 : Image Container

Next, we create the image container that will hold the pattern and the red circle. This is accomplished by creating an image object using the imagecreatetruecolor() function.

 // image container $image = imagecreatetruecolor($width, $height);

We then create color variables in the same image object.

 // background color of the image container $white = imagecolorallocate($image, 230, 230, 230); $red = imagecolorallocate($image, 255, 0, 0); $blue = imagecolorallocate($image, 0, 0, 230);

Then fill it with white.

 // fill the image container imagefilledrectangle($image, 0, 0, $width, $height ,$white);

Lastly, we create a spiral pattern on the image background.

 // create the spiral pattern on the image container
  $theta = 1; $thetac = 7; $radius = 16; $circles = 20; $points = 32;
  for ($i = 0; $i < ($circles * $points) - 1; $i++) { $theta = $theta + $thetac; $rad = $radius * ($i / $points ); $x = ($rad * cos($theta)) + $x_axis; $y = ($rad * sin($theta)) + $y_axis; $theta = $theta + $thetac; $rad1 = $radius * (($i + 1) / $points); $x1 = ($rad1 * cos($theta)) + $x_axis; $y1 = ($rad1 * sin($theta )) + $y_axis; imageline($image, $x, $y, $x1, $y1, $blue); $theta = $theta - $thetac; }

Step 3 : The Blob and the Mask

Next, we’re going to draw our red circle and build our mask copy as well.

The Blob:

We randomize where we will place the blob in our image and then render it to our captcha image using imagefilledellipse().

  // blob location $x_axis = rand($blob_width, $width) - ($blob_width / 2); $y_axis = rand($blob_height, $height) - ($blob_height / 2);

We also use the $red color variable that we have declared initially.

 // render the blob on the image container  imagefilledellipse ($image, $x_axis, $y_axis, $blob_width, $blob_height, $red);

The Mask:

Very similar to our captcha image on step 2, we create a new instance of the image using imagecreatetruecolor().

 // create the mask image $mask_image = imagecreatetruecolor($width, $height);

We also create two color variables ó one for our background and for our blob. On rendering our blob (red circle), we use the same location where we rendered our circle in our captcha image.

 // background color of the mask image $mask_white = imagecolorallocate($mask_image, 255, 255, 255); $mask_red = imagecolorallocate($mask_image, 255, 0, 0);
  // fill the image container imagefilledrectangle($mask_image, 0, 0, $width, $height ,$mask_white);
  // render the blob on the mask image imagefilledellipse ($mask_image, $x_axis, $y_axis, $blob_width, $blob_height, $mask_red);

Step 4: Save our Mask to Our Server Session

Now for the tricky part, we need to save our mask image to our server session. To do this, we need to render our mask somewhere and retrieve it as raw data before saving it to our session.

We use ob_start() to open an output buffering and write data on a scratch/virtual location.

 // write the mask image to the buffer ob_start();

Next, we render the mask using imagepng().

 imagepng($mask_image);

We then retrieved its raw data using ob_get_contents(), which also returns buffer data as a string.

 $mask_image_data = ob_get_contents(); // we retrive the data that was written in the buffer

We use ob_end_clean() to make sure we clear our buffer.

 ob_end_clean();

Next, we convert the data we got from buffer to Base64. This is to convert all special characters to acceptable characters that can be stored in our session.

 // convert the image data to Base64 $mask_image_data_b64 = base64_encode($mask_image_data);

Finally, we save the Base64 value to the session.

 // save the base64 mask image data to the session $_SESSION['captcha_image_code'] = $mask_image_data_b64;

Step 5: Render it out!

Next step is to render out our captcha. We need to tell our browser the content type of what we are rendering to make sure it will display properly.

 // Set the content type header('Content-type: image/jpeg'); header('Cache-control: no-cache');
  // render it imagejpeg($image);
  imagedestroy($image);

Let’s save and preview it to our browser. This is what it looks like.

Below is the whole captcha.php code:

 <?php
  // start a session session_start();
  // settings variables $width = 180; $height = 90; $blob_width = 40; $blob_height = 40;
  // image container $image = imagecreatetruecolor($width, $height);
  // background color of the image container $white = imagecolorallocate($image, 230, 230, 230); $red = imagecolorallocate($image, 255, 0, 0); $blue = imagecolorallocate($image, 0, 0, 230);
  // fill the image container imagefilledrectangle($image, 0, 0, $width, $height ,$white);
 
  // create the spiral pattern on the image container
  $theta = 1; $thetac = 7; $radius = 16; $circles = 20; $points = 32;
  for ($i = 0; $i < ($circles * $points) - 1; $i++) { $theta = $theta + $thetac; $rad = $radius * ($i / $points ); $x = ($rad * cos($theta)) + $x_axis; $y = ($rad * sin($theta)) + $y_axis; $theta = $theta + $thetac; $rad1 = $radius * (($i + 1) / $points); $x1 = ($rad1 * cos($theta)) + $x_axis; $y1 = ($rad1 * sin($theta )) + $y_axis; imageline($image, $x, $y, $x1, $y1, $blue); $theta = $theta - $thetac; }
  // blob location $x_axis = rand($blob_width, $width) - ($blob_width / 2); $y_axis = rand($blob_height, $height) - ($blob_height / 2);
  // render the blob on the image container  imagefilledellipse ($image, $x_axis, $y_axis, $blob_width, $blob_height, $red);
  // create the mask image $mask_image = imagecreatetruecolor($width, $height);
  // background color of the mask image $mask_white = imagecolorallocate($mask_image, 255, 255, 255); $mask_red = imagecolorallocate($mask_image, 255, 0, 0);
  // fill the image container imagefilledrectangle($mask_image, 0, 0, $width, $height ,$mask_white);
  // render the blob on the mask image imagefilledellipse ($mask_image, $x_axis, $y_axis, $blob_width, $blob_height, $mask_red);
  // write the mask image to the buffer ob_start(); imagepng($mask_image); $mask_image_data = ob_get_contents(); // we retrive the data that was written in the buffer ob_end_clean();
  // convert the image data to Base64 $mask_image_data_b64 = base64_encode($mask_image_data);
  // save the base64 mask image data to the session $_SESSION['captcha_image_code'] = $mask_image_data_b64;
 
  // Set the content type header('Content-type: image/jpeg'); header('Cache-control: no-cache');
  // render it imagejpeg($image);
  imagedestroy($image);
  ?>

Step 6: Build our Form

Let’s build a new PHP script and name it as index.php. The page will contain a form that we will validate using our ‘click-in’ captcha.

HTML Form:

Replace the submit button with an image button. We’ll name it ’submit’, but of course you can name it whatever you like.

 <form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post" enctype="multipart/form-data"> <p>Name<br/><input type="text" name="name" /></p> <p>Comment<br/><textarea name="message"></textarea></p> <p> Click the Red Circle to continue:<br/> <input type='image' name='submit' src='captcha.php' alt='Captcha Security' /> </p> </form>

It should look like this:

Step 7: Validate it!

Once everything is working and the captcha image is showing, we need to validate our form.

Below is our PHP validation code. The key features we need to make it work are:

  1. session_start()
  2. $_POST['submit_x'] and $_POST['submit_y']
  3. Finding out the color of the clicked x and y location

Here, we make sure that all of the entries are filled. We also need to make sure that there is a clicked X and Y coordinate.

 session_start();   if(isset($_POST['submit_x']) && isset($_POST['submit_y'])) {   if(!empty($_POST['name']) && !empty($_POST['message'])) {   // retrive the image captcha data $data = base64_decode($_SESSION['captcha_image_code']);
  $captcha_image = imagecreatefromstring($data); $x = $_POST['submit_x']; $y = $_POST['submit_y'];
  // get the pixel color of the clicked x and y coordinate $rgb = imagecolorat($captcha_image, $x, $y); $color_tran = imagecolorsforindex($captcha_image, $rgb);
  // check if the color is red and red only $captcha_ok = ($color_tran['red'] == 255 && $color_tran['green'] == 0 && $color_tran['blue'] == 0 && $color_tran['alpha'] == 0) ;
  if($captcha_ok) {   $result = "Thank you for submitting your comment.";   } else {   $result = "Please make sure you click the red circle!";   }   } else {   $result = "Please fill out the entire form.";   }   }

An additional change here is to retrieve the mask image from the session and put that back to an image object and then get the pixel color of X and Y.

To do this, we have to first retrieve the mask image from session and then decode it as shown below:

 // retrive the image captcha data $data = base64_decode($_SESSION['captcha_image_code']);

We then convert it back to an image object using the imagecreatefromstring() function.

 $captcha_image = imagecreatefromstring($data);

Then we retrieve the X and Y coordinate from the user’s submitted click along with the pixel’s color using imagecolorsforindex(). We make sure we only get a red color and nothing else.

 // get the pixel color of the clicked x and y coordinate $rgb = imagecolorat($captcha_image, $x, $y); $color_tran = imagecolorsforindex($captcha_image, $rgb);
  // check if the color is red and red only $captcha_ok = ($color_tran['red'] == 255 && $color_tran['green'] == 0 && $color_tran['blue'] == 0 && $color_tran['alpha'] == 0) ;

Lastly, we validate using $captcha_ok to see if the user have clicked the right spot.


Below is what the final index.php file should look like.

<?php session_start();  
if(isset($_POST['submit_x']) && isset($_POST['submit_y'])) {   if(!empty($_POST['name']) && !empty($_POST['message'])) {   // retrive the image captcha data $data = base64_decode($_SESSION['captcha_image_code']);
  $captcha_image = imagecreatefromstring($data); $x = $_POST['submit_x']; $y = $_POST['submit_y'];
  // get the pixel color of the clicked x and y coordinate $rgb = imagecolorat($captcha_image, $x, $y); $color_tran = imagecolorsforindex($captcha_image, $rgb);
  // check if the color is red and red only $captcha_ok = ($color_tran['red'] == 255 && $color_tran['green'] == 0 && $color_tran['blue'] == 0 && $color_tran['alpha'] == 0) ;
  if($captcha_ok) {   $result = "Thank you for submitting your comment.";   } else {   $result = "Please make sure you click the red circle!";   }   } else {   $result = "Please fill out the entire form.";   }  
} ?>
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">    Captcha Demo   
  
<?php if(!empty($result)) echo "
"
. $result . "
"; ?>  
<?php echo $_SERVER['PHP_SELF']; ?>" method="post" enctype="multipart/form-data">

Name

Comment

Click the Red Circle to continue:

 

Done!

Now you have a very unique captcha implementation. I hope you like it.

Extra! Extra!

Another variation of this implementation:

Math based Click-In-Captcha
(Taken from http://ww2.unforgivnwar.com)

Download the Source




Copyright 2009. E-mail Me
Auto Spare Parts