A while back I posted a snippet on how to implement a Google reCAPTCHA v2 Checkbox. In this post, I am going to demo how to implement the Google reCAPTCHA v3, which doesn’t require any extra input from the user in order to prove they are human. The code below shows two ways to implement the reCAPTCHA v3.
The Code (Easy Way)
This way is easier and it works by binding the challenge to your button.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
////create the reCAPTCHA v3 with google //go to https://www.google.com/recaptcha/admin/ and create a v3 reCAPTCHA if you haven't already done this ////in <head> <style> .grecaptcha-badge { visibility: hidden; } /* This hides the reCAPTCHA badge. According to Google, you are allowed to hide the badge as long as you include the reCAPTCHA branding visibly elsewhere in the user flow */ </style> <script src='https://www.google.com/recaptcha/api.js'></script> <script> function onSubmit(token) { document.getElementById("myform").submit(); } </script> ////in recapv3.php <?php /** * A ReCaptchaResponse is returned from checkAnswer(). */ function file_get_contents_curl($url) { $ch = curl_init(); curl_setopt($ch, CURLOPT_AUTOREFERER, TRUE); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE); $data = curl_exec($ch); curl_close($ch); return $data; } class ReCaptchaResponse { public $success; public $errorCodes; } class ReCaptcha { private static $_signupUrl = "https://www.google.com/recaptcha/admin"; private static $_siteVerifyUrl = "https://www.google.com/recaptcha/api/siteverify?"; private $_secret; private static $_version = "php_1.0"; /** * Constructor. * * @param string $secret shared secret between site and ReCAPTCHA server. */ function ReCaptcha($secret) { if ($secret == null || $secret == "") { die("To use reCAPTCHA you must get an API key from <a href='" . self::$_signupUrl . "'>" . self::$_signupUrl . "</a>"); } $this->_secret=$secret; } /** * Encodes the given data into a query string format. * * @param array $data array of string elements to be encoded. * * @return string - encoded request. */ private function _encodeQS($data) { $req = ""; foreach ($data as $key => $value) { $req .= $key . '=' . urlencode(stripslashes($value)) . '&'; } // Cut the last '&' $req=substr($req, 0, strlen($req)-1); return $req; } /** * Submits an HTTP GET to a reCAPTCHA server. * * @param string $path url path to recaptcha server. * @param array $data array of parameters to be sent. * * @return array response */ private function _submitHTTPGet($path, $data) { $req = $this->_encodeQS($data); $response = file_get_contents_curl($path . $req); return $response; } /** * Calls the reCAPTCHA siteverify API to verify whether the user passes * CAPTCHA test. * * @param string $remoteIp IP address of end user. * @param string $response response string from recaptcha verification. * * @return ReCaptchaResponse */ public function verifyResponse($remoteIp, $response) { // Discard empty solution submissions if ($response == null || strlen($response) == 0) { $recaptchaResponse = new ReCaptchaResponse(); $recaptchaResponse->success = false; $recaptchaResponse->errorCodes = 'missing-input'; return $recaptchaResponse; } $getResponse = $this->_submitHttpGet( self::$_siteVerifyUrl, array ( 'secret' => $this->_secret, 'remoteip' => $remoteIp, 'v' => self::$_version, 'response' => $response ) ); $answers = json_decode($getResponse, true); $recaptchaResponse = new ReCaptchaResponse(); if (trim($answers ['success']) == true) { $recaptchaResponse->success = true; } else { $recaptchaResponse->success = false; $recaptchaResponse->errorCodes = $answers['error-codes']; } $recaptchaResponse->answers = $answers; return $recaptchaResponse; } } ?> ////in your form processor include($_SERVER['DOCUMENT_ROOT']."/path/to/recapv3.php"); $secret = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'; // Your Google Secret key which you can find in your recaptcha settings page https://www.google.com/recaptcha/admin/ // empty response $response = null; // check secret key $reCaptcha = new ReCaptcha($secret); // if submitted check response if ($_POST["g-recaptcha-response"]) { $response = $reCaptcha->verifyResponse( $_SERVER["REMOTE_ADDR"], $_POST["g-recaptcha-response"] ); } //captcha pass or fail if ($response != null && $response->success) { $mycaptcha = "pass"; $answers = $response->answers; $score = $answers["score"]; //this is the score which rates how likely the user is a bot. 1.0 is very likely a good interaction, 0.0 is very likely a bot. By default, you can use a threshold of 0.5 so score higher than .5 would be good, and a score under .5 would be a bot } else { $mycaptcha = "fail"; } ////in the form html (get your sitekey from https://www.google.com/recaptcha/admin/) <form method="post" action="" id="myform"> <!--form questions go here--> <button class="g-recaptcha" data-sitekey="your-sitekey-from-google" data-callback='onSubmit' data-action='submit' />Submit</button> </form> ////in your google recaptcha settings page (https://www.google.com/recaptcha/admin/) //add desired domain so google knows to allow it |
The Code (Harder Way)
This way works by binding the challenge programmatically. Though slightly more difficult, it can be better to use this method, because you have more control of the logic in terms of when to run the reCAPTCHA check. In the example below, we run a basic validation check to make sure the name field isn’t empty before sending to reCAPTCHA
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
////create the reCAPTCHA v3 with google //go to https://www.google.com/recaptcha/admin/ and create a v3 reCAPTCHA if you haven't already done this ////in <head> (get your sitekey from https://www.google.com/recaptcha/admin/) <style> .grecaptcha-badge { visibility: hidden; } /* This hides the reCAPTCHA badge. According to Google, you are allowed to hide the badge as long as you include the reCAPTCHA branding visibly elsewhere in the user flow */ </style> <script src="//code.jquery.com/jquery-2.1.3.min.js" type="text/javascript"></script> <script type="text/javascript"> $(function() { $('#myform').submit(function(event) { event.preventDefault(); //a basic example of some logic you could do before submitting the recaptcha. in this case, we are checking if the name field is empty, and if it is we don't bother sending to the recaptcha. if($("#name").val()==""){ alert("name can't be empty"); return false; } //var email = $('#email').val(); //if we made it this far, that means we have passed our basic validation checks. we are ready to send to recaptcha grecaptcha.ready(function() { grecaptcha.execute('your-sitekey-from-google', {action: 'submit_form'}).then(function(token) { $('#myform').prepend('<input type="hidden" name="g-recaptcha-response" value="' + token + '">'); $('#myform').unbind('submit').submit(); });; }); }); }); </script> <script src="https://www.google.com/recaptcha/api.js?render=your-sitekey-from-google"></script> ////in recapv3.php <?php /** * A ReCaptchaResponse is returned from checkAnswer(). */ function file_get_contents_curl($url) { $ch = curl_init(); curl_setopt($ch, CURLOPT_AUTOREFERER, TRUE); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE); $data = curl_exec($ch); curl_close($ch); return $data; } class ReCaptchaResponse { public $success; public $errorCodes; } class ReCaptcha { private static $_signupUrl = "https://www.google.com/recaptcha/admin"; private static $_siteVerifyUrl = "https://www.google.com/recaptcha/api/siteverify?"; private $_secret; private static $_version = "php_1.0"; /** * Constructor. * * @param string $secret shared secret between site and ReCAPTCHA server. */ function ReCaptcha($secret) { if ($secret == null || $secret == "") { die("To use reCAPTCHA you must get an API key from <a href='" . self::$_signupUrl . "'>" . self::$_signupUrl . "</a>"); } $this->_secret=$secret; } /** * Encodes the given data into a query string format. * * @param array $data array of string elements to be encoded. * * @return string - encoded request. */ private function _encodeQS($data) { $req = ""; foreach ($data as $key => $value) { $req .= $key . '=' . urlencode(stripslashes($value)) . '&'; } // Cut the last '&' $req=substr($req, 0, strlen($req)-1); return $req; } /** * Submits an HTTP GET to a reCAPTCHA server. * * @param string $path url path to recaptcha server. * @param array $data array of parameters to be sent. * * @return array response */ private function _submitHTTPGet($path, $data) { $req = $this->_encodeQS($data); $response = file_get_contents_curl($path . $req); return $response; } /** * Calls the reCAPTCHA siteverify API to verify whether the user passes * CAPTCHA test. * * @param string $remoteIp IP address of end user. * @param string $response response string from recaptcha verification. * * @return ReCaptchaResponse */ public function verifyResponse($remoteIp, $response) { // Discard empty solution submissions if ($response == null || strlen($response) == 0) { $recaptchaResponse = new ReCaptchaResponse(); $recaptchaResponse->success = false; $recaptchaResponse->errorCodes = 'missing-input'; return $recaptchaResponse; } $getResponse = $this->_submitHttpGet( self::$_siteVerifyUrl, array ( 'secret' => $this->_secret, 'remoteip' => $remoteIp, 'v' => self::$_version, 'response' => $response ) ); $answers = json_decode($getResponse, true); $recaptchaResponse = new ReCaptchaResponse(); if (trim($answers ['success']) == true) { $recaptchaResponse->success = true; } else { $recaptchaResponse->success = false; $recaptchaResponse->errorCodes = $answers['error-codes']; } $recaptchaResponse->answers = $answers; return $recaptchaResponse; } } ?> ////in your form processor include($_SERVER['DOCUMENT_ROOT']."/path/to/recapv3.php"); $secret = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'; // Your Google Secret key which you can find in your recaptcha settings page https://www.google.com/recaptcha/admin/ // empty response $response = null; // check secret key $reCaptcha = new ReCaptcha($secret); // if submitted check response if ($_POST["g-recaptcha-response"]) { $response = $reCaptcha->verifyResponse( $_SERVER["REMOTE_ADDR"], $_POST["g-recaptcha-response"] ); } //captcha pass or fail if ($response != null && $response->success) { $mycaptcha = "pass"; $answers = $response->answers; $score = $answers["score"]; //this is the score which rates how likely the user is a bot. 1.0 is very likely a good interaction, 0.0 is very likely a bot. By default, you can use a threshold of 0.5 so score higher than .5 would be good, and a score under .5 would be a bot } else { $mycaptcha = "fail"; } ////in the form html (get your sitekey from https://www.google.com/recaptcha/admin/) <form method="post" action="" id="myform"> <!--form questions go here--> <input type="text" name="name" id="name"> <input class="submit" type="submit" value="Submit" /> </form> ////in your google recaptcha settings page (https://www.google.com/recaptcha/admin/) //add desired domain so google knows to allow it |
As someone who is definitely not a robot, this is very useful information!