How to implement google reCAPTCHA on my site?

32

I'm trying to implement the reCAPTCHA of Google on my site, and I can not do the integration Server-Side (I use the PHP language). How can I make reCAPTCHA work, and do the validation before submitting my form data?

Google Source and Documentation reCAPTCHA

    
asked by anonymous 24.04.2015 / 16:19

3 answers

46

Introduction to reCAPTCHA

reCAPTCHA is a new Google tool to protect your site against spammers and bots. It comes from a novice idea, because until then the captchas were seen more as an obstacle than a helper by the users. With reCAPTCHA this is different because all you have to do is click on a checkbox , confirming that it is not a robot. That way everyone wins, the user has faster access to the information they want, and you keep unwanted visitors to your site.

Incredible! I want to have one of these, how do I?

The first step is to get a key to your site. Go to the site below and click the blue button located at the top-right position of the site, typed "Get reCAPTCHA": link

Once you have registered your site, you will have two important information at hand: the site key , and the secret (I'll call it the secret key). The first step in implementing reCAPTCHA on your site is to insert the API into your site. Enter the code inside the head tag of your site:

<script src='https://www.google.com/recaptcha/api.js'></script>

All ready for the next step.

Creating the form

Create a common form, I did with two fields: one for the user to put the name, and another for any message. The markup looks like this:

<h1>Exemplo de formulário com o reCaptcha</h1>
		
<form action="formulario.php" method="post">
  Digite seu nome: <input type="text" name="nome"><br><br>
  Deixe sua mensagem: <br>
  <textarea name="mensagem" rows="7" cols="35"></textarea><br><br>
  <input type="submit" value="Submit" name="formulario">
</form>

Inserting reCAPTCHA into the form is extremely simple, you just need to add the following element in the position you want it to appear:

<div class="g-recaptcha" data-sitekey="SUA-CHAVE"></div>

Do not forget to replace YOUR KEY with the key you received on the site, remembering that it is the site key , not the secret key >!

Replace the action property in the form tag with the name of the PHP file that will validate the form. You can validate on the same page, but I preferred to leave it in a separate one so the code gets simpler.

But can not I validate using JavaScript at the time?

No :) You'll understand why.

Creating the PHP code to validate the form

Let's get the value of the name and message field that the user sent:

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

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

From here the validation of captcha actually happens. We are sent via POST a value provided by reCAPTCHA, it is possible to retrieve this value by the variable $_POST['g-recaptcha-response'] . Logo:

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

// Se nenhum valor foi recebido, o usuário não realizou o captcha
if (!$captcha_data) {
    echo "Por favor, confirme o captcha.";
    exit;
}

It looks like it's over, right? Not! Now that's the fun part, remember when I said it was necessary that the captcha had to undergo a PHP validation? This is necessary because reCAPTCHA uses information in the Google database, which contains various information about the user who "made" the captcha. This way it is possible to distinguish an ordinary user from a bot. To validate the user, we need to make a request for the reCAPTCHA API, using file_get_contents . Note:

$resposta = file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret=SUA-CHAVE-SECRETA&response=".$captcha_data."&remoteip=".$_SERVER['REMOTE_ADDR']);

Look in the middle of the URL for YOUR-KEY-SECRET and replace it with yours. What this command does is to retrieve data in the reCAPTCHA API for information about the values that were provided by the captcha, in addition to sending the user's IP for future evaluations.

With the request sent, we only need to address the answer:

if ($resposta.success) {
    echo "Obrigado por deixar sua mensagem!";
} else {
    echo "Usuário mal intencionado detectado. A mensagem não foi enviada.";
    exit;
}

I hope you have understood how the system works. Any questions you know, we're here to help. ;)

    
25.04.2015 / 04:32
14

TOTALLY REFORMED RESPONSE . Reason: I put the information as I discovered it and it got very bad. I thank Rafael Almeida for the first response, which helped me a lot and led me to discover more things. And the administrators, who made changes that guided me to improve the answer. My answer exists only to add information to the excellent work already done by Rafael Almeida.

Client-side code (HTML and JavaScript)

A question raised: but I can not validate using JavaScript at the time?

In fact, using AJAX: send the information to PHP and get the answer before submitting the entire form with the rest of the fields. However, it does not seem like a necessary effort, because by clicking reCAPTCHA, it does not release until the user has given the correct answer. At least I did not see anything else happen with or without the " check " flag to indicate that everything is OK (for example, I did not see a red X in place). In other words, reCAPTCHA is all or nothing: either the user did not respond or answered and answered right.

