jQuery Form CAPTCHA Code Example

  1. Client-side
  2. Server-side

I. Client-side

The jQuery Form Captcha code example shows how to add BotDetect CAPTCHA protection to a typical jQuery form.

Captcha validation is integrated with other form fields validation, and only submissions that meet all validation criteria are accepted.

This kind of validation could be used on various types of public forms which accept messages, and are at risk of unwanted automated submissions.

For example, it could be used to ensure bots can't submit anything to a contact form, add guestbook entries, blog post comments or anonymous message board / forum replies.

Download the BotDetect Java CAPTCHA Library and run this example

Downloaded Location

The jQuery Form CAPTCHA code example is included in the examples/simple-api/bdc4-simple-api-jquery-captcha-example.war file of the download package. When deploying (unpacking) the file you will see the following main source code files:

contact-captcha.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>BotDetect jQuery CAPTCHA Examples</title>
  <link href="styles/styles.css" type="text/css" rel="stylesheet">
</head>
<body>
  <header>
    <div class="header-content"><h1>BotDetect jQuery CAPTCHA Examples</h1></div>
  </header>

  <nav>
   <ul class="nav">
    <li><a href="basic-captcha.html">Basic Example</a></li>
    <li><a href="contact-captcha.html" class="active">Contact Example</a></li>
   </ul>
  </nav>

  <section id="main-content">
    <form id="contactForm" method="POST">
      <div id="form-messages"></div>

      <label>
        <span>Name:</span>
        <input type="text" id="name" name="name">
      </label>
      <div class="error name"></div>


      <label>
        <span>Email</span>
        <input type="email" id="email" name="email" >
      </label>
      <div class="error email"></div>


      <label>
        <span>Subject:</span>
        <input type="text" id="subject" name="subject">
      </label>
      <div class="error subject"></div>


      <label>
        <span>Message:</span>
        <textarea id="message" name="message"></textarea>
      </label>
      <div class="error message"></div>


      <!-- show Captcha image html-->
      <div id="botdetect-captcha" data-stylename="jqueryFormCaptcha"></div>

      <label>
        <span>Retype the characters from the picture:</span>
        <!-- captcha code user input textbox -->
        <input 
          type="text" 
          id="captchaCode" 
          name="captchaCode" 
          data-correct-captcha
        >
      </label>
      <div class="error captchaCode"></div>

      <button type="submit" id="submitButton" disabled="disabled" class="btn btn-primary">Send</button>
    </form>
  </section>
  
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
  <script src="node_modules/jquery-captcha/dist/jquery-captcha.min.js"></script>
  <script src="js/contact.js"></script>
</body>
</html>

Adding Captcha protection to the jQuery form is as simple as declaring an HTML element and set to data-stylename attribute a Captcha style name defined in botdetect.xml configuration file below.

In captcha code input element, we add data-correct-captcha attribute. It will tell BotDetect Captcha jQuery plugin to validate captcha code on blur event.

Beside the captcha code input field, the example form contains three other fields which are going to be validated in contact.js later.

At the bottom of the file, we do not forget to include the BotDetect Captcha jQuery plugin in your HTML template.

contact.js

