Using reCAPTCHA with PHP and Javascript

Using reCAPTCHA with PHP and Javascript
Photo by Olav Ahrens Røtne / Unsplash

I had to update the page of one of my clients to use some verification before guests can submit the form because they receive many unwanted messages from there. One of the ways is using reCAPTCHA and making guests solve puzzles before they can submit the form.

Prepare

To implement reCAPTCHA on your PHP page, you will first need to sign up for an API key pair on the reCAPTCHA website. Once you have your API key pair, you can add the following code to your PHP page to display the reCAPTCHA widget:

<!-- HTML for reCAPTCHA widget -->
<div class="g-recaptcha" data-sitekey="YOUR_SITE_KEY"></div>

<!-- Your existing PHP code -->

<!-- JavaScript to render reCAPTCHA widget -->
<script src="https://www.google.com/recaptcha/api.js" async defer></script>

Replace YOUR_SITE_KEY with the site key that you obtained from the reCAPTCHA website.

After the user has completed the reCAPTCHA challenge, you can then verify the user's response on your server using the following PHP code:

// Get user's response and your site key
$response = $_POST['g-recaptcha-response'];
$secret = 'YOUR_SECRET_KEY';

// Verify the user's response
$verify = file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret={$secret}&response={$response}");
$captcha_success = json_decode($verify);

if ($captcha_success->success) {
    // handle your request here
} else {
    // The user failed the reCAPTCHA challenge
    // Handle the error as appropriate
}

Replace YOUR_SECRET_KEY with the secret key that you obtained from the reCAPTCHA website.

Making reCaptcha required

By default (as implemented above) reCAPTCHA is not a required field. It allows you to send the form even if the puzzle is not solved or even if you didn't click to reCAPTCHA. This situation in my case is handled by PHP on the server but you can prevent this happen and limit requests to your server by making it required field.

To make the reCAPTCHA widget required, you can add the required attribute to the div the element that contains the widget as follows:

<div class="g-recaptcha" data-sitekey="YOUR_SITE_KEY" required></div>

This will prevent the form that contains the reCAPTCHA widget from being submitted unless the user completes the reCAPTCHA challenge.

Alternatively, you can also use JavaScript to validate the reCAPTCHA widget before the form is submitted. To do this, you can add an event listener to the form's submit event, and check if the reCAPTCHA widget has been completed. If the reCAPTCHA has not been completed, you can prevent the form from being submitted and display an error message to the user.

Here is an example of how you might do this:

<!-- HTML for reCAPTCHA widget -->
<div class="g-recaptcha" data-sitekey="YOUR_SITE_KEY"></div>

<!-- Your existing PHP code -->

<!-- JavaScript to render reCAPTCHA widget -->
<script src="https://www.google.com/recaptcha/api.js" async defer></script>

<!-- JavaScript to validate reCAPTCHA widget on form submission -->
<script>
  // Get the form element
  var form = document.getElementById('form-id');

  // Add an event listener to the form's submit event
  form.addEventListener('submit', function(event) {
    // Check if the reCAPTCHA widget has been completed
    if (!grecaptcha.getResponse()) {
      // Prevent the form from being submitted
      event.preventDefault();

      // Display an error message
      alert('Please complete the reCAPTCHA challenge to submit the form.');
    }
  });
</script>

In this example, form-id should be replaced with the id attribute of the form the element that contains the reCAPTCHA widget.

Another way to do it is by adding the following script to your header (this is the way i did it)

<script>
  // make recaptcha verified
  function validateCaptcha() {
    var response = grecaptcha.getResponse();
      if(response.length == 0) {
	    alert("Please verify that you are not a robot");
		return false;
	}
	return true;
  }
</script>

Bonus: jQuery + Validate plugin

The page I needed to update used Validate plugin for jQuery.

To use reCaptcha with jQuery and Validate plugin you can use the following code

<!-- ... -->
  <script>
    $("#myForm").validate({
      submitHandler: function(form) {
        // Get the reCAPTCHA response
        var response = grecaptcha.getResponse();

        // If the response is not empty, proceed with form submission
        if (response !== "") {
          // Submit the form
          form.submit();
        } else {
          // Otherwise, display an error message
          alert("Please complete the reCAPTCHA to continue.");
        }
      }
    });
  </script>
<!-- ... -->

In the validate method, the submitHandler function is used to handle the form submission. This function checks the reCAPTCHA response to make sure it's not empty and then submits the form if the response is valid.

If you are using AJAX to send your form, do not forget to reset your reCAPTCHA or refresh (or redirect somewhere else) your page after submitting the form.

To uncheck the reCAPTCHA widget after a successful form submission, you can use the reset method provided by the reCAPTCHA API. Here is an example of how you can do this:

  <script>
    $("#myForm").validate({
      submitHandler: function(form) {
        // Get the reCAPTCHA response
        var response = grecaptcha.getResponse();

        // If the response is not empty, proceed with form submission
        if (response !== "") {
          // Submit the form
          form.submit();

          // Reset the reCAPTCHA widget
          grecaptcha.reset();
        } else {
          // Otherwise, display an error message
          alert("Please complete the reCAPTCHA to continue.");
        }
      }
    });
  </script>

As you can see is not that hard to make your public form (e.g. contact form, comment form) a little bit more secure. You can also use this on your registration forms if you did not do this till now.

The whole guide above is for pure PHP + jQuery, but it's not a problem to rewrite it for some of the frameworks. The main difference will be how you getting server requests, here is a little hint:

// Pure PHP
$response = $_POST['g-recaptcha-response'];

// CakePHP
$respone = $this->request->getData('g-recaptcha-response');

// Laravel
$respone = Input::get('g-recaptcha-response');

That's all for now. Stay safe!