Tuesday 21 July 2015

Web Tutorial: The CAPTCHA (Part 4/4)

And finally. We're going to distort the image that your tt_getcaptcha.php script sends to your front-end.

Usually this involves a graphics library, but that's too much like work. Instead, I'm going to generate three sets of digits from 0 to 9, using CSS shapes. You may recall that earlier this year, I put up a web tutorial detailing how to use CSS to simulate Chinese brush strokes. Well, we're going to use the same techniques here. This CSS code will be written right into the PHP script.

Confused yet? Or intimidated? Don't be. It'll all become clear presently. Open your tt_getcaptcha.php file, and add the following code to your existing code.

tt_getcaptcha.php
<?php
session_start();

$numbers=array();

for ($i=0;$i<=9;$i++)
{
    $numbers[$i]=array();

    for ($j=0;$j<=2;$j++)
    {
        $numbers[$i][$j]=array();
    }   
}


$_SESSION["captcha"]="";

for ($i=1;$i<=6;$i++)
{
    $captcha_char=rand(0,9);
    $_SESSION["captcha"].=$captcha_char;
}

echo $_SESSION["captcha"];
?>


Here, I have 3 sets of numbers for 0 to 9. So I'm going to use a multi-dimensional array $numbers to store them. So I declare the number of numbers (0 to 9) as one dimension, Each element, from 0 to 9, has 3 variations, from 0 to 2. Here's a tabular representation of the array below.

Set 0 Set 1 Set 2
$numbers[0] [0][0] [0][1] [0][2]
$numbers[1] [1][0] [1][1] [1][2]
$numbers[2] [2][0] [2][1] [2][2]
$numbers[3] [3][0] [3][1] [3][2]
$numbers[4] [4][0] [4][1] [4][2]
$numbers[5] [5][0] [5][1] [5][2]
$numbers[6] [6][0] [6][1] [6][2]
$numbers[7] [7][0] [7][1] [7][2]
$numbers[8] [8][0] [8][1] [8][2]
$numbers[9] [9][0] [9][1] [9][2]

Now, each number of each set requires a certain number of strokes to represent it. For instance, element $numbers[3][2] is the number "3" in set 2.

We'll require 2 strokes to render the number "3". So do this:

<?php
session_start();

$numbers=array();

for ($i=0;$i<=9;$i++)
{
    $numbers[$i]=array();

    for ($j=0;$j<=2;$j++)
    {
        $numbers[$i][$j]=array();
    }   
}

$numbers[3][2][0]=array();
$numbers[3][2][0]["width"]="20px";
$numbers[3][2][0]["height"]="20px";
$numbers[3][2][0]["box-shadow"]="5px 2px 0 0px";
$numbers[3][2][0]["margin"]="5px auto 0px 5px";
$numbers[3][2][0]["rotate"]=0;

$numbers[3][2][1]=array();
$numbers[3][2][1]["width"]="20px";
$numbers[3][2][1]["height"]="20px";
$numbers[3][2][1]["box-shadow"]="5px 2px 0 0px";
$numbers[3][2][1]["margin"]="22px auto 0px -4px";
$numbers[3][2][1]["rotate"]=0;


$_SESSION["captcha"]="";

for ($i=1;$i<=6;$i++)
{
    $captcha_char=rand(0,9);
    $_SESSION["captcha"].=$captcha_char;
}

echo $_SESSION["captcha"];
?>

OK, what I did here was to create yet another array inside each array element to store the strokes. $numbers[3][2][0] stores the first stroke, and $numbers[3][2][0] stores the second stroke. These two strokes make up the number "3".

See?

And each stroke is also an array which stores the CSS properties and values of that stroke so we can render them later. That makes $numbers a four-dimensional array.

Wow.

Anyway. there's the entire set. See the number "3" on the bottom row? That's the one we just drew. Number "3", set 2 ($numbers[3][2]).


I've done the same with all the other numbers in all the sets. The code is here, and I'm not about to replicate them on-screen in this blogpost. The good news is, you can just go and copy-paste from the link without having to listen to any more of this drivel. I agree that it's a bit more complicated than it needed to be here.

Let's get on with it!

So I assume you've copied the contents of the entire four-dimensional array. What next? Why, outputting the relevant numbers on the screen, of course! Make the following changes.

<?php
.
.
.
(for the rest of the code, click here)
.
.
.
$_SESSION["captcha"]="";
$captcha_content="";

for ($i=1;$i<=6;$i++)
{
    $captcha_char=rand(0,9);
    $_SESSION["captcha"].=$captcha_char;

    $random_set=rand(0,2);

    $random_degree=rand(-25,25);

}

echo $captcha_content;
?>

Here, we define a new variable $captcha_content which will hold all the HTML codes that we'll be generating. And we'll output $captcha_content in place of $_SESSION["captcha"].

$random_set defines which set of numbers you'll use.

$random_degree is a number that will cause your number to be rotated by that many degrees, randomly.

Next, we'll begin adding data to $captcha_content. It begins with an outer div for each number, which will be totated by $random_degree degrees.
<?php
for ($i=1;$i<=6;$i++)
{
    $captcha_char=rand(0,9);
    $_SESSION["captcha"].=$captcha_char;

    $random_set=rand(0,2);

    $random_degree=rand(-25,25);

    $captcha_content.="<div style=\"display:inline-block;width:30px;height:50px;margin-left:-5px;-ms-transform: rotate(".$random_degree."deg);-webkit-transform: rotate(".$random_degree."deg);transform: rotate(".$random_degree."deg);\">";

    $captcha_content.="</div>";
}

echo $captcha_content;
?>

And the last segment of code, in a Foreach Loop. For each stroke in each selected digit, the HTML and CSS will be written into the containing outer div.
<?php
for ($i=1;$i<=6;$i++)
{
    $captcha_char=rand(0,9);
    $_SESSION["captcha"].=$captcha_char;

    $random_set=rand(0,2);

    $random_degree=rand(-25,25);

    $captcha_content.="<div style=\"display:inline-block;width:30px;height:50px;margin-left:-5px;-ms-transform: rotate(".$random_degree."deg);-webkit-transform: rotate(".$random_degree."deg);transform: rotate(".$random_degree."deg);\">";

    foreach($numbers[$captcha_char][$random_set] as $stroke)
    {
        $captcha_content.="<div style=\"position:absolute;-webkit-border-radius: 63px 63px 63px 63px / 108px 108px 72px 72px;border-radius: 50% 50% 50% 50% / 60% 60% 40% 40%;";
        $captcha_content.="width:".$stroke["width"].";";
        $captcha_content.="height:".$stroke["height"].";";
        $captcha_content.="box-shadow:".$stroke["box-shadow"].";";
        $captcha_content.="margin:".$stroke["margin"].";";
        $captcha_content.="-ms-transform: rotate(".$stroke["rotate"]."deg);";
        $captcha_content.="-webkit-transform: rotate(".$stroke["rotate"]."deg);";
        $captcha_content.="transform: rotate(".$stroke["rotate"]."deg);";
        $captcha_content.="\">";
        $captcha_content.="</div>";
    }


    $captcha_content.="</div>";
}

echo $captcha_content;
?>


Now run your code again. This is what you should see.

And that completes your web tutorial. There's a lot more you could do with this - introduce wavy lines or circles to further confuse any bots that hackers might try to sneak past you. But in essence, this is the CAPTCHA.

That was a lot to digest. Sorry to have CAPT you waiting!
T___T

No comments:

Post a Comment