$(function() {

  // load BotDetect Captcha, it requires you to configure 
  // BotDetect Java Captcha path to captchaEndpoint setting
  var captcha = $('#botdetect-captcha').captcha({
    captchaEndpoint: '/bdc4-simple-api-jquery-captcha-example/botdetectcaptcha'
  });
  
  // error messages of input fields
  var errorMessages = {
    name: 'Name must be at least 3 characters.',
    email: 'Email is invalid.',
    subject: 'Subject must be at least 10 characters.',
    message: 'Message must be at least 10 characters.',
    captchaCode: 'Invalid code.'
  };
  
  // global variables that holds validation status of captcha input field, 
  // use them for checking validation status when form is submitted
  var isValidName = false,
      isValidEmail = false,
      isValidSubject = false,
      isValidMessage = false,
      isCorrectCaptchaCode = false;
  
  
  function validateName() {
    var name = $('#name').val();
    isValidName = (name.length >= 3);
    if (isValidName) {
      $('.name').text('');
    } else {
      $('.name').text(errorMessages.name);
    }
  }
  
  function validateEmail() {
    var email = $('#email').val();
    var emailRegEx = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
    isValidEmail = emailRegEx.test(email);
    if (isValidEmail) {
      $('.email').text('');
    } else {
      $('.email').text(errorMessages.email);
    }
  }
  
  function validateSubject() {
    var subject = $('#subject').val();
    isValidSubject = (subject.length >= 10);
    if (isValidSubject) {
      $('.subject').text('');
    } else {
      $('.subject').text(errorMessages.subject);
    }
  }
  
  function validateMessage() {
    var message = $('#message').val();
    isValidMessage = (message.length >= 10);
    if (isValidMessage) {
      $('.message').text('');
    } else {
      $('.message').text(errorMessages.message);
    }
  }
  
  // validate input fields on blur event
  $('#name').blur(validateName);
  $('#email').blur(validateEmail);
  $('#subject').blur(validateSubject);
  $('#message').blur(validateMessage);
  
  // UI captcha validation on blur event by using the custom 'validatecaptcha' event
  // and checking the 'isCorrect' variable to either show error messages 
  // or check captcha code input field status when form is submitted
  $('#captchaCode').on('validatecaptcha', function(event, isCorrect) {
    // update validation status of captcha code input
      isCorrectCaptchaCode = isCorrect;
      
      // display or remove error message
      if (isCorrect) {
        $('.captchaCode').text('');
        $('#submitButton').attr('disabled', false);
      } else {
        $('.captchaCode').text(errorMessages.captchaCode);
        $('#submitButton').attr('disabled', true);
      }
  });
  
  
  // On contact form submit
  $('#contactForm').submit(function(event) {
    
    if (isValidName && isValidEmail && isValidSubject 
          && isValidMessage && isCorrectCaptchaCode) {
      // form is valid
      // we send contact data as well as captcha data to server-side for
      // validating once again before they are inserted into database
      

      // captcha id for validating captcha at server-side
      var captchaId = captcha.getCaptchaId();

      // captcha code input value for validating captcha at server-side
      var captchaCode = $('#captchaCode').val();

      var postData = {
        name: $('#name').val(),
        email: $('#email').val(),
        subject: $('#subject').val(),
        message: $('#message').val(),
        captchaId: captchaId,
        captchaCode: captchaCode
      };
      
      $.ajax({
        method: 'POST',
        url: '/bdc4-simple-api-jquery-captcha-example/contact',
        data: JSON.stringify(postData),
        success: function(response) {
          if (response.success) {
            // captcha, other form data passed and the data is also stored in database
            // show success message
            $('#form-messages')
              .removeClass()
              .addClass('alert alert-success')
              .text('Your message was sent successfully!.');
          } else {
            // form validation failed
            $('#form-messages')
              .removeClass()      
              .addClass('alert alert-error')
              .text('An error occurred while sending your message, please try again.');
          }
        },
        complete: function() {
          // always reload captcha image after validating captcha at server-side 
          // in order to update new captcha code for current captcha id
          captcha.reloadImage();
          
          $('#submitButton').attr('disabled', true);
        },
        error: function(error) {
          throw new Error(error);
        }
      });
    } else {
      // form is invalid
      $('#form-messages')
        .removeClass()      
        .addClass('alert alert-error')
        .text('The form fields could not be empty.');
    } 
    
    event.preventDefault();
  });
  
});

We first load BotDetect Captcha jQuery plugin, it requires you to configure a BotDetect Java Captcha path to captchaEndpoint setting.

Once we add data-correct-captcha attribute in the captcha code input element, BotDetect Captcha jQuery plugin will then automatically validate captcha code on blue event in default. And to check the UI captcha validation result, we listen the custom validatecaptcha event, which will be fired on captcha code input blur event.

We also define validation functions and perform blur validation for other contact fields.

On form submit, after the form is valid we need to send captcha id value and captcha code visitors submitted to server-side to validate Captcha code once at server-side api. Once request finished, we always reload Captcha by calling reloadImage() function of captcha object. This is needed to generate the new captcha code for the current captcha id.

II. Server-side

