My friend the spammer !

Stop spammers (part 2) : Using Stop Form Spam module

wednesday 03 july 2013 at 15h19 • categories : How to

In the first part, we learned how to create one custom registration form.
We also tried to limit spam by adding one hidden field, supposed to be filled out by bots.

Unfortunately, bots learned how to not fill out hidden fields, so the honey pot isn't a good antispam system anymore.
Let's use the new SFS ionize module to check our friend's IP and email against the "Stop Forum Spam" database.

What is Stop Form Spam ?

The SFS (Stop Form Spam) module uses the the Stop Forum Spam database to avoid been spammed by of known spammers.

Basically, when someone strongly suspect a spammer, he send the spammers data (IP, username, email, evidence data) to the StopForumSpam website.
What the module will do is to check if the IP or the email already exists in this database. If one of these exists in the StopForumSpam database, the module will tell us.

The module can also send your own data about spammers if you get one API key.
This is optional and is not needed to make the module work.

Install the SFS module

The SFS (Stop Form Spam) module needs ionize 1.0.4.

You can download it here : https://github.com/ionize/ionize-module-sfs

  • Copy the folder "Sfs" into the "/modules" folder of your Ionize installation.
  • In the ionize backend, go to : Modules > Administration
  • Click on "install"
  • Reload the backend panel

Setup the module

  • In ionize, open the admin panel of the module
  • In the setup field called "Event", set one event, for example "Myform.register.check"
    This event will be used by the module to check the posted data

Optional : If you wish to also send your spammers data :

  • Get one API key by registering on : http://www.stopforumspam.com/signup
  • Setup the API key in the API key field
  • Fill in the "evidence" field (which is basically the content the spammer sent you, like the message content)
  • Setup the fields used as username

Setup your Registration Form processing method

In the previous part, we created one custom Registration Form processing method.

We will modify this method to add the module's check.
Edit the file : /themes/your_theme/libraries/Tagmanager/Register.php :

<?php

class TagManager_Register extends TagManager
{
    public static function process_data(FTL_Binding $tag)
    {
        if (TagManager_Form::validate('register'))
        {
            $post = self::$ci->input->post();

            // Fire the event we setup : returns an array
            $results = Event::fire('Myform.register.check', $post);

            $return = TRUE;

            if (is_array($results))
            {
                foreach($results as $result)
                    if ( ! $result)
                        $return = FALSE;
            }

            // The user can register
            if ( return == TRUE)
            {
                // Get user's allowed fields
                $fields = TagManager_Form::get_form_fields('register');
                if ( is_null($fields))
                    show_error('No definition for the form "register"');

                $fields = array_fill_keys($fields, FALSE);
                $user = array_merge($fields, self::$ci->input->post());

                // Compliant with User, based on username
                $user['username'] = $user['email'];
                $user['join_date'] = date('Y-m-d H:i:s');

                // Register fails ?
                if ( ! User()->register($user))
                {
                    $message = User()->error();
                    if ( empty($message))
                        $message = TagManager_Form::get_form_message('error');

                    TagManager_Form::set_additional_error('register', $message);
                }
                else
                {
                    // Get the user saved in DB
                    $user = self::$ci->user_model->find_user($user['username']);

                    if (is_array($user))
                    {
                        // Must be set before set the clear password
                        $user['activation_key'] = User()->calc_activation_key($user);

                        $user['password'] = User()->decrypt($user['password'], $user);

                        // Merge POST data for email template
                        $user = array_merge($user, self::$ci->input->post());

                        // Create data array and Send Emails
                        $user['ip'] = self::$ci->input->ip_address();

                        // Add the SFS API key to the data we will use in the email
                        $sfs_config = Modules()->get_module_config('Sfs');
                        $user['sfs_api_server'] = $sfs_config['api_server'];
                        $user['sfs_api_key'] = $sfs_config['api_key'];
                        $user['sfs_username'] = urlencode($user['firstname'].' '.$user['lastname']);
                        $user['sfs_evidence'] = urlencode($user['message']);

                        TagManager_Email::send_form_emails($tag, '', $user);

                        $message = TagManager_Form::get_form_message('success');
                        TagManager_Form::set_additional_success('register', $message);

                        // Potentially redirect to the page setup in /application/config/forms.php
                        $redirect = TagManager_Form::get_form_redirect();
                        if ($redirect !== FALSE) redirect($redirect);
                    }
                    else
                    {
                        $message = TagManager_Form::get_form_message('error');
                        TagManager_Form::set_additional_error('register', $message);
                    }
                }
            }
            // User cannot register
            // Let's tell him he registered successfully !
            else
            {
                Event::fire('User.register.check.fail', $post);

                $message = TagManager_Form::get_form_message('success');
                TagManager_Form::set_additional_success('register', $message);

                $redirect = TagManager_Form::get_form_redirect();
                if ($redirect !== FALSE) redirect($redirect);
            }
        }
    }
}

We added the SFS result data to the data we send to TagManager_Email::send_form_emails().

The purpose is simply to be able to use these data to build one link to be able to submit the user's data to the Stop Forum Spam database if this spammer wasn't found.

Build one link to submit unknown spammer to SFS

When one user register, 2 emails are sent :

  • One to the user, with its data and the activation link
  • One to the admin of the website

We will create one custom admin email, with one link to the spammer submission API of Stop Forum Spam.

Create the custom email view

Copy the file :
/application/views/mail/register/to_admin.php
to :
/themes/your_theme/views/mail/register/to_admin.php
.

ionize will use the theme view instead the default's core one.

Adapt the custom email view

Edit the file /themes/your_theme/views/mail/register/to_admin.php and add, after <ion:message /> (at the bottom of the email) :

<p style="font-size: 11px;color: #444;">
   <br/>
   <br/>
   Declare as SPAM :<br/>
   <a href="<ion:data:sfs_api_server />/add?api_key=<ion:data:sfs_api_key />&username=<ion:data:sfs_username />&email=<ion:data:email />&ip_addr=<ion:data:ip />&evidence=<ion:data:sfs_evidence />">
      <ion:data:sfs_api_server />/add?api_key=<ion:data:sfs_api_key />&username=<ion:data:firstname />%20<ion:data:lastname />&email=<ion:data:email />&ip_addr=<ion:data:ip />
   </a>
</p>

That's it !

We now have one registration form protected against spam with the SFS module.