CAPTCHA Error: POST does not match SESSION key

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']) {