Web Development with PHP and MySQL

Dynamic, database-driven small business web sites done right.    

Try Firefox



See also
phpvs.com

 

Prevent Form Spam - How to reduce and/or prevent spam sent by Contact Us forms

Update 23 November 2008 - I've been working on a Basic Multi-Language AJAX / PHP web "Contact Form" that includes minimal basic Javascript validation examples. I'd appreciate it if a few PHP developers would request a copy of the files and provide feedback about the project's usability.

Banning user agents based on IP address can be a waste of time if the IP address is spoofed. If someone is smart enough to create a spam-bot, they're also smart enough to spoof the IP address sent with the request.

Open your stylesheet and add a new style class that suppresses the display of a particular class.

input.my-url{display:none;}

Open your Contact form and add a field named "my_url" near the submit button.

<input type="text" name="my_url" class="my-url" value="">

In your script which validates user input for the Contact form, evaluate the contents of $_POST['my_url']. It should be empty. The stylesheet should have suppressed display to humans, but a spam robot would likely enter a value.

<?php if(!empty($_POST['my_url'])){ die('Have a nice day elsewhere.'); } ?>

Another technique is to instantiate sessions using PHP. This should initialize $_COOKIE['PHPSESSID']. Simply suppress the display of your Contact form if $_COOKIE['PHPSESSID'] is not set, and echo a statement about cookies being required for form submission. This is relatively easy to do, and may prevent some spambots from ever seeing your Contact form.

While using PHP sessions, generate a random string when the user first arrives at the site, and save it in a session variable. On the Contact form, break up the random string into about 4 chunks, each displayed using a different font color. Ask the user to enter the red characters in a box near the submit button. Validate the submitted data and generate an error message if the wrong value is posted. An example of this is available here. Robots won't be able to guess the random string. A red string of letters is easier for the user to deal with than skewed Captcha images.

Using random questions and answers can also work, but if the site evolves into a multi-language site, then there are more translations required. Usage of a randomly generated string is less hassle than translating a bunch of questions and answers.

Spambots often post the same data to multiple fields, often "http://" or "[url". Most validation scripts loop through the $_POST variables. When looping through the $_POST values, conditionally increment a counter.

<?php
$http_counter = 0;
foreach($_POST as $key => $val){
   if(stristr($val, 'http://')){ $http_counter++; }
   if(stristr($val, '[url=')){ $http_counter++; }
}
// Legitimate users might enter one URL in their message.
if($http_counter > 1){ die('Have a nice day elsewhere.'); }
?>

Validate fields against one another ... disallow the posting the same value to multiple fields. Proper validation of user input is key to beating form spam.

Refrain from displaying email addresses on web page in text form. Display images instead, or force users to use the Contact form in order to help measure user interest in the site.

You can find some examples of PHP code for forms and validation of user input by visiting this project where you can select a MySQL database, select a table, and then select the type of code to generate. The selected table is analyzed and a variety of forms generated in a few seconds. For your other form needs, see also PHP Form Generator.

<?php
function remove_html_entities($str)
{
   // Remove HTML entities from a submitted string
   return preg_replace("/&[a-z0-9]{2,6}+;/i", '', $str);
}
// usage
if(stristr($str, '&'))){ $str = remove_entities($str); }
?>

Spammers often post alpha characters a-z to Zip Code fields. Upon validation, check that 5 or more digits (0-9) are present. Similarly, you might also want to test Telephone fields for 10 numeric digits after stripping out alpha characters.

if($_POST['zip']){
   $test = strlen(trim(preg_replace("/[^[:digit:]]/", '', $_POST['zip'])));
   if($test < 5){
      $errors['zip'] = 'Please enter a valid zip code';
   }
}

If form users are posting unwanted HTML entities to forms, you might apply this function in an attempt to filter them out.

function remove_entities($str)
{
   return preg_replace("/&[a-z0-9]{2,6}+;/i", '', $str);
};

Spammers usually spoof their IP address. Thus, banning future access to the site based on an IP address is probably a waste of time.

A non-empty address field should always contain at least one space character. Validating for 2 spaces might be excessive.

if($_POST['address']){
   $pos = stripos($_POST['address'], ' ');
   if(empty($pos)){
      $errors[] = 'The address entered does not appear to be valid';
   }
}

Consider adding two hidden fields having similar names such as token1 and token2. Populate token1 with a random value. Populate token2 with a reversed string using PHP's strrev() function, and then validate upon POST. Many spammers will post data to both fields and never expect validation to sort of mirror each other.

// When form is loaded apply
$token1 = md5(uniqid(rand(), TRUE));
$token2 = strrev($token1);
// HTML for the form
<input type="hidden" name="token1" value="<?php echo $token1; ?>">
<input type="hidden" name="token2" value="<?php echo $token2; ?>">
// Input validation on POST
if(empty($_POST['token1']) || $_POST['token1'] != strrev($_POST['token2'])){
   die('Trouble in paradise');
}

 

web hosting