botdetect.xml

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

  <captchaStyles>
    <captchaStyle>
      <name>jqueryFormCaptcha</name>
      <userInputID>captchaCode</userInputID>
      <codeLength>4-6</codeLength>
      <codeStyle>ALPHANUMERIC</codeStyle>
    </captchaStyle>
  </captchaStyles>

</botdetect>

In WEB-INF/botdetect.xml, we configure some captcha options for our jquery form captcha. You can find a full list of available Captcha configuration options and related instructions at the Captcha configuration options page.

ContactServlet.java

package com.captcha.botdetect.examples.jquery.contact_form;

import com.captcha.botdetect.web.servlet.SimpleCaptcha;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ContactServlet extends HttpServlet {

  @Override
  protected void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    
    PrintWriter out = response.getWriter();
    Gson gson = new Gson();
    Map<String, String> errors = new HashMap<String, String>();
    
    response.setContentType("application/json; charset=utf-8");
    
    JsonParser parser = new JsonParser();
    JsonObject formDataObj = (JsonObject) parser.parse(request.getReader());
    
    String name = formDataObj.get("name").getAsString();
    String email = formDataObj.get("email").getAsString();
    String subject = formDataObj.get("subject").getAsString();
    String message = formDataObj.get("message").getAsString();
    String captchaId = formDataObj.get("captchaId").getAsString();
    String captchaCode = formDataObj.get("captchaCode").getAsString();
     
    if (!isValidName(name)) {
      errors.put("name", "Name must be at least 3 characters.");
    }
    
    if (!isValidEmail(email)) {
      errors.put("email", "Email is invalid.");
    }
    
    if (!isValidSubject(subject)) {
      errors.put("message", "Subject must be at least 10 characters.");
    }
    
    if (!isValidMessage(message)) {
      errors.put("message", "Message must be at least 10 characters.");
    }
    
    if (!isCaptchaCorrect(request, captchaCode, captchaId)) {
      errors.put("captchaCode", "CAPTCHA validation failed.");
    }
    
    if (errors.isEmpty()) {
      // everything is ok
      // TODO: Insert form data into your database
    }
    
    // the object that stores validation result
    ContactValidationResult validationResult = new ContactValidationResult();
    validationResult.setSuccess(errors.isEmpty());
    validationResult.setErrors(errors);
    
    try {
      // write the validation result as json string for sending it back to client
      out.write(gson.toJson(validationResult));
    } finally {
      out.close();
    }
  }
  
 
  private boolean isCaptchaCorrect(HttpServletRequest request, String captchaCode, String captchaId) {
    SimpleCaptcha captcha = SimpleCaptcha.load(request);
    return captcha.validate(captchaCode, captchaId);
  }
  
  private boolean isValidName(String name) {
    if (name == null) {
      return false;
    }
    return (name.length() >= 3);
  }
  
  private boolean isValidEmail(String email) {
    if (email == null) {
      return false;
    }
    return email.matches("^[\\w-_\\.+]*[\\w-_\\.]\\@([\\w]+\\.)+[\\w]+[\\w]$");
  }
  
  private boolean isValidSubject(String subject) {
    if (subject == null) {
      return false;
    }
    return (subject.length() > 9) && (subject.length() < 255);
  }
  
  private boolean isValidMessage(String message) {
    if (message == null) {
      return false;
    }
    return (message.length() > 9) && (message.length() < 255);
  }
}

At server-side api, we will get captchaId and captchaCode values sent from client-side and use validate(captchaCode, captchaId) method of SimpleCaptcha instance to validate Captcha code. Finally, we write the validation result as json string for sending it back to client.

ContactValidationResult.java

package com.captcha.botdetect.examples.jquery.basic_form;

public class ContactValidationResult {
  private boolean success;

  public BasicValidationResult() {
  }

  public boolean getSuccess() {
    return success;
  }

  public void setSuccess(boolean success) {
    this.success = success;
  }
}

This class is to store Captcha validation result and use it to convert to JSON string using Gson library in ContactServlet.


Please Note

Angular Captcha Module requires the new experimental Simple API that is currently available in BotDetect Java version (4.0.Beta3+) and BotDetect PHP version (4.2.0+). Click here to find out when the Simple API will be available in BotDetect ASP.NET.