User registration is a common thing in web development. To ensure that only human registered as a user, it is common to use Completely Automated Public Turing test to tell Computers and Humans Apart (CAPTCHA).
There are several CAPTCHA library available. This article will show how you can integrate 2 such library to provide CAPTCHA verification for user registration.
The library I used are kCAPTCHAand reCAPTCHA. Let’s start with reCAPTCHA.
reCAPTCHA is recommended as the official CAPTCHA implementation by the original CAPTCHA creators. Here is how you do it, step-by-step:
2. Sign up for the API key. reCAPTCHA is a web service so you need to sign up for API key to be able to use it. Notice on signing up , you will be asked to fill in a domain name. As far as I know you can put anything, I tried putting my domain and localhost, both accepted. After signing up you will have two keys one public key (for the user) and the other a private key (for communication between our server with reCAPTCHA server).
3. Extract and put the result at your vendors folder ( [web]/app/vendors/ ).
4. Create a component file
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | <?php class RecaptchaComponent extends Object { var $publickey = "..."; // use your public key here var $privatekey = "..."; // user your private key here function startup(&$controller) { $this->controller = $controller; } function render() { vendor('recaptcha/recaptchalib'); $error = null; echo recaptcha_get_html($this->publickey, $error); } function verify() { vendor('recaptcha/recaptchalib'); $resp = recaptcha_check_answer ($this->privatekey, $_SERVER["REMOTE_ADDR"], $_POST["recaptcha_challenge_field"], $_POST["recaptcha_response_field"]); if ($resp->is_valid) { return true; } else { return false; } } } ?> |
store this at [web]/app/controllers/components/recaptcha.php
5. Create User Model and User Controller
Model:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | <?php class User extends AppModel { var $name = 'User'; /** * validation rules */ var $validate = array ( 'user_login' => array( 'exists' => array( 'rule' => array( 'checkUnique', 'user_login' ), 'message' => 'The Username you entered has been taken.' ), 'minLength' => array( 'rule' => array('minLength', 3), 'message' => 'Username must at least be 3 character long.' ) ), 'user_pass' => array( 'mingLength' => array( 'rule' => array('minLength', '6'), 'message' => 'Mimimum 6 characters long' ) ), 'user_name' => array( 'minLength' => array( 'rule' => array('minLength', 3), 'message' => 'Username must at least be 3 character long.' ) ), 'user_email' => array ( 'email' => array( 'rule' => 'email', 'message' => 'Please supply a valid email address.' ), 'exists' => array( 'rule' => array( 'checkUnique', 'user_email' ), 'message' => 'The email you entered has been registered.' ) ) ); /** * Validate if the data is unique. * * @param $data The data to be compared. * @param $fieldName The field name to check. * @return true If the field name unique. False otherwise. */ function checkUnique( $data, $fieldName ) { $valid = false; if(isset($fieldName) && $this->hasField($fieldName)) { $valid = $this->isUnique(array($fieldName => $data)); } return $valid; } } ?> |
store this as [web]/app/models/users.php.
Controller:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | <?php class UsersController extends AppController { var $name = 'Users'; var $components = array('Auth', 'Recaptcha'); function beforeFilter() { $this->Auth->fields = array('username' => 'user_login', 'password' => 'user_pass'); $this->Auth->allow('register', 'recaptcha'); } /** * This method handle the user registration process. * It will first of all, get the user basic information. * After user submit the information, a hash key will be generated and * stored in the database. An email will then send to user and pending * for user activation */ function register() { if ( !empty( $this->data ) ){ if ( $this->data['User']['user_pass'] == $this->Auth->password( $this->data['User']['user_pass_confirm'])) { if ( $this->Recaptcha->verify() ){ $temp = array( 'user_registered'=> date('Y-m-d'), 'user_activation_key'=>sha1( time() ), 'user_status' => 0 ); $this->data['User'] = array_merge( $this->data['User'], $temp ); unset( $this->data['User']['captcha']); $this->User->create(); if ( $this->User->save($this->data) ){ // do other stuff here like send activation email to user // or/and redirect to other page } } else { $this->Session->setFlash('captcha verification failed'); } } else { $this->Session->setFlash('password mismatch'); } } } function recaptcha() { $this->Recaptcha->render(); } } ?> |
store this as [web]/app/controllers/users_controller.php.
6. Create the view
1 2 3 4 5 6 7 8 9 10 11 | <?php echo $form->create( 'User', array('action' => 'register' ) ); echo $form->input('user_login', array( 'label' => 'User Name :' ) ); echo $form->input('user_name', array( 'label' => 'Full name :' ) ); echo $form->input('user_email', array( 'label' => 'Email :') ); echo $form->input('user_pass', array( 'label' => 'Password :', 'type' => 'password') ); echo $form->input('user_pass_confirm', array( 'label' => 'Retype Password :', 'type' => 'password' ) ); $this->requestAction('users/recaptcha'); echo $form->submit(); echo $form->end(); ?> |
store this as [web]/app/views/register.ctp.
7. voila!, We are done!!
Now, let’s move on to kCAPTCHA. It is pretty much the same. Unlike reCAPTCHA, kCAPTCHA is not a web service. So you need not sign up for anything.
2. Extract and put the result at your vendors folder ( [web]/app/vendors/ ).
3. Create component.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <?php class KCaptchaComponent extends Object { function startup(&$controller) { $this->controller = $controller; } function render() { vendor('kcaptcha/kcaptcha'); $kcaptcha = new KCAPTCHA(); $this->controller->Session->write('captcha', $kcaptcha->getKeyString()); } } ?> |
store this as [web]/app/controllers/components/kcaptcha.php
4. The Users model is the same as above.
5. The User controller is pretty much the same, but I will rewrite the whole code anyway.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | <?php class UsersController extends AppController { var $name = 'Users'; var $components = array('Auth', 'KCaptcha'); function beforeFilter() { $this->Auth->fields = array('username' => 'user_login', 'password' => 'user_pass'); $this->Auth->allow('register','kcaptcha' ); } /** * This method handle the user registration process. * It will first of all, get the user basic information. * After user submit the information, a hash key will be generated and * stored in the database. An email will then send to user and pending * for user activation */ function register() { if ( !empty( $this->data ) ){ if ( $this->data['User']['user_pass'] == $this->Auth->password( $this->data['User']['user_pass_confirm'])) { if ( strtolower($this->data['User']['captcha']) == strtolower( $this->Session->read('captcha')) ) { $temp = array( 'user_registered'=> date('Y-m-d'), 'user_activation_key'=>sha1( time() ), 'user_status' => 0 ); $this->data['User'] = array_merge( $this->data['User'], $temp ); unset( $this->data['User']['captcha']); $this->User->create(); if ( $this->User->save($this->data) ){ // do other stuff here like send activation email to user // or/and redirect to other page } } else { $this->Session->setFlash('captcha verification failed'); } } else { $this->Session->setFlash('password mismatch'); } } } function kcaptcha() { $this->KCaptcha->render(); } } ?> |
store this as [web]/app/controllers/users_controller.php
6. The view
1 2 3 4 5 6 7 8 9 10 11 12 | <?php echo $form->create( 'User', array('action' => 'register' ) ); echo $form->input('user_login', array( 'label' => 'User Name :' ) ); echo $form->input('user_name', array( 'label' => 'Full name :' ) ); echo $form->input('user_email', array( 'label' => 'Email :') ); echo $form->input('user_pass', array( 'label' => 'Password :', 'type' => 'password') ); echo $form->input('user_pass_confirm', array( 'label' => 'Retype Password :', 'type' => 'password' ) ); echo $form->input('captcha', array( 'label' => 'Please type the text presented in the image : ', 'before' => '<img src="'. $html->url('/users/kcaptcha') . '"') ); echo $form->submit(); echo $form->end(); ?> |
store this as [web]/app/views/register.ctp.
7. voila!, We are done!!
Here is same screenshots showing CAPTCHA user registration in action.









May 12th, 2008 at 12:52 pm
Interesting Article ..
Keep the good posting Bro
May 15th, 2008 at 11:57 am
Good article.
The kCaptcha is, I think, vulnerable. I could register once, and then submitting many time the form (ie: not requesting it first), changing informations except the captcha string of my first registration.
Solution: be sure to delete the string from Session in success/failure case.
thanks.
May 30th, 2008 at 8:07 pm
very nice article.
August 4th, 2008 at 10:19 pm
Hey, small fix for everyone experiencing trouble with CakePHP 1.2 RC2. Seems like the vendor() function has been depreciated.
You must change:
vendor(’recaptcha/recaptchalib’);
on lines 14 and 26 to:
App::import(’vendor’, ‘Recaptcha’, array(’file’=>’recaptcha/recaptchalib.php’));
I hope this helps someone.
August 5th, 2008 at 8:29 am
This is an awesome article about CAPTCHA and email verification, thank you very much for sharing! Not only do I need the captcha I was also confused about the user activation e-mail which you have also covered here!
August 12th, 2008 at 12:41 pm
Keep rocks!
September 18th, 2008 at 11:46 am
just what I need. Thank you!