3 Steps Simple Captcha In PHP (Free Download)

Welcome to a tutorial on how to create a simple captcha in PHP. Have a website that is constantly being spammed by angry keyboard warriors? Time to put in some security and prevention measures. Let us walk through an example in this guide, without the use of any 3rd party frameworks – Read on!

ⓘ I have included a zip file with all the source code at the end of this tutorial, so you don’t have to copy-paste everything… Or if you just want to dive straight in.

 

 

TABLE OF CONTENTS

 

DOWNLOAD & NOTES

Firstly, here is the download link to the example code as promised.

 

QUICK NOTES

  • Please enable the GD extension extension=gd (gd2 prior to PHP8) in php.ini.
  • Launch 2-form.php in your browser, that’s all.
If you spot a bug, feel free to comment below. I try to answer short questions too, but it is one person versus the entire world… If you need answers urgently, please check out my list of websites to get help with programming.

 

SCREENSHOT

 

EXAMPLE CODE DOWNLOAD

Click here to download the source code, I have released it under the MIT license, so feel free to build on top of it or use it in your own project.

 

 

PHP CAPTCHA

All right, let us now get into the details of creating a simple PHP captcha.

 

STEP 1) PHP CAPTCHA CLASS

captcha.php
<?php
class Captcha {
  // (A) CAPTCHA SETTINGS
  private $length = 8; // number of characters
  private $capW = 300; // captcha width
  private $capH = 100; // captcha height
  private $capF = __DIR__ . DIRECTORY_SEPARATOR . "TuffyBold.ttf"; // captcha font
  private $capFS = 24; // captcha font size
  private $capB = __DIR__ . DIRECTORY_SEPARATOR . "CapBack.jpg"; // captcha background
 
  // (B) AUTO START SESSION
  function __construct () {
    if (session_status()==PHP_SESSION_DISABLED) { exit("Sessions disabled"); }
    if (session_status()==PHP_SESSION_NONE) { session_start(); }
  }
 
  // (C) PRIME THE CAPTCHA - GENERATE RANDOM STRING IN SESSION
  function prime () {
    $char = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    $max = strlen($char) - 1;
    $_SESSION["captcha"] = "";
    for ($i=0; $i<=$this->length; $i++) { $_SESSION["captcha"] .= substr($char, rand(0, $max), 1); }
  }
 
  // (D) DRAW THE CAPTCHA IMAGE
  function draw ($mode=0) {
    // (D1) FUNKY BACKGROUND IMAGE
    if (!isset($_SESSION["captcha"])) { exit("Captcha not primed"); }
    $captcha = imagecreatetruecolor($this->capW, $this->capH);
    list($bx, $by) = getimagesize($this->capB);
    $bx = ($bx-$this->capW) < 0 ? 0 : rand(0, ($bx-$this->capW));
    $by = ($by-$this->capH) < 0 ? 0 : rand(0, ($by-$this->capH));
    imagecopy($captcha, imagecreatefromjpeg($this->capB), 0, 0, $bx, $by, $this->capW, $this->capH);
 
    // (D2) RANDOM TEXTBOX POSITION
    $ta = rand(-20, 20); // random angle
    $tc = imagecolorallocate($captcha, rand(120, 255), rand(120, 255), rand(120, 255)); // random text color
    $ts = imagettfbbox($this->capFS, $ta, $this->capF, $_SESSION["captcha"]);
    if ($ta>=0) {
      $tx = rand(abs($ts[6]), $this->capW - (abs($ts[2]) + abs($ts[6])));
      $ty = rand(abs($ts[5]), $this->capH);
    } else {
      $tx = rand(0, $this->capW - (abs($ts[0]) + abs($ts[4])));
      $ty = rand(abs($ts[7]), abs($ts[7]) + $this->capH - (abs($ts[3]) + abs($ts[7])));
    }
    imagettftext($captcha, $this->capFS, $ta, $tx, $ty, $tc, $this->capF, $_SESSION["captcha"]);
 
    // (D3) OUTPUT CAPTCHA
    if ($mode==0) {
      ob_start();
      imagepng($captcha);
      $ob = base64_encode(ob_get_clean());
      echo "<img src='data:image/png;base64,$ob'/>";
    } else {
      header("Content-type: image/png");
      imagepng($captcha); imagedestroy($captcha);
    }
  }
 
