PHP Login Form CAPTCHA Code Example

Download the BotDetect PHP CAPTCHA Library and run this example

The PHP Login Captcha code example shows how to add BotDetect CAPTCHA validation to simple PHP login forms.

First Time Here?

Check the BotDetect PHP Captcha Quickstart for key integration steps.

To prevent bots from trying to guess the login info by brute force submission of a large number of common values, the visitor first has to prove they are human (by solving the CAPTCHA), and only then is their username and password submission checked against the authentication data store.

To keep the example code simple, the example doesn't access a data store to authenticate the user, but accepts all logins with usernames and passwords at least 5 characters long as valid.

Example Location

The PHP login form Captcha code example is included in the examples/simple-api/simple-api-php-login-form-captcha-example folder of the download package.

lib/config/botdetect.xml

<?xml version="1.0" encoding="UTF-8"?>
<botdetect xmlns="https://captcha.com/schema/php"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="https://captcha.com/schema/php
     https://captcha.com/schema/php/botdetect-4.2.3.xsd">

  <captchaStyles>
    <captchaStyle>
      <name>LoginCaptcha</name>
      <userInputID>CaptchaCode</userInputID>
      <codeLength>4</codeLength>
      <imageWidth>200</imageWidth>
      <helpLinkMode>Image</helpLinkMode>
      <codeStyle>Alpha</codeStyle>
    </captchaStyle>
  </captchaStyles>

</botdetect>

Configure Simple Captcha options in config/botdetect.xml configuration file. You can find a full list of available Simple Captcha configuration options and related instructions at the Simple Captcha configuration options page.

index.php

<?php require("lib/simple-botdetect.php"); ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
  <title>BotDetect PHP CAPTCHA Validation: PHP Login Form CAPTCHA Code Example</title>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <link type="text/css" rel="Stylesheet" href="stylesheet.css" />
</head>
<body>
  <form method="post" action="process-login.php" class="column" id="form1">

  <h1>BotDetect PHP CAPTCHA Validation: <br /> PHP Login Form CAPTCHA Code Example</h1>

  <fieldset>
   <legend>CAPTCHA included in PHP Login form validation</legend>

   <div class="input">
    <label for="Username">Username:</label>
    <input type="text" name="Username" id="Username" class="textbox" value="<?php if (isset($_REQUEST['Username'])) { echo $_REQUEST['Username']; } ?>" />
   </div>
   
   <div class="input">
    <label for="Password">Password:</label>
    <input type="password" name="Password" id="Password" class="textbox" />
   </div>

   <?php // authentication failed, show error message
    $error = '';
    if (isset($_REQUEST['error'])) {
     $error = $_REQUEST['error'];
    }
    if ('Format' == $error) { ?>
     <p class="incorrect">Invalid authentication info</p><?php
    } else if ('Auth' == $error) { ?>
     <p class="incorrect">Authentication failed</p><?php
    }
   ?>

   <div class="input">
    <label for="CaptchaCode">Retype the characters from the picture:</label>

     <?php // Adding BotDetect Captcha to the page
      $LoginCaptcha = new SimpleCaptcha('LoginCaptcha');
      echo $LoginCaptcha->Html();
     ?>
     <input type="text" name="CaptchaCode" id="CaptchaCode" class="textbox" /><?php

     // CAPTCHA validation failed, show error message
     if ('Captcha' == $error) { ?>
      <span class="incorrect">Incorrect code</span><?php
     }
   ?>
   </div>

   <input type="submit" name="SubmitButton" id="SubmitButton" value="Submit"  />

  </fieldset>
  </form>
</body>
</html>

The example login form is simple, containing textboxes for username and password input, and remembering the username even when form validation fails (the password input is not remembered for obvious reasons). We add Captcha protection to the form using the standard procedure.

Note that we use the IsSolved property of the Captcha object to only display Captcha protection if it hasn't already been solved.

process-login.php