What seems to be useful here to do the check in JS before sending to PHP to know if the user has at least used reCAPTCHA, to avoid sending the entire form. This is very easy because the API already has the function, just put something like this in the function that executes on the onsubmit of the form:

 if (grecaptcha.getResponse() == "")
 {
      alert("Você não clicou no reCAPTCHA, por favor, faça!")
      return false;
 }

Server-side code (PHP)

What led me to get more information is that the code with file_get_contents did not work for me. Initially, I thought the problem was the method of sending the function (GET, while the reCAPTCHA website says it needs to be POST). Then I discovered that it works perfectly on the copy of the site hosted on my PC. That is, it is the hosting server (I use Hostmídia) that blocks. I've tried, but unsuccessful :

ini_set('allow_url_fopen', 1)

The alternative answer, based on cURL , can be useful for those who have the site in the same hosting or another that also blocks. Anyway, it might be interesting to avoid that in case of warning , the URL including the secret key is not registered in the log . Here is the code:

# Os parâmetros podem ficar em um array
$vetParametros = array (
    "secret" => "SUA-CHAVE-SECRETA",
    "response" => $_POST["g-recaptcha-response"],
    "remoteip" => $_SERVER["REMOTE_ADDR"]
);
# Abre a conexão e informa os parâmetros: URL, método POST, parâmetros e retorno numa string
$curlReCaptcha = curl_init();
curl_setopt($curlReCaptcha, CURLOPT_URL,"https://www.google.com/recaptcha/api/siteverify");
curl_setopt($curlReCaptcha, CURLOPT_POST, true);
curl_setopt($curlReCaptcha, CURLOPT_POSTFIELDS, http_build_query($vetParametros));
curl_setopt($curlReCaptcha, CURLOPT_RETURNTRANSFER, true);
# A resposta é um objeto json em uma string, então só decodificar em um array (true no 2º parâmetro)
$vetResposta = json_decode(curl_exec($curlReCaptcha), true);
# Fecha a conexão
curl_close($curlReCaptcha);
# Analisa o resultado (no caso de erro, pode informar os códigos)
if ($vetResposta["success"]) echo "<p>Captcha OK!</p>\n";
else 
{
    echo "$<p>Problemas:</p>\n";
    foreach ($vetResposta["error-codes"] as $strErro) echo "$strTab<p>Erro: $strErro</p>\n";
}

A little more, still on the server side ...

If you look at the reCAPTCHA site's instructions, there is an indication of a library that is in github, in / google / recaptcha. Also works fine: just put the src folder of the ZIP downloaded somewhere on the site and use the code similar to their example. The only problem is that I was giving the following error:

  

invalid-json

Then I found a hint in another Stackoverflow article (% method argument):

$recaptcha = new \ReCaptcha\ReCaptcha($secret, new \ReCaptcha\RequestMethod\CurlPost());
$resp = $recaptcha->verify($gRecaptchaResponse, $remoteIp);
if ($resp->isSuccess()) {
    // verified!
} else {
    $errors = $resp->getErrorCodes();
}

For this, I did not test if the problem was in the hosting or the library class itself.

09.12.2015 / 19:44
0

Here is a complete implementation of reCaptcha that I'm using on a website I'm developing, the only thing that's missing to run 100% is creating the objects, but I've described how to create them, I'm just a student so I did the best I could

