Recaptcha V2 hopefully made simple. Both HTML and PHP code included here

2,459 views
Skip to first unread message

Donna S

unread,
Jul 13, 2015, 3:19:16 PM7/13/15
to reca...@googlegroups.com
I had been using ReCaptcha V1 for a number of years with no real problem. Figuring out how the heck to get V2 running became a nightmare. As much as anyone would like to think it's well documented, IT'S NOT unless you happen to be a master coder. These days I scrape by on coding, so having a very clear, simple and straight forward example would be wonderful. I found a lot of examples of people using Curl and other fun ways to implement this. All of those examples ended up with the stupid recaptcha always being SUCCESS : FALSE and I still don't understand why. Anyway, I do now having it working and hopefully someone can benefit from these short example files I'm attaching. I certainly don't claim to be a great coder, but this actually does work consistently.

I happen to use sessions in my forms but code still works the same with or without session enabled.

Here's the HTML (again, if you don't want sessions, eliminate the PHP line at the top and call your file cap_test.html). I got this code from codeforgeek so I definitely thank them so much!!

CAP_TEST.PHP

<?php session_start(); ?>
<html>
  <head>
    <title>Google recapcha demo - Codeforgeek</title>
    <script src='https://www.google.com/recaptcha/api.js'></script>
  </head>
  <body>
    <h1>Google reCAPTHA V2 Demo</h1>

    <form id="comment_form" action="cap_process.php" method="post">

      <input type="email" placeholder="Type your email" size="40"><br><br>
      <textarea name="comment" rows="8" cols="39"></textarea><br><br>

       <div class="g-recaptcha" data-sitekey="enter your site key here"></div>

       <input type="submit" name="submit" value="Post comment">

    </form>
  </body>
</html>


CAP_PROCESS.PHP

<?php
session_start();

$secret = "enter your secret captcha code here";

$email;$comment;$captcha;

if(isset($_POST['email']))  { $email=$_POST['email']; }

if(isset($_POST['comment']))  { $email=$_POST['comment']; }

if(isset($_POST['g-recaptcha-response']))  { $captcha=$_POST['g-recaptcha-response'];  }
 
// If !$captcha  is true, that says the user hit the submit without doing the captcha
     
if (!$captcha) {
          echo '<h2>Please check the the captcha form.</h2>';
              exit;
           }

// This gets the response and checks it for being true. If it is it prints thanks for posting the comment and exits.
     
$response = file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret=$secret&response=".$captcha."&remoteip=".$_SERVER['REMOTE_ADDR']);

if($response.'success'==true)   {  echo '<h2>Thanks for posting comment.</h2>';   }

?>


So this is fun for testing. In my real form, I don't really care whether they tried to bypass the captcha or if it failed for some reason, I'm still going to make them try again, so this is a small bit of the actual code I use in my PHP processing script:

// Set errorflag variable to false so we'll assume this will run with no errors

$_SESSION["errorflag"] = "false";

// Now go check if the recaptcha was entered correctly
// If $_POST['g-recaptcha-response'] is not set, that means the user hit submit without completing the recapcha and we'll send it back

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

// So if $captcha was set, lets go see if it was successfull by getting the response and putting the answer into $response

