Captcha component with PhpCaptcha

By Spout aka "spout"
PhpCaptcha is a library for generating visual and audio CAPTCHAs (completely automated public Turing test to tell computers and humans apart).
Supported Features
  • Multiple random TrueType fonts
  • Character rotation
  • Optional chararacter shadow support
  • Optional site owner display text
  • Random custom background images
  • Font size selection
  • Greyscale or colour lines and characters
  • Character set selection
  • Integration of validation function for checking the user entered code with the generated code



NB: The audio CAPTCHA requires the Flite text to speech synthesis engine.



1.- Download PhpCaptcha http://www.ejeliot.com/pages/2 and unzip archive in /vendors/phpcaptcha directory
2.- Download Vera font files: http://ftp.gnome.org/pub/GNOME/sources/ttf-bitstream-vera/1.10/ttf-bitstream-vera-1.10.zip and unzip archive in /vendors/phpcaptcha/fonts/
3.- Create Captcha component:

Component Class:

Download code <?php 
vendor
('phpcaptcha'.DS.'php-captcha.inc');

class 
CaptchaComponent extends Object
{
    var 
$controller;
 
    function 
startup( &$controller ) {
        
$this->controller = &$controller;
    }

    function 
image(){
        
        
$imagesPath realpath(VENDORS 'phpcaptcha').'/fonts/';
        
        
$aFonts = array(
            
$imagesPath.'VeraBd.ttf',
            
$imagesPath.'VeraIt.ttf',
            
$imagesPath.'Vera.ttf'
        
);
        
        
$oVisualCaptcha = new PhpCaptcha($aFonts20060);
        
$oVisualCaptcha->UseColour(true);
        
//$oVisualCaptcha->SetOwnerText('Source: '.FULL_BASE_URL);
        
$oVisualCaptcha->SetNumChars(6);
        
$oVisualCaptcha->Create();
    }
    
    function 
audio(){
        
$oAudioCaptcha = new AudioPhpCaptcha('/usr/bin/flite''/tmp/');
        
$oAudioCaptcha->Create();
    }
    
    function 
check($userCode$caseInsensitive true){
        if (
$caseInsensitive) {
            
$userCode strtoupper($userCode);
        }
        
        if (!empty(
$_SESSION[CAPTCHA_SESSION_ID]) && $userCode == $_SESSION[CAPTCHA_SESSION_ID]) {
            
// clear to prevent re-use
            
unset($_SESSION[CAPTCHA_SESSION_ID]);
            
            return 
true;
        }
        else return 
false;
        
    }
}
?>


4.- Use it in your Users controller

Controller Class:

Download code <?php 
class UsersController extends AppController
{
    ...
    var 
$components = array('Captcha');
    ...
    function 
captcha_image()
    {
        
$this->Captcha->image();
    }
    
    function 
captcha_audio()
    {
        
$this->Captcha->audio();
    }
    ...
}
?>


5.- Display captcha image, in your template view:

View Template:

Download code
<img id="captcha" src="<?php echo $html->url('/users/captcha_image');?>" alt="" />
 <a href="javascript:void(0);" onclick="javascript:document.images.captcha.src='<?php echo $html->url('/users/captcha_image');?>?' + Math.round(Math.random(0)*1000)+1">Reload image</a>

Pretty cool, we can reload captcha image if unreadable ;o)

6.- Validate captcha code in your controllers with $this->Captcha->check() method.

With my cake apps I use the improved validation method explained on the bakery. http://bakery.cakephp.org/articles/view/more-improved-advanced-validation
I've added this validation function to validation.php

Download code
function validateCaptcha($fieldName, $params){
        $caseInsensitive = true;
        
        $val = $this->data[$this->name][$fieldName];
        
        if ($caseInsensitive) {
            $val = strtoupper($val);
        }
        
        //php-captcha.inc.php
        if(!defined('CAPTCHA_SESSION_ID'))
            define('CAPTCHA_SESSION_ID', 'php_captcha');
         
         if (!empty($_SESSION[CAPTCHA_SESSION_ID]) && $val == $_SESSION[CAPTCHA_SESSION_ID]) {
            // clear to prevent re-use
            unset($_SESSION[CAPTCHA_SESSION_ID]);
            
            return true;
         }
         
         return false;
    }


And voil�

Comments 442

CakePHP team comments Author comments

Comment

1 Nice Work

Hey, this is a handy component. I was just looking for this.

Here are a few things i noticed:

on line 14 of captcha.php:
$imagesPath = realpath(VENDORS . 'phpcaptcha').'/fonts/';

