<?php
/********* codegrunt CAPTCHA Class ********/

// Author: slave@codegrunt.com / http://codegrunt.com
// This is a CAPTCHA generator class which requires no extra 
// PHP libraries to function (it uses just the built in GD functions)
//
// if you would like help expanding this class to fulfill
// your needs drop me a note 

/*
usage:  

This class requires a MySQL database table as well as an instance of
my MySQL class setup as $GLOBALS['db'];

The MySQL table definition looks like this:

CREATE TABLE IF NOT EXISTS `captcha` (
  `ident` varchar(80) NOT NULL,
  `captcha` varchar(20) NOT NULL,
  `created` datetime NOT NULL,
  `ip` varchar(15) default NULL,
  `ua` varchar(120) default NULL,
  `status` int(11) NOT NULL default '0',
  KEY `captcha` (`captcha`,`status`),
  KEY `ident` (`ident`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

each CAPTCHA code generated is good for one use only.  I have ran the output
through a couple of free OCR applications and they were unable to decipher
the code (though your mileage may vary of course).

*/

// change this define to match whatever you have called the CAPTCHA table
define('_table_captcha','captcha');

class 
CAPTCHA
{
    var 
$captcha;
    var 
$created;
    var 
$ip;
    var 
$ua;
    var 
$status// has this captcha been used or not

    
function CAPTCHA()
    {
        
$this->captcha='';
        
$this->ip=getenv('REMOTE_ADDR');
        
$this->ua=getenv('HTTP_USER_AGENT');
        
$this->created='';
        
$this->ident=md5(uniqid(rand(0,200)));
        
$this->status=0;
    }

    function 
use_captcha($del=1)
    {
        
// perform random cleanup
        
if($del)
        {
            if(
rand(0,100)==0)
            {
                
$sql='DELETE FROM '._table_captcha.'
                WHERE UNIX_TIMESTAMP()-UNIX_TIMESTAMP(created) > 600'
;
                
$GLOBALS['db']->do_query($sql);
            }

            
$sql='DELETE FROM '._table_captcha.'
            WHERE captcha="'
.mysql_real_escape_string($this->captcha).'"
            AND ident="'
.mysql_real_escape_string($this->ident).'"
            AND status=1
            AND UNIX_TIMESTAMP()-UNIX_TIMESTAMP(created) < 600'
;
        }
        else
        {
            
$sql='UPDATE '._table_captcha.'
            SET status=2
            WHERE captcha="'
.mysql_real_escape_string($this->captcha).'"
            AND ident="'
.mysql_real_escape_string($this->ident).'"
            AND status=1
            AND UNIX_TIMESTAMP()-UNIX_TIMESTAMP(created) < 600'
;
        }
        
$GLOBALS['db']->do_query($sql);
        if(
$GLOBALS['db']->affected_rows()>0)
        {
            return 
1// used captcha
        
}
        else
        {
            return 
0// no active captcha found
        
}
    }

    function 
update_db()
    {
        if(!isset(
$GLOBALS['db'])) die('no database connection found');
        
$sql='INSERT INTO captcha (ident,captcha,ip,ua,created,status) VALUES (
        "'
.mysql_real_escape_string($this->ident).'",
        "'
.mysql_real_escape_string($this->captcha).'",
        "'
.mysql_real_escape_string($this->ip).'",
        "'
.mysql_real_escape_string($this->ua).'",
        NOW(),
        0
        )'
;
        
$GLOBALS['db']->do_query($sql);
    }

    function 
create_captcha($tot)
    {
        
$this->captcha=$this->gen_random_string((int)$tot);
        
$this->update_db();
    }

    function 
