Implementing google reCAPTCHA on a form in symfony 3

Implementing google reCAPTCHA on a form in symfony 3

What is reCAPTCHA

reCAPTCHA is a free service that protects your website from spam and abuse. reCAPTCHA uses an advanced risk analysis engine and adaptive CAPTCHAs to keep automated software from engaging in abusive activities on your site. It does this while letting your valid users pass through with ease. 

reCAPTCHA doesn’t depend solely on text distortions to separate man from machines. Rather it uses advanced risk analysis techniques, considering the user’s entire engagement with the CAPTCHA, and evaluates a broad range of cues that distinguish humans from bots.reCAPTCHA knows when to be easy on people and hard on bots. Easy CAPTCHAs are a breeze for legitimate users.

Requirements

To use reCAPTCHA on your website, you'll need to :

After your registration of your website, you'll be redirected to the admin panel, there will be all the websites that you have. Click on the one you want to use.

You'll find a menu with the keys, client-side integration example and server-side integration example. Be sure to save your site key and secret key as we'll need them later.

Keys recaptcha example

That should be enough to handle the client-side integration.

  • Include the google recaptcha php library to your project using composer.

To include the google recaptcha php library, add the following line to your composer.json file (in the require property):

"google/recaptcha": "~1.1"

Or require it directly in the composer console executing :

composer require google/recaptcha "~1.1"

If you don't use composer, read how to install it using require_once here.

That should be enough to handle the server-side integration, let's get started !

Implementing

For this example, we are going to use a plain contact html form, you can obviously use a self-made symfony form or a crud-generated form. Just be sure to add the new field inside the form.

<!-- Important to add the recaptcha api in your document -->
<script src='https://www.google.com/recaptcha/api.js'></script>

<form method="post" action="path/to/action" id="contact-form">
  <input type="text" name="name" />
  <input type="subject" name="subject" />
  <textarea rows="5" name="message"></textarea>
  <!-- Now add the widget with the sitekey that you retrieve in the registration -->
  <div class="g-recaptcha" data-sitekey="mypublicdata-sitekey-ofthe-google-panel"></div>
  <button type="submit">Send message</button>
</form>

 {# or if you're using twig #}

{{form_start(form)}}
   {{form_widget(form.name)}}
   {{form_widget(form.subject)}}
   {{form_widget(form.message)}}
   <!-- Now add the widget with the sitekey that you retrieve in the registration --> 
   <div class="g-recaptcha" data-sitekey="mypublicdata-sitekey-ofthe-google-panel"></div>

   {{form_widget(form.submit)}}
{{form_end(form)}}

No matter the way you render your form, just be sure that the widget is inside the form. Now the widget should appear in your form already without any problem if your data-sitekey value is correct and matches with your website. With the captcha api, this div will be a form element inside the form, this will contain a value that we will retrieve with php on the submit event to validate it.

Now you only need to process the submit action in the controller, where your form is pointing to.

Your controller now just should look something like :

use Symfony\Component\HttpFoundation\Request; // Handle the request in the controller
use ReCaptcha\ReCaptcha; // Include the recaptcha lib

public function mysubmitedAction(Request $request){
  $recaptcha = new ReCaptcha('here-is-the-secret-key-that-no-one-but-you-shouldKnow');
  $resp = $recaptcha->verify($request->request->get('g-recaptcha-response'), $request->getClientIp());

  if (!$resp->isSuccess()) {
    // Do something if the submit wasn't valid ! Use the message to show something
    $message = "The reCAPTCHA wasn't entered correctly. Go back and try it again." . "(reCAPTCHA said: " . $resp->error . ")";
  }else{
    // Everything works good ;) your contact has been saved.
  }
}

The verify method has 3 parameters, you can read more about the methods here or check the documentation in the official repository.

Using a Macro in Twig to render the reCAPTCHA field

Normally, for a custom element in a form of symfony, we would need to create a Custom FormType, however as the reCAPTCHA field isn't really a form element (select, checkbox or radio) we can't do it in that way. But if you want to make your code more maintainable, you can create a Macro if you're using Twig.

Create a new twig file with the name form_elements.html.twig in App/Resources/views/Macros with the following content (if you decided to change the path, read more about how a macro in twig works here):

{#app/Resources/views/Macros/form_elements.html.twig#}
{# 
 # The recaptcha method allow you to render a reCAPTCHA element. It expects as first parameter the site key
 #}
{% macro recaptcha(siteKey)%}
    <script src='https://www.google.com/recaptcha/api.js'></script>
    <div class="g-recaptcha" data-sitekey="{{siteKey}}"></div>
{% endmacro %}

And now, instead of create on every form the div of recaptcha and the script tag where you need it, you can simply use in your form:

{% import "Macros/form_elements.html.twig" as formElements %}

{{form_start(form)}}
   {{form_widget(form.name)}}
   {{form_widget(form.subject)}}
   {{form_widget(form.message)}}
   <!-- Now add the widget with the sitekey that you retrieve in the registration --> 
   {{formElements.recaptcha("mypublicdata-sitekey-ofthe-google-panel")}}
   
   {{form_widget(form.submit)}}
{{form_end(form)}}

Now your form should be protected against robots, have fun !

Become a more social person