Simple CAPTCHA System in PHP Without External APIs

Simple CAPTCHA System in PHP Without External APIs

In today’s digital landscape, ensuring website security is more important than ever. One of the simplest and most effective ways to prevent spam and automated bot interactions is by implementing a CAPTCHA system. CAPTCHA (Completely Automated Public Turing test to tell Computers and Humans Apart) is widely used in online forms to verify that the user is human.

Many developers rely on third-party services like Google reCAPTCHA, but these services often come with dependencies, API calls, and potential privacy concerns. In this article, we will walk through the process of building a simple CAPTCHA system in PHP without any external APIs. By leveraging PHP’s GD Library, we can generate a CAPTCHA image dynamically and validate user input efficiently.

Why Use a Custom CAPTCHA System?

While third-party CAPTCHA solutions like Google reCAPTCHA provide strong security, there are several reasons why a developer might opt for a self-hosted CAPTCHA system:

  1. No External Dependencies – A custom CAPTCHA system does not rely on external APIs, ensuring complete control over implementation.
  2. Privacy-Friendly – User data remains within the website, eliminating concerns about data sharing with third-party services.
  3. Performance – Since the CAPTCHA is generated locally, there are no external API calls that could introduce latency.
  4. Customization – Developers can tailor the CAPTCHA system to meet specific security needs, including custom fonts, colors, and difficulty levels.

Implementing a CAPTCHA System in PHP

Our CAPTCHA system consists of three primary components:

  • captcha.php – Generates the CAPTCHA image dynamically.
  • index.php – Displays the form with the CAPTCHA.
  • verify.php – Handles the CAPTCHA verification.

Follow this video for complete guidance :

Captcha using PHP – Source Code

index.php

