I am following a CAPTCHA tutorial on TutsPlus.com and I keep getting the ‘Incorrect Captcha message, meaning my $_POST user input does not match the stored $_SESSION string.
Upon further probing, I tried to echo $_SESSION[‘captcha_text’] and I got the error: ‘Undefined array key.’ As if I hadn’t stored the solution at all.
I have looked at my logs and used developer tools but the only other error is ‘Uncaught TypeError: Cannot set properties of null (setting ‘onclick’)’ which is probably why my javascript won’t run either.
Here is my captcha.php script:
// Store all characters we wish to use to generate CAPTCHA string. Only capital letters to avoid confusion.
$permitted_chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
/**
* Generate cryptographically secure random numbers using random_int() or non-secure random numbers using mt_rand()
* @param string permitted chars used in CAPTCHA
* @param int length of random string, default = 5
* @param bool secure or not, default is secure
* @return string random string
*/
function secure_generate_string($input, $strength = 5, $secure = TRUE) {
$input_length = strlen($input);
$random_string = '';
for($i = 0; $i < $strength; $i++) {
if($secure) {
$random_character = $input[random_int(0, $input_length - 1)];
} else {
$random_character = $input[mt_rand(0, $input_length - 1)];
}
$random_string .= $random_character;
}
return $random_string;
}
// Render the CAPTCHA background. Image will be 200x50px in size and use five different colors for background.
$image = imagecreatetruecolor(200, 50);
imageantialias($image, true);
$colors = [];
// Generate random colors
$red = rand(125, 175);
$green = rand(125, 175);
$blue = rand(125, 175);
// Generate progressively darker shades of original colors. Store colors in array with darkest color as last element.
for($i = 0; $i < 5; $i++) {
$colors[] = imagecolorallocate($image, $red - 20*$i, $green - 20*$i, $blue - 20*$i);
}
// Lightest color used to fill whole background of image.
imagefill($image, 0, 0, $colors[0]);
// Draw rectangles at random locations on original image. Thickness of rectangles varies between 2 and 10, while color chosen randomly from last four values of $colors array
for($i = 0; $i < 10; $i++) {
imagesetthickness($image, rand(2, 10));
$rect_color = $colors[rand(1,4)];
imagerectangle($image, rand(-10, 190), rand(-10, 10), rand(-10, 190), rand(40, 60), $rect_color);
}
// Letters are mix of black and white
$black = imagecolorallocate($image, 0, 0, 0);
$white = imagecolorallocate($image, 255, 255, 255);
$textcolors = [$black, $white];
// Fonts downloaded from Google to get variation in characters
$fonts = [FONT . 'Acme' . DS . 'Acme-Regular.ttf', FONT . 'Ubuntu' . DS . 'Ubuntu-Regular.ttf', FONT . 'Merriweather' . DS . 'Merriweather-Regular.ttf', FONT . 'Gideon_Roman' . DS . 'GideonRoman-Regular.ttf', FONT . 'Yeseva_One' . DS . 'YesevaOne-Regular.ttf'];
$string_length = 6;
$captcha_string = secure_generate_string($permitted_chars, $string_length);
$_SESSION['captcha_text'] = $captcha_string;
// Padding 15px on both sides of image. Leftover space (170px) is divided equally among all CAPTCHA letters
for($i = 0; $i < $string_length; $i++) {
$letter_space = 170/$string_length;
$initial = 15;
imagettftext($image, 20, rand(-15, 15), $initial + $i*$letter_space, rand(20, 40), $textcolors[rand(0, 1)], $fonts[array_rand($fonts)], $captcha_string[$i]);
}
header('Content-type: image/png');
imagepng($image);
imagedestroy($image);
Here is my captcha.js script:
var refreshButton = document.querySelector('.refresh-captcha');
refreshButton.onclick = function() {
document.querySelector('.captcha-image').src = 'captcha.php?' + Date.now();
}
My login.php where the captcha is displayed:
<div class='captcha-container'>
<label for='captcha'>Please Enter the Captcha Text</label>
<br>
<img src='<?php echo FUNCT_URL;?>captcha.php' class='captcha-image' alt='captcha'>
<i class='fa-solid fa-arrow-rotate-right re
fresh-captcha'></i>
<br>
<input class='input-field' type='text' id='captcha' name='captcha_challenge' pattern='[A-Z]{6}' required>
</div>
<button class='submit-btn' type='submit' name='loginSubmit'>Login</button>
<!--this custom_captcha id is used in js file,you can change in js and html both-->
<div id='custom_captcha'></div>
And finally, user_account where the login is processed:
if(isset($_POST['captcha_challenge']) && $_POST['captcha_challenge'] == $_SESSION['captcha_text']) {