Angular Form CAPTCHA Code Example

  1. Client-side
    1. Angular 2/4/5/6+
    2. AngularJS 1.x
  2. Server-side

I. Client-side

a) Angular 2/4/5/6+

The Angular Form Captcha code example shows how to add BotDetect CAPTCHA protection to a typical Angular 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 PHP CAPTCHA Library and run this example

Downloaded Location

The Angular Form CAPTCHA code example is included in the examples/simple-api/angular/simple-api-angular-captcha-example folder of the download package. When opening the folder you will see the following main source code files:

app.module.ts

import { NgModule } from '@angular/core';
  import { BrowserModule } from '@angular/platform-browser';
  import { FormsModule, ReactiveFormsModule } from '@angular/forms';
  import { HttpModule } from '@angular/http';
  
  import { AppRoutingModule } from './app-routing.module';
  import { BotDetectCaptchaModule } from 'angular-captcha';
  
  import { AppComponent } from './app.component';
  import { ContactComponent }   from './contact/contact.component';
  
  import { ValuesPipe } from './values.pipe';
  
  @NgModule({
    imports: [
      BrowserModule,
      FormsModule,
      HttpModule,
      ReactiveFormsModule,
      AppRoutingModule,
      BotDetectCaptchaModule.forRoot({
        captchaEndpoint: 'captcha-endpoint/simple-botdetect.php',
      })
    ],
    declarations: [
      AppComponent,
      ContactComponent,
      ValuesPipe
    ],
    providers: [],
    bootstrap: [AppComponent]
  })
  export class AppModule { }
  

We import BotDetectCaptchaModule, then declare it in metadata imports of NgModule and configure BotDetect PHP Captcha path in captchaEndpoint settings.

contact.component.html

<form novalidate (ngSubmit)="send(contact)" [formGroup]="contact">
  
    <div class="alert alert-success" *ngIf="successMessages">
      {{ successMessages }}
    </div>
  
    <div class="alert alert-error" *ngIf="errorMessages">
      <ul class="list-messages">
        <li *ngFor="let error of errorMessages | values">
          {{ error }}
        </li>
      </ul>
    </div>
  
    <label>
      <span>Name:</span>
      <input
        type="text"
        name="name"
        formControlName="name">
    </label>
  
    <div
      class="error"
      *ngIf="contact.get('name').hasError('minlength') && contact.get('name').touched"
      >
      Name must be at least 3 characters.
    </div>
  
  
    <label>
      <span>Email:</span>
      <input
        type="email"
        name="email"
        formControlName="email">
    </label>
  
    <div
      class="error"
      *ngIf="contact.get('email').hasError('pattern') && contact.get('email').touched"
      >
      Email is invalid.
    </div>
  
  
    <label>
      <span>Subject:</span>
      <input
        type="text"
        name="subject"
        formControlName="subject">
    </label>
  
    <div
      class="error"
      *ngIf="contact.get('subject').hasError('minlength') && contact.get('subject').touched"
      >
      Subject must be at least 10 characters.
    </div>
  
  
    <label>
      <span>Message:</span>
      <textarea
        name="message"
        formControlName="message"></textarea>
    </label>
  
    <div
      class="error textarea-error"
      *ngIf="contact.get('message').hasError('minlength') && contact.get('message').touched"
      >
      Message must be at least 10 characters.
    </div>
    
    <!-- show captcha html -->
    <botdetect-captcha styleName="angularFormCaptcha"></botdetect-captcha>
  
    <label>
      <span>Retype the characters from the picture:</span>
      <input
        type="text"
        id="captchaCode"
        name="captchaCode"
        formControlName="captchaCode"
        >
    </label>
  
    <button type="submit">Send</button>
  </form>
  

Adding Captcha protection to the Angular form is as simple as using botdetect-captcha element, which is provided by BotDetect Captcha Angular Module and set to styleName attribute a Captcha style name defined in botdetect.xml configuration file below.

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

contact.component.ts

import { Component, ViewChild, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Observable } from 'rxjs/Rx';

import { CaptchaComponent } from 'angular-captcha';