<?php ini_set('display_errors',1); ini_set('display_startup_erros',1); error_reporting(E_ALL); ?><!--Força o php a mostrar todo tipo de erro, linha temporária-->
    <?php
    function __autoload($class_name){
        require_once '../_lib/'.$class_name.'.php';//-->lê minhas classes de forma automática
    }
    ?>
    <!DOCTYPE html>
    <html>
    <head>
        <link rel="stylesheet" type="text/css" href="_css/login.css"/>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script><scriptsrc='https://www.google.com/recaptcha/api.js'></script><script>$(document).ready(function(){$('#send').prop('disabled',true);//desativaobotãoenviar$('.g-recaptcha').hide();//escondeocaptchavalidate();$('#inputEmail,#inputPassword').change(validate);});functionvalidate(){if($('#inputEmail').val().length>10){//enquantoocampodeemailnaotivermenosque10caracteres,nãoativaoreCaptcha$('.g-recaptcha').show();//exibeoreCaptcha}else{//semudardeideiaereduzirocampopramenosde10caracteres...$('.g-recaptcha').hide();//oreCaptchaseescondenovmanete}}functionenableSend(){$('#send').prop('disabled',false);//quandoocaptchaéconfirmado,ativaobotaoenviar}</script></head><body><?php$helper=newHelpers();//-->objetocomváriosmétodosimportantesif(isset($_POST['attempt'])){//verificasetemtentativarestante$attempt=intval($helper->validation($_POST['attempt']));//validation=métodoqueverificaeescapaminhasring(trim(),stripcslashes()ehtmlspecialchars())}else{$attempt=3;//senãofordefinidonúmerodetentativas,aquiédefinidocomo3}if(isset($_POST['g-recaptcha-response'])andisset($_POST['username'])andisset($_POST['password'])){//garantequetodososcamposforampreenchidos$captcha_data=$_POST['g-recaptcha-response'];if($captcha_data){//VerificaçãodoreCaptcha$resposta=file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret=DIGITE-SUA-CHAVE-SECRETA-GERADA-PELO-GOOGLE-AQUI=" . $captcha_data . "&remoteip=" . $_SERVER['REMOTE_ADDR']);
            if ($resposta) {//validação do reCaptcha
                $username = strtolower($helper->validation($_POST['username']));
                $password = $helper->validation($_POST['password']);
                $user = new User();//--->meu objeto que acessa o banco de dados usando PDO
                $userValidated = $user->checkPasswordHash($username);//--->método do meu objeto que procura o usuario no bacno de dados (SELECT * FROM tbl_Users WHERE username = $username)
                if ($userValidated){//verifica se o email existe, se existir...
                    if ($userValidated->status == 1){//verifica se a conta está bloqueada ou não
                        echo 'Essa conta está bloqueada, criar botão para reenviar o email de recuperação...';
                    }else{
                    $hash = $userValidated->password;//retorna o hash do password
                    if (password_verify($password, $hash)) {//compara a senha e o hash que foi criado usando password_hash() e salvo no banco de dados
                        echo 'Password é válido, inserir código que inicia as sessões e chama a próxima página';//-->insira seu código
                    } else {//caso o password estjeja errado, perde uma tentativa
                        if ($attempt != 1){//se a tentativa restante for igual a 1, a proxima vez será direcionado para a página de recuperação de senha
                            $attempt--;
                            echo 'Usuário e senha não combinam, você tem mais '.$attempt.' tentativas';//mostra o número de tentativas restante
                        }else{//bloqueia a conta e chama a página de recuperação de senha
                            echo 'inserir código que bloqueia a conta e abre pagina de recuperaçao de senha';//-->insira seu código de bloqueio
                        }
                    }
                    }
                }else{//se o email não existir, perde uma tentativa mas não avisa se o erro foi no email ou na senha
                    if ($attempt != 0){
                        $attempt--;
                        echo 'Usuário e senha não combinam, você tem mais '.$attempt.' tentativas';//mostra o número de tentativas restante
                    }else{//bloqueia a conta e chama a página de recuperação de senha
                        echo 'inserir código que bloqueia a conta e abre pagina de recuperaçao de senha';//-->insira seu código de bloqueio
                    }
                }
            } else {
                echo "Validação não concluída, tente novamente.";
                exit;
            }
        } else {
            echo "Validação não concluída, tente novamente.";
            exit;
        }
    }
    ?>
    <section>
        <form class="login" action="login.php" method="post">
            <fieldset>
                <legend>Login</legend>
                <label for="inputEmail" class="Label">Email: </label>
                <input id="inputEmail" class="inputText" type="email" maxlength="30" name="username" required>
                <label for="inputPassword" class="Label">Password: </label>
                <input id="inputPassword" class="inputPassword" type="password" maxlength="20" name="password" required>
                <div class="g-recaptcha" data-sitekey="DIGITE-A-CHAVE-DO-SEU-SITE-CRIADA-PELO-GOOGLE-AQUI" data-callback="enableSend"></div><!--Linha que adiciona o recaptcha-->
                <input type="hidden" name="attempt" value=<?php echo $attempt ?> /><!--envia por post o numero de tentativas restante-->
                <input type="submit" value="Confirmar" id="send" class="send">
            </fieldset>
        </form>
    </section>

    </body>
    </html>
    
09.08.2016 / 06:08