BotDetect CAPTCHA Options: Request Dynamic Settings Code Example

The PHP Captcha options: Request dynamic settings code example shows how to dynamically adjust Captcha configuration, potentially on each Http request made by the client.

First Time Here?

Check the BotDetect Developer Crash Course for key integration steps.

Any PHP code setting Captcha properties in the CaptchaConfig.php file will be executed not only for each protected form GET or POST request (like Captcha configuration code placed in form source would be), but also for each each GET request loading a Captcha image or sound, or making an Ajax Captcha validation call.

If configured values are dynamic (e.g. CaptchaRandomization helper or other function calls in CaptchaConfig.php code), they will be re-calculated for each Captcha challenge generated. For example, Captcha ImageStyle randomized in CaptchaConfig.php code will change on each Captcha reload button click.

This means your code can reliably keep track of visitor interaction with the Captcha challenge and dynamically adjust its settings. Also, while CaptchaConfig.php settings apply to all Captcha instances by default, you can also selectively apply them based on CaptchaId.

To show an example of the possible dynamic Captcha configuration adjustments, this code example increases the difficulty of the Captcha test if the visitor associated with the current PHP Session fails a certain number of Captcha validation attempts, and also sets the Captcha locale to Chinese for requests from a certain IP range.

Download the BotDetect PHP CAPTCHA Generator archive to run this example

Within this page, the root folder of the extracted archive is referred as the <BDC-DIR>.

This example is in the <BDC-DIR>/examples/t_api-captcha~conf_via-dynamic_config/ folder; and contains the following files:

index.php

<?php session_start(); ?>
<?php require("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 Options: 
    Request Dynamic Settings Code Example</title>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <link type="text/css" rel="Stylesheet" 
    href="<?php echo CaptchaUrls::LayoutStylesheetUrl() ?>" />
  <link type="text/css" rel="Stylesheet" href="stylesheet.css" />
</head>
<body>
  <form method="post" action="" class="column" id="form1">

    <h1>BotDetect PHP CAPTCHA Options: <br /> 
      Request Dynamic Settings Code Example</h1>

    <fieldset>
      <legend>PHP CAPTCHA validation</legend>
      <label for="CaptchaCode">Retype the characters from the picture:</label>

      <?php // Adding BotDetect Captcha to the page
        $DynamicCaptcha = new Captcha("DynamicCaptcha");
        $DynamicCaptcha->UserInputID = "CaptchaCode";
        echo $DynamicCaptcha->Html();
      ?>

      <div class="validationDiv">
        <input name="CaptchaCode" type="text" id="CaptchaCode" />
        <input type="submit" name="ValidateCaptchaButton" value="Validate" 
          id="ValidateCaptchaButton" />

        <?php // when the form is submitted
          if ($_POST) {
            // validate the Captcha to check we're not dealing with a bot
            $isHuman = $DynamicCaptcha->Validate();
            if (!$isHuman) {
              // Captcha validation failed, show error message
              echo "<span class=\"incorrect\">Incorrect code</span>";
              IncrementFailedValidationsCount();
            } else {
              // Captcha validation passed, perform protected action
              echo "<span class=\"correct\">Correct code</span>";
              ResetFailedValidationsCount(); // reset counter after successful validation
            }
          }
        ?>
      </div>
    </fieldset>
    
    <div id="output">
    <?php
      $count = GetFailedValidationsCount();
      echo "<p>Failed Captcha validations: {$count}</p>";
      if ($count < 3) {
        echo "<p>Dynamic Captcha difficulty: Easy</p>";
      } else if ($count < 10) {
        echo "<p>Dynamic Captcha difficulty: Moderate</p>";
      } else {
        echo "<p>Dynamic Captcha difficulty: Hard</p>";
      }
    ?>
    </div>
  </form>
</body>
</html>

In the form source, we follow the standard procedure for adding Captcha protection to a PHP form.

On POST request, if Captcha validation fails, the increment of failed validation is executed by calling IncrementFailedValidationsCount() function. Otherwise, it will be reset by calling the ResetFailedValidationsCount() function.

counter.php

<?php

// helper functions for counting Captcha validation failures at form submission
if ((function_exists('session_status ') && PHP_SESSION_NONE === session_status()) || !isset($_SESSION)) {
  session_start(); 
}

define('FAILED_VALIDATIONS_COUNT_KEY', 'FailedValidationsCount');

function GetFailedValidationsCount() {
  $count = 0;
  if (isset($_SESSION) && array_key_exists(FAILED_VALIDATIONS_COUNT_KEY, $_SESSION)) {
    $temp = unserialize($_SESSION[FAILED_VALIDATIONS_COUNT_KEY]);
    if (false !== $temp) {
      $count = $temp;
    }
  }
  return $count;
}

function IncrementFailedValidationsCount() {
  $count = GetFailedValidationsCount();
  $count++;
  $_SESSION[FAILED_VALIDATIONS_COUNT_KEY] = serialize($count);
}

function ResetFailedValidationsCount() {
  unset($_SESSION[FAILED_VALIDATIONS_COUNT_KEY]);
}

?>

The helper functions for counting Captcha validation failures at form submission.

CaptchaConfig.php

<?php

// BotDetect PHP Captcha configuration options
// ---------------------------------------------------------------------------

// CaptchaConfig.php settings are usually global and apply to all Captcha instances in
// the application; if some settings need to be apply only to a particular Captcha 
// instance, this is how settings can be conditionally applied based on CaptchaId
if (0 == strcasecmp($CurrentCaptchaId, 'DynamicCaptcha')) {
  $BotDetect->SoundEnabled = false;
}

// re-calculated on each image request
$BotDetect->ImageStyle = CaptchaRandomization::GetRandomImageStyle(
  array(ImageStyle::Graffiti, ImageStyle::SunAndWarmAir, ImageStyle::Overlap)
);

// dynamic Captcha settings depending on failed validation attempts: increase Captcha 
// difficulty according to number of previously failed validations
include_once('counter.php');
$count = GetFailedValidationsCount();
if ($count < 3) {
  $BotDetect->CodeLength = CaptchaRandomization::GetRandomCodeLength(3, 4);
  $BotDetect->CodeStyle = CodeStyle::Numeric;
  $BotDetect->CodeTimeout = 600; // 10 minutes
} else if ($count < 10) {
  $BotDetect->CodeLength = CaptchaRandomization::GetRandomCodeLength(4, 6);
  $BotDetect->CodeStyle = CodeStyle::Alpha;
  $BotDetect->CodeTimeout = 180; // 3 minutes
} else {
  $BotDetect->CodeLength = CaptchaRandomization::GetRandomCodeLength(6, 9);
  $BotDetect->CodeStyle = CodeStyle::Alphanumeric;
  $BotDetect->CodeTimeout = 60; // 1 minute
}


// set Captcha locale to Chinese for requests from a certain IP range
$test_ip_range = '223.254.';
if (array_key_exists('REMOTE_ADDR', $_SERVER) && 
    substr($_SERVER['REMOTE_ADDR'], 0, strlen($test_ip_range)) === $test_ip_range) {
  $BotDetect->CodeStyle = CodeStyle::Alpha;
  $BotDetect->Locale = 'cmn';
}

?>

Since the code example includes the BotDetect Captcha library from a shared location, we use a local config file to override base Captcha settings. If you are just copying the whole Captcha library to the root folder of your website, you could make the same changes which are described at the Captcha configuration options page .

The dynamic Captcha settings will have various values according to number of previously failed validations. It also sets Captcha locale to Chinese for requests from a certain IP range (i.e. '223.254.' in code above) .