96

Until now, I was working with Google Recaptcha v2, but now I want to update my WebApp using the lastest version (v3).

Is it possible to anyone add a fully working Google Recaptcha v3 example for a basic form as I can't find any working demos of it?

I'd really appreciate it.

Thank you very much.

PS: I'm using Java Servlets on the server side, but it doesn't matter if you explain using PHP or whatever.

Ommadawn
  • 2,450
  • 3
  • 24
  • 48
  • 11
    I have created a demo but this in PHP Visit my blog [link](https://phpkishan.blogspot.com/2018/11/recaptcha-v3-example-in-php.html) – PHP Kishan Nov 03 '18 at 04:44
  • 1
    I posted a simple but detailed demo in pure JS and PHP here: https://stackoverflow.com/questions/50405977/how-to-verify-google-recaptcha-v3-response/57202461#57202461 – wkille Jul 25 '19 at 12:54
  • 2
    Here is the link: https://recaptcha-demo.appspot.com/ Just request the score for v3 and it will give a response back in JSON – Suleman Sep 11 '18 at 13:43
  • but how can i put in div ? – Freddy Sidauruk Nov 09 '18 at 04:14
  • @FreddySidauruk You don't put in a div, it is executed via javascript function that calls google api which will then result you a response just like recaptchav2. – Suleman Nov 09 '18 at 11:30
  • For example on clicking a button, you call this function: grecaptcha.execute("Recaptcha v3 site key", { action: 'test' }) .then((token) => { console.log(token)}) – Suleman Nov 09 '18 at 11:33

8 Answers8

136

Simple code to implement ReCaptcha v3

The basic JS code

<script src="https://www.google.com/recaptcha/api.js?render=your reCAPTCHA site key here"></script>
<script>
    grecaptcha.ready(function() {
    // do request for recaptcha token
    // response is promise with passed token
        grecaptcha.execute('your reCAPTCHA site key here', {action:'validate_captcha'})
                  .then(function(token) {
            // add token value to form
            document.getElementById('g-recaptcha-response').value = token;
        });
    });
</script>

The basic HTML code

<form id="form_id" method="post" action="your_action.php">
    <input type="hidden" id="g-recaptcha-response" name="g-recaptcha-response">
    <input type="hidden" name="action" value="validate_captcha">
    .... your fields
</form>

The basic PHP code

if (isset($_POST['g-recaptcha-response'])) {
    $captcha = $_POST['g-recaptcha-response'];
} else {
    $captcha = false;
}

if (!$captcha) {
    //Do something with error
} else {
    $secret   = 'Your secret key here';
    $response = file_get_contents(
        "https://www.google.com/recaptcha/api/siteverify?secret=" . $secret . "&response=" . $captcha . "&remoteip=" . $_SERVER['REMOTE_ADDR']
    );
    // use json_decode to extract json response
    $response = json_decode($response);

    if ($response->success === false) {
        //Do something with error
    }
}

//... The Captcha is valid you can continue with the rest of your code
//... Add code to filter access using $response . score
if ($response->success==true && $response->score <= 0.5) {
    //Do something to denied access
}

You have to filter access using the value of $response.score. It can takes values from 0.0 to 1.0, where 1.0 means the best user interaction with your site and 0.0 the worst interaction (like a bot). You can see some examples of use in ReCaptcha documentation.

Pedro Lobito
  • 94,083
  • 31
  • 258
  • 268
kikerrobles
  • 2,079
  • 3
  • 16
  • 26
  • 5
    The code you've posted doesn't check the value of the `score` field; if I understand the [docs](https://developers.google.com/recaptcha/docs/v3) correctly, `success` only indicates whether the posted request was valid; the actual information about the interaction (i.e. legitimate or not) is contained in the `score` field. – user4520 Sep 12 '19 at 19:34
  • You are right, this is just a basic code for ReCaptcha to work. But warn that the filter is done through the "score" is necessary, thanks. – kikerrobles Sep 16 '19 at 13:31
  • to avoid the `timeout-or-duplicate` error, I suggest using `setInterval` to refresh the token ([example](https://github.com/google/recaptcha/issues/302#issuecomment-572110826)) – xinthose Jan 09 '20 at 18:43
  • 19
    Its in the docs: `Note: reCAPTCHA tokens expire after two minutes. If you're protecting an action with reCAPTCHA, make sure to call execute when the user takes the action.` However, you call execute once the library is loaded. I would fix that. – Adam Feb 04 '20 at 22:59
  • 5
    One has to wonder, why they require the developer to pass their key twice. – cdosborn Mar 17 '20 at 14:58
  • Ditto what @Adam said, however I've noticed that calling `grecaptcha.execute` on form submit can add a VERY notable lag while the token is retrieved from Google. I've seen response times peak over 1000ms (tested today). Any suggestions on how to get around this? – Luke A. Leber Mar 26 '20 at 20:09
  • @LukeA.Leber you can use `setInterval` to refresh the token. – Adam Jun 29 '20 at 15:30
  • 1
    @Adam - is there any guidance available from Google as to whether or not this would negatively affect scores for certain users? Imagine if a user walks away for a few hours and comes back to complete the form. The same user would have requested over 100 tokens in the same browsing session. – Luke A. Leber Jun 30 '20 at 16:51
  • A bit non-related but is it possible to make only one request to the server using Google recaptcha. Because in current flow there are two request first to Google to get the token and then to the server. Instead can we just request our backend server directly and the backend server can make request on client behalf. – sktguha Aug 03 '20 at 06:09
  • 18
    I wonder how a BAD example like this contains so many up-votes. – Pedro Lobito Sep 01 '20 at 19:00
  • 3
    After having no success with several answers (including this one), I had more luck with [this answer](https://stackoverflow.com/a/60036326/8112776). – ashleedawg Nov 27 '20 at 12:18
  • @Jack this evaluation is for denied access, not for allow it. – kikerrobles Sep 05 '21 at 00:24
30

I thought a fully-functioning reCaptcha v3 example demo in PHP, using a Bootstrap 4 form, might be useful to some.

Reference the shown dependencies, swap in your email address and keys (create your own keys here), and the form is ready to test and use. I made code comments to better clarify the logic and also included commented-out console log and print_r lines to quickly enable viewing the validation token and data generated from Google.

The included jQuery function is optional, though it does create a much better user prompt experience in this demo.


PHP file (mail.php):

Add secret key (2 places) and email address where noted.

<?php

if ($_SERVER["REQUEST_METHOD"] == "POST") {

  # BEGIN Setting reCaptcha v3 validation data
  $url = "https://www.google.com/recaptcha/api/siteverify";
  $data = [
    'secret' => "your-secret-key-here",
    'response' => $_POST['token'],
    'remoteip' => $_SERVER['REMOTE_ADDR']
  ];

  $options = array(
    'http' => array(
      'header'  => "Content-type: application/x-www-form-urlencoded\r\n",
      'method'  => 'POST',
      'content' => http_build_query($data)
    )
    );
  
  # Creates and returns stream context with options supplied in options preset 
  $context  = stream_context_create($options);
  # file_get_contents() is the preferred way to read the contents of a file into a string
  $response = file_get_contents($url, false, $context);
  # Takes a JSON encoded string and converts it into a PHP variable
  $res = json_decode($response, true);
  # END setting reCaptcha v3 validation data
   
    // print_r($response); 
# Post form OR output alert and bypass post if false. NOTE: score conditional is optional
# since the successful score default is set at >= 0.5 by Google. Some developers want to
# be able to control score result conditions, so I included that in this example.

  if ($res['success'] == true && $res['score'] >= 0.5) {
 
    # Recipient email
    $mail_to = "youremail@domain.com";
    
    # Sender form data
    $subject = trim($_POST["subject"]);
    $name = str_replace(array("\r","\n"),array(" "," ") , strip_tags(trim($_POST["name"])));
    $email = filter_var(trim($_POST["email"]), FILTER_SANITIZE_EMAIL);
    $phone = trim($_POST["phone"]);
    $message = trim($_POST["message"]);
    
    if (empty($name) OR !filter_var($email, FILTER_VALIDATE_EMAIL) OR empty($phone) OR empty($subject) OR empty($message)) {
      # Set a 400 (bad request) response code and exit
      http_response_code(400);
      echo '<p class="alert-warning">Please complete the form and try again.</p>';
      exit;
    }

    # Mail content
    $content = "Name: $name\n";
    $content .= "Email: $email\n\n";
    $content .= "Phone: $phone\n";
    $content .= "Message:\n$message\n";

    # Email headers
    $headers = "From: $name <$email>";

    # Send the email
    $success = mail($mail_to, $subject, $content, $headers);
    
    if ($success) {
      # Set a 200 (okay) response code
      http_response_code(200);
      echo '<p class="alert alert-success">Thank You! Your message has been successfully sent.</p>';
    } else {
      # Set a 500 (internal server error) response code
      http_response_code(500);
      echo '<p class="alert alert-warning">Something went wrong, your message could not be sent.</p>';
    }   

  } else {

    echo '<div class="alert alert-danger">
        Error! The security token has expired or you are a bot.
       </div>';
  }  

} else {
  # Not a POST request, set a 403 (forbidden) response code
  http_response_code(403);
  echo '<p class="alert-warning">There was a problem with your submission, please try again.</p>';
} ?>

HTML <head>

Bootstrap CSS dependency and reCaptcha client-side validation Place between <head> tags - paste your own site-key where noted.

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
<script src="https://www.google.com/recaptcha/api.js?render=your-site-key-here"></script>

HTML <body>

Place between <body> tags.

<!-- contact form demo container -->
<section style="margin: 50px 20px;">
  <div style="max-width: 768px; margin: auto;">
    
    <!-- contact form -->
    <div class="card">
      <h2 class="card-header">Contact Form</h2>
      <div class="card-body">
        <form class="contact_form" method="post" action="mail.php">

          <!-- form fields -->
          <div class="row">
            <div class="col-md-6 form-group">
              <input name="name" type="text" class="form-control" placeholder="Name" required>
            </div>
            <div class="col-md-6 form-group">
              <input name="email" type="email" class="form-control" placeholder="Email" required>
            </div>
            <div class="col-md-6 form-group">
              <input name="phone" type="text" class="form-control" placeholder="Phone" required>
            </div>
            <div class="col-md-6 form-group">
              <input name="subject" type="text" class="form-control" placeholder="Subject" required>
            </div>
            <div class="col-12 form-group">
              <textarea name="message" class="form-control" rows="5" placeholder="Message" required></textarea>
            </div>

            <!-- form message prompt -->
            <div class="row">
              <div class="col-12">
                <div class="contact_msg" style="display: none">
                  <p>Your message was sent.</p>
                </div>
              </div>
            </div>

            <div class="col-12">
              <input type="submit" value="Submit Form" class="btn btn-success" name="post">
            </div>

            <!-- hidden reCaptcha token input -->
            <input type="hidden" id="token" name="token">
          </div>

        </form>
      </div>
    </div>

  </div>
</section>
<script>
  grecaptcha.ready(function() {
    grecaptcha.execute('your-site-key-here', {action: 'homepage'}).then(function(token) {
       // console.log(token);
       document.getElementById("token").value = token;
    });
    // refresh token every minute to prevent expiration
    setInterval(function(){
      grecaptcha.execute('your-site-key-here', {action: 'homepage'}).then(function(token) {
        console.log( 'refreshed token:', token );
        document.getElementById("token").value = token;
      });
    }, 60000);

  });
</script>

<!-- References for the optional jQuery function to enhance end-user prompts -->
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script src="form.js"></script>

Optional jQuery function for enhanced UX (form.js):

(function ($) {
'use strict';

var form = $('.contact_form'),
  message = $('.contact_msg'),
  form_data;

// Success function
function done_func(response) {
  message.fadeIn()
  message.html(response);
  setTimeout(function () {
    message.fadeOut();
  }, 10000);
  form.find('input:not([type="submit"]), textarea').val('');
}

// fail function
function fail_func(data) {
  message.fadeIn()
  message.html(data.responseText);
  setTimeout(function () {
    message.fadeOut();
  }, 10000);
}

form.submit(function (e) {
  e.preventDefault();
  form_data = $(this).serialize();
  $.ajax({
    type: 'POST',
    url: form.attr('action'),
    data: form_data
  })
  .done(done_func)
  .fail(fail_func);
}); })(jQuery);
Talk Nerdy To Me
  • 626
  • 5
  • 21
Gatsby
  • 745
  • 9
  • 13
  • 3
    very thorough; I got this one quickly working after giving up on the other (higher scored) answers. Thanks! – ashleedawg Nov 27 '20 at 12:16
  • 2
    **Note**: "`reCAPTCHA tokens expire after two minutes. If you're protecting an action with reCAPTCHA, make sure to call execute when the user takes the action rather than on page load.`"([src](https://developers.google.com/recaptcha/docs/v3)) This is especially important on a comment form -- I've had that happen as a user on live sites, after typing out detailed (lengthy) angry feedback, and then the site's form doesn't let me submit it. It can be *very* frustrating! – ashleedawg Nov 27 '20 at 12:55
  • 2
    @ashleedawg edited to include refreshing token every 60 seconds – Talk Nerdy To Me Feb 08 '21 at 17:58
  • @TalkNerdyToMe excuse my ignorance, in what part of your code are you refreshing the token every 60 seconds? – Albert Feb 23 '21 at 20:48
  • @Albert No ignorance at all - it appears that the edit that I submitted was rejected. I guess SO only lets you know when an edit has been accepted?? That edit would really have helped so I don't know why it would have been thrown out. I have submitted the edit again so hopefully it won't be rejected this time, and if it is, I'll just do my best to explain it. – Talk Nerdy To Me Feb 23 '21 at 21:37
  • @TalkNerdyToMe Sorry for the oversight on approving the edit, guys. I meant to test that out before approving a while back. Just tested it out - good to go - nice functionality improvement. Fun watching the token refresh in the console log too :). – Gatsby Feb 24 '21 at 03:01
  • @Gatsy I also just submitted another edit to fix another issue that when using the optional jQuery for enhanced UX the token needs to be refreshed or else it fails unless you wait to resubmit the form until the token refreshes by itself from the previous edit's addition. – Talk Nerdy To Me Feb 24 '21 at 18:30
  • @TalkNerdyToMe Hmm. I haven't been able to reproduce that error, unless I'm misunderstanding you. After initial page load, with the non-refreshed first token visible in the console, I'm able to submit forms successfully, even multiple form submissions work fine after the refresh function triggers a new token. And I'm referencing jQuery 3.3.1. So, can you elaborate? Also, since the Google token expires after 2 minutes, I'm curious why you want to refresh at 60 seconds? No big deal, I left it, yet I wanted to mention. – Gatsby Feb 25 '21 at 03:56
  • @Gatsby I just thought to refresh it every minute instead of two purely for safety's sake. [This answer](https://stackoverflow.com/a/61619548/6450661) does it every three seconds, but I personally think that's way overkill. The error occurs after you submit the form and then immediately submit it again before the token refresh cycle happens again. You just need to refresh the token again on successful form completion (run `grecaptcha.execute()` inside `done_func()`). I just tested it again to confirm. – Talk Nerdy To Me Feb 25 '21 at 19:08
  • I get Failed to load resource: the server responded with a status of 500 (Internal Server Error) I am not sure what is the reason for this because it is linked to mail.php. ANy idea is highly appreciated! – Abe Mar 17 '21 at 21:07
  • 1
    You can get your SITE key and SECRET key here: https://www.google.com/recaptcha/admin/create – timgavin Apr 19 '21 at 14:08
  • I was under the impression that the captcha is supposed to analyze the form content, but it appears to not be the case in this example. Or am I missing something? – Robert Sinclair Dec 21 '22 at 02:09
5

I am assuming you have site key and secret in place. Follow this step.

In your HTML file, add the script.

 <script src="https://www.google.com/recaptcha/api.js?render=put your site key here"></script>

Also, do use jQuery for easy event handling.

Here is the simple form.

 <form id="comment_form" action="form.php" method="post" >
      <input type="email" name="email" placeholder="Type your email" size="40"><br><br>
      <textarea name="comment" rows="8" cols="39"></textarea><br><br>
      <input type="submit" name="submit" value="Post comment"><br><br>
    </form>

You need to initialize the Google recaptcha and listen for the ready event. Here is how to do that.

     <script>
       // when form is submit
    $('#comment_form').submit(function() {
        // we stoped it
        event.preventDefault();
        var email = $('#email').val();
        var comment = $("#comment").val();
        // needs for recaptacha ready
        grecaptcha.ready(function() {
            // do request for recaptcha token
            // response is promise with passed token
            grecaptcha.execute('put your site key here', {action: 'create_comment'}).then(function(token) {
                // add token to form
                $('#comment_form').prepend('<input type="hidden" name="g-recaptcha-response" value="' + token + '">');
                $.post("form.php",{email: email, comment: comment, token: token}, function(result) {
                        console.log(result);
                        if(result.success) {
                                alert('Thanks for posting comment.')
                        } else {
                                alert('You are spammer ! Get the @$%K out.')
                        }
                });
            });
        });
  });
  </script>

Here is the sample PHP file. You can use Servlet or Node or any backend language in place of it.

<?php

        $email;$comment;$captcha;
        if(isset($_POST['email'])){
          $email=$_POST['email'];
        }if(isset($_POST['comment'])){
          $comment=$_POST['comment'];
        }if(isset($_POST['token'])){
          $captcha=$_POST['token'];
          }
        if(!$captcha){
          echo '<h2>Please check the the captcha form.</h2>';
          exit;
        }
        $secretKey = "put your secret key here";
        $ip = $_SERVER['REMOTE_ADDR'];

        // post request to server

        $url =  'https://www.google.com/recaptcha/api/siteverify?secret=' . urlencode($secretKey) .  '&response=' . urlencode($captcha);
        $response = file_get_contents($url);
        $responseKeys = json_decode($response,true);
        header('Content-type: application/json');
        if($responseKeys["success"]) {
                echo json_encode(array('success' => 'true'));
        } else {
                echo json_encode(array('success' => 'false'));
        }
?>

Here is the tutorial link: https://codeforgeek.com/2019/02/google-recaptcha-v3-tutorial/

Hope it helps.

SSpoke
  • 5,656
  • 10
  • 72
  • 124
Shaikh Shahid
  • 1,185
  • 11
  • 13
  • 8
    This is wrong and doesn't take into account the score which is needed in v3. Don't follow this guide, read in comments on the page linked. – tony Apr 09 '20 at 07:59
  • After having no success with several answers (including this one), I had more luck with [this answer](https://stackoverflow.com/a/60036326/8112776). – ashleedawg Nov 27 '20 at 12:18
3

We use recaptcha-V3 only to see site traffic quality, and used it as non blocking. Since recaptcha-V3 doesn't require to show on site and can be used as hidden but you have to show recaptcha privacy etc links (as recommended)

Script Tag in Head

<script src="https://www.google.com/recaptcha/api.js?onload=ReCaptchaCallbackV3&render='SITE KEY' async defer></script>

Note: "async defer" make sure its non blocking which is our specific requirement

JS Code:

<script>
    ReCaptchaCallbackV3 = function() {
        grecaptcha.ready(function() {
            grecaptcha.execute("SITE KEY").then(function(token) {
                $.ajax({
                    type: "POST",
                    url: `https://api.${window.appInfo.siteDomain}/v1/recaptcha/score`,
                    data: {
                        "token" : token,
                    },
                    success: function(data) {
                        if(data.response.success) {
                            window.recaptchaScore = data.response.score;
                            console.log('user score ' + data.response.score)
                        }
                    },
                    error: function() {
                        console.log('error while getting google recaptcha score!')
                    }
                });

            });
        });
    };
</script> 

HTML/Css Code:

there is no html code since our requirement is just to get score and don't want to show recaptcha badge.

Backend - Laravel Code:

Route:

Route::post('/recaptcha/score', 'Api\\ReCaptcha\\RecaptchaScore@index');


Class:

class RecaptchaScore extends Controller
{
    public function index(Request $request)
    {
        $score = null;

        $response = (new Client())->request('post', 'https://www.google.com/recaptcha/api/siteverify', [
            'form_params' => [
                'response' => $request->get('token'),
                'secret' => 'SECRET HERE',
            ],
        ]);

        $score = json_decode($response->getBody()->getContents(), true);

        if (!$score['success']) {
            Log::warning('Google ReCaptcha Score', [
                'class' => __CLASS__,
                'message' => json_encode($score['error-codes']),
            ]);
        }

        return [
            'response' => $score,
        ];
    }
} 

we get back score and save in variable which we later user when submit form.

Reference: https://developers.google.com/recaptcha/docs/v3 https://developers.google.com/recaptcha/

Furqan Freed
  • 366
  • 1
  • 3
  • 9
  • After having no success with several answers (including this one), I had more luck with [this answer](https://stackoverflow.com/a/60036326/8112776). – ashleedawg Nov 27 '20 at 12:18
  • @ashleedawg sorry if that didn't work for you ! i've just tested again and look like all good ! your reference is simple php implementation if you use this colutin which i've mentioned is written for #Laravel but it should also work if you simply use RecaptchaScore class. – Furqan Freed Nov 28 '20 at 17:15
3

I have seen most of the articles that don't work properly that's why new developers and professional developers get confused about it.

I am explaining to you in a very simple way. In this code, I am generating a google Recaptcha token at the client side at every 3 seconds of time interval because the token is valid for only a few minutes that's why if any user takes time to fill the form then it may be expired.

First I have an index.php file where I am going to write HTML and JavaScript code.

    <!DOCTYPE html>
<html>
   <head>
      <title>Google Recaptcha V3</title>
   </head>
   <body>
      <h1>Google Recaptcha V3</h1>
      <form action="recaptcha.php" method="post">
         <label>Name</label>
         <input type="text" name="name" id="name">
         <input type="hidden" name="token" id="token" /> 
         <input type="hidden" name="action" id="action" /> 
         <input type="submit" name="submit">
      </form>
      <script src="https://www.google.com/recaptcha/api.js?render=put your site key here"></script>
      <script  src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
      <script type="text/javascript">
         $(document).ready(function(){
            setInterval(function(){
            grecaptcha.ready(function() {
                grecaptcha.execute('put your site key here', {action: 'application_form'}).then(function(token) {
                    $('#token').val(token);
                    $('#action').val('application_form');
                });
            });
            }, 3000);
         });

      </script>
   </body>
</html>

Next, I have created recaptcha.php file to execute it at the server side

<?php

if ($_POST['submit']) {
    $name   = $_POST['name'];
    $token  = $_POST['token'];
    $action = $_POST['action'];

    $curlData = array(
        'secret' => 'put your secret key here',
        'response' => $token
    );

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, "https://www.google.com/recaptcha/api/siteverify");
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($curlData));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $curlResponse = curl_exec($ch);

    $captchaResponse = json_decode($curlResponse, true);

    if ($captchaResponse['success'] == '1' && $captchaResponse['action'] == $action && $captchaResponse['score'] >= 0.5 && $captchaResponse['hostname'] == $_SERVER['SERVER_NAME']) {
        echo 'Form Submitted Successfully';
    } else {
        echo 'You are not a human';
    }
}

Source of this code. If you would like to know the explanation of this code please visit. Google reCAPTCHA V3 integration in PHP

Sumit Kumar Gupta
  • 2,132
  • 1
  • 22
  • 21
  • I agree with your first sentence... and this didn't work for me either. ("`You are not a human`"). The only answer that worked for me was [this](https://stackoverflow.com/a/60036326/8112776). – ashleedawg Nov 27 '20 at 12:26
  • Hi @clayray, I have already applied score in code. – Sumit Kumar Gupta Dec 06 '20 at 12:34
  • Ah yes, so you have @SumitKumarGupta. Apologies, I will delete my comment. – clayRay Dec 07 '20 at 00:09
  • 1
    this worked for me. there are two places for site key and one place for secret. dont miss that out guys – Chris Jun 07 '21 at 06:46
  • I implemented V3 and generated the recaptcha token on post, when they click the, in this case, "Submit" button. No need to create new key every [interval of time]. – Kershaw Aug 22 '22 at 20:01
  • Hi @Kershaw, if user open a form till more than 1 or 2 hour then need new token – Sumit Kumar Gupta Aug 23 '22 at 07:20
2

I process POST on PHP from an angular ajax call. I also like to see the SCORE from google.

This works well for me...

$postData = json_decode(file_get_contents('php://input'), true); //get data sent via post
$captcha = $postData['g-recaptcha-response'];

header('Content-Type: application/json');
if($captcha === ''){
    //Do something with error
    echo '{ "status" : "bad", "score" : "none"}';
} else {
    $secret   = 'your-secret-key';
    $response = file_get_contents(
        "https://www.google.com/recaptcha/api/siteverify?secret=" . $secret . "&response=" . $captcha . "&remoteip=" . $_SERVER['REMOTE_ADDR']
    );
    // use json_decode to extract json response
    $response = json_decode($response);

    if ($response->success === false) {
        //Do something with error
        echo '{ "status" : "bad", "score" : "none"}';
    }else if ($response->success==true && $response->score <= 0.5) {
        echo '{ "status" : "bad", "score" : "'.$response->score.'"}';
    }else {
        echo '{ "status" : "ok", "score" : "'.$response->score.'"}';
    }
}

On HTML

<input type="hidden" id="g-recaptcha-response" name="g-recaptcha-response">

On js

$scope.grabCaptchaV3=function(){
     var myCaptcha = angular.element('#g-recaptcha-response').val();         
     var params = {
                     method: 'POST',
                     url: 'api/recaptcha.php',
                     headers: {
                       'Content-Type': undefined
                     },
                     data:   {'g-recaptcha-response' : myCaptcha }
     }
     $http(params).then(function(result){ 
                console.log(result.data);
     }, function(response){
                console.log(response.statusText);
     }); 
}
Chris Lambrou
  • 356
  • 2
  • 7
2

For a "basic form" (as the original question asks) what's needed is simple if you're content to validate on the server. Here's a complete HTML page:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<script src="https://www.google.com/recaptcha/api.js"></script>
<script>
<!--
function onSubmit() {
    var form = document.forms[0];
    if ( form['name'].value ) {
        form.submit();
    } else {
        alert( 'Please provide a name.' );
    }
}
//-->
</script> 
</head>
<body>
    <form action="process.asp" method="post">
        Name: <input type="text" name="name" /><br /><br />
        <button class="g-recaptcha" data-sitekey="SITE_KEY" data-callback='onSubmit' data-action='contact'>Send</button>
    </form>
</body>
</html>

And here's the complete page for processing it, using Classic ASP (filename = process.asp) for simplicity:

<%@ Language=JavaScript %>
<%
var name = Request( 'name' ).Item;
var recaptchaResponse = Request( 'g-recaptcha-response' ).Item;
var ip = Request.ServerVariables( 'REMOTE_ADDR' );
var xmlhttp = Server.CreateObject( 'MSXML2.ServerXMLHTTP' );
var query = 'secret=SECRET_KEY&response=' + recaptchaResponse + '&remoteip=' + ip;
xmlhttp.open( 'POST', 'https://www.google.com/recaptcha/api/siteverify?' + query, false ); // false says to wait for response
xmlhttp.send();
var response = JSON.parse( xmlhttp.responseText );
Response.Write( name + ' is a ' + (response.success && response.action == 'contact' && response.score > 0.5 ? 'HUMAN' : 'ROBOT') );
%>

A few notes:

  1. You'll supply your own SITE_KEY and SECRET_KEY.
  2. You'll need a JSON parser.
  3. You'll do the server-side POST using a method suitable for your server.
  4. I added one simple form field validation so you can see how to integrate that.
  5. You can make the "action" string anything you want, but be sure that what's on the server is consistent with what's in the HTML.
  6. You might want to respond differently to a response.success that isn't true or a response.action that doesn't match your action string, or do other error checking.
  7. You might want a score conditional other than "> 0.5".
  8. This code has no problems with the two-minute timeout.
Dragonfly
  • 814
  • 8
  • 12
0

if you are newly implementing recaptcha on your site, I would suggest adding api.js and let google collect behavioral data of your users 1-2 days. It is much fail-safe this way, especially before starting to use score.

burkul
  • 113
  • 1
  • 5