Spam-less And Robot-less Forms With jQuery

This tutorial has been converted to a jQuery plugin which you can find here – http://jasonlau.biz/home/a-better-form-a-jquery-plugin

Are you trying to figure out how to reduce or eliminate spam on your website email or comment forms?

My website was slammed by spammers on a daily basis. Typically, the spam attacks would be from robots that would root-out the form fields on each webpage and then automate form submissions which were loaded with spam.

I created an easy solution that does not involve the use of annoying CAPTCHA security phrase generators or similar technology blunders.

My idea does however require javascript and jQuery.

The idea is simple – spam-bots cannot submit a form that does not exist. Nor can spam-bots use a form field which has no name. So, if you remove the form elements from the webpage you effectively stop the robots.

How can I use a form that does not exist? That is easily done with jQuery. I’ll
show you how.

  1. Include jQuery in the HTML document’s <head> section before the </head>
    tag .

    <script src=”http://code.jquery.com/jquery-latest.js” type=”text/javascript”></script>

  2. Add a <noscript> tag to your document body so visitors will know javascript
    is needed to use the website. I found it’s best to add this tag to the end
    of the HTML body so that it does not affect how your website is displayed
    in search engine results. Adding it to the beginning may cause it to show
    up as the description for your webpage in the search engine results.

    <noscript>Javascript
    is required to view this webpage properly. Please enable javascript in your
    browser settings.</noscript>

  3. Create a div container for your form in your HTML document’s <body>
    section before the </body> tag.

    <div
    id=”form-container”></div>

  4. Make a form inside the form-container div following these simple rules.
    1. When you make your form do not include the <form> tag. The form
      tag is a target for robots.
    2. Rather than using the name attribute for each form field, use
      the id attribute instead. The name attribute is another target
      for robots.
    3. If you need to include a submit button in your form, use type=button
      instead of type=submit.
    4. Add disabled=”disabled” to each form element except the first.
    <strong>Email:</strong> <input id=”email” />
    <strong>Comment:</strong>
    <textarea id=”comment” disabled=”disabled”></textarea>
    <input type=”button” id=”sub-button” value=”Submit” disabled=”disabled”
    />

  5. After the form is assembled, go back to the <head> section where the
    script for the form will be placed.
  6. Make a jQuery javascript block which will call jQuery on page load. The
    form script will be placed where noted in the script below.

    <script type=”text/javascript”>

    $(document).ready(function () {

    // Form script goes here

    });
    </script>

  7. I am going to include some basic email address validation in this example
    which will verify that the email field is actually an email address.

    var checkRegexp = function(o,regexp){
    if(!(regexp.test(o.val()))){
    return false;
    } else {
    return true;
    }
    };

  8. I disabled most of the form fields in step 4-4 so the user must follow a
    certain order while filling in form data. To make this work, I will make a
    script to enable or disable each field based on user interaction. Basically,
    if there is no data in field 1, field 2 is disabled. Field1 is not enabled
    until field 2 value has changed and contains data, and so on. Also, this is
    where I implement the email address validation. In this example, when the
    email field is changed, the address is validated and the user is alerted if
    validation fails.

    $(“#email”).change(function(){
    if(!$(“#email-tip”).html()){
    $(this).after(‘<div id=”email-tip” style=”display: none; background-color:
    #FFFFFF;”>Please enter a valid email address.</div>’);
    }

    if($(this).val() != ” && $(this).val() != ‘ ‘ && !checkRegexp($(this),/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i))
    {
    $(“#comment”).attr(‘disabled’,'disabled’);
    $(“#email-tip”).show();
    $(“#email-tip”).animate( { fontSize:”2em” } , 500 )
    .animate( { fontSize:”1em” } , 500 );
    } else {
    if($(“#email-tip”).attr(‘display’) != ‘none’){
    $(“#email-tip”).hide(‘slow’);
    }
    $(“#comment”).attr(‘disabled’,”);
    }
    });

    $(“#comment”).change(function(){
    if($(this).val() != ” && $(this).val() != ‘ ‘) {
    $(“#sub-button”).attr(‘disabled’,”);
    } else {
    $(“#sub-button”).attr(‘disabled’,'disabled’);
    }
    });

  9. If you want to eliminate certain types of user input, such as html links
    or bbcode links, here is a handy little addition I made just for that.

    $(“#comment”).bind(“keyup”,function(){
    var comment_filters = ['url=','link=','http:','www.','href','<a'];
    var comment = $(“#comment”).val();
    for(var i in comment_filters){
    var checkit = comment.split(comment_filters[i]);
    if(checkit.length > 1){
    $(“#comment”).val(checkit[0]);
    }
    }
    });

    That script will basically erase the unwanted input AS the user attempts to
    type it into the form. The offending input will simply disappear before their
    very eyes. I have added a number of filters to the variable comment_filters
    which will eliminate links from the user input. There is no limit to the number
    of filters I can use. Of course, the user could always type in spaces between
    each letter to post links, but they will not be click-able, followable, or
    even copy/paste-able. Too much work for a spammer!

  10. Everything is ready now for the form submission script. Once the user has
    appropriately filled in all of the form fields the submit button has been
    enabled and the form is ready to submit.

    In earlier steps I left out the form
    tag, left out all of the name attributes, and made a regular button
    instead of a submit button. Now I have to fix all of that, but only after
    the user has actually interacted with the button. I will bind a click
    function to the button object so that the user must use a mouse to manually
    click the button; an action a spam-bot is unable to reproduce. This function
    will wrap the form-container div with a form tag, will add the name attributes
    to the input fields, and finally, will submit the form for processing.

    For each input, textarea, or select menu, this script will create a name attribute
    by copying the id attribute for that object. This only takes place in the
    form-container so it does not affect other forms on the same page.

    $(“#sub-button”).bind(“click”,function(){
    $(‘#form-container input, #form-container textarea, #form-container select’).each(function(){
    $(this).attr(‘name’,$(this).attr(‘id’));
    });

    $(‘#form-container’).wrap(‘<form id=”comment-form” action=”#” method=”POST”></form>’);
    alert(‘Your comment has been submitted!’);
    $(“#comment-form”).submit();
    });

  11. Save.

So, as you can see, I have created a form that is not really a form at all. My
form is lacking the elements that spam-bots rely upon for automated submissions.
My method will eliminate most if not all of the automated form submissions on
your website.

Here is the complete, working code:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">

<head>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
<meta name="author" content="Jason Lau" />

<title>JasonLau.biz Robot-less And Spam-less Forms With jQuery</title>
<script src="http://jasonlau.biz/javascript/jquery/latest/jquery-latest.js"
type="text/javascript"></script>
<script type="text/javascript">
<!–
/* Spam-less Robot-less Forms Example – (c)2010 JasonLau.biz */
$(document).ready(function(){
var checkRegexp = function(o,regexp){
if(!(regexp.test(o.val()))){
return false;
} else {
return true;
}
};

$("#email").change(function(){
if(!$("#email-tip").html()){
$(this).after('<div id="email-tip" style="display: none; background-color:
#FFFFFF;">Please enter a valid email address.</div>');
}
if($(this).val() != '' && $(this).val() != ' ' && !checkRegexp($(this),/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i))
{
$("#comment").attr('disabled','disabled');
$("#email-tip").show();
$("#email-tip").animate({ fontSize:"2em" },500)
.animate({ fontSize:"1em" },500);
} else {
if($("#email-tip").attr('display') != 'none'){
$("#email-tip").hide('slow');
}
$("#comment").attr('disabled','');
}
});

$("#comment").change(function(){
if($(this).val() != '' && $(this).val() != ' '){
$("#sub-button").attr('disabled','');
} else {
$("#sub-button").attr('disabled','disabled');
}
});

$("#comment").bind("keyup",function(){

var comment_filters = ['url=','link=','http:','www.','href','<a'];

var comment = $("#comment").val();
for(var i in comment_filters){
var checkit = comment.split(comment_filters[i]);
if(checkit.length > 1){
$("#comment").val(checkit[0]);
}
}
});

$("#sub-button").bind("click",function(){
$('#form-container input, #form-container textarea, #form-container
select').each(function(){
$(this).attr('name',$(this).attr('id'));
});
$('#form-container').wrap('<form id="comment-form" action="#"
method="POST"></form>');
alert('Your comment has been submitted!');
$("#comment-form").submit();

});
});
–>
</script>
</head>

<body>

<div id="form-container">
<strong>Email:</strong> <input id="email" /><br />
<strong>Comment:</strong><br />
<textarea id="comment" disabled="disabled"></textarea><br />
<input type="button" id="sub-button" value="Submit" disabled="disabled" />
</div>

<noscript>Javascript is required to view this webpage properly. Please enable
javascript in your browser settings.</noscript>

</body>
</html>