First draft of a "captcha" class that asks the user the sum of two numbers. It helps you write code to ask a question like this:
What is the total of five plus three? (answer with a word) [ ]
The user should respond with "eight".
A captcha needs to "remember" the question that it posed to the user. To do this, the constructor takes an argument that's used as the key. It then saves the captcha data to a file in tmp/ named with the key.
I suggest using the value of $_SERVER['REMOTE_ADDR'] or their username. It needs to be reasonably unique.
When a captcha is made, it tries to read in the saved captcha. If it cannot, it creates a new one, and saves it. After it's created, you can clear it with the clear() method. You should clear it after it's been answered.
The captcha algorithm is simple. It picks two random number between 1 and 5, and the answer is the sum. Everything is done in written English, mainly to make it a little harder for bots. The toString() method returns the question as a string like "four plus two". The answerMatches() method is provided to compare the answer in English, to the stored answer (a number).
You should check out the test_craptcha_class.inc.php, below, to see how to use it.
craptcha_class.inc.php
<?php
// vim:set ts=4 sw=4 ai:
/**
* A pseudo-captcha class. It asks a math question and requests
* an answer.
*/
class Craptcha
{
var $a;
var $b;
var $answer;
var $file;
function Craptcha( $key )
{
$dir = 'tmp/craptcha';
if (!is_dir($dir))
{
mkdir($dir);
}
$this->file = $file = "$dir/$key";
if (file_exists($file))
{
list($this->a,$this->b,$this->answer) =
unserialize(file_get_contents($file));
}
else
{
$this->a = rand(1,5);
$this->b = rand(1,5);
$this->answer = $this->a + $this->b;
$text = serialize(array($this->a,$this->b,$this->answer));
$fh = fopen($file,'w');
fwrite($fh, $text);
fclose($fh);
}
}
function clear()
{
if (file_exists($this->file))
unlink($this->file);
}
function answerMatches( $word )
{
return ($this->numToString( $this->answer) == $word);
}
function toString()
{
return $this->numToString( $this->a ) . ' plus ' .
$this->numToString( $this->b );
}
function getAnswer()
{
return $this->numToString( $this->answer );
}
function numToString( $num )
{
switch($num)
{
case 1: return 'one';
case 2: return 'two';
case 3: return 'three';
case 4: return 'four';
case 5: return 'five';
case 6: return 'six';
case 7: return 'seven';
case 8: return 'eight';
case 9: return 'nine';
case 10: return 'ten';
}
}
}
?>
The following is test_craptcha_class.inc.php
<?php
// vim:set ts=4 sw=4 ai:
include('craptcha_class.inc.php');
$guess = $_REQUEST['guess'];
$c = new Craptcha( $_SERVER['REMOTE_ADDR'] );
if ($guess)
{
if ($c->answerMatches($guess))
{
$c->clear();
echo "correct
";
echo "again";
exit;
}
else
{
echo "incorrect
";
echo "again";
exit;
}
}
?>
What is the total of <?=$c->toString()?>?
(answer in written English)
Comments
Nice piece of code, I
Nice piece of code, I modified it so that the numbers that are presented are in an image form.
It's quick and dirty! thanks for the code.