if($captcha){$response=file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret=$secret&response=".$captcha."&remoteip=".$_SERVER['REMOTE_ADDR']);}

// So now if either the $captcha was not set OR we did not get a success from recaptcha
// we'll set the error flag to indicate that recaptcha was bad
// and load the sanitized form data into session variables and go on back to the form

if ((!$captcha) or ($response."success"==false)) {

    $_SESSION["applocation"] = $applocation;
    $_SESSION["firstname"] = $firstname;



Martin Brilliant

unread,
Jul 13, 2015, 9:14:24 PM7/13/15
to reca...@googlegroups.com
How carefully did you test this code? I added some debugging statements, and then tested it by altering the secret key. The debugging showed false, but the test always succeeded. So, meanwhile, I'm still using V1.

Here is my code (after getting the POST parameters and the $response to the file_get_contents statement):

<?php
                      //this is some debugging code
echo "reCAPTCHA says " ;
print_r($response);
echo ".<br><br>";

if (!$captcha) {
          echo '<h2>Please use the the captcha form.</h2>';
              exit;
           }

if($response.'success' == true)
{
    echo '<h2>Thanks for getting it right</h2>';
    exit;
}
else
{
    echo "You have been identified as a robot " .
    "(reCAPTCHA said: " . $result["error-codes"][0] . "). " .
    "Please hit your browser back button and try again.<br>";
    exit;
}

and here is the resulting output:

reCAPTCHA says { "success": false, "error-codes": [ "invalid-input-secret" ] }.

Thanks for getting it right


My conclusion is that you don't need cURL, because the debugging code shows true when everything is OK and false when there's something wrong. But testing if($response.'success'==true) does not work, because it always returns true. We need a different test.

On Monday, July 13, 2015 at 3:19:16 PM UTC-4, Donna S wrote:
I had been using ReCaptcha V1 for a number of years with no real problem. Figuring out how the heck to get V2 running became a nightmare. As much as anyone would like to think it's well documented, IT'S NOT unless you happen to be a master coder. These days I scrape by on coding, so having a very clear, simple and straight forward example would be wonderful. I found a lot of examples of people using Curl and other fun ways to implement this. All of those examples ended up with the stupid recaptcha always being SUCCESS : FALSE and I still don't understand why. Anyway, I do now having it working and hopefully someone can benefit from these short example files I'm attaching. I certainly don't claim to be a great coder, but this actually does work consistently.

... etc. etc.

Martin Brilliant

unread,
Jul 13, 2015, 9:45:30 PM7/13/15
to reca...@googlegroups.com
I looked on the web and I think I have a working test. Since $response is a JSON object, it should be decoded to an associative array, and then the appropriate element of the array should be tested. So we need, first,

      $response = json_decode($response, true);

and then the test should be

      if($response['success'])

With those changes, I got "You have been identified as a robot" when the secret key was wrong, and "Thanks for getting it right" after I restored the correct secret key.

I'm waiting for somebody else to verify that this code is OK before I use it. Meanwhile I'm still using V1.

BTW I got a new key pair for V2, different from the pair I was using for V1. I have a vague recollection that I tried the same code before, but using the same key pair as for V1, and it always tested false. If so, you need a new key pair for V2. But I could be mistaken.

Donna S

unread,
Jul 14, 2015, 1:14:56 PM7/14/15
to reca...@googlegroups.com
I think I'm going to have to disagree with you about the code in my original post. Here's what I did to test it so you can try and recreate it.

When I got to the recaptcha, I got the series of pictures but I picked the wrong photos intentionally, so it gave me a new set. While those new pics were up on the screen, I clicked the submit button and I got the error message to check the recaptcha.

If I go back to the process routine and have it dump $captcha it in fact is null.

So then I commented out the the code which checks for  !$captcha and let it fall through and execute the $response = file_get_contents("https ... and
just had it echo $response and here was what I got when I repeated the same test of not answering the pictures correctly:

{ "success": false, "error-codes": [ "missing-input-response" ] }

So I would say the code in fact works just fine. The HOWEVER I would put in there is if in fact you wanted to find out what the error code was (in my case I don't care), you could then use EXPLODE or some other code to go extract the error code.

Again I don't take credit for this code as it was not in fact mine but I love the simplicity of it.

Thanks for looking and making me look at the code closer.
Donna

Martin Brilliant

unread,
Jul 14, 2015, 4:35:25 PM7/14/15
to reca...@googlegroups.com
Donna, It's my turn to thank you for making me revisit the code (which we both got independently from codeforgeek.com).

I agree with you up to a point. Your test for (!$captcha) does correctly check whether it exists or not. When you echo $response you verify, as I did, that $response really has valid information as to whether the user did or did not complete the captcha correctly. So far, so good. But echo $response is only human-readable; it can't control what the code does next.

What I want to know is, when your echo $response came back with false, missing input response, what did if($response.'success'==true) tell you? If that test failed, then you're OK. But for me, that test always succeeded, even when I clicked Submit without doing the captcha.

BTW I submitted a later post in this thread that says if I first decode the JSON object, and then test the resulting associative array, I get a test that works.

Anyway,
that page on codeforgeek.com had a lot of disagreeing comments, some saying you have to json_decode(), others saying you don't. Apparently, for reasons I don't understand, different users can get different results with what looks like the same code. "Your mileage may vary."
Message has been deleted

Donna S

unread,
Jul 14, 2015, 11:57:53 PM7/14/15
to reca...@googlegroups.com
I played with this code for quite a bit longer. In the end, my live code works and the reason I think it works is that if you either try to bypass the recaptcha or if you enter bad data and then submit, the g-recaptcha-response will always be false. so it almost doesn't matter what's in the response but I'm not really sure what it is the bots do. With that being said, this little change in the PHP code does seem to work simply and accurately. Once I get the $response (which is a string), I just search for the string "true" in it. If it can't find it, then $capt_resp will be FALSE.

$response = file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret=$secret&response=".$captcha."&remoteip=".$_SERVER['REMOTE_ADDR']);
$capt_resp = strpos($response, "true");
if ($capt_resp === false)
{
    echo "The captcha was false!!";
    exit;
}


You could obviously check for either 'true' or 'false' on the STRPOS command.

Donna

kh99

unread,
Jul 15, 2015, 1:16:00 AM7/15/15
to reca...@googlegroups.com
Martin is right, I think. This line is a problem:

if($response.'success'==true)   {  echo '<h2>Thanks for posting comment.</h2>';   }

A '.' is string concatenation, so you're checking whatever string is in $response, with 'success' tacked on the end. The resulting string is always evaluating to true.

If you want to verify this, try temporarily changing your html. Comment out the div like this:

<!-- <div class="g-recaptcha" data-sitekey="enter your site key here"></div> -->

and insert this instead:

<input type="hidden" name="g-recaptcha-reponse" value="anything">

which will send "anything" as g-recaptcha-response, and you'll see that it succeeds, even though you have not even displayed a recaptcha widget.


On Monday, July 13, 2015 at 3:19:16 PM UTC-4, Donna S wrote:

Martin Brilliant

unread,
Jul 16, 2015, 2:14:05 PM7/16/15
to reca...@googlegroups.com
Thanks, kh99, for pointing out an issue I was staring at for weeks without seeing it. I was looking at that dot and thinking it was an object property pointer. It is in some languages, but not in PHP. The result of $response.'success' is a non-empty string, which will always evaluate to true.

A correct PHP object property pointer won't work anyway. According to Google's documentation, $response is a JSON object. A JSON object in PHP is just a string, and in order to do anything sensible with it (other than parsing it as a string) you have to convert it to something else. A commenter on the codeforgeek.com page recommended converting it to an associative array, and that's what I did. I found another site that show how to convert it to a PHP object. But treating the JSON string as an object in PHP, without converting it, won't play.

I must confess I don't know PHP. I'm trying to get along by using and adapting other people's code and rummaging around for explanations. I think what I just wrote makes sense.

kh99

unread,
Jul 16, 2015, 8:07:57 PM7/16/15
to reca...@googlegroups.com
Martin,

What you wrote sounds right to me. I also saw your comment at codeforgeek.com. I also tried to leave a comment, but for some reason it wasn't posted (maybe they thought I was a spammer :) .  But I had said basically the same thing you said, so we'll see if the guy responds.

By the way, I didn't see Donna's last post before responding. I think the strpos method also works. as long as the 'success' doesn't appear in an error message (and I can't see why it would). But it's easy enough to use json_decode() to get an array, and then you have access to the error messages, so I think that's a better method. I don't know if there is any way to make it an actual object, but it's not necessary.

Also, I unfortunately made a typo in my previous post, and I misspelled g-recaptcha-response in the hidden input tag I suggested to use as a test, which would make the script fail. So if anyone actually wants to try that, make sure to add the missing 's' to 'g-recaptcha-reponse'.
Message has been deleted

Donna S

unread,
Jul 17, 2015, 1:22:04 AM7/17/15
to reca...@googlegroups.com
The STRPOS code actually works just fine. I don't check for "success" I check for 'false' but you can check for 'true' as well depending on how you want to proceed in your code. I'm absolutely certain doing the json_decode would work but this is just so much more simple. That's the wonderful thing about coding ... there are many ways to solve the same problem. I just think it's incredibly unfortunate that Google has not provided very clear coding examples that the non-coder can understand or at least follow. So many of us have obviously wasted hours searching for help that could be avoided by Google doing their job better.

I usually work alone but I really enjoy opportunities to bounce ideas off others and get a different perspective. Thank you!

Martin Brilliant

unread,
Jul 18, 2015, 4:03:12 PM7/18/15
to reca...@googlegroups.com
Donna, you really taught me something. I kept saying things like "unless you want to parse it as a string" as though that were the last thing in the world you would want to do with it. Now it turns out that's the easiest thing to do with it!

I agree with you about bouncing ideas. Ideas are maybe the only things that bounce higher with every bounce!

24birotihinbd Bangladesh

unread,
Oct 27, 2017, 12:06:35 AM10/27/17
to reCAPTCHA
{
"success": true|false,
"challenge_ts": timestamp, // timestamp of the challenge load (ISO format yyyy-MM-dd'T'HH:mm:ssZZ)
"apk_package_name": string, // the package name of the app where the reCAPTCHA was solved
"error-codes": [...] // optional
}
Reply all
Reply to author
Forward
0 new messages