One of the duties of a webmaster is to prevent spam bots from submitting web forms. If spammers are not blocked, the data collected from the visitors will contaminated with spam and it's a real nuisance to clean out this data every so often. I have been researching ways to block spam on the web forms we have on our website and found a solution that works reasonably well.

The solution is based on Giorgos Tsiledakis' work, which he posted in Google Project and PHPClasses.org named formSpamBotBlocker (v0.3). I have greatly simplified the class and made the form values URL-friendly so that the class can be used to make Ajax calls. I've also made the public methods static so that the class can be used without instantiating an object.

// This script has been re-written from Giorgos Tsiledakis' 
// formSpamBotBlocker v0.3. The new script removes the session 
// checking feature. The form values are 
// URL friendly for Ajax use, and the script has been simplified greatly.
//
// Edit the private variables for security and customization.

class SpamTrap
{
	private static $version = "0.2";  // Release Version
        // A hash key used to encrypt/decrypt a string.
	private static $hashKey = "4SeCuRiTy";  
	private static $minSubmitTime = 3;    // 3 Seconds.
	private static $maxSubmitTime = 43200;  // 24 Hours. 
        // Name of field where visitor info will be stored.
	private static $visitorName = "_visitor";  
        // Honeypot Field - leave blank to disable. 
        // Do not use typical field names such as
        // "honey", "trap" or "honeypot" in the name.
	private static $honeypotName = "company";
	
	public static function display()
	{
		$visitor = self::encrypt($_SERVER['HTTP_USER_AGENT'] 
                  . $_SERVER['REMOTE_ADDR']);
		$data = "\n";
		$name = "_" . substr($visitor, 0, 8);
		$value = self::encrypt(time());
		$data .= "\n";
		if (!empty(self::$honeypotName)) {
			$data .= "\n";
			$data .= "\n";
			$data .= "\n";
		}
		return $data;
	}
	
	public static function encrypt($data)
	{
		// Base64 is not URL friendly, so translate non-URL friendly characters
		// to URL-friendly characters.
		return strtr(base64_encode($data . self::$hashKey), '+=/', '-_:');
	}

	public static function decrypt($data)
	{
		return  preg_replace('/'.self::$hashKey.'$/', '', 
                          base64_decode(strtr($data, '-_:', '+=/')));
	}
	
	public static function isSpam($data)
	{
		// Check visitor info (user agent and IP).
		$visitorNew = $_SERVER['HTTP_USER_AGENT'] 
                    . $_SERVER['REMOTE_ADDR'];
		$visitorOld = self::decrypt($data[self::$visitorName]);
		if ($visitorNew != $visitorOld) {
			return true;
		}
		
		// If honeypot tag is enabled, make sure it's empty.
		if (!empty(self::$honeypotName)) {
			if ($data[self::$honeypotName] != "") {
				return true;
			}
		}
		
		// Verify the form submit took at least $minSubmitTime;
		$name = "_" . substr($data[self::$visitorName], 0, 8);
		$elapsed = time() - self::decrypt($data[$name]);
		if (($elapsed <= self::$minSubmitTime) || 
                    ($elapsed > self::$maxSubmitTime)) {
			return true;
		}
		
		return false;
	}
	
	public static function debug($data)
	{
		$message = "";
		
		// Check visitor info (user agent and IP).
		$visitorNew = $_SERVER['HTTP_USER_AGENT']
                   . $_SERVER['REMOTE_ADDR'];
		$visitorOld = self::decrypt($data[self::$visitorName]);
		if ($visitorNew != $visitorOld) {
			$message .= "Different user agent or IP address. ";
		}
	
		// If honeypot tag is enabled, make sure it's empty.
		if (!empty(self::$honeypotName)) {
			if ($data[self::$honeypotName] != "") {
				$message .= "Honeypot trapped. ";
			}
		}
	
		// Verify the form submit took at least $minSubmitTime;
		$name = "_" . substr($data[self::$visitorName], 0, 8);
		$elapsed = time() - self::decrypt($data[$name]);
		if (($elapsed <= self::$minSubmitTime) || 
                   ($elapsed > self::$maxSubmitTime)) {
			$message .= "Form submitted in {$elapsed} second(s).";
		}
		
		$message .= " Form submitted from " 
                   . $_SERVER['REMOTE_ADDR'] . ".";
		return $message;
	}
}

References

Share this post

Comments (0)

    No comment

Leave a comment

All comments are moderated. Spammy and bot submitted comments are deleted. Please submit the comments that are helpful to others, and we'll approve your comments. A comment that includes outbound link will only be approved if the content is relevant to the topic, and has some value to our readers.


Login To Post Comment