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!

 

 

TABLE OF CONTENTS

 

DOWNLOAD & NOTES

Here is the download link to the example code, so you don’t have to copy-paste everything.

 

EXAMPLE CODE DOWNLOAD

Source code on GitHub Gist

Just click on “download zip” or do a git clone. I have released it under the MIT license, so feel free to build on top of it or use it in your own project.

 

SORRY FOR THE ADS...

But someone has to pay the bills, and sponsors are paying for it. I insist on not turning Code Boxx into a "paid scripts" business, and I don't "block people with Adblock". Every little bit of support helps.

Buy Me A Coffee Code Boxx eBooks

 

PHP CAPTCHA

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

 

STEP 1) PHP CAPTCHA CLASS

1-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 = "C:/Windows/Fonts/arial.ttf"; // font - CHANGE TO YOUR OWN!
  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 () : void {
    $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) : void {
    // (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.

 

 

EXTRAS

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, here are some additional security that can be added to this simple captcha.

  • Use a “difficult to read” font, and rotate between a few different backgrounds.
  • 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 “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.

 

 

RELOADING THE CAPTCHA

Want to add a “reload captcha” button to the form? Some simple modifications will do the trick:

  • “Move” the captcha creation to a separate mycap.php script – <?php require "1-captcha.php"; $PHPCAP->prime(); $PHPCAP->draw();
  • Modify 2-form.php, replace the captcha with an empty <div id="cap">
  • Use Javascript fetch to load/reload the captcha.
    • var cap = () => fetch("mycap.php").then(res=>res.text()).then(txt=>document.getElementById("cap").innerHTML = txt);
    • window.addEventListener("load", cap);
    • <input type="button" value="Reload Captcha" onclick="cap()">

 

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!

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

  1. Hi!
    Really a great job!
    Just one question: a trick to reload the captcha only (not the whole page), in case it is difficult to read, in php?

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

  3. 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 *