How to implement google reCAPTCHA on my website?

Asked

Viewed 39,993 times

40

I’m trying to implement the reCAPTCHA from Google on my site, and I can’t do the integration Server-Side (I use the language PHP). How can I make reCAPTCHA work, and perform the validation before sending the data from my form?

Google reCAPTCHA Source and Documentation

  • your server side is what ? java, php, . net or Assembly ? Edit your question and add the language tag :o)

  • Edited fields. My Serv-side is php

  • 1

    I found your question interesting because it seems that there is no reCAPTCHA page in Portuguese. I know a lot of you think every programmer has to know English, but I think it’s okay to have something like a "guide" to reCAPTCHA around here... (or is it out of scope?) I think it would help if you improved the question a little bit more, including the specific error you are unable to resolve, and put at least some code you are already using.

3 answers

56


Introduction to reCAPTCHA

reCAPTCHA is a new Google tool to protect your site from spammers and bots. It comes from a new idea, because until then the Caps were seen more as an obstacle than a helper by users. With reCAPTCHA this is different, because all the user needs to do is click on one checkbox, confirming you’re not a robot. This way everyone wins, the user has faster access to the desired information, and you keep unwanted visitors from your site.

Awesome! I want to have one of those, like I do?

The first step is you get a key to your website. Go to the site below and click the blue button located at the top-right position of the site, written "Get reCAPTCHA": https://www.google.com/recaptcha/intro/index.html

After registering your site, you will have in hand two important information: a site key, and the secret (I’ll call it a secret key). The first step to implementing reCAPTCHA on your site is to insert the API on your site. Enter the code within the tag head of your website:

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

All set for the next step.

Creating the form

Create a common form, I did it with two fields: one for the user to put the name, and another for any message. The markup was 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 at the position you want it to appear:

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

Don’t forget to replace YOUR KEY by the key you received on the site, remembering that is the site key, not the secret key!

Replace the property action on the tag form for 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 for the code to be simpler.

But I can’t validate using Javascript on the fly?

No :) You will already understand why.

Creating PHP code to validate the form

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

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

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

From here the captcha validation actually happens. It is sent to us via POST a value provided by reCAPTCHA, it is possible to recover this value by the variable $_POST['g-recaptcha-response']. Soon:

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;
}

Looks like it’s over, huh? No! Now that comes the fun part, remember when I said it was necessary that captcha had to go through a PHP validation? This is necessary because reCAPTCHA uses information in Google’s database, which contains various information about the user who "performed" 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 the file_get_contents. Observe:

$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 SECRET KEY and replace it with yours. What this command does is recover data in the reCAPTCHA API by information about the values that were provided by captcha, and send the user IP for future evaluations.

With the request sent, we only have to process the reply:

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 understand how the system works. Any doubt you know, we are here to help. ;)

  • 1

    Dude, after almost tearing my hair out for two days, here I was able to solve the problem of a Recaptcha wasn’t working on a new client. For some reason there was no way to work and with your guidelines IT WORKED! : ) Thank you

16

COMPLETELY REWORDED RESPONSE. Reason: I put the information as I was discovering it and it got really bad. I thank Rafael Almeida for the first reply, which helped me a lot and led me to discover more. And the administrators, who made changes that guided me to improve the response. My answer is 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’t validate using Javascript on time?

You could even do, 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 on reCAPTCHA, it does not release until the user gives the right answer. At least I saw nothing else happen except with or without the mark "check in" 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 didn’t answer or answered correctly.

What seems to be useful here to check the JS before sending it to PHP to see if the user has even 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 runs on onsubmit 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 It didn’t work out for me. Initially, I thought the problem was the function sending method (GET, while the reCAPTCHA site says it needs to be POST). Later, I discovered that it works perfectly in the copy of the website hosted on my PC. That is, it is the hosting server (I use Hostmedia) that blocks. I still tried, but unsuccessful:

ini_set('allow_url_fopen', 1)

The alternative response, based on cURL, can be useful for those who have the site in the same or other hosting that also blocks. Anyway, it may be interesting to avoid that in case of Warning, is not recorded on log the URL including the secret key. Follow 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 website instructions, there is an indication of a library that is on github, in /google/recaptcha. It also works well: just put the ZIP src folder downloaded somewhere on the site and use code similar to their example. The only problem is I was making the following mistake:

invalid-json

Then I found hint in another article Stackoverflow (indication of the method CurlPost):

$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 whether the problem was in the hosting or in the library class itself.


  • And how to install the ReCaptcha\ReCaptcha? Via Composer?

0

Follow a complete implementation of reCaptcha I’m using on a site I’m developing, the only thing missing to work 100% is to create the objects, but I left well 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>
        <script src='https://www.google.com/recaptcha/api.js'></script>
        <script>
            $(document).ready(function() {
                $('#send').prop('disabled', true);//desativa o botão enviar
                $('.g-recaptcha').hide();//esconde o captcha
                validate();
                $('#inputEmail, #inputPassword').change(validate);
            });
            function validate() {
                if ($('#inputEmail').val().length > 10) {//enquanto o campo de email nao tiver menos que 10 caracteres, não ativa o reCaptcha
                    $('.g-recaptcha').show();//exibe o reCaptcha
                }else{//se mudar de ideia e reduzir o campo pra menos de 10 caracteres...
                    $('.g-recaptcha').hide();//o reCaptcha se esconde novmanete
                }
            }
            function enableSend() {
                $('#send').prop('disabled', false);//quando o captcha é confirmado, ativa o botao enviar
            }
        </script>
    </head>

    <body>
    <?php
    $helper = new Helpers();//-->objeto com vários métodos importantes
    if (isset($_POST['attempt'])){//verifica se tem tentativa restante
        $attempt = intval($helper->validation($_POST['attempt']));//validation=método que verifica e escapa minha sring (trim(), stripcslashes() e htmlspecialchars())
    }else{
        $attempt = 3;//se não for definido número de tentativas, aqui é definido como 3
    }

    if (isset($_POST['g-recaptcha-response']) and isset($_POST['username']) and isset($_POST['password'])) {//garante que todos os campos foram preenchidos
        $captcha_data = $_POST['g-recaptcha-response'];
        if ($captcha_data) {//Verificação do reCaptcha
            $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>

Browser other questions tagged

You are not signed in. Login or sign up in order to post.