-1

I am trying to set up reCaptcha v3 and it sort of works. For some reason the first time I submit the form it fails but from the second submit onwards it is fine. I can't figure out why this is happening?

<script src="https://www.google.com/recaptcha/api.js?render=MY_SITE_KEY"></script>
<script>
grecaptcha.ready(function () {
    grecaptcha.execute('MY_SITE_KEY', { action: 'contact' }).then(function (token) {
        var recaptchaResponse = document.getElementById('captcha-response');
        recaptchaResponse.value = token;
    });
});
</script>




 <input type="hidden" name="captcha-response" id="captcha-response">

PHP

$verifyResponse = file_get_contents('https://www.google.com/recaptcha/api/siteverify?secret='.$secretKey.'&response='.$_POST['captcha-response']);
$responseData = json_decode($verifyResponse);

     if(!$responseData->score < 0.5) {
      $message .= "Verification failed " . $responseData->score;
  }

When I submit the form the first time, I get the validation error but my score is 0.9.

user10980228
  • 597
  • 1
  • 6
  • 21

2 Answers2

0

Why you have added "!" with "$responseData->score"? you may need to replace your condition with the following:

Replace this:

if(!$responseData->score < 0.5) {
    $message .= "Verification failed " . $responseData->score;
}

With this one:

if($responseData->score < 0.5) {
    $message .= "Verification failed " . $responseData->score;
}

P.S: Following code takes few seconds to properly load and get a "captcha-reponse" code, so you may need to disable all submit button and wait till you got a "captcha-reponse" to enable the submit button in form or you needs to implementent another way to delay the submit to execute only once you got a "captcha-response" code otherwise you will keep getting "missing-input-response" error message

<script src="https://www.google.com/recaptcha/api.js?render=MY_SITE_KEY"></script>
<script>
  grecaptcha.ready(function() {
    grecaptcha.execute('MY_SITE_KEY', {
      action: 'contact'
    }).then(function(token) {
      var recaptchaResponse = document.getElementById('captcha-response');
      recaptchaResponse.value = token;
    });
  });
</script>
  • Ah, how silly. I had the ! because previously I wasn't using a score, it was just success/fail so the logic was `!$responseData->success` – user10980228 Sep 30 '19 at 08:43
  • However, now it works for the first time but if I submit again I see no score, just null. – user10980228 Sep 30 '19 at 08:50
  • 1
    Possible reason is that In case you're trying to submit the form with refresh button, then you will keep getting "null" as score because with Re-captcha you can submit the form only once and then you need to load the page again to get a new "captcha-response" code. – Azhar Rasheed Sep 30 '19 at 08:55
  • No, I am submitting the form via Ajax. So, it posts the token every time I click submit along with the other form data. But I see what you are saying that it needs to reload and get a new token. Will have to think about how to implement this though. – user10980228 Sep 30 '19 at 08:55
  • 1
    Yes you need to generate the token every time for each request, it's got expired once you used it. – Azhar Rasheed Sep 30 '19 at 09:00
  • Okay, I figured out a way to do it and it works now. Thanks! – user10980228 Sep 30 '19 at 09:00
0

You should re-generate the reCaptcha token after error form validation occured. The token reCaptcha only valid for ONE TIME.

So, you have two options to fixes this issue.

1. Reload the page when error occured

This is the easiest way. You only need to reload the page whenever form validation error occured.

Of course, this will trigger the reCaptcha to generate new token.

2. Handle with AJAX (Non-reload page)

This is the best approach, since this will helps the user not losing the form data and continue to fill the form.

So, here's what you should do.

<!-- Put this hidden input inside of your form tag -->
<input name="_recaptcha" type="hidden">

<script src="https://www.google.com/recaptcha/api.js?render=YOUR_SITEKEY_HERE"></script>
<script>
  // This will generate reCaptcha token and set to input hidden
  const generateRecaptcha = function() {
    grecaptcha.execute(
      "YOUR_SITEKEY_HERE", {
        action: "YOUR_ACTION_NAME"
      }).then(function(token) {
      if (token) {
        document.querySelector("input[name='_recaptcha']").value = token;
      }
    });
  }

  // Call it when page successfully loaded
  grecaptcha.ready(function() {
    generateRecaptcha();
  });

  // Do your AJAX code here
  $.ajax({
    url: "https://example.com",
    success: function(response) {
      console.log(response);
    },
    error: function(error) {
      // Call again the generator token reCaptcha whenever error occured
      generateRecaptcha();
    }
</script>

Don't forget to put your Site key and your action name. Make sure the action name matches with your Backend action name.

Medium Article

ibnɘꟻ
  • 830
  • 13
  • 15