<?php session_start(); ?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Secure CAPTCHA Verification</title>
    <link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.2/css/bootstrap.min.css" rel="stylesheet">
    <style>
        body {
            background: #f8f8f8;
            min-height: 100vh;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        .captcha-card {
        	margin:0 auto;
            max-width: 400px;
            width: 100%;
            padding: 2rem;
        }
        .captcha-image {
            background: #f8f9fa;
            border-radius: 0.5rem;
            margin-bottom: 1.5rem;
        }
        .form-control {
            font-size: 1.1rem;
            text-align: center;
            letter-spacing: 0.1em;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="card shadow-lg captcha-card">
            <div class="card-body">
                <div class="text-center mb-4">
                    <h2 class="h3 mb-2">Security Verification</h2>
                    <p class="text-muted">Please enter the characters you see below</p>
                </div>

                <form action="verify.php" method="POST">
                    <div class="captcha-image text-center shadow-sm">
                        <img src="captcha.php" alt="CAPTCHA" class="img-fluid rounded">
                    </div>

                    <div class="mb-4">
                        <input 
                            type="text" 
                            name="captcha" 
                            class="form-control form-control-lg"
                            placeholder="Enter CAPTCHA code" 
                            required
                        >
                    </div>

                    <button type="submit" class="btn btn-primary btn-lg w-100">
                        Verify
                    </button>
                </form>
            </div>
        </div>
    </div>
</body>
</html>

captcha.php

<?php
session_start();

// Generate random text
$captcha_text = substr(str_shuffle("ABCDEFGHJKLMNPQRSTUVWXYZ23456789"), 0, 5);
$_SESSION['captcha'] = $captcha_text;

// Create image
$width = 120;
$height = 40;
$image = imagecreate($width, $height);

// Colors
$bg_color = imagecolorallocate($image, 255, 255, 255); // White
$text_color = imagecolorallocate($image, 0, 0, 0); // Black
$noise_color = imagecolorallocate($image, 100, 100, 100); // Gray

// Add noise
for ($i = 0; $i < 50; $i++) {
    imagesetpixel($image, rand(0, $width), rand(0, $height), $noise_color);
}

// Add text
$font_size = 5; 
$x = ($width - (imagefontwidth($font_size) * strlen($captcha_text))) / 2;
$y = ($height - imagefontheight($font_size)) / 2;
imagestring($image, $font_size, $x, $y, $captcha_text, $text_color);
  
// Output image
header("Content-type: image/png");
imagepng($image);
imagedestroy($image);
?>

verify.php

<?php session_start();?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Secure CAPTCHA Verification</title>
    <link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.2/css/bootstrap.min.css" rel="stylesheet">
    <style>
        body {
            background: #f8f8f8;
            min-height: 100vh;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        .captcha-card {
        	margin:0 auto;
            max-width: 400px;
            width: 100%;
            padding: 2rem;
        }
        .captcha-image {
            background: #f8f9fa;
            border-radius: 0.5rem;
            margin-bottom: 1.5rem;
        }
        .form-control {
            font-size: 1.1rem;
            text-align: center;
            letter-spacing: 0.1em;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="card shadow-lg captcha-card">
            <?php 
              if ($_SERVER["REQUEST_METHOD"] == "POST") {
            $user_input = trim($_POST["captcha"]);

            if ($user_input === $_SESSION["captcha"]) {
                echo "<strong style='color:green;'>CAPTCHA Verified Successfully!</strong>";
            } else {
                echo "<strong style='color:red;'>Incorrect CAPTCHA.</strong>";
            }
        }
        unset($_SESSION["captcha"]);
      ?>
      <div class="mt-3 text-center">
        <a href="index.php">Try Again</a>
      </div>
        </div>
    </div>
</body>
</html>

 

Understanding How CAPTCHA Works

A CAPTCHA system works in the following steps:

  1. A random string of characters is generated.
  2. This string is stored in the session to verify later.
  3. An image is created dynamically, displaying the CAPTCHA text with noise for security.
  4. The image is embedded in a form where the user enters the CAPTCHA value.
  5. When the form is submitted, the input value is checked against the stored session value.
  6. If the values match, the form submission proceeds; otherwise, an error is shown.

Generating the CAPTCHA Image

The first step is to create a script (captcha.php) that generates a CAPTCHA image. This script does the following:

  • Generates a random five-character string.
  • Stores this string in the session.
  • Creates a 120×40 pixel image with a white background.
  • Adds random noise to make it harder for bots to interpret.
  • Renders the CAPTCHA text using PHP’s built-in font.
  • Outputs the image as a PNG file.

Displaying the CAPTCHA Form

The next step is to integrate the CAPTCHA into an HTML form (index.php). The CAPTCHA image is displayed using the <img> tag that references captcha.php. Users must enter the text displayed in the image before submitting the form.

Validating User Input

Once the user submits the form, verify.php checks whether the entered CAPTCHA matches the stored session value. If the values match, the form submission is successful; otherwise, an error message is displayed.

Enhancing CAPTCHA Security

A simple CAPTCHA system is functional but may still be vulnerable to automated attacks. Here are some ways to improve security:

  1. Increase Randomness – Use a mix of uppercase and lowercase letters with numbers to make the CAPTCHA harder to guess.
  2. Add More Noise – Introduce random lines, dots, or background patterns to obfuscate the text.
  3. Use a Distorted Font – Instead of built-in fonts, use custom TTF fonts with slight distortions to prevent easy OCR recognition.
  4. Limit Attempts – Prevent brute-force attempts by limiting the number of incorrect attempts within a time frame.
  5. Rotate CAPTCHA Images – Randomly rotate or skew the text slightly to add complexity.

Building a CAPTCHA system in PHP without external dependencies provides a lightweight and effective way to prevent spam on your website. By leveraging PHP’s GD Library, developers can generate CAPTCHA images dynamically, ensuring better security and control over the implementation.

While a basic CAPTCHA is useful, enhancing its complexity with custom fonts, distortions, and additional security measures can significantly improve its effectiveness against automated bots. If you’re working on a PHP-based web project, implementing a custom CAPTCHA is a great way to strengthen form security while maintaining full control over the user experience.

Related Posts

Leave a Reply

Your email address will not be published. Required fields are marked *