if your vendors path is inside your app directory, you need something like this:

$imagesPath = APP . 'vendors' . DS . 'phpcaptcha'.'/fonts/';


also, for the validation, i changed:

function validateCaptcha($fieldName, $params){
        $caseInsensitive = true;


to :

function validateCaptcha($fieldName, $caseInsensitive = true){

since the $params var is not used in the function, and it's handy to have the case sensitivity as a parameter.

Also, for anyone using this who is also using sessions (either Cake's or your own), be sure to look at the vendor file php-captcha.inc and comment out line 46, where the script calls session_start() , or you will definitely experience some session problems.

Thanks for the work, Spout.

dd
posted Wed, Jun 13th 2007, 18:06 by darius

Question

2 I cant get it to work

i tried in windows and linux, and i couldn't get it to work, gives me an 'X' image on IE and blank on FF.

when i am trying to debug by accesing directly to the url /users/captcha_image says that the view is missing.

what should i do?

posted Thu, Jun 21st 2007, 15:39 by Manuel Dorado

Comment

3 I get it to work

i tried in windows and linux, and i couldn't get it to work, gives me an 'X' image on IE and blank on FF.

when i am trying to debug by accesing directly to the url /users/captcha_image says that the view is missing.

what should i do?


i shold recompile my php to support gd libraries, and be carefull with the imagesPath directory...

very great component! thanks Spout.

i realize that after debug step by step the vendor captcha php.

posted Thu, Jun 21st 2007, 16:47 by Manuel Dorado

Bug

4 FireFox is unable to work

Have anybody got solution.
Thank!!
posted Wed, Jul 11th 2007, 04:38 by Jersus Soo

Question

5 How to add error message that captcha you typed is wrong

Ok, i was able to make this work.

Although, i am a bit clueless. On how will i add an error message on the template itself. Here are sample of my codes.


Controller Class:

<?php 
...
if (empty(
$this->data))
{
    
$this->render();
}
else
{

    if (
$this->Email->save($this->data))
    {
    if (
$this->Captcha->check($this->data['Email']['userCode'])) { 
        
    
// Flash that it has been sent
    
$this->flash('Your email has been sent.','/emails');
            
    }
        
    }
    else
    {
        
$this->set('errorMessage''Please correct errors below.');
        
$this->render();
    }

}
...
?>

I was able to validate the usual fields i added:

View Template:


...
<label>Name:</label>
<?php echo $html->input('Email/name', array('class' => 'input''style' => 'width: 200px;')); ?>
<?php 
echo $html->tagErrorMsg('Email/name''Name is required.'); ?>
<label>Message:</label>
<?php echo $html->textarea('Email/message', array('rows'=>'10''cols'=>'40')); ?>
<?php 
echo $html->tagErrorMsg('Email/message''Message is required.'); ?>

<label>Captcha:</label>
<?php echo $html->input('Email/userCode', array('class' => 'input''style' => 'width: 200px;')); ?>
<?php 
echo $html->tagErrorMsg('Email/userCode''Captcha is required.'); ?>
...


which is name and message and captcha (if its empty only).

But to show that what you typed is wrong, i don't know what to do.

Please help!

posted Thu, Jul 26th 2007, 00:50 by Louie Miranda

Comment

6 Captcha with CakePHP 1.2

This is what I had to do to get Captcha component working with validator (CakePHP 1.2). It is quiet easy but I had some troubles to understand the new validation process. Hope it will help somebody else.

Model Class:

<?php 

    $validate 
= array(
        
'captcha' => array (
            
'validateCaptcha' => array (
                
'rule' => 'validateCaptcha',
                
'message' => 'Your captcha error message'
            
)
        )
    );

    function 
validateCaptcha($check) {
        if (!
defined('CAPTCHA_SESSION_ID')) {
            
define('CAPTCHA_SESSION_ID''php_captcha');
        }

        if (!empty (
$_SESSION[CAPTCHA_SESSION_ID]) && $check == $_SESSION[CAPTCHA_SESSION_ID]) {
            unset (
$_SESSION[CAPTCHA_SESSION_ID]);
            return 
true;
        }
        return 
false;
    }
?>


Note that the field $validate has been declared in my child model class called "Post" and the method validateCaptcha is in the parent AppModel class.
posted Sat, Jul 28th 2007, 07:15 by Sam Contesse

Question

7 reload image not working in Internet Explorer

My captcha validation is working properly in FF,but the Reload Image link is not working in the internet explorer.

Can any body suggest me actualy where i am wrong

Waiting for a reply
posted Tue, Aug 28th 2007, 04:09 by sivaprasad

Question

8 Implementation

I tried it on Windows using CakePHP 1.2alpha and PHP 5. It's giving me an "X" image on IE and FF. I've read the post by Manuel Dorado but my gd library is already working.

Your help is greatly appreciated.

Thank you.
posted Sun, Oct 14th 2007, 09:01 by Wendell Malpas

Comment

9 v1.2

also trying to get it work on 1.2.
seems like the response headers are already sent and php-captcha.inc.php kannt set the mime-type header to image/jpg
posted Mon, Nov 5th 2007, 06:21 by danny thuering

Comment

10 solved

hehe

der was an space after my closing ?> tag in captcha.php which caused the headers to be send...

:-)
posted Mon, Nov 5th 2007, 06:44 by danny thuering

Comment

11 great component

Thanks for the submission, I had captcha working within minutes with no trouble at all!

p.s. it seems I'm not able to rate anything on Bakery, as soon as this issue is fixed I'll give it a 5 :-)
posted Mon, Dec 17th 2007, 07:51 by Hannibal Lecter

Question

12 Problem to get this working

hi ! first thanks for this great component.
phpcaptcha works fine on mine server as standalone. so all libs a working properly.

if i want to use it within my controller, i just got an "broken-image" in IE or the url in Firefox.
when viewing the source i noticed, that there are html-elements.. looks like some parts of my layout...
maybe this causes the failure?

i got absolutely no idea why my layout is used.
even a

Controller Class:

<?php 
    
function captcha_image()
    {    
        
$this->layout FALSE;
        
$this->Captcha->image();
    }
?>


won't work.. any ideas on that?
posted Mon, Mar 31st 2008, 16:07 by Lars

Question

13 additional info

i just noticed that before output, starts, there are
THREE BLANK SPACES and i can't explain where they are from. even with no layout - these spaces are there..

but guess what: they are on every page generated within cakephp. on every site 3 blank spaces at the beginning. anyone has an idea which scripts generates them? maybe because of them already html output has been startet and the image could be displayed.

thx in advance for every help ( if i get some ^^ )
posted Tue, Apr 1st 2008, 10:52 by Lars

Question

14 Cant download Component

I'm not seeing where I can download this component, something wrong with the bakery?
posted Tue, Apr 29th 2008, 12:36 by Mark

Comment

15 Working on 1.2

Hi, I see that many people have problems with phpcaptcha working on cakephp 1.2 so I paste here version which runs perfectly:

Component Class:

<?php 
App
::import('Vendor','PhpCaptcha' ,array('file'=>'phpcaptcha/php-captcha.php'));
        
class 
CaptchaComponent extends Object
{
    var 
$controller;
 
    function 
startup( &$controller ) {
        
$this->controller = &$controller;
    }

    function 
image(){
        
        
$imagesPath APP 'vendors' DS 'phpcaptcha'.'/fonts/';
        
        
$aFonts = array(
            
$imagesPath.'VeraBd.ttf',
            
$imagesPath.'VeraIt.ttf',
            
$imagesPath.'Vera.ttf'
        
);
        
        
$oVisualCaptcha = new PhpCaptcha($aFonts20060);
        
        
$oVisualCaptcha->UseColour(true);
        
//$oVisualCaptcha->SetOwnerText('Source: '.FULL_BASE_URL);
        //$oVisualCaptcha->SetNumChars(6);
        
$oVisualCaptcha->Create();
    }
    
    function 
audio(){
        
$oAudioCaptcha = new AudioPhpCaptcha('/usr/bin/flite''/tmp/');
        
$oAudioCaptcha->Create();
    }
    
    function 
check($userCode$caseInsensitive true){
        if (
$caseInsensitive) {
            
$userCode strtoupper($userCode);
        }
        
        if (!empty(
$_SESSION[CAPTCHA_SESSION_ID]) && $userCode == $_SESSION[CAPTCHA_SESSION_ID]) {
            
// clear to prevent re-use
            
unset($_SESSION[CAPTCHA_SESSION_ID]);
            
            return 
true;
        }
        else return 
false;
        
    }
}
?>


This is action which renders captcha:


  function captcha_image()
  {
    Configure::write('debug',0);
    $this->layout = null;  
    $this->Captcha2->image();
    $this->render();
  } 
posted Mon, May 12th 2008, 15:36 by Kubasko

Login to Submit a Comment