import { Contact } from './contact.interface';
import { ContactService } from './contact.service';

@Component({
  moduleId: module.id,
  selector: 'contact-form',
  templateUrl: 'contact.component.html',
  styleUrls: ['contact.component.css'],
  providers: [ContactService]
})
export class ContactComponent implements OnInit {
  
  contact: FormGroup;

  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,}))$/;

  /**
   * Captcha validation messages.
   */
  errorMessages: Object;
  successMessages: string;

  /**
   * BotDetect CAPTCHA component.
   */
  @ViewChild(CaptchaComponent) captchaComponent: CaptchaComponent;

  constructor(
    private fb: FormBuilder,
    private contactService: ContactService
  ) { }

  ngOnInit(): void {
    this.contact = this.fb.group({
      name: ['', [Validators.required, Validators.minLength(3)]],
      email: ['',  [Validators.required, Validators.pattern(this.emailRegex)]],
      subject: ['',  [Validators.required,Validators.minLength(10)]],
      message: ['',  [Validators.required,Validators.minLength(10)]],
      captchaCode: [''] // we use 'validateUnsafe' method to validate captcha code control when form is submitted
    });
  }

  send({ value }: { value: Contact }): void {

    // use validateUnsafe() method to perform client-side captcha validation
    this.captchaComponent.validateUnsafe((isCaptchaCodeCorrect: boolean) => {

      if (isCaptchaCodeCorrect && this.contact.controls.name.valid && this.contact.controls.email.valid
            && this.contact.controls.subject.valid && this.contact.controls.message.valid) {

        // 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

        let postData = {
          name: value.name,
          email: value.email,
          subject: value.subject,
          message: value.message,
          captchaCode: this.captchaComponent.captchaCode,
          captchaId: this.captchaComponent.captchaId
        };
    
        this.contactService.send(postData)
          .subscribe(
            response => {
              if (response.success) {
                // captcha validation passed at server-side
                this.successMessages = 'CAPTCHA validation passed.';
                this.errorMessages = null;
              } else {
                // captcha validation failed at server-side
                this.errorMessages = response.errors;
                this.successMessages = '';
              }
    
              // always reload captcha image after validating captcha at server-side 
              // in order to update new captcha code for current captcha id
              this.captchaComponent.reloadImage();
            },
            error => {
              throw new Error(error);
            });
            
      } else {
        this.errorMessages = { formInvalid: 'Please enter valid values.' }
        this.successMessages = '';
      }
    });

  }
}

In the code above, we inject CaptchaComponent into ContactComponent using @ViewChild.

On form submit, we use validateUnsafe() method to perform client-side captcha validation and we also need to send both captcha id (via captchaComponent.captchaId property) and captcha code visitor submited (via captchaComponent.captchaCode property) to server-side to validate Captcha code once.

Once request finished, we always reload Captcha by calling the reloadImage() function of CaptchaComponent. This is needed to generate the new captcha code for the current captcha id.

contact.service.ts

import { Injectable }    from '@angular/core';
  import { Http, Response, Headers, RequestOptions } from '@angular/http';
  
  import { Observable } from 'rxjs/Rx';
  
  @Injectable()
  export class ContactService {
  
    // contact api url
    contactUrl = 'contact.php';
  
    constructor(private http: Http) { }
  
    send(data: Object): Observable<any> {
      const headers = new Headers({ 'Content-Type': 'application/json' });
      const options = new RequestOptions({ headers: headers });
  
      return this.http.post(this.contactUrl, data, options)
        .map((response: Response) => response.json())
        .catch((error:any) => Observable.throw(error.json().error));
    }
  }
  

In this ContactService, we simply add a function that posts data to the contact api url using Http post of HttpModule.

contact.interface.ts

export interface Contact {
    name: string;
    email: string;
    subject: string;
    message: string;
    captchaCode: string;
  }
  

We implement this interface to use in contact.component.ts.

b) AngularJS 1.x

The AngularJS Form Captcha code example shows how to add BotDetect CAPTCHA protection to a typical AngularJS 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 PHP CAPTCHA Library and run this example

