Create a Sessionless Captcha in PHP

sessionless_captcha

Demo Download

Sometimes you can have session issues on your server, issues such as sessions not being stored on the browser and there is no way to retrieve the data. In some cases, sessions might work on Chrome but not in Firefox or vise versa.

I spent half a day trying to solve session issues with my captcha until I decided to create a sessionless captcha.

The idea of this sessionless captcha is generating a random word(s) on the server side, two-way encrypt it and then put the encrypted string in the form as a hidden variable. In addition, provide the encrypted string in the image url that gets generated dynamically. The image request can decode the string and then render the captcha image. When the user submits the value, the form contains the user’s value and the encrypted value which can be confirmed on the server.

Sample Form with validation:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<?php

$errorsucc = '';

if (isset($_POST["captcha_check"])) {
         
    $code = str_decrypt($_POST["captcha_check"]);  
   
    if (empty($_POST['captcha_code'])) {
        $errorsucc = '<p style="color:red">Please Enter the security code.</p>';
       
    } elseif(!( $code == $_POST['captcha_code'] && !empty($code) )) {
        $errorsucc = '<p style="color:red">Incorrect Code Entered.</p>';
       
    } else {
        $errorsucc = '<p style = "green">Nice, you entered the correct code.</p>'; 
    }
}

$captcha = new CaptchaCode();
$code = str_encrypt($captcha->generateCode(6));
?>

<html>
    <title>Sessionless Captcha</title>
    <div style = "background: #e2e2e2; padding: 20px; width: 20%; box-shadow: 5px 5px #ccc;">
        <?php echo $errorsucc; ?>
        <form name="captchaform" method="post">
            <table border="0" cellpadding="4" cellspacing="0">
                <tr><td valign="middle" align="left">Security Code:</td>
                    <td valign="middle" align="left"><img src="captcha_images.php?width=150&height=50&code=<?php echo $code?>" /></td>
                </tr>
                <tr><td valign="middle" align="left">Enter Code:</td>
                    <td valign="middle" align="left"><input id="captcha_code" name="captcha_code" style="width:150px" type="text" /></td>
                </tr>

                <tr><td valign="top" align="left">
                    </td>
                    <td valign="top" align="left">
                        <input border="0" type="submit" value="Submit" />  
                    </td>
                </tr>
            </table>
            <input type="hidden" name="captcha_check" value="<?php echo $code?>" />
        </form>
    </div>
</html>

Generate images just like any other captcha:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    /* font size will be 75% of the image height */
    $font_size = $height * 0.75;
    $image = @imagecreate($width, $height) or die('Cannot initialize new GD image stream');
    /* set the colours */
    $background_color = imagecolorallocate($image, 255, 255, 255);
    $text_color = imagecolorallocate($image, 0, 26, 26);
    $noise_color = imagecolorallocate($image, 25, 89, 89);
    /* generate random dots in background */
    for( $i=0; $i<($width*$height)/3; $i++ ) {
        imagefilledellipse($image, mt_rand(0,$width), mt_rand(0,$height), 1, 1, $noise_color);
    }
    /* generate random lines in background */
    for( $i=0; $i<($width*$height)/150; $i++ ) {
        imageline($image, mt_rand(0,$width), mt_rand(0,$height), mt_rand(0,$width), mt_rand(0,$height), $noise_color);
    }
    /* create textbox and add text */
    $textbox = imagettfbbox($font_size, 0, $this->font, $code) or die('Error in imagettfbbox function');
    $x = ($width - $textbox[4])/2;
    $y = ($height - $textbox[5])/2;
    imagettftext($image, $font_size, 0, $x, $y, $text_color, $this->font , $code) or die('Error in imagettftext function');
    /* output captcha image to browser */
    header('Content-Type: image/jpeg');
    imagejpeg($image);
    imagedestroy($image);