05 - May - 2009

Whipping Mollom into analysing custom Drupal forms

Post by Mike C

Mollom is a web service that helps you identify content quality and, more importantly, helps you stop spam on your blog, social network or community website. The goal is to make moderation easier, you have more time and energy to interact with your community.

The Mollom service definitely reduces the amount of junk form submissions coming through, however the current (v1.7 at the time of writing) Mollom Drupal module isn't very flexible in what forms in your Drupal powered site it will protect.

All the common forms are covered: user registration, user log in, commenting, node creation. However when you want to protect a custom form on your site there's no documented clean way to add support. With a bit of mollom.module tracing and some test hacking this morning I've come up with a solution to add Mollom analysis to you custom forms using a relatively small module.

You might need some PHP programming skills to understand the next part, but some copy and pasting coupled with trial and error can get you far.

First you need to add in Mollom support to your custom form when it's being displayed on the page. You'll need to know the unique form_id, which is easy enough to work. We'll add in the custom Mollom form element using Drupals powerful/magic hook_form_alter() API hook.

In this exercise we'll add Mollom content analysis to a form created using the excellent webform.module. You can determine the correct form_id by printing the $form_id variable to the screen at the beginning of the custommollom_form_alter() function.

function custommollom_form_alter(&$form, $form_state, $form_id) {
  if ($form_id == 'webform_client_form_170') {
    // Add Mollom support if module enabled
    if (module_exists('mollom')) {
      // Add Mollom form protection widget.
      $form['mollom'] = array( '#type' => 'mollom', '#mode' => MOLLOM_MODE_ANALYSIS );
      // Add a submit handler that will clean the Mollom state
      // as soon as the form is successfully submitted.
      $form['#submit'][] = 'mollom_clean_state';
    }
  }
}

Webform module is a little tricky as it adds the node ID to each form_id making them unique and more clumbsy to support in a simple one-module-fits-all solution.

Analysing Data

The secret to the Mollom support is the '#type' => 'mollom' that we inject in to the 'webform_client_form_170' form.

$form['mollom'] = array(
  '#type' => 'mollom',
  '#mode' => MOLLOM_MODE_ANALYSIS
);

   When the form is rendered, the mollom #type element is expanded by the mollom_expand_element() function. How that magic works is beyond this post though.

The #mode can be set to two possible options:

  • MOLLOM_MODE_CAPTCHA will inject a CAPTCHA based challenge form widget in to the form, as well as a sound playback option for accessibility. If you want to use this mode you may want to copy and paste the code from the mollom_form_alter() to ensure the CAPTCHA widget is correctly positioned at the end of the form.
  • MOLLOM_MODE_ANALYSIS provides a more streamlined check on form submission by analysing the submitted form values. I opted for this as it removes messy form fields ruining our page layout.

When a form is submitted Mollom jumps in and collects up the data from the form submission in order to send it to the Mollom server for analysis. This is handled in the mollom_validate_analysis() function. Only two cases are catered for here - create node forms, and everything else. In order to not hack the mollom.module we'll fall in to the "everything else" category. Mollom attempts to call a custom named function which matches your form_id (as specified in the custommollom_form_alter() function above). The function is built from 'mollom_data_'. $form_id

function mollom_data_webform_client_form_170($form_state) {
  global $user; $body = '';
  foreach($form_state['submitted'] as $field) {
    $body .= $field . '\n';
  }
  $data = array(
    'post_title' => NULL,
    'post_body' => isset($body) ? $form_state['submitted']['enquiry'] : NULL,
    'author_name' => isset($form_state['submitted']['your_name']) ? $form_state['submitted']['your_name'] : (isset($user->name) ? $user->name : NULL),
    'author_mail' => isset($form_state['submitted']['your_email_address']) ? $form_state['submitted']['your_email_address'] : (isset($user->mail) ? $user->mail : NULL),
    'author_url' => NULL, 'author_openid' => NULL,
    'author_id' => $user->uid > 0 ? $user->uid : NULL,
    'author_ip' => ip_address(),
  );
  return $data;
}

   The custom data function maps our webform fields to Molloms data structure. Now all fields are required, but the more you can map the better. The mollom.module has a number of examples you can learn/copy from _mollom_data_contact_mail(), mollom_data_comment_form() etc.

Mollom Developer Mode

The mapping of the 'post_body' can be important during testing. In the above function you may have noticed that I aggregated all the webform fields together into a variable called $body. This is then mapped to the Mollom 'post_body' key. However, if you wish to test Mollom is working in developer mode you cannot aggregate all your fields if they have default values (such as a username, date, email address).

The above example is simply mapping a single webform textarea to the 'post_body' which allowed me to enter SPAM, HAM, UNSURE as the test keywords for Mollom and check the responses.

Code

Below is the complete code for a module which adds Mollom submission analysis to a Webform generated Node with an ID of 170.

custommollom.module

<?php
function custommollom_form_alter(&$form, $form_state, $form_id) {
  if ($form_id == 'webform_client_form_170') {
    // Add Mollom support if module enabled
    if (module_exists('mollom')) {

      // Add Mollom form protection widget.
      $form['mollom'] = array(
        '#type' => 'mollom',
        '#mode' => MOLLOM_MODE_ANALYSIS
      );

      // Add a submit handler that will clean the Mollom state
      // as soon as the form is successfully submitted.
      $form['#submit'][] = 'mollom_clean_state';
    }
  }
}

function mollom_data_webform_client_form_170($form_state) {
  global $user;

  $body = '';

  foreach($form_state['submitted'] as $field) {
    $body .= $field . '\n';
  }

  $data = array(
    'post_title' => NULL,
    'post_body' => isset($body) ? $body : NULL,
    'author_name' => isset($form_state['submitted']['your_name']) ? $form_state['submitted']['your_name'] : (isset($user->name) ? $user->name : NULL),
    'author_mail' => isset($form_state['submitted']['your_email_address']) ? $form_state['submitted']['your_email_address'] : (isset($user->mail) ? $user->mail : NULL),
    'author_url' => NULL,
    'author_openid' => NULL,
    'author_id' => $user->uid > 0 ? $user->uid : NULL,
    'author_ip' => ip_address(),
  );

  return $data;
}

custommollon.info

name = Custom Mollom
description = Provides custom form integration for Mollom
core = 6.x
dependencies[] = mollom

  

Conclusion

To add Mollom support to any custom Drupal form you need two functions, one to add Mollom processing to the form during rendering, and a function to map the submitted forms values to Mollom's data analysis structure.

Mike C

Managing Director

12 years of Drupal development wrangling and a background in digital project architecture.

Comments

Absolutely tremendous tutorial. Got me up and running on a specific webform on my site. Just a note to other users who might end up here. In the line(s) which read:

['submitted']['your_name']

you must replace the ['your_name'] piece with the specific input field name in your form. A simple thing, I know, but it saved me a bunch of headaches.
Thanks again.

N

Great info. I was looking for scripts that could hack the mollom captcha from displaying as I am facing some spam attack.

Edmund

Hi, thanks for sharing. That post is great and helped me a big deal. Hope it also helps me fixong my other Drupal problems on spam...

Visitor

Thx for this useful post. I don't like spam either. I'll try Drupal for my blogs then :-)

Pete

Add new comment

Share this article

Sign up to our newsletter!

Our thoughts

Let's work together

Get in touch and find out how we can empower your organisation.
Back to top