Downloaded Location

The AngularJS Form CAPTCHA code example is included in the examples/simple-api/angular/simple-api-angularjs-captcha-example folder of the download package. When opening the folder you will see the following main source code files:

contact-captcha.html

<form name="contactForm" novalidate ng-controller="ContactController" ng-submit="send(contactForm.$valid)" >
  
  <div class="alert alert-success" ng-show="successMessages">
    {{ successMessages }}
  </div>

  <div class="alert alert-error" ng-show="errorMessages">
    <ul class="list-messages" ng-repeat="(field, message) in errorMessages">
      <li>{{ message }}</li>
    </ul>
  </div>
  
  
  <label>
    <span>Name:</span>
    <input type="text" name="name" ng-model="name" ng-minlength="3">
  </label>
  
  <div class="error" ng-show="contactForm.name.$error.minlength && !contactForm.name.$pristine">
    Name must be at least 3 characters.
  </div>
  
  
  <label>
    <span>Email</span>
    <input type="email" name="email" ng-model="email" required>
  </label>
  
  <div class="error" ng-show="contactForm.email.$invalid && !contactForm.email.$pristine">
    Email is invalid.
  </div>
  

  <label>
    <span>Subject:</span>
    <input type="text" name="subject" ng-model="subject" ng-minlength="10">
  </label>
  
  <div class="error" ng-show="contactForm.subject.$error.minlength">
    Subject must be at least 10 characters.
  </div>
  
  
  <label>
    <span>Message:</span>
    <textarea name="message" ng-model="message" ng-minlength="10"></textarea>
  </label>
  
  <div class="error" ng-show="contactForm.message.$error.minlength">
    Message must be at least 10 characters.
  </div>
  
  
  <!-- show Captcha image html-->
  <botdetect-captcha styleName="angularFormCaptcha"></botdetect-captcha>
  
  <label>
    <span>Retype the characters from the picture:</span>
    <!-- captcha code user input textbox -->
    <input type="text" name="captchaCode" ng-model="captchaCode" correct-captcha id="captchaCode" autocomplete="off">
  </label>

  <button type="submit" class="btn btn-primary">Send</button>
</form>

Adding Captcha protection to the AngularJS form is as simple as using botdetect-captcha element, which is provided by BotDetect Captcha AngularJS Module and set to styleName attribute a Captcha style name defined in botdetect.xml configuration file below.

We have used correct-captcha directive attribute in captcha code input field to perform UI Captcha validation on blur event.

To display captcha error message, we simply check $invalid of captchaCode. If it returns true, this means that UI captcha validation failed.

Beside the captcha code input field, the example form contains three other fields which are validated using AngularJS directive validation.

app.js

var app = angular.module('app', ['BotDetectCaptcha']);

app.config(function($routeProvider, captchaSettingsProvider) {
  captchaSettingsProvider.setSettings({
    // declare your captcha endpoint, it will be served for getting captcha html, reload icon, sound icons, etc.
    captchaEndpoint: 'captcha-endpoint/simple-botdetect.php'
  });
});

app.controller('ContactController', function($scope, $http, Captcha) {
  // captcha validation messages
  $scope.successMessages = '';
  $scope.errorMessages = '';
  
  // contact url
  var contactUrl = 'contact.php';

  $scope.send = function(contactForm) {

    // create new BotDetect Angular Captcha instance
    var captcha = new Captcha();

    captcha.validateUnsafe(function(isCaptchaCodeCorrect) {
      
      if (isCaptchaCodeCorrect && contactForm.name.$valid && contactForm.email.$valid 
            && contactForm.subject.$valid && contactForm.message.$valid) {
    
        // after UI form validation passed, 
        // we will need to validate captcha at server-side before we save form data in database, etc.

        // captcha id for validating captcha at server-side
        var captchaId = captcha.captchaId;
        
        // captcha code input value for validating captcha at server-side
        var captchaCode = $scope.captchaCode;
        
        var postData = {
          name: $scope.name,
          email: $scope.email,
          subject: $scope.subject,
          message: $scope.message,
          captchaId: captchaId,
          captchaCode: captchaCode
        };
        
        $http({
          method: 'POST',
          url: contactUrl,
          data: JSON.stringify(postData)
        })
          .then(function(response) {
            if (response.data.success) {
              // captcha, other form data passed and the data is also stored in database
              // show success message
              $scope.successMessages = 'Your message was sent successfully!';
              $scope.errorMessages = null;
            } else {
              // form validation failed
              $scope.errorMessages = response.data.errors;
              $scope.successMessages = null;
            }
            
            // always reload captcha image after validating captcha at server-side 
            // in order to update new captcha code for current captcha id
            captcha.reloadImage();
          }, function(error) {
            console.log(error.data);
          });
      } else {
        $scope.errorMessages = { formInvalid: 'Please enter valid values.' };
        $scope.successMessages = null;
      }
    });
  };
  
});

