Please note that the forum isn't realy used anymore.

If you have questions, want support or just simply want to talk to us you can find us on slack.

 

Google Recaptcha in FormBuilder Guide

For a client I had to add ReCaptcha as we noticed an increase in spam. The Akismet protection only works for blog comments and the hidden checkbox defense did not work sufficiently. We couldn't really find a module for this (or we forgot how to Google?).

First we wanted to go with the extending the FormBuilder as we also upgraded @jdesloovere's file plugin to work with Fork 3.9. Unfortunately this was too much of a hassle with the dependency on the legacy Spoon Framework. I opted to 'hack' in the the ReCaptcha for now as we will do a major overhaul of the website once Twig support is stable.

It turned out to be fairly simple.

Please note that this guide is more of a hack and not really an extension. Furthermore we didn't use *phpcs to validate the code as this will not go into the contributions.*

0. Dependencies

  • Fork CMS 3.9 (might work in previous versions as well but untested)
  • cURL and php_curl

1. Sign up for Google ReCaptcha

Go to https://www.google.com/recaptcha and register a new website.

2. Add the javascript to your head.tpl file

Add this snipped just before you close the header using the tag.

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

3. Edit your form

Go to our form and add a paragraph item to your form where you would like to have your ReCaptcha appear.

<div class="g-recaptcha" data-sitekey="[public-site-key from step 1]">Please verify your enquiry.</div>

4. Add your private ReCaptcha key and verify URI

In app/config/parameters.yml add the following:

recaptcha.api_key: [secret] recaptcha.verify_url: https://www.google.com/recaptcha/api/siteverify

If this parameter works in dev but not in prod don't forget to clear your cache.

5. Edit Frontend\Modules\FormBuilder\Widgets\Form

Because we also have forms without the ReCaptcha we had to add the if statement. Based on the spam attack vector they could just not include the POST parameter and it could potentially fail. If you have ReCaptchas in all your forms you can adapt the above to always validate the post parameter. Another option is to check by form name or id but this implies you need to edit the code below every time you add a new form. We did notice an decrease in spam using the method below.

Before

// validate fields

Add

       // get the request object
        $request = Request::createFromGlobals();
        array_key_exists('g-recaptcha-response', $request->request->all()) ? $recaptcha = true : $recaptcha = false;

        // we added recaptcha in this form so need to validate
        if($recaptcha) {
            $status = $this->recaptcha($request->request->get('g-recaptcha-response'));
            if(!$status) {
                $this->frm->addError(FL::err('FormReCaptcha'));
            }
        }

This implies that use have the Symfony Request object in your use statements.

Before the end of the class add the following private functions.

/**
 * @return string
 */
private function getIp()
{
    if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
        $ip = $_SERVER['HTTP_CLIENT_IP'];
    } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
    } else {
        $ip = $_SERVER['REMOTE_ADDR'];
    }
    return $ip;
}

/**
 * @return bool
 */
private function recaptcha($response)
{
    $ch = curl_init();

    curl_setopt($ch, CURLOPT_URL, $this->getContainer()->getParameter('recaptcha.verify_url'));
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS,
        http_build_query(
            array(
                'secret' => $this->getContainer()->getParameter('recaptcha.api_key'),
                'response' => $response,
                'remoteip' => $this->getIp()
            )
        )
    );
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $server_output = curl_exec($ch);

    // successful cURL request to Google's Recaptcha and extract the verification result
    if($server_output) {
        return json_decode($server_output)->success;
    }

    // We couldn't perform the cURL request
    return false;

}

6. Add the error translation message

Go to your translations and add an error message with FormReCaptcha as key. Select Frontend and Error from the dropdowns.

Any feedback is appreciated!

Comment

The forum is deprecated in favor of our Slack channel, which provides real-time support for your issues.

Join us on Slack here: https://fork-cms.herokuapp.com/