get_captcha()
    {
        
$sql='SELECT captcha FROM '._table_captcha.' WHERE ident="'.mysql_real_escape_string($this->ident).'" AND status=0 LIMIT 1';

        
$GLOBALS['db']->do_query($sql);
        if(
$GLOBALS['db']->result[0]['numrows']==1)
        {
            
$this->captcha=$GLOBALS['db']->result[0]['captcha'];
            
// mark captcha as displayed (only get one shot)
            
$sql='UPDATE '._table_captcha.'
            SET status=1
            WHERE ident="'
.mysql_real_escape_string(strtolower($this->ident)).'"
            AND status=0'
;
            
$GLOBALS['db']->do_query($sql);
            return 
1;
        }
        else
        {
            
$this->captcha='';
            return 
0;
        }
    }

    function 
render_captcha()
    {
        
header("Content-type: image/jpg");
        
$fw=imagefontwidth(5);
        
$fh=imagefontheight(5);
        
$im=imagecreate(($fw)*strlen($this->captcha)*3,$fh*4);
        
$bgc=imagecolorallocate($im,rand(156,255),rand(156,255),rand(156,255));

        
$px=ceil(imagesx($im)/2);
        
$py=ceil(imagesy($im)/2);

        
$length=strlen($this->captcha)*2// include space
        
$start=$px-floor(($length/2)*$fw);
        
// obfuscation (borrowed from PEAR class)
        
for ($i=0$i<3$i++)
        {
            
$x1 rand(0imagesx($im) - 1);
            
$y1 rand(0imagesy($im) - 1);
            
$x2 rand(0imagesx($im) - 1);
            
$y2 rand(0imagesy($im) - 1);
            
imageline($im$x1$y1$x2$y2imagecolorallocate($im,rand(0,255),rand(0,255),rand(0,255)));
            
$x1 rand(0imagesx($im) - 1);
            
$y1 imagesy($im) - rand(1round(imagesy($im) / 100));
            
$x2 imagesx($im) - rand(1round(imagesx($im) / 100));
            
$y2 rand(0imagesy($im) - 1);
            
imageline($im$x1$y1$x2$y2imagecolorallocate($im,rand(0,255),rand(0,255),rand(0,255)));
            
$cx rand(0imagesx($im) - 50) + 25;
            
$cy rand(0imagesy($im) - 50) + 25;
            
$w rand(10round(imagesy($im)/2)+1);
            
imagearc($im$cx$cy$w$w0360imagecolorallocate($im,rand(0,255),rand(0,255),rand(0,255)));
            
imagefill($imrand(0,imagesx($im)), rand(0,imagesx($im)),  imagecolorallocate($im,rand(0,255),rand(0,255),rand(0,255)));
               }
               for(
$x=0;$x<$length;$x++)
        {
            
$fc=NULL;
            
$fx=$start+($fw*$x*2)+rand(-$fh,+$fh)/3;
            
$fy=$py-($fh/2)+rand(-$fh,+$fh);
            
$fc=imagecolorallocate($im,rand(0,155),rand(0,155),rand(0,155));
            
imagestring($im5$fx+1$fy+1substr($this->captcha,$x,1).' '$fc);
            
imagestring($im5$fx-1$fy-1substr($this->captcha,$x,1).' '$fc);
            
imagestring($im5$fx-1$fy+1substr($this->captcha,$x,1).' '$fc);
            
imagestring($im5$fx+1$fy-1substr($this->captcha,$x,1).' '$fc);
            
imagestring($im5$fx$fysubstr($this->captcha,$x,1).' 'imagecolorallocate($im,rand(156,255),rand(156,255),rand(156,255)));
        }
        
imagejpeg($im);
        
imagedestroy($im);
    }



    function 
gen_random_string($len)
        {
                
$str='';
                if(
$len>1024$len=1024;
                
$v=array();
                
$v[0][0]=50// 2-9
                
$v[0][1]=57;
                
$v[1][0]=97// a-z
                
$v[1][1]=122;
                
$v[2][0]=65// A-Z
                
$v[2][1]=90;
                
$bad=array('I','o','O','l'); // characters that are confusing to deal with
                
while($len>0)
                {
                        
$o=rand(0,2);
                        
$a=chr(rand($v[$o][0],$v[$o][1]));
                        if(
in_array($a,$bad)) continue;
                        
$str.=$a;
                        
$len--;
                }
                return(
$str);
        }
}

?>