I bloody hate squinting at captcha images and trying to decipher what they say, but I hate comment spam more. With the exception of comparing that $REMOTE_ADDR matches on the form and save scripts, the (next) simplest possible way to filter out spamming machines has to be asking a random text question. To this end, there are two options: you can have a finite number of tricky questions like so or you can ask lots of really easy randomly generated maths questions.
The question() function needs to be available to both the form and save scripts; I stuck it in the same include with all my db connection stuff that gets used on every page.
<?
function question(){
/*
Reads a session variable $_SESSION["qseed"]
Returns a string like "Five times two"
Also sets a global varible $eqn, which contains the numeric answer.*/
global $eqn; // this is the variable that ultimately stores the answer
/* There's more than one way to generate this number and subsequently manipulate it into two integers. I went for plain randomness but there'd be nothing wrong with, say, using date("mdhis") and then taking the digit sum % 10 for one and all the ASCII values of the string % 12 for the other. Be creative! */
if(!$_SESSION["qseed"]){
$_SESSION["qseed"] = rand(1000,9999);
}
$seed = ($_SESSION["qseed"]); // The session variable ensures that the question invoked in the form will have the same answer as when it is invoked in the subsequent save script;
/* I learned my 12-times tables in school so I wouldn't force you to go any higher than that! */
/* NOTE: There are a million and one ways you can play around with the seed string to get two usable integers. This is just one way - and it's not how my site does it! */
$first = substr($seed,0,2) % 12
$second = substr($seed,2,2) % 12;
$operator = array("plus","times","minus");
$operator = $operator[$seed % 3]; // use the random seed to pick the operator too
if($second > $first){ //we want the bigger number first in case the operator is "minus"
$swap = $first;
$first = $second;
$second = $swap;
}
switch($operator) {
case "plus":
$eqn = $first + $second;
break;
case "minus":
$eqn = $first - $second;
break;
case "times":
$eqn = $first * $second;
break;
}
$Words = array("Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve");
$words = array("zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve");
return $Words[$first]." $operator ".$words[$second];
}
?>
Somewhere on your comment form, you'll add a field like so. question() will return a string saying "Five times two" or something similar.
<label><?=question()?> = </label><input name="answer" size="3">
When saving the comment, you call question() again and compare its answer (which gets put in the $eqn global variable) with $_POST['answer'].
<?
$answer = $_POST["answer"];
$question = question();
if($eqn-$answer == 0){
//accept and save the comment
}
/* And finally, create a new seed for the next time you fill out the form */
$_SESSION["qseed"] = rand(1000,9999);
?>
© 2006-2008 Dave Whyte. Send comments to me@thisdomainname