React Captcha Component: The Contact Form Code Example
Click on the link below that matches your BotDetect CAPTCHA React Component usage scenario:
First Time Here?
The React CAPTCHA Integration Guide is the best place to start!
- React-based Frontend and an ASP.NET Core-based Backend
- React-based Frontend and a legacy ASP.NET-based Backend
- React-based Frontend and a Java-based Backend
- React-based Frontend and a PHP-based Backend
..............................................................
React-based Frontend and the web API with MVC Core 1/2 on Backend
This is a partial walk-through of the example source code. It is not meant to replace a proper step-by-step guide. If you are new to BotDetect, skip it for now; and do start your first React captcha integration by following our step-by-step React CAPTCHA Integration Guide.
Introduction
This contact form React captcha example shows the code required to display and validate captchas in a contact form of the application with a React frontend and a web API with MVC Core 1/2 backend.
Download the BotDetect ASP.NET CAPTCHA Component and run this exampleWithin this page, the root folder of the extracted archive is referred as the <BDC-DIR>
.
This example is in the <BDC-DIR>/core-on-core/examples/s_api-captcha-react-webapi_mvccore2/
folder; and contains the following files:
- Frontend code:
- Backend code:
Frontend: contact.jsx
The react-src/views/contact.jsx
source file does the following:
- Loads the BotDetect CAPTCHA React Component into the page
- Sets the
captchaEndpoint
property to point to the captcha endpoint path on backend - Displays the captcha and user-input markups on the page
- Loads the captcha challenges from backend
- Sends the post request with the captcha id and the user entered captcha code to backend
- Processes the captcha validation results:
-
- when the captcha validation fails -- it reloads captcha and displays an error message
- when the captcha validation succeeds -- it executes by the captcha protected action
import React from 'react'; import axios from 'axios'; import { Captcha, captchaSettings } from 'reactjs-captcha'; class Contact extends React.Component { constructor(props) { super(props); // set the captchaEndpoint property to point to // the captcha endpoint path on your app's backend captchaSettings.set({ captchaEndpoint: 'simple-captcha-endpoint.ashx' }); } componentDidMount() { let self = this; // the validation-error messages for the form's data-input fields const errorMessages = { name: 'Name must be at least 3 chars long!', email: 'Email is invalid!', subject: 'Subject must be at least 10 chars long!', message: 'Message must be at least 10 chars long!' }; // the global variables that hold the validation-status flags of the form's data-input fields; // those validation-status flags will be checked on form submit this.isNameValid = false; this.isEmailValid = false; this.isSubjectValid = false; this.isMessageValid = false; function validateName() { var name = document.getElementById('name').value; self.isNameValid = (name.length >= 3); if (self.isNameValid) { document.getElementsByClassName('name')[0].innerHTML = ''; } else { document.getElementsByClassName('name')[0].innerHTML = errorMessages.name; } } function validateEmail() { var email = document.getElementById('email').value; 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,}))$/; self.isEmailValid = emailRegEx.test(email); if (self.isEmailValid) { document.getElementsByClassName('email')[0].innerHTML = ''; } else { document.getElementsByClassName('email')[0].innerHTML = errorMessages.email; } } function validateSubject() { var subject = document.getElementById('subject').value; self.isSubjectValid = (subject.length >= 10); if (self.isSubjectValid) { document.getElementsByClassName('subject')[0].innerHTML = ''; } else { document.getElementsByClassName('subject')[0].innerHTML = errorMessages.subject; } } function validateMessage() { var message = document.getElementById('message').value; self.isMessageValid = (message.length >= 10); if (self.isMessageValid) { document.getElementsByClassName('message')[0].innerHTML = ''; } else { document.getElementsByClassName('message')[0].innerHTML = errorMessages.message; } } // validate the form's data-input fields on blur event document.getElementById('name').addEventListener('blur', validateName); document.getElementById('email').addEventListener('blur', validateEmail); document.getElementById('subject').addEventListener('blur', validateSubject); document.getElementById('message').addEventListener('blur', validateMessage); } // process the contact form on submit event onFormSubmitHandler(event) { let self = this; let formMessage = document.getElementById('form-messages'); if (self.isNameValid && self.isEmailValid && self.isSubjectValid && self.isMessageValid) { // get the user-entered captcha code value to be validated at the backend side let userEnteredCaptchaCode = this.captcha.getUserEnteredCaptchaCode(); // get the id of a captcha instance that the user tried to solve let captchaId = this.captcha.getCaptchaId(); var postData = { name: document.getElementById('name').value, email: document.getElementById('email').value, subject: document.getElementById('subject').value, message: document.getElementById('message').value, // add the user-entered captcha code value to the post data userEnteredCaptchaCode: userEnteredCaptchaCode, // add the id of a captcha instance to the post data captchaId: captchaId }; // post both the form-data and captcha data to the backend axios.post('api/contact-captcha', postData) .then(response => { if (response.data.success == false) { // captcha validation failed; show the error message formMessage.setAttribute('class', 'alert alert-error'); formMessage.innerHTML = response.data.errors.userEnteredCaptchaCode; // call the self.captcha.reloadImage() // in order to generate a new captcha challenge self.captcha.reloadImage(); } else { // captcha validation succeeded; proceed with the workflow self.props.history.push('/contact-success-notify'); } }).catch(error => { throw new Error(error); }); } else { formMessage.setAttribute('class', 'alert alert-error'); formMessage.innerHTML = 'Please enter valid values.'; } event.preventDefault(); } render() { var self = this; return ( <div id="main-content"> <form id="contactForm" method="POST" onSubmit={self.onFormSubmitHandler.bind(self)}> <div id="form-messages"></div> <label> <span>Name:</span> <input type="text" id="name"/> </label> <div className="error name"></div> <label> <span>Email</span> <input type="email" id="email"/> </label> <div className="error email"></div> <label> <span>Subject:</span> <input type="text" id="subject"/> </label> <div className="error subject"></div> <label> <span>Message:</span> <textarea id="message"></textarea> </label> <div className="error message"></div> {/* captcha challenge: placeholder */} <Captcha captchaStyleName="reactFormCaptcha" ref={(captcha) => {this.captcha = captcha;}} /> <label> <span>Retype the chars long from the picture:</span> {/* captcha code: user-input textbox */} <input type="text" id="userCaptchaInput" /> </label> <button type="submit" id="submitButton">Send</button> </form> </div> ) } } export default Contact;
[back to the top of react & web api with mvc core 1/2 backend section]
Backend: appsettings.json
The appsettings.json
source file contains the following:
BotDetect
configuration section that defines theCaptchaEndpointPath
path
{ "Logging": { "IncludeScopes": false, "LogLevel": { "Default": "Warning" } }, "BotDetect": { "CaptchaEndpointPath": "simple-captcha-endpoint.ashx" } }
[back to the top of react & web api with mvc core 1/2 backend section]
Backend: Startup.cs
The Startup.cs
source file does the following:
- Configures the application pipeline to use
SimpleCaptcha
middleware
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using BotDetect.Web; using BotDetect.Web.Http; namespace ReactWebAPIwithMVC6CaptchaExample { public class Startup { public Startup(IHostingEnvironment env) { var builder = new ConfigurationBuilder() .SetBasePath(env.ContentRootPath) .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) .AddEnvironmentVariables(); Configuration = builder.Build(); } public IConfigurationRoot Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { // You can omit the next line on .NET Core 2.0 or higher services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); services.AddMemoryCache(); // Adds a default in-memory // implementation of // IDistributedCache // Add framework services. services.AddMvc(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddDebug(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseDefaultFiles(options); app.UseStaticFiles(); // Configure the application pipeline to use SimpleCaptcha middleware app.UseSimpleCaptcha(Configuration.GetSection("BotDetect")); app.UseMvc(); } } }
[back to the top of react & web api with mvc core 1/2 backend section]
Backend: botdetect.xml
The botdetect.xml
source file contains the following:
- Captcha style definitions consisting of:
-
- The name of a captcha style
- The ID of an
<input>
element in which user enters captcha codes - Other option settings -- the captcha code length in this particular case
<?xml version="1.0" encoding="UTF-8"?> <botdetect xmlns="https://captcha.com/schema/net" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://captcha.com/schema/net https://captcha.com/schema/net/botdetect-4.4.2.xsd"> <captchaStyles> <captchaStyle> <name>reactFormCaptcha</name> <userInputID>userCaptchaInput</userInputID> <codeLength>4-6</codeLength> </captchaStyle> </captchaStyles> </botdetect>
[back to the top of react & web api with mvc core 1/2 backend section]
Backend: ContactApiController.cs
The Controllers/ContactApiController.cs
source file does the following:
- Extracts the
userEnteredCaptchaCode
andcaptchaId
values posted from the frontend - Validates captchas by calling the
Validate(userEnteredCaptchaCode, captchaId)
method - Returns the json-formatted captcha validation results to frontend
using Microsoft.AspNetCore.Mvc; using System.Collections.Generic; using System.Text.RegularExpressions; using BotDetect.Web; namespace ReactWebAPIwithMVC6CaptchaExample.Controllers { [Route("api/contact-captcha")] public class ContactApiController : Controller { [HttpPost] public IActionResult Post([FromBody] Models.ContactFormModel data) { string name = data.Name; string email = data.Email; string subject = data.Subject; string message = data.Message; string userEnteredCaptchaCode = data.UserEnteredCaptchaCode; string captchaId = data.CaptchaId; // validate the form data Dictionary<string, string> errors = new Dictionary<string, string>(); if (!IsValidName(name)) { errors.Add("name", "Name must be at least 3 chars long!"); } if (!IsValidEmail(email)) { errors.Add("email", "Email is invalid!"); } if (!IsValidSubject(subject)) { errors.Add("subject", "Subject must be at least 10 chars long!"); } if (!IsValidMessage(message)) { errors.Add("message", "Message must be at least 10 chars long!"); } // validate the user entered captcha code if (!IsCaptchaCorrect(userEnteredCaptchaCode, captchaId)) { errors.Add("userEnteredCaptchaCode", "CAPTCHA validation failed!"); // TODO: consider logging the attempt } bool isErrorsEmpty = errors.Count > 0 ? false : true; if (isErrorsEmpty) { // TODO: all validations succeeded; execute the protected action // (send email, write to database, etc...) } // create an object that stores the validation result Dictionary<string, object> validationResult = new Dictionary<string, object>(); validationResult.Add("success", isErrorsEmpty); validationResult.Add("errors", errors); // return the json string with the validation result to the frontend return Json(validationResult); } // the captcha validation function private bool IsCaptchaCorrect(string userEnteredCaptchaCode, string captchaId) { // create a captcha instance to be used for the captcha validation SimpleCaptcha captcha = new SimpleCaptcha(); // execute the captcha validation return captcha.Validate(userEnteredCaptchaCode, captchaId); } private bool IsValidName(string name) { if (name == null) { return false; } return (name.Length >= 3); } private bool IsValidEmail(string email) { if (email == null) { return false; } Regex regex = new Regex(@"^[\w-_\.+]*[\w-_\.]\@([\w]+\.)+[\w]+[\w]$"); Match match = regex.Match(email); return match.Success; } private bool IsValidSubject(string subject) { if (subject == null) { return false; } return (subject.Length > 9) && (subject.Length < 255); } private bool IsValidMessage(string message) { if (message == null) { return false; } return (message.Length > 9) && (message.Length < 255); } } }
[back to the top of react & web api with mvc core 1/2 backend section]
..............................................................
React-based Frontend and the Legacy ASP.NET Web-API 2 on Backend
This is a partial walk-through of the example source code. It is not meant to replace a proper step-by-step guide. If you are new to BotDetect, skip it for now; and do start your first React captcha integration by following our step-by-step React CAPTCHA Integration Guide.
Introduction
This contact form React captcha example shows the code required to display and validate captchas in a contact form of the application with a React frontend and a legacy ASP.NET Web-API 2 backend.
Download the BotDetect ASP.NET CAPTCHA Component and run this exampleWithin this page, the root folder of the extracted archive is referred as the <BDC-DIR>
.
This example is in the <BDC-DIR>/lgcy-on-lgcy/examples/s_api-captcha-react-webapi2/csharp/
folder; and contains the following files:
- Frontend code:
- Backend code:
Frontend: contact.jsx
The react-src/views/contact.jsx
source file does the following:
- Loads the BotDetect CAPTCHA React Component into the page
- Sets the
captchaEndpoint
property to point to the captcha endpoint path on backend - Displays the captcha and user-input markups on the page
- Loads the captcha challenges from backend
- Sends the post request with the captcha id and the user entered captcha code to backend
- Processes the captcha validation results:
-
- when the captcha validation fails -- it reloads captcha and displays an error message
- when the captcha validation succeeds -- it executes by the captcha protected action
import React from 'react'; import axios from 'axios'; import { Captcha, captchaSettings } from 'reactjs-captcha'; class Contact extends React.Component { constructor(props) { super(props); // set the captchaEndpoint property to point to // the captcha endpoint path on your app's backend captchaSettings.set({ captchaEndpoint: 'simple-captcha-endpoint.ashx' }); } componentDidMount() { let self = this; // the validation-error messages for the form's data-input fields const errorMessages = { name: 'Name must be at least 3 chars long!', email: 'Email is invalid!', subject: 'Subject must be at least 10 chars long!', message: 'Message must be at least 10 chars long!' }; // the global variables that hold the validation-status flags of the form's data-input fields; // those validation-status flags will be checked on form submit this.isNameValid = false; this.isEmailValid = false; this.isSubjectValid = false; this.isMessageValid = false; function validateName() { var name = document.getElementById('name').value; self.isNameValid = (name.length >= 3); if (self.isNameValid) { document.getElementsByClassName('name')[0].innerHTML = ''; } else { document.getElementsByClassName('name')[0].innerHTML = errorMessages.name; } } function validateEmail() { var email = document.getElementById('email').value; 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,}))$/; self.isEmailValid = emailRegEx.test(email); if (self.isEmailValid) { document.getElementsByClassName('email')[0].innerHTML = ''; } else { document.getElementsByClassName('email')[0].innerHTML = errorMessages.email; } } function validateSubject() { var subject = document.getElementById('subject').value; self.isSubjectValid = (subject.length >= 10); if (self.isSubjectValid) { document.getElementsByClassName('subject')[0].innerHTML = ''; } else { document.getElementsByClassName('subject')[0].innerHTML = errorMessages.subject; } } function validateMessage() { var message = document.getElementById('message').value; self.isMessageValid = (message.length >= 10); if (self.isMessageValid) { document.getElementsByClassName('message')[0].innerHTML = ''; } else { document.getElementsByClassName('message')[0].innerHTML = errorMessages.message; } } // validate the form's data-input fields on blur event document.getElementById('name').addEventListener('blur', validateName); document.getElementById('email').addEventListener('blur', validateEmail); document.getElementById('subject').addEventListener('blur', validateSubject); document.getElementById('message').addEventListener('blur', validateMessage); } // process the contact form on submit event onFormSubmitHandler(event) { let self = this; let formMessage = document.getElementById('form-messages'); if (self.isNameValid && self.isEmailValid && self.isSubjectValid && self.isMessageValid) { // get the user-entered captcha code value to be validated at the backend side let userEnteredCaptchaCode = this.captcha.getUserEnteredCaptchaCode(); // get the id of a captcha instance that the user tried to solve let captchaId = this.captcha.getCaptchaId(); var postData = { name: document.getElementById('name').value, email: document.getElementById('email').value, subject: document.getElementById('subject').value, message: document.getElementById('message').value, // add the user-entered captcha code value to the post data userEnteredCaptchaCode: userEnteredCaptchaCode, // add the id of a captcha instance to the post data captchaId: captchaId }; // post both the form-data and captcha data to the backend axios.post('api/webapi/contact', postData) .then(response => { if (response.data.success == false) { // captcha validation failed; show the error message formMessage.setAttribute('class', 'alert alert-error'); formMessage.innerHTML = response.data.errors.userEnteredCaptchaCode; // call the self.captcha.reloadImage() // in order to generate a new captcha challenge self.captcha.reloadImage(); } else { // captcha validation succeeded; proceed with the workflow self.props.history.push('/contact-success-notify'); } }).catch(error => { throw new Error(error); }); } else { formMessage.setAttribute('class', 'alert alert-error'); formMessage.innerHTML = 'Please enter valid values.'; } event.preventDefault(); } render() { var self = this; return ( <div id="main-content"> <form id="contactForm" method="POST" onSubmit={self.onFormSubmitHandler.bind(self)}> <div id="form-messages"></div> <label> <span>Name:</span> <input type="text" id="name"/> </label> <div className="error name"></div> <label> <span>Email</span> <input type="email" id="email"/> </label> <div className="error email"></div> <label> <span>Subject:</span> <input type="text" id="subject"/> </label> <div className="error subject"></div> <label> <span>Message:</span> <textarea id="message"></textarea> </label> <div className="error message"></div> {/* captcha challenge: placeholder */} <Captcha captchaStyleName="reactFormCaptcha" ref={(captcha) => {this.captcha = captcha;}} /> <label> <span>Retype the chars long from the picture:</span> {/* captcha code: user-input textbox */} <input type="text" id="userCaptchaInput" /> </label> <button type="submit" id="submitButton">Send</button> </form> </div> ) } } export default Contact;
[back to the top of react & legacy asp.net web-api 2 backend section]
Backend: web.config
The web.config
source file does the following:
- Registers the
simple-captcha-endpoint.ashx
path - Maps it to the
BotDetect.Web.SimpleCaptchaHandler
<?xml version="1.0" encoding="utf-8"?> <configuration> <appSettings></appSettings> <system.web> <compilation debug="false" targetFramework="4.5"/> <httpRuntime targetFramework="4.5"/> <httpHandlers> <!-- Register the HttpHandler used for BotDetect Captcha requests --> <add verb="GET" path="simple-captcha-endpoint.ashx" type="BotDetect.Web.SimpleCaptchaHandler, BotDetect"/> </httpHandlers> </system.web> <system.webServer> <validation validateIntegratedModeConfiguration="false"/> <handlers> <!-- Register the HttpHandler used for BotDetect Captcha requests (IIS 7.0+) --> <remove name="BotDetectCaptchaHandler"/> <add name="BotDetectCaptchaHandler" preCondition="integratedMode" verb="GET" path="simple-captcha-endpoint.ashx" type="BotDetect.Web.SimpleCaptchaHandler, BotDetect"/> </handlers> </system.webServer> </configuration>
[back to the top of react & legacy asp.net web-api 2 backend section]
Backend: botdetect.xml
The botdetect.xml
source file contains the following:
- Captcha style definitions consisting of:
-
- The name of a captcha style
- The ID of an
<input>
element in which user enters captcha codes - Other option settings -- the captcha code length in this particular case
<?xml version="1.0" encoding="UTF-8"?> <botdetect xmlns="https://captcha.com/schema/net" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://captcha.com/schema/net https://captcha.com/schema/net/botdetect-4.4.2.xsd"> <captchaStyles> <captchaStyle> <name>reactFormCaptcha</name> <userInputID>userCaptchaInput</userInputID> <codeLength>4-6</codeLength> </captchaStyle> </captchaStyles> </botdetect>
[back to the top of react & legacy asp.net web-api 2 backend section]
Backend: WebApiController.cs
The Backend/Controllers/WebApiController.cs
source file does the following:
- Extracts the
userEnteredCaptchaCode
andcaptchaId
values posted from the frontend - Validates captchas by calling the
Validate(userEnteredCaptchaCode, captchaId)
method - Returns the json-formatted captcha validation results to frontend
using System.Collections.Generic; using System.Text.RegularExpressions; using System.Web.Http; using BotDetect.Web; namespace ReactWebAPICaptchaExampleCSharp.Backend.Controllers { public class WebApiController : ApiController { // POST api/webapi/contact public IHttpActionResult Contact([FromBody]CaptchaContactModel data) { string name = data.Name; string email = data.Email; string subject = data.Subject; string message = data.Message; string userEnteredCaptchaCode = data.UserEnteredCaptchaCode; string captchaId = data.CaptchaId; // validate the form data Dictionary<string, string> errors = new Dictionary<string, string>(); if (!IsValidName(name)) { errors.Add("name", "Name must be at least 3 chars long!"); } if (!IsValidEmail(email)) { errors.Add("email", "Email is invalid!"); } if (!IsValidSubject(subject)) { errors.Add("subject", "Subject must be at least 10 chars long!"); } if (!IsValidMessage(message)) { errors.Add("message", "Message must be at least 10 chars long!"); } // validate the user entered captcha code if (!IsCaptchaCorrect(userEnteredCaptchaCode, captchaId)) { errors.Add("userEnteredCaptchaCode", "CAPTCHA validation failed!"); // TODO: consider logging the attempt } bool isErrorsEmpty = errors.Count <= 0; if (isErrorsEmpty) { // TODO: all validations succeeded; execute the protected action // (send email, write to database, etc...) } // create an object that stores the validation result Dictionary<string, object> validationResult = new Dictionary<string, object>(); validationResult.Add("success", isErrorsEmpty); validationResult.Add("errors", errors); // return the json string with the validation result to the frontend return Ok(validationResult); } // the captcha validation function private bool IsCaptchaCorrect(string userEnteredCaptchaCode, string captchaId) { // create a captcha instance to be used for the captcha validation SimpleCaptcha captcha = new SimpleCaptcha(); // execute the captcha validation return captcha.Validate(userEnteredCaptchaCode, captchaId); } private bool IsValidName(string name) { if (name == null) { return false; } return (name.Length >= 3); } private bool IsValidEmail(string email) { if (email == null) { return false; } Regex regex = new Regex("^[\\w-_\\.+]*[\\w-_\\.]\\@([\\w]+\\.)+[\\w]+[\\w]$"); Match match = regex.Match(email); return match.Success; } private bool IsValidSubject(string subject) { if (subject == null) { return false; } return (subject.Length > 9) && (subject.Length < 255); } private bool IsValidMessage(string message) { if (message == null) { return false; } return (message.Length > 9) && (message.Length < 255); } } public class CaptchaContactModel { [JsonProperty("name")] public string Name { get; set; } [JsonProperty("email")] public string Email { get; set; } [JsonProperty("subject")] public string Subject { get; set; } [JsonProperty("message")] public string Message { get; set; } [JsonProperty("captchaId")] public string CaptchaId { get; set; } [JsonProperty("userEnteredCaptchaCode")] public string UserEnteredCaptchaCode { get; set; } } }
[back to the top of react & legacy asp.net web-api 2 backend section]
..............................................................
React-based Frontend and the Legacy ASP.NET Generic Handler on Backend
This is a partial walk-through of the example source code. It is not meant to replace a proper step-by-step guide. If you are new to BotDetect, skip it for now; and do start your first React captcha integration by following our step-by-step React CAPTCHA Integration Guide.
Introduction
This contact form React captcha example shows the code required to display and validate captchas in a contact form of the application with a React frontend and a legacy ASP.NET Generic Handler backend.
Download the BotDetect ASP.NET CAPTCHA Component and run this exampleWithin this page, the root folder of the extracted archive is referred as the <BDC-DIR>
.
This example is in the <BDC-DIR>/lgcy-on-lgcy/examples/s_api-captcha-react-generic_handler/csharp/
folder; and contains the following files:
- Frontend code:
- Backend code:
Frontend: contact.jsx
The react-src/views/contact.jsx
source file does the following:
- Loads the BotDetect CAPTCHA React Component into the page
- Sets the
captchaEndpoint
property to point to the captcha endpoint path on backend - Displays the captcha and user-input markups on the page
- Loads the captcha challenges from backend
- Sends the post request with the captcha id and the user entered captcha code to backend
- Processes the captcha validation results:
-
- when the captcha validation fails -- it reloads captcha and displays an error message
- when the captcha validation succeeds -- it executes by the captcha protected action
import React from 'react'; import axios from 'axios'; import { Captcha, captchaSettings } from 'reactjs-captcha'; class Contact extends React.Component { constructor(props) { super(props); // set the captchaEndpoint property to point to // the captcha endpoint path on your app's backend captchaSettings.set({ captchaEndpoint: 'simple-captcha-endpoint.ashx' }); } componentDidMount() { let self = this; // the validation-error messages for the form's data-input fields const errorMessages = { name: 'Name must be at least 3 chars long!', email: 'Email is invalid!', subject: 'Subject must be at least 10 chars long!', message: 'Message must be at least 10 chars long!' }; // the global variables that hold the validation-status flags of the form's data-input fields; // those validation-status flags will be checked on form submit this.isNameValid = false; this.isEmailValid = false; this.isSubjectValid = false; this.isMessageValid = false; function validateName() { var name = document.getElementById('name').value; self.isNameValid = (name.length >= 3); if (self.isNameValid) { document.getElementsByClassName('name')[0].innerHTML = ''; } else { document.getElementsByClassName('name')[0].innerHTML = errorMessages.name; } } function validateEmail() { var email = document.getElementById('email').value; 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,}))$/; self.isEmailValid = emailRegEx.test(email); if (self.isEmailValid) { document.getElementsByClassName('email')[0].innerHTML = ''; } else { document.getElementsByClassName('email')[0].innerHTML = errorMessages.email; } } function validateSubject() { var subject = document.getElementById('subject').value; self.isSubjectValid = (subject.length >= 10); if (self.isSubjectValid) { document.getElementsByClassName('subject')[0].innerHTML = ''; } else { document.getElementsByClassName('subject')[0].innerHTML = errorMessages.subject; } } function validateMessage() { var message = document.getElementById('message').value; self.isMessageValid = (message.length >= 10); if (self.isMessageValid) { document.getElementsByClassName('message')[0].innerHTML = ''; } else { document.getElementsByClassName('message')[0].innerHTML = errorMessages.message; } } // validate the form's data-input fields on blur event document.getElementById('name').addEventListener('blur', validateName); document.getElementById('email').addEventListener('blur', validateEmail); document.getElementById('subject').addEventListener('blur', validateSubject); document.getElementById('message').addEventListener('blur', validateMessage); } // process the contact form on submit event onFormSubmitHandler(event) { let self = this; let formMessage = document.getElementById('form-messages'); if (self.isNameValid && self.isEmailValid && self.isSubjectValid && self.isMessageValid) { // get the user-entered captcha code value to be validated at the backend side let userEnteredCaptchaCode = this.captcha.getUserEnteredCaptchaCode(); // get the id of a captcha instance that the user tried to solve let captchaId = this.captcha.getCaptchaId(); var postData = { name: document.getElementById('name').value, email: document.getElementById('email').value, subject: document.getElementById('subject').value, message: document.getElementById('message').value, // add the user-entered captcha code value to the post data userEnteredCaptchaCode: userEnteredCaptchaCode, // add the id of a captcha instance to the post data captchaId: captchaId }; // post both the form-data and captcha data to the backend axios.post('form/ContactHandler.ashx', postData) .then(response => { if (response.data.success == false) { // captcha validation failed; show the error message formMessage.setAttribute('class', 'alert alert-error'); formMessage.innerHTML = response.data.errors.userEnteredCaptchaCode; // call the self.captcha.reloadImage() // in order to generate a new captcha challenge self.captcha.reloadImage(); } else { // captcha validation succeeded; proceed with the workflow self.props.history.push('/contact-success-notify'); } }).catch(error => { throw new Error(error); }); } else { formMessage.setAttribute('class', 'alert alert-error'); formMessage.innerHTML = 'Please enter valid values.'; } event.preventDefault(); } render() { var self = this; return ( <div id="main-content"> <form id="contactForm" method="POST" onSubmit={self.onFormSubmitHandler.bind(self)}> <div id="form-messages"></div> <label> <span>Name:</span> <input type="text" id="name"/> </label> <div className="error name"></div> <label> <span>Email</span> <input type="email" id="email"/> </label> <div className="error email"></div> <label> <span>Subject:</span> <input type="text" id="subject"/> </label> <div className="error subject"></div> <label> <span>Message:</span> <textarea id="message"></textarea> </label> <div className="error message"></div> {/* captcha challenge: placeholder */} <Captcha captchaStyleName="reactFormCaptcha" ref={(captcha) => {this.captcha = captcha;}} /> <label> <span>Retype the chars long from the picture:</span> {/* captcha code: user-input textbox */} <input type="text" id="userCaptchaInput" /> </label> <button type="submit" id="submitButton">Send</button> </form> </div> ) } } export default Contact;
[back to the top of react & legacy asp.net generic handler backend section]
Backend: web.config
The web.config
source file does the following:
- Registers the
simple-captcha-endpoint.ashx
path - Maps it to the
BotDetect.Web.SimpleCaptchaHandler
<?xml version="1.0" encoding="UTF-8"?> <configuration> <system.web> <compilation debug="true" targetFramework="4.5"/> <httpRuntime targetFramework="4.5"/> <httpHandlers> <!-- Register the HttpHandler used for BotDetect Captcha requests --> <add verb="GET" path="simple-captcha-endpoint.ashx" type="BotDetect.Web.SimpleCaptchaHandler, BotDetect"/> </httpHandlers> </system.web> <system.webServer> <validation validateIntegratedModeConfiguration="false" /> <handlers> <!-- Register the HttpHandler used for BotDetect Captcha requests (IIS 7.0+) --> <remove name="BotDetectCaptchaHandler"/> <add name="BotDetectCaptchaHandler" preCondition="integratedMode" verb="GET" path="simple-captcha-endpoint.ashx" type="BotDetect.Web.SimpleCaptchaHandler, BotDetect"/> </handlers> </system.webServer> </configuration>
[back to the top of react & legacy asp.net generic handler backend section]
Backend: botdetect.xml
The botdetect.xml
source file contains the following:
- Captcha style definitions consisting of:
-
- The name of a captcha style
- The ID of an
<input>
element in which user enters captcha codes - Other option settings -- the captcha code length in this particular case
<?xml version="1.0" encoding="UTF-8"?> <botdetect xmlns="https://captcha.com/schema/net" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://captcha.com/schema/net https://captcha.com/schema/net/botdetect-4.4.2.xsd"> <captchaStyles> <captchaStyle> <name>reactFormCaptcha</name> <userInputID>userCaptchaInput</userInputID> <codeLength>4-6</codeLength> </captchaStyle> </captchaStyles> </botdetect>
[back to the top of react & legacy asp.net generic handler backend section]
Backend: ContactHandler.ashx
The form/ContactHandler.ashx
source file does the following:
- Extracts the
userEnteredCaptchaCode
andcaptchaId
values posted from the frontend - Validates captchas by calling the
Validate(userEnteredCaptchaCode, captchaId)
method - Returns the json-formatted captcha validation results to frontend
<%@ WebHandler Language="C#" Class="ContactHandler" %> using System; using System.Web; using System.IO; using Newtonsoft.Json; using System.Collections.Generic; using System.Text.RegularExpressions; using BotDetect.Web; public class ContactHandler : IHttpHandler { public void ProcessRequest (HttpContext context) { if (HttpContext.Current.Request.HttpMethod == "POST") { string dataJson = new StreamReader(context.Request.InputStream).ReadToEnd(); Dictionary<string, string> formDataObj = new Dictionary<string, string>(); formDataObj = JsonConvert.DeserializeObject<Dictionary<string, string>>(dataJson); string name = formDataObj["name"]; string email = formDataObj["email"]; string subject = formDataObj["subject"]; string message = formDataObj["message"]; string userEnteredCaptchaCode = formDataObj["userEnteredCaptchaCode"]; string captchaId = formDataObj["captchaId"]; // validate the form data Dictionary<string, string> errors = new Dictionary<string, string>(); if (!IsValidName(name)) { errors.Add("name", "Name must be at least 3 chars long!"); } if (!IsValidEmail(email)) { errors.Add("email", "Email is invalid!"); } if (!IsValidSubject(subject)) { errors.Add("subject", "Subject must be at least 10 chars long!"); } if (!IsValidMessage(message)) { errors.Add("message", "Message must be at least 10 chars long!"); } // validate the user entered captcha code if (!IsCaptchaCorrect(userEnteredCaptchaCode, captchaId)) { errors.Add("userEnteredCaptchaCode", "CAPTCHA validation failed!"); // TODO: consider logging the attempt } bool isErrorsEmpty = (errors.Count > 0) ? false : true; if (isErrorsEmpty) { // TODO: all validations succeeded; execute the protected action // (send email, write to database, etc...) } // create an object that stores the validation result Dictionary<string, object> validationResult = new Dictionary<string, object>(); validationResult.Add("success", isErrorsEmpty); validationResult.Add("errors", errors); // return the json string with the validation result to the frontend context.Response.ContentType = "application/json; charset=utf-8"; context.Response.Write(JsonConvert.SerializeObject(validationResult)); } else { context.Response.ContentType = "text/plain"; context.Response.Write("Only HTTP POST requests are allowed."); } } // the captcha validation function private bool IsCaptchaCorrect(string userEnteredCaptchaCode, string captchaId) { // create a captcha instance to be used for the captcha validation SimpleCaptcha captcha = new SimpleCaptcha(); // execute the captcha validation return captcha.Validate(userEnteredCaptchaCode, captchaId); } private bool IsValidName(string name) { if (name == null) { return false; } return (name.Length >= 3); } private bool IsValidEmail(string email) { if (email == null) { return false; } Regex regex = new Regex("^[\\w-_\\.+]*[\\w-_\\.]\\@([\\w]+\\.)+[\\w]+[\\w]$"); Match match = regex.Match(email); return match.Success; } private bool IsValidSubject(string subject) { if (subject == null) { return false; } return (subject.Length > 9) && (subject.Length < 255); } private bool IsValidMessage(string message) { if (message == null) { return false; } return (message.Length > 9) && (message.Length < 255); } public bool IsReusable { get { return false; } } }
[back to the top of react & legacy asp.net generic handler backend section]
..............................................................
React-based Frontend and the Java Servlet on Backend
This is a partial walk-through of the example source code. It is not meant to replace a proper step-by-step guide. If you are new to BotDetect, skip it for now; and do start your first React captcha integration by following our step-by-step React CAPTCHA Integration Guide.
Introduction
This contact form React captcha example shows the code required to display and validate captchas in a contact form of the application with a React frontend and a Java Servlet backend.
Download the BotDetect Java CAPTCHA Library archive and run this exampleWithin this page, the root folder of the extracted archive is referred as the <BDC-DIR>
.
This example is in the <BDC-DIR>/examples/s_api-captcha-react-servlet/
folder; and contains the following files:
- Frontend code:
- Backend code:
Frontend: contact.jsx
The src/main/webapp/react-src/views/contact.jsx
source file does the following:
- Loads the BotDetect CAPTCHA React Component into the page
- Sets the
captchaEndpoint
property to point to the captcha endpoint path on backend - Displays the captcha and user-input markups on the page
- Loads the captcha challenges from backend
- Sends the post request with the captcha id and the user entered captcha code to backend
- Processes the captcha validation results:
-
- when the captcha validation fails -- it reloads captcha and displays an error message
- when the captcha validation succeeds -- it executes by the captcha protected action
import React from 'react'; import axios from 'axios'; import { Captcha, captchaSettings } from 'reactjs-captcha'; class Contact extends React.Component { constructor(props) { super(props); // set the captchaEndpoint property to point to // the captcha endpoint path on your app's backend captchaSettings.set({ captchaEndpoint: 'simple-captcha-endpoint' }); } componentDidMount() { let self = this; // the validation-error messages for the form's data-input fields const errorMessages = { name: 'Name must be at least 3 chars long!', email: 'Email is invalid!', subject: 'Subject must be at least 10 chars long!', message: 'Message must be at least 10 chars long!' }; // the global variables that hold the validation-status flags of the form's data-input fields; // those validation-status flags will be checked on form submit this.isNameValid = false; this.isEmailValid = false; this.isSubjectValid = false; this.isMessageValid = false; function validateName() { var name = document.getElementById('name').value; self.isNameValid = (name.length >= 3); if (self.isNameValid) { document.getElementsByClassName('name')[0].innerHTML = ''; } else { document.getElementsByClassName('name')[0].innerHTML = errorMessages.name; } } function validateEmail() { var email = document.getElementById('email').value; 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,}))$/; self.isEmailValid = emailRegEx.test(email); if (self.isEmailValid) { document.getElementsByClassName('email')[0].innerHTML = ''; } else { document.getElementsByClassName('email')[0].innerHTML = errorMessages.email; } } function validateSubject() { var subject = document.getElementById('subject').value; self.isSubjectValid = (subject.length >= 10); if (self.isSubjectValid) { document.getElementsByClassName('subject')[0].innerHTML = ''; } else { document.getElementsByClassName('subject')[0].innerHTML = errorMessages.subject; } } function validateMessage() { var message = document.getElementById('message').value; self.isMessageValid = (message.length >= 10); if (self.isMessageValid) { document.getElementsByClassName('message')[0].innerHTML = ''; } else { document.getElementsByClassName('message')[0].innerHTML = errorMessages.message; } } // validate the form's data-input fields on blur event document.getElementById('name').addEventListener('blur', validateName); document.getElementById('email').addEventListener('blur', validateEmail); document.getElementById('subject').addEventListener('blur', validateSubject); document.getElementById('message').addEventListener('blur', validateMessage); } // process the contact form on submit event onFormSubmitHandler(event) { let self = this; let formMessage = document.getElementById('form-messages'); if (self.isNameValid && self.isEmailValid && self.isSubjectValid && self.isMessageValid) { // get the user-entered captcha code value to be validated at the backend side let userEnteredCaptchaCode = this.captcha.getUserEnteredCaptchaCode(); // get the id of a captcha instance that the user tried to solve let captchaId = this.captcha.getCaptchaId(); var postData = { name: document.getElementById('name').value, email: document.getElementById('email').value, subject: document.getElementById('subject').value, message: document.getElementById('message').value, // add the user-entered captcha code value to the post data userEnteredCaptchaCode: userEnteredCaptchaCode, // add the id of a captcha instance to the post data captchaId: captchaId }; // post both the form-data and captcha data to the backend axios.post('contact', postData) .then(response => { if (response.data.success == false) { // captcha validation failed; show the error message formMessage.setAttribute('class', 'alert alert-error'); formMessage.innerHTML = response.data.errors.userEnteredCaptchaCode; // call the self.captcha.reloadImage() // in order to generate a new captcha challenge self.captcha.reloadImage(); } else { // captcha validation succeeded; proceed with the workflow self.props.history.push('/contact-success-notify'); } }).catch(error => { throw new Error(error); }); } else { formMessage.setAttribute('class', 'alert alert-error'); formMessage.innerHTML = 'Please enter valid values.'; } event.preventDefault(); } render() { var self = this; return ( <div id="main-content"> <form id="contactForm" method="POST" onSubmit={self.onFormSubmitHandler.bind(self)}> <div id="form-messages"></div> <label> <span>Name:</span> <input type="text" id="name"/> </label> <div className="error name"></div> <label> <span>Email</span> <input type="email" id="email"/> </label> <div className="error email"></div> <label> <span>Subject:</span> <input type="text" id="subject"/> </label> <div className="error subject"></div> <label> <span>Message:</span> <textarea id="message"></textarea> </label> <div className="error message"></div> {/* captcha challenge: placeholder */} <Captcha captchaStyleName="reactFormCaptcha" ref={(captcha) => {this.captcha = captcha;}} /> <label> <span>Retype the chars long from the picture:</span> {/* captcha code: user-input textbox */} <input type="text" id="userCaptchaInput" /> </label> <button type="submit" id="submitButton">Send</button> </form> </div> ) } } export default Contact;
[back to the top of react & java servlet backend section]
Backend: web.xml
The src/main/webapp/WEB-INF/web.xml
source file does the following:
- Registers the
simple-captcha-endpoint
path - Maps it to the
com.captcha.botdetect.web.servlet.SimpleCaptchaServlet
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <session-config> <session-timeout> 30 </session-timeout> </session-config> <servlet> <servlet-name>BotDetect Captcha</servlet-name> <servlet-class>com.captcha.botdetect.web.servlet.SimpleCaptchaServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>BotDetect Captcha</servlet-name> <url-pattern>/simple-captcha-endpoint</url-pattern> </servlet-mapping> <servlet> <servlet-name>Contact Captcha</servlet-name> <servlet-class>com.captcha.botdetect.examples.reactjs.contact_form.ContactServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>Contact Captcha</servlet-name> <url-pattern>/contact</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.html</welcome-file> </welcome-file-list> </web-app>
[back to the top of react & java servlet backend section]
Backend: botdetect.xml
The src/main/webapp/WEB-INF/botdetect.xml
source file contains the following:
- Captcha style definitions consisting of:
-
- The name of a captcha style
- The ID of an
<input>
element in which user enters captcha codes - Other option settings -- the captcha code length in this particular case
<?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.7.xsd"> <captchaStyles> <captchaStyle> <name>reactFormCaptcha</name> <userInputID>userCaptchaInput</userInputID> <codeLength>4-6</codeLength> </captchaStyle> </captchaStyles> </botdetect>
[back to the top of react & java servlet backend section]
Backend: ContactServlet.java
The src/main/java/com/captcha/botdetect/examples/reactjs/contact_form/
source file does the following:
ContactServlet.java
- Extracts the
userEnteredCaptchaCode
andcaptchaId
values posted from the frontend - Validates captchas by calling the
validate(userEnteredCaptchaCode, captchaId)
method - Returns the json-formatted captcha validation results to frontend
package com.captcha.botdetect.examples.reactjs.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(); 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 userEnteredCaptchaCode = formDataObj.get("userEnteredCaptchaCode").getAsString(); String captchaId = formDataObj.get("captchaId").getAsString(); // validate the form data Map<String, String> errors = new HashMap<String, String>(); if (!isValidName(name)) { errors.put("name", "Name must be at least 3 chars long!"); } if (!isValidEmail(email)) { errors.put("email", "Email is invalid!"); } if (!isValidSubject(subject)) { errors.put("message", "Subject must be at least 10 chars long!"); } if (!isValidMessage(message)) { errors.put("message", "Message must be at least 10 chars long!"); } // validate the user entered captcha code if (!isCaptchaCorrect(request, userEnteredCaptchaCode, captchaId)) { errors.put("userEnteredCaptchaCode", "CAPTCHA validation failed!"); // TODO: consider logging the attempt } if (errors.isEmpty()) { // TODO: all validations succeeded; execute the protected action // (send email, write to database, etc...) } // create an object that stores the validation result ContactValidationResult validationResult = new ContactValidationResult(); validationResult.setSuccess(errors.isEmpty()); validationResult.setErrors(errors); try { // return the json string with the validation result to the frontend out.write(gson.toJson(validationResult)); } finally { out.close(); } } // the captcha validation function private boolean isCaptchaCorrect(HttpServletRequest request, String userEnteredCaptchaCode, String captchaId) { // create a captcha instance to be used for the captcha validation SimpleCaptcha captcha = SimpleCaptcha.load(request); // execute the captcha validation return captcha.validate(userEnteredCaptchaCode, 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); } } class ContactValidationResult { private boolean success; private Map<String, String> errors; public ContactValidationResult() { errors = new HashMap<String, String>(); } public boolean getSuccess() { return success; } public void setSuccess(boolean success) { this.success = success; } public Map<String, String> getErrors() { return errors; } public void setErrors(Map<String, String> errors) { this.errors = errors; } }
[back to the top of react & java servlet backend section]
..............................................................
React-based Frontend and the plain PHP on Backend
This is a partial walk-through of the example source code. It is not meant to replace a proper step-by-step guide. If you are new to BotDetect, skip it for now; and do start your first React captcha integration by following our step-by-step React CAPTCHA Integration Guide.
Introduction
This contact form React captcha example shows the code required to display and validate captchas in a contact form of the application with a React frontend and the plain PHP backend.
Download the BotDetect PHP CAPTCHA Library archive and run this exampleWithin this page, the root folder of the extracted archive is referred as the <BDC-DIR>
.
This example is in the <BDC-DIR>/examples/s_api-captcha-react-plainphp/
folder; and contains the following files:
- Frontend code:
- Backend code:
Frontend: contact.jsx
The react-src/views/contact.jsx
source file does the following:
- Loads the BotDetect CAPTCHA React Component into the page
- Sets the
captchaEndpoint
property to point to the captcha endpoint path on backend - Displays the captcha and user-input markups on the page
- Loads the captcha challenges from backend
- Sends the post request with the captcha id and the user entered captcha code to backend
- Processes the captcha validation results:
-
- when the captcha validation fails -- it reloads captcha and displays an error message
- when the captcha validation succeeds -- it executes by the captcha protected action
import React from 'react'; import axios from 'axios'; import { Captcha, captchaSettings } from 'reactjs-captcha'; class Contact extends React.Component { constructor(props) { super(props); // set the captchaEndpoint property to point to // the captcha endpoint path on your app's backend captchaSettings.set({ captchaEndpoint: 'botdetect-captcha-lib/simple-botdetect.php' }); } componentDidMount() { let self = this; // the validation-error messages for the form's data-input fields const errorMessages = { name: 'Name must be at least 3 chars long!', email: 'Email is invalid!', subject: 'Subject must be at least 10 chars long!', message: 'Message must be at least 10 chars long!' }; // the global variables that hold the validation-status flags of the form's data-input fields; // those validation-status flags will be checked on form submit this.isNameValid = false; this.isEmailValid = false; this.isSubjectValid = false; this.isMessageValid = false; function validateName() { var name = document.getElementById('name').value; self.isNameValid = (name.length >= 3); if (self.isNameValid) { document.getElementsByClassName('name')[0].innerHTML = ''; } else { document.getElementsByClassName('name')[0].innerHTML = errorMessages.name; } } function validateEmail() { var email = document.getElementById('email').value; 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,}))$/; self.isEmailValid = emailRegEx.test(email); if (self.isEmailValid) { document.getElementsByClassName('email')[0].innerHTML = ''; } else { document.getElementsByClassName('email')[0].innerHTML = errorMessages.email; } } function validateSubject() { var subject = document.getElementById('subject').value; self.isSubjectValid = (subject.length >= 10); if (self.isSubjectValid) { document.getElementsByClassName('subject')[0].innerHTML = ''; } else { document.getElementsByClassName('subject')[0].innerHTML = errorMessages.subject; } } function validateMessage() { var message = document.getElementById('message').value; self.isMessageValid = (message.length >= 10); if (self.isMessageValid) { document.getElementsByClassName('message')[0].innerHTML = ''; } else { document.getElementsByClassName('message')[0].innerHTML = errorMessages.message; } } // validate the form's data-input fields on blur event document.getElementById('name').addEventListener('blur', validateName); document.getElementById('email').addEventListener('blur', validateEmail); document.getElementById('subject').addEventListener('blur', validateSubject); document.getElementById('message').addEventListener('blur', validateMessage); } // process the contact form on submit event onFormSubmitHandler(event) { let self = this; let formMessage = document.getElementById('form-messages'); if (self.isNameValid && self.isEmailValid && self.isSubjectValid && self.isMessageValid) { // get the user-entered captcha code value to be validated at the backend side let userEnteredCaptchaCode = this.captcha.getUserEnteredCaptchaCode(); // get the id of a captcha instance that the user tried to solve let captchaId = this.captcha.getCaptchaId(); var postData = { name: document.getElementById('name').value, email: document.getElementById('email').value, subject: document.getElementById('subject').value, message: document.getElementById('message').value, // add the user-entered captcha code value to the post data userEnteredCaptchaCode: userEnteredCaptchaCode, // add the id of a captcha instance to the post data captchaId: captchaId }; // post both the form-data and captcha data to the backend axios.post('form/contact.php', postData) .then(response => { if (response.data.success == false) { // captcha validation failed; show the error message formMessage.setAttribute('class', 'alert alert-error'); formMessage.innerHTML = response.data.errors.userEnteredCaptchaCode; // call the self.captcha.reloadImage() // in order to generate a new captcha challenge self.captcha.reloadImage(); } else { // captcha validation succeeded; proceed with the workflow self.props.history.push('/contact-success-notify'); } }).catch(error => { throw new Error(error); }); } else { formMessage.setAttribute('class', 'alert alert-error'); formMessage.innerHTML = 'Please enter valid values.'; } event.preventDefault(); } render() { var self = this; return ( <div id="main-content"> <form id="contactForm" method="POST" onSubmit={self.onFormSubmitHandler.bind(self)}> <div id="form-messages"></div> <label> <span>Name:</span> <input type="text" id="name"/> </label> <div className="error name"></div> <label> <span>Email</span> <input type="email" id="email"/> </label> <div className="error email"></div> <label> <span>Subject:</span> <input type="text" id="subject"/> </label> <div className="error subject"></div> <label> <span>Message:</span> <textarea id="message"></textarea> </label> <div className="error message"></div> {/* captcha challenge: placeholder */} <Captcha captchaStyleName="reactFormCaptcha" ref={(captcha) => {this.captcha = captcha;}} /> <label> <span>Retype the chars long from the picture:</span> {/* captcha code: user-input textbox */} <input type="text" id="userCaptchaInput" /> </label> <button type="submit" id="submitButton">Send</button> </form> </div> ) } } export default Contact;
[back to the top of react & plain php backend section]
Backend: botdetect.xml
The botdetect-captcha-lib/config/botdetect.xml
source file contains the following:
- Captcha style definitions consisting of:
-
- The name of a captcha style
- The ID of an
<input>
element in which user enters captcha codes - Other option settings -- the captcha code length in this particular case
<?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.5.xsd"> <captchaStyles> <captchaStyle> <name>angularBasicCaptcha</name> <userInputID>userCaptchaInput</userInputID> <codeLength>3-5</codeLength> </captchaStyle> </captchaStyles> </botdetect>
[back to the top of react & plain php backend section]
Backend: contact.php
The form/contact.php
source file does the following:
- Extracts the
$userEnteredCaptchaCode
and$captchaId
values posted from the frontend - Validates captchas by calling the
Validate($userEnteredCaptchaCode, $captchaId)
method - Returns the json-formatted captcha validation results to frontend
<?php header('Content-Type: application/json'); if ($_SERVER['REQUEST_METHOD'] === 'POST') { require('../botdetect-captcha-lib/simple-botdetect.php'); $postedData = (array) json_decode(file_get_contents('php://input'), true); $name = $postedData['name']; $email = $postedData['email']; $subject = $postedData['subject']; $message = $postedData['message']; $userEnteredCaptchaCode = $postedData['userEnteredCaptchaCode']; $captchaId = $postedData['captchaId']; // validate the form data $error = array(); if (!isValidName($name)) { $error['name'] = "Name must be at least 3 chars long!"; } if (!isValidEmail($email)) { $error['email'] = "Email is invalid!"; } if (!isValidSubject($subject)) { $error['subject'] = "Subject must be at least 10 chars long!"; } if (!isValidMessage($message)) { $error['message'] = "Message must be at least 10 chars long!"; } // validate the user entered captcha code if (!isCaptchaCorrect($userEnteredCaptchaCode, $captchaId)) { $error['userEnteredCaptchaCode'] = "CAPTCHA validation failed!"; // TODO: consider logging the attempt } if (empty($error)) { // TODO: all validations succeeded; execute the protected action // (send email, write to database, etc...) } // return the json string with the validation result to the frontend $result = array('success' => empty($error), 'errors' => $error); echo json_encode($result, true); exit; } // the captcha validation function function isCaptchaCorrect($userEnteredCaptchaCode, $captchaId) { // create a captcha instance to be used for the captcha validation $captcha = new SimpleCaptcha(); // execute the captcha validation return $captcha->Validate($userEnteredCaptchaCode, $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); }
[back to the top of react & plain php backend section]
Please Note
The new experimental Simple API is still work-in-progress. This Integration Guide & Examples require you to have the React Captcha Component v1.3.1 on frontend, and one of the following BotDetect CAPTCHA releases on backend: ASP.NET v4.4.2+, Java v4.0.Beta3.7+, PHP v4.2.5+.
Current BotDetect Versions
-
BotDetect ASP.NET CAPTCHA
2019-07-22v4.4.2 -
BotDetect Java CAPTCHA
2019-07-22v4.0.Beta3.7 -
BotDetect PHP CAPTCHA
2019-07-22v4.2.5