Integrate CakePHP with Kcaptcha
Simple way to integrate CakePHP with Kcaptcha.
KCAPTCHA is a free and open source PHP solution to generate human validation images (CAPTCHA).
KCAPTCHA is meant to be a very strong protected one but requires no special hosting featires, only PHP with GD library.
You can download Kcaptcha from here: http://captcha.ru/en/kcaptcha/. After this, put kcaptcha folder into vendors directory.
Create Captcha component:
Component Class:
Download code
<?php
class CaptchaComponent extends Object
{
function startup(&$controller)
{
$this->controller = $controller;
}
function render()
{
vendor('kcaptcha/kcaptcha');
$kcaptcha = new KCAPTCHA();
$this->controller->Session->write('captcha', $kcaptcha->getKeyString());
}
}
?>
Use this component in UsersController:
Controller Class:
Download code
<?php
class UsersController extends AppController
{
...
var $components = array('Session', 'Captcha');
...
function captcha()
{
$this->Captcha->render();
}
...
}
?>
Create image tag in view:
View Template:
Download code
<img src="<?php echo $html->url('/users/captcha'); ?>" />
That's all :)
Comments
Bug
1 Nothing appears
Everything is corect but no image :(
help me please
Comment
2 There is an error
This line have an error:
$this->controller->Session->write('captcha', $kaptcha->getKeyString());
Must be:
$this->controller->Session->write('captcha', $kcaptcha->getKeyString());
Missing 'c' y kcaptcha object ;-)
Comment
3 I notice this
I notice this error and i fixed , and i cann't see the image :(
Comment
4 There is an error
But in debug mode 1 - I don't see error.
Error in Kcaptcha?
When I look url: site.com/users/captcha - I see JFIF bla bla may be valid code?) but at the end - I see layout. May be problem here?
Comment
5 About image not showing
Check the kcaptcha docs, see what they require and then check with your host to see if they provide it.
later
Comment
6 About image not showing
So. After some fun with placing $this->layout = '';
I get this:
http://surnin.kiev.ua/users/captcha (you see - this image, but wrong header).
So image generating, but not showing - wrong header... Why?
COnstruction
img src=" echo html-> ...." -not work.
Sorry for bad english ;)
Comment
7 About image not showing
In your response headers, the image is served as Content-Type: text/html
Comment
8 About image not showing
But why here this header? ;-)
I do all by this manual... Even creating empty captcha.thtml (without this file - not work).
Till this time I cann't find - where put wrong header.
Question
9 About image not showing
When I past/copy code from this page, I copy also " " in component & controller code... Then I get wrong header.
After removing "?> " in both files I got result.
Sorry for all & thanks! ;-)
Comment
10 Thanks
With CakePHP it is really rapid development!
Question
11 Not working .. period
After 2 nights of suffering and 12 search tabs open in Firefox, i reached the following conclusions:
- KeyString generation works fine and the keystring gets stored in Session.
- The image is generated but the headers are always sent wrong. Even if $layout = "" .. or $layout = null etc.. and even if you exit() after calling $this->Captcha->render().
- Never use IE for debugging .. use Firefox's document source.
I revised my code thoroughly for hidden spaces and missing functions .. everything is clean and still no results.
- Cakephp is not for people with high blood pressure.
- A standalone KCAPTCHA works perfectly. Therefore, all what you need is to use the index.php (that is packeged with KCAPTCHA) directly as the src of your img tag .. and to hell with Cakephp's "Vendor" crap.
now .. my question is .. how can i get Cake to output the image correctly ?
Thanks in advance.
P.S. source code will be available upon request
Question
12 generate only a new kcaptcha image
the situation:
my image tag in the view:
<img class="captchapict" src="<?php echo $html->url('/users/captcha'); ?>" alt="This is a captcha-picture. It is used to prevent mass-access by robots. (see: http://captcha.ru)" name="Captcha">
and a textarea for a message:
<?php echo
$html->textarea('Invitation/personal', array('cols'=>'42', 'rows'=>'4')); ?>
i have a submit button that must generate a new captcha image and the data in the textarea must remain preserved / saved.
<? echo $html->submit('new ID'); ?>
but my problem is that i dont know how to implement this in cakephp. When i press the submit button (new ID) that the image is a new captcha image and the entered data in the textarea is saved!?
the form:
<form action="<?echo $html->url('/users/invite')?>" method="post"> .... </form>
can you help me? thanks!
PS: sorry for my bad english :(
MfG Maidi
Comment
13 Problem fixed
This echo is used to output performance info but it is corrupting the image file.
Comment
14 Be careful integrating this Captcha
Comment
15 It works
First you need to check you have GD, doing a
<?php echo phpinfo(); ?>will tell you if you have that.Once I had it working I add a function to validation.php file (like Spout did in http://bakery.cakephp.org/articles/view/captcha-component-with-phpcaptcha) but with some changes
<?php
function validateCaptcha($fieldName, $params) {
$val = $this->data[$this->name][$fieldName];
if(!defined('captcha'))
define('captcha', 'kcaptcha');
if (!empty($_SESSION['captcha']) && $val == $_SESSION['captcha']) {
// clear to prevent re-use
unset($_SESSION['captcha']);
return true;
}
return false;
}
?>
in captcha() function I add this (not really necessary)
function captcha(){
if ($this->referer() != "/users/registro"){ /* "/users/registro" is the view I am calling captcha() from */
$this->redirect("/");
}
else {
$this->Captcha->render();
}
}
My view looks like this
<?php echo $html->hidden("User/foo")?>
<p>Enter the text that appears above</p>
<p>
<?php echo $html->input('User/captchaText');?>
<?php echo $error->fieldErrors('User/captchaText'); ?>
</p>
You might wonder what is that hidden field for, someone said (don't remember where, sorry) that idea and I added, sometimes bots fills all fields they find, so we leave this field empty, if the controller checks the field is not empty then we are dealing with a bot.
Finally, in my controller I added this validation rule (so you can see how to do it on your model) as well the hidden field conditional
if (empty($this->data['User']['foo'])) {
$this->User->validate = array('captchaText' => array('Mycaptcha' => array('method' => 'validateCaptcha', 'message' => 'your error message')));
...
}
Question
16 Ajax Request Change The Captcha Image
how it is possible to change the captcha image with an ajax request?
thank u very much for your help.
Regards,
Maidi
Question
17 the captcha shows very slow
Comment
18 Not working .. period... Not so sure...
I tried KCAPTCHA and I had the same problems as described on post (11). And I did found an answer to this question : "how can i get Cake to output the image correctly ?"
Well, rather than putting the render() method in a component, I created this controller :
Controller Class:
<?php
class CaptchaController extends AppController {
var $name = 'Captcha';
var $uses = array();
function index(){
vendor('kcaptcha'.DS.'kcaptcha');
$kcaptcha = new KCAPTCHA();
$this->Session->write('captcha', $kcaptcha->getKeyString());
}
}
?>
In my login view i have put :
View Template:
...
<?php
echo $form->labelTag('Captcha/usercode', 'Are you human ?').'<br/>';
echo '<img id="captcha" src="'.$html->url('/captcha').'" alt="Captcha" ></img><br/>';
echo $html->input('Captcha/captcha').'<br/>';
echo '<a href="javascript:void(0);" onclick="javascript:document.images.captcha.src=\''.$html->url('/captcha').'\'">Reload?</a><br/>';
?>
...
The javascript beneath the captcha answers the question of the post (16). "how it is possible to change the captcha image with an ajax request?". Well there's no need for an ajax request to update the captcha.
In the captcha component I have put :
Component Class:
<?php
class CaptchaComponent extends Object
{
function startup(&$controller){
$this->controller = $controller;
}
function validateCaptcha($fieldName, $params = array()) {
$name = $this->controller->name;
if(isset($params['name'])){
$name = $params['name'];
}
$val = $this->controller->data[$name][$fieldName];
if (!defined('captcha'))
define('captcha', 'kcaptcha');
if (!empty ($_SESSION['captcha']) && $val == $_SESSION['captcha']) {
// clear to prevent re-use
unset ($_SESSION['captcha']);
return true;
}
return false;
}
}
?>
And finally I can put in the login action :
if($this->Captcha->validateCaptcha('captcha',array('name'=>'Captcha'))){
}
It worked for me, I hope that It'll work for you. I'm using kcaptcha 1.2.5 and cake 1.18.
Comment
19 Disable Cache I Hate IE
Ideally, the kcaptcha code should already do this, but since it doesn't (and I don't like modifying vendor code)...
Just add this to your controller action:
$this->disableCache();
Comment
20 An update for 1.2
App::import('Vendor', 'kcaptcha/kcaptcha');
instead of:
vendor('kcaptcha/kcaptcha');