Anti-Spam and Captcha

Spam is a big problem on the web. If you leave your contact form unsecured on your website it won't be long before you have many, many spam responses. Fortunately, Concrete CMS contains several systems to combat this plague. All user-facing forms, including those used by the Form block, the Survey block, and the registration system route their input through our Anti-Spam layer. Additionally, Captcha is an option on all these forms.

Enabling Anti-Spam and Captcha

Want more information on how to enable this functionality on your site? Check out the Captcha and Spam Control sections of the Editors Documentation.

Adding Captcha Support To Your Forms

To add a captcha to your own own custom form, just add this code to the bottom of the view layer:

<form method="post" action="<?=$view->action('submit_form')?>">
<?php
$captcha = Core::make('captcha');
?>
<div class="form-group">
    <label class="control-label"><?=$captcha->label()?></label>
    <div><?php $captcha->display(); ?></div>
    <div><?php $captcha->showInput(); ?></div>
</div>
</form>

That will display the output of the selected Captcha library.

Next, you'll need to check the Captcha when your form is submitted.

public function submit_form()
{
    $captcha = \Core::make("captcha");
    if ($captcha->check()) {
        // Proceed with submission
    } else {
        // Show the captcha error to the end user...
    }
}

That's it! Your form is now protected by a captcha.

Adding Anti-Spam Support to Your Forms

It's similarly simple to add anti-spam support to your forms. Let's say the form above has the following input fields it's tracking:

  • first_name
  • last_name
  • feedback

We want to check these fields for spam. We'll take the method above and add the following code:

$antispam = \Core::make('helper/validation/antispam');
$message = "First Name: {$this->request->request->get('first_name')}\n";
$message .= "Last Name: {$this->request->request->get('last_name')}\n";
$message .= "Feedback: {$this->request->request->get('feedback')}\n";
$u = new \User();
$additionalArgs = array('user' => $u);
if (!$antispam->check($message, 'feedback_form', $additionalArgs)) {
    return false;
}

This is pretty self-explanatory: first, we load up the anti-spam service. Next, we craft a single string that contains all the elements we want to check for spam. Then we retrieve the current user's User object, and pass it in as an additional argument. Finally, we run the check() method on our anti-spam library. If it returns false, that means the message is thought to be spam, and we return silently.

Building Your Own Captcha Service

The Anti-Spam and Captcha services are meant to be extendable; by default, Concrete doesn't come with any Anti-Spam services installed, and only the fairly basic SecurImage Captcha as the default Captcha library. It is easy to write your own Captcha and Anti-Spam libraries as part of a Package.

First, install your Captcha

In your package's install() method, you'll want to install your Captcha library. Let's say you've written a package named "Awesome Captcha" with the package handle "awesome_captcha" and you want to actually name the Captcha object itself "Awesome Captcha"

public function install()
{
    $pkg = parent::install();
    \Concrete\Core\Captcha\Library::add('awesome_captcha', t('Awesome Captcha'), $pkg);
}

That's it! Concrete now believes there to be a valid Captcha library with the handle "awesome_captcha".

Next, a Captcha Class

Now, you'll need to create a capcha class within your package. If you add this to your package controller:

$pkgAutoloaderMapCoreExtensions = true;

your file will be found here:

packages/awesome_captcha/src/Concrete/Captcha/AwesomeCaptchaController.php

and its namespace will be

namespace Concrete\Package\AwesomeCaptcha\Captcha;

If you don't add $pkgAutoloaderMapCoreExtensions = true to your class, the file will be found here:

packages/awesome_captcha/src/Captcha/AwesomeCaptchaController.php

and its namespace will be

namespace Concrete\Package\AwesomeCaptcha\Src\Captcha;

Once you've added your class in the right spot, you'll need to implement the required methods:

  • showInput() - shows an input on the page for this Captcha library
  • display() - Displays the graphical portion of the Captcha
  • label() - Displays the label for the form
  • check() - Runs server-side to validate the submitted Captcha

Optional: Custom Options Form

Does your Captcha have custom options? For example, to use Google's ReCaptcha captcha service, you'll need to provide an API key. Fortunately the Concrete Captcha system makes it easy to ask for custom options in the Dashboard, and save them against the captcha library.

First, simply create a form at packages/awesome_captcha/elements/system/captcha/awesome_captcha/form.php. This is simple HTML/PHP form, containing form fields for whatever custom elements you need to track against your captcha.

Then, simply define a saveOptions($data) method in your controller above, which is responsible for saving the data submitted in the form. Typically, we would use the Configuration system to store this data.

Example

A great, full-featured example of a working Captcha in a package is the ExchangeCore ReCaptcha Add-On

Building Your Own Anti-Spam Provider

First, install your Provider

In your package's install() method, you'll want to install your Anti-Spam library. Let's say you've written a package for the Wordpress "Akismet" Anti-Spam service with the package handle "akismet" and you want to actually name the Captcha object itself "Akismet"

public function install()
{
    $pkg = parent::install();
    \Concrete\Core\Antispam\Library::add('akismet', t('Akismet'), $pkg);
}

That's it!

Next, an Anti-Spam Class

Now, much like the Captcha class, you'll need to create an Anti-Spam class within your package. If you add this to your package controller:

$pkgAutoloaderMapCoreExtensions = true;

your file will be found here:

packages/akismet/src/Concrete/Antispam/AkismetController.php

and its namespace will be

namespace Concrete\Package\Akismet\Captcha;

If you don't add $pkgAutoloaderMapCoreExtensions = true to your class, the file will be found here:

packages/awesome_captcha/src/Antispam/AkismetController.php

and its namespace will be

namespace Concrete\Package\AwesomeCaptcha\Src\Antispam;

Once you've added your class in the right spot, you'll need to implement the required methods:

  • check($data) - Checks the submitted data for spam. Returns true if the data is free of spam.
  • report($data) - Reports spam to the Spam service

Optional: Custom Options Form

Does your Captcha have custom options? For example, to use Google's ReCaptcha captcha service, you'll need to provide an API key. Fortunately the Concrete Captcha system makes it easy to ask for custom options in the Dashboard, and save them against the captcha library.

First, simply create a form at packages/akismet/elements/system/antispam/akismet/form.php. This is simple HTML/PHP form, containing form fields for whatever custom elements you need to track against your captcha.

Then, simply define a saveOptions($data) method in your controller above, which is responsible for saving the data submitted in the form. Typically, we would use the Configuration system to store this data.