  // (E) VERIFY CAPTCHA
  function verify ($check) {
    if (!isset($_SESSION["captcha"])) { exit("Captcha not primed"); }
    if ($check == $_SESSION["captcha"]) {
      unset($_SESSION["captcha"]);
      return true;
    } else { return false; }
  }
}

// (F) CAPTCHA OBJECT
$PHPCAP = new Captcha();

First, we start with the “core engine”, the Captcha library. Yes, this looks complicated at first, but keep calm and explore it slowly.

  • (A) A whole bunch of captcha settings. Feel free to change to your own font, change the background, captcha image dimensions, etc…
  • (B & F) When $PHPCAP = new Captcha() is created, the constructor automatically starts the session if it is not already started.
  • (C To E) There are only 3 “real captcha functions”.
    • prime() Step 1 of the process, pretty much just generates a random string into $_SESSION["captcha"].
    • draw() Step 2 of the process, use this to output the HTML captcha image.
    • verify() When the user submits the form, use this to verify the user’s captcha against the session.

 

 

STEP 2) GENERATE CAPTCHA IN HTML FORM

2-form.php
<form method="post" action="3-submit.php">
  <!-- (A) FORM FIELDS -->
  <label>Name</label>
  <input name="name" type="text" required value="Jon Doe">
  <label>Email</label>
  <input name="email" type="email" required value="jon@doe.com">
 
  <!-- (B) CAPTCHA HERE -->
  <label>Are you human?</label>
  <?php
  require "1-captcha.php";
  $PHPCAP->prime();
  $PHPCAP->draw();
  ?>
  <input name="captcha" type="text" required>
 
  <!-- (C) GO! -->
  <input type="submit" value="Go!">
</form>
  1. The “usual form fields”.
  2. Generate the captcha.
    • Captain Obvious to the rescue, require "1-captcha.php" to load the library.
    • Call the $PHPCAP->prime() function to generate a random captcha string into the session.
    • Call the $PHPCAP->draw() function to generate the captcha image.

 

 

STEP 3) CAPTCHA VERIFICATION UPON SUBMISSION

3-submit.php
<?php
// (A) LOAD CAPTCHA LIBRARY
require "1-captcha.php";
 
// (B) VERIFIED - DO SOMETHING
if ($PHPCAP->verify($_POST["captcha"])) {
  $result = "Congrats, CAPTCHA is correct.";
  print_r($_POST);
}
 
// (C) NOPE
else { echo "CAPTCHA does not match!"; }

On submitting the form, we only need to use $PHPCAP->verify($_POST["captcha"]) to check if the user has entered the correct captcha – Proceed if the challenge passed, or show an error message if it failed.

 

 

EXTRA BITS & LINKS

That’s all for the code, and here are a few small extras that may be useful to you.

 

MORE SECURITY

Before the “security experts” start to bang on their keyboards, some additional security can be added to this simple captcha.

  • Impose a time limit/expiry on the captcha, 10 minutes for example – $_SESSION["cexpire"] = strtotime("now") + 600.
  • Change the verify() function to also do a time check – if ($_SESSION["cexpire"] > strototime("now")) { NOPE }.
  • Add a number of times a user can challenge the captcha. Decide what to do if the challenge fails too many times – Maybe require the user to click on an email verification link.
  • Very simply, use HTTPS.

 

LINKS & REFERENCES

 

THE END

Thank you for reading, and we have come to the end of this guide. I hope that it has helped you to better fight spam in your project, and if you want to share anything with this guide, please feel free to comment below. Good luck and happy coding!

3 thoughts on “3 Steps Simple Captcha In PHP (Free Download)”

  1. Excellent code !!!…….
    Followed your quick tips and executed successfully without any errors …
    Keep uploading cool programs …..

  2. Hi,
    excellent code.
    But I have a problem. The downloaded sources placed on my localhost (PHP 7.1.8) returns no captcha code (only the background is visible).
    What’s wrong?

    1. If it is only generating the image:

      1) The captcha code is probably not primed into the session, I.E. $_SESSION[‘captcha’] is missing. Make sure that the session is started.
      2) Alternatively, the font may not be set properly; GD cannot access the font file, cannot generate the image captcha properly.

      Good luck!

Leave a Comment

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