First, we add BotDetectCaptcha to the app module as a dependency and configure BotDetect Java Captcha path to captchaEndpoint settings in config function.

In the code above, we inject Captcha into ContactController.

On form submit, we use validateUnsafe() method to perform client-side captcha validation and we also need to send captchaId property of Captcha object and captcha code visitors submitted to server-side to validate Captcha code once.

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/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>angularFormCaptcha</name>
        <userInputID>captchaCode</userInputID>
        <codeLength>4-6</codeLength>
        <codeStyle>ALPHANUMERIC</codeStyle>
      </captchaStyle>
    </captchaStyles>
  
  </botdetect>
  

In config/botdetect.xml, we configure some captcha options for our angularjs basic captcha. You can find a full list of available Captcha configuration options and related instructions at the Captcha configuration options page.

contact.php

<?php
  
  require("captcha-endpoint/simple-botdetect.php");
  $form_page = "index.html";
  
  // directly accessing this script is an error
  if ($_SERVER['REQUEST_METHOD'] != "POST") {
    header("Location: ${form_page}");
    exit;
  }
  
  // get input params
  $inputJSON = file_get_contents('php://input');
  $input = json_decode($inputJSON, TRUE);
  
  $name = $input["name"];
  $email = $input["email"];
  $subject = $input["subject"];
  $message = $input["message"];
  $userInput = $input["captchaCode"];
  $captchaId = $input["captchaId"];
  
  // store error message
  $error = array();
  
  if (!isValidName($name)) {
    $error["name"] = "Name must be at least 3 characters.";
  }
  
  if (!isValidEmail($email)) {
    $error["email"] = "Email is invalid.";
  }
  
  if (!isValidSubject($subject)) {
    $error["subject"] = "Subject must be at least 10 characters.";
  }
  
  if (!isValidMessage($message)) {
    $error["message"] = "Message must be at least 10 characters.";
  }
  
  if (!isCaptchaCorrect($userInput, $captchaId)) {
    $error["captchaCode"] = "CAPTCHA validation failed.";
  }
  
  if (empty($error)) {
    // everything is ok
    // TODO: Insert form data into your database
  }
  
  
  $result = array('success' => empty($error), 'error' => $error);
  echo json_encode($result, true);
  exit;
  
  // validate function
  
  function isCaptchaCorrect($userInput, $captchaId) {
    // Captcha validation
    $FormCaptcha = new SimpleCaptcha();
    return $FormCaptcha->Validate($userInput, $captchaId);
  }
  
  function isValidName($name) {
    if($name == null) {
      return false;
    }
    return (strlen($name) >= 3);
  }
  
  function isValidEmail($email) {
    if($email == null) {
      return false;
    }
  
    return preg_match("/^[\\w-_\\.+]*[\\w-_\\.]\\@([\\w]+\\.)+[\\w]+[\\w]$/", $email, $matches);
  }
  
  function isValidSubject($subject) {
    if($subject == null) {
      return false;
    }
  
    return (strlen($subject) > 9) && (strlen($subject) < 255);
  }
  
  function isValidMessage($message) {
    if($message == null) {
      return false;
    }
  
    return (strlen($message) > 9) && (strlen($message) < 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.

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.