Creating a dynamic captcha image with PHP

Sick of my contact form being used as an express way for spammers i set about to make a solution to end the spam to which i was surprised still exists so much in 2019.

I need a custom solution to which would still allow me to use my compressed index.html to keep the lightning quick page load times. I also wanted to avoid adding more JavaScript and using a third-party tool like Google’s reCAPTCHA which can gather data and it actually helps ai improve and get better.  Thats something im not gonna support at this stage thanks.

With help from the code here i made the following function in PHP this code is what I point the cron job at to create the captcha:

function create_captcha_image($save_as)
    $connect = mysqli_connect("localhost", "USERNAME", "PASSWORD", "captcha");//MySQL connection
    $selection = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWUXYZ";//Characters to choose from
    for ($i = 0; $i < 5; $i++) {//loop 5 times = get 5 characters
        $pos = rand(0, 62);//choose random number between 0 and 62
        $string .= $selection[$pos];//uses the random number to as a pos to select the character ie. 0 = a, 5 = f
    $result = mysqli_query($connect, "UPDATE `captcha` SET `string` = '$string';");//Update the DB with our new string to authenticate with
    $image = ImageCreate(60, 24) or die ("Error making image");//make the base image
    $background_color = ImageColorAllocate($image, rand(0, 255), rand(0, 255), rand(0, 255));//base image background color
    $text_color = ImageColorAllocate($image, 255, 255, 255);//White text
    $img = ImageString($image, rand(20, 50), rand(1, 8), rand(1, 8), $string, $text_color);//text position
    $img = Imagepng($image, $save_as);//finish the image generation

echo create_captcha_image('captcha.png');//create the new captcha and saves the captach image as captcha.png

In short terms it will create an image 60×24 with a random background color, choose 5 random characters from the $selection string, update the database to have this string and put the string onto the image at a random position with white text color.

You will see the function rand() used a lot, rand(0, 100) will return a value anywhere from 0 to 100 and so forth.

A sample of the created captcha is: sample php captcha

SQL file for the MySQL database:

USE `captcha`;

CREATE TABLE `captcha` (
  `string` varchar(255) NOT NULL

INSERT INTO `captcha` (`string`) VALUES

Now i needed to include a text input in the contact form for the captcha text and alongside it the captcha image we are generating.

<div class="field">
    <img alt="captcha" src="captcha.png" />
    <label class="label">Captcha</label>
    <div class="control">
        <textarea class="textarea" placeholder=" " name="captcha" rows="1"></textarea>

Then finally in the form post php file, which checks for correct inputs and sends the actual email i need to add checks for the captcha. To check that text was inputted and to check that its correct this was done like so:

if (!isset($_POST['captcha'])) {
//no captcha text inputted
} else {
//captcha input had text
    $connect = mysqli_connect("localhost", "USERNAME", "PASSWORD", "captcha");
    $result = mysqli_query($connect, "SELECT `string` FROM `captcha` LIMIT 1;");
    while ($row = $result->fetch_assoc()) {
        $string = $row["string"];
    if ($_POST['captcha'] !== $string) {
        //The Captcha input was not the same as what we have stored in the DB
    } else {
        //Captcha was a match with stored string
        //Continue with validation checks for email address, subject and body content.....

After testing that the validation worked correctly the last step was to point a cron job at the captcha create file.

The interval could have been set at anything from 1 minute through to every 6 hours, it doesn’t matter. However for best usage to avoid manual intervention in getting the captcha code I choose every 5 minutes for a new captcha.

Had you set it for several hours long a human could come and crack the captcha code and then use the spam bot for the duration before you got a new captcha generated. With the shorter intervals a new captcha comes along at a shorter timeframe.