<?php
  require("simple-botdetect.php");

  $form_page = "index.php";

  // directly accessing this script is an error
  if (!$_SERVER['REQUEST_METHOD'] == "POST") {
    header("Location: ${form_page}");
    exit;
  }

  // sumbitted login data
  $username = $_REQUEST['Username'];
  $password = $_REQUEST['Password'];


  // CAPTCHA user input validation
  $LoginCaptcha = new SimpleCaptcha('LoginCaptcha');
  $isHuman = $LoginCaptcha->Validate();
  if (!$isHuman) {
    // CAPTCHA validation failed, show error message
    $form_page = $form_page . '?Username=' . urlencode($username) . "&error=Captcha";
    header("Location: ${form_page}");
    exit;
  }

  // CAPTCHA validation passed, only now do we perform the protected action (try to authenticate the user)

  // check login format
  $isValidLogin = ValidateLogin($username, $password);
  if (!$isValidLogin) {
    // invalid login format, show error message
    $form_page = $form_page . '?Username=' . urlencode($username) . "&error=Format";
    header("Location: ${form_page}");
    exit;
  }

  // authenticate the user
  $isAuthenticated = Authenticate($username, $password);
  if (!$isAuthenticated) {

    // authentication attempt failed, show error message
    $form_page = $form_page . '?Username=' . urlencode($username) . "&error=Auth";
    header("Location: ${form_page}");
    exit;
  }


  function ValidateLogin($p_Username, $p_Password) {
    $result = false;
    // we check both username and password are specified and alphanumeric
    if (strlen($p_Username) > 0 && strlen($p_Password) > 0) {
      $pattern = '/^[a-zA-Z0-9_]+$/'; // alphanumeric chars and underscores only
      $result = (1 == preg_match($pattern, $p_Username));
      $result &= (1 == preg_match($pattern, $p_Password));
    }
    return $result;
  }

  function Authenticate($p_Username, $p_Password) {
    $result = false;
    // Since this is a simple example project, we consider all authentication attempts with usernames and
    // passwords longer than 5 characters valid instead of looking up the info in a database etc.
    if (strlen($p_Username) > 4 && strlen($p_Password) > 4) {
      $result = true;
    }
    return $result;
  }

?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
  <title>BotDetect PHP CAPTCHA Validation: PHP Login Form CAPTCHA Code Example</title>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <link type="text/css" rel="Stylesheet" href="stylesheet.css" />
</head>
<body>
  <div class="column">
  <h1>BotDetect PHP CAPTCHA Validation: <br /> PHP Login Form CAPTCHA Code Example</h1>

  <h2>Protected Page</h2>

  <fieldset id="Properties">
   <legend>Validation passed!</legend>

   <div class="input">
    <label for="Username">Username:</label>
    <input name="Username" id="Username" type="text" class="textbox" readonly="readonly" value="<?php echo urlencode($username); ?>" />
   </div>

   <div class="input">
    <label for="Password">Password:</label>
    <input name="Password" id="Password" type="text" class="textbox" readonly="readonly" value="<?php echo urlencode($password); ?>" />
   </div>

   <p class="navigation">
    <a href="index.php">Back to login page</a>
   </p>
  </fieldset>
  </div>
</body>
</html>

The login attempt processing code can only be accessed by posting the login form, and redirects back to in when accessed directly - or when from validation fails.

We need to include the BotDetect Captcha library, and create a Captcha object with the same CaptchaStyle name ('LoginCaptcha') value as were used to show the Captcha on the login form.

This allows us to implement the proper Login form workflow:

  • The user must first solve the Captcha to prove they are human. This keeps the bots away from the authentication code, both conserving its resources and improving its security (since usernames and passwords will not be forwarded to the underlying data store if the Captcha is not solved first).
  • If the user fails three authentication requests, they are shown a new Captcha which they must solve before continuing. This throttles authentication access, ensuring username + password combinations cannot be brute-forced, while real human users get theoretically unlimited authentication attempts (as long as they don't mind solving further Captchas).

As previously mentioned, the actual authentication code is not implemented, but the example code should demonstrate the underlying principles adequately.

After successful authentication, the example just displays the user input (while a real login form would set an auth cookie and redirect the user to actual functionality).


Current BotDetect Versions