How to add Captcha verification in the comments of the Yii blog demo

This post is about adding captcha verification in the comments section of the Yii demo blog. This post was triggered from two comments posted on the page of the tutorial (Comment 1 and Comment 2). In order for you to follow through the current post you need to have the Yii framework in place and you need to have followed all the steps of the Blog Tutorial up untill the “Creating and Displaying Comments” section. So, let’s start:

If you have followed the tutorial you should by now have a working Leave a comment form in place that is displayed underneath each individual post of your blog web application. The form should contain the Name, Email, Website and Comment fields that will populate the corresponding properties of your Comment model. The Post ID should be set on submit, the Status of the Comment should also be set on submit and the Time Created should be set just before saving the Comment (if this is a newly created comment).

OK, now the only field missing from our form is a Captcha verification code image which can easily find out how to add by going through the Contact form view generated as part of the skeleton webapp application that we used to create the blog. The code that generates the Captcha field is the following

[code language=”php”]

labelEx($model,’verifyCode’); ?>

widget(‘CCaptcha’); ?>
textField($model,’verifyCode’); ?>
Please enter the letters as they are shown in the image above.

Letters are not case-sensitive.

error($model,’verifyCode’); ?>

[/code]

So, we need to copy & paste the above code to the view file that is responsiple for displaying the Comment form on our Post page. Remember that the view that is responsible for displaying an individual post is located relative to the protected directory in /protected/views/post/view.php and within that view we are actually calling a partially rendered form that displays the Comment form. You should be able to locate the following lines in your /protected/views/post/view.php file

[code language=”php”]
renderPartial(‘/comment/_form’,array(
‘model’=>$comment,
)); ?>
[/code]

This means that the Comment form is displayed as it is defined withing the /protected/views/comment/_form.php view file which is the file in which we need to add the Captcha verification field with the code mentioned above.

Now, if we take a closer look at the piece of code we just used to add a Captcha verification field in the Comment form we will see that now apart from all the other fields we mentioned before there is now a newly added field on the form for which we are using the label with id ‘verifyCode’ and the the field is named ‘verifyCode’ as well. But our model does not know of this field yet and we can certainly say that our model does not have a property to save the value of this field either. So the next step is to make our Comment model aware of this new field. The value of this field is not going to be stored in the database but we still need a property to save the value of the field for validation purposes. So we need to add a property to hold the value typed by the user. Add the following in your /protected/models/Comment.php file

[code language=”php”]
public $verifyCode;
[/code]

In the same file we also need to ammend the attributeLabels() function to add a descriptive text of our choice for the Captcha verification field. After adding the text your attributeLabels() function should look something like this:

[code language=”php”]
public function attributeLabels()
{
return array(
‘id’ => ‘Id’,
‘content’ => ‘Comment’,
‘status’ => ‘Status’,
‘create_time’ => ‘Create Time’,
‘author’ => ‘Name’,
’email’ => ‘Email’,
‘url’ => ‘Website’,
‘post_id’ => ‘Post’,
‘verifyCode’=>’Verification Code’, // we have added this line
);
}
[/code]

Now, the last change we need to make to our Comment Model has to do with the validation of this Captcha verification field which our Model so far knows nothing about. The rules for validating the current Comment Model can be found in the same file /protected/models/Comment.php and are defined within the rules() function. Now if we look at the ContactForm Model that was created as part of the webapp application we will see the following line in the rules() function

[code language=”php”]
array(‘verifyCode’, ‘captcha’, ‘allowEmpty’=>!CCaptcha::checkRequirements()),
[/code]

which means run the captcha validation rule on the verifyCode field but allow the field to be empty if the Captcha requirements have not been met in which case based on the code we added to the Comment form the Captcha field will not be displayed at all. Now we may choose to simply replicate the following line in the rules() function of our Comment form or we may want to allow registered users not to fill in the verification code (as suggested in the comments mentioned above). For the scope of this example we will simply replicate the behavior defined in the ContactForm and we will add the above line in our model. After that our rules() function should look something like this

[code language=”php”]
public function rules()
{
return array(
array(‘content, author, email’, ‘required’),
array(‘author, email, url’, ‘length’, ‘max’=>128),
array(’email’,’email’),
array(‘url’,’url’),
array(‘verifyCode’, ‘captcha’, ‘allowEmpty’=>!CCaptcha::checkRequirements())
);
}
[/code]

Now we are really close but not quite there yet. If you try to navigate to the view page of an individual post on your blog application you will come across an error page with an Exception listed that goes something like “CCaptchaValidator.action “captcha” is invalid. Unable to find such an action in the current controller.”. Now this is happening because the Controller responsible for rendering the page and does not have a captcha action responsible for rendering the Captcha image to be displayed to the user as part of the Captcha verification code field of the Comment form.

So, we need to make such an action available to our Post Controller. We can find the code that handles that for the ContactForm within the Site Controller (since this is the controller responsible for showing the Contact us page for our blog application). Having found the code we need to add the following code in our Post Controller found at /protected/controllers/Post.php.

[code language=”php”]
/**
* Declares class-based actions.
*/
public function actions()
{
return array(
// captcha action renders the CAPTCHA image displayed on the contact page
‘captcha’=>array(
‘class’=>’CCaptchaAction’,
‘backColor’=>0xFFFFFF,
),
);
}
[/code]

Refreshing your page after that will either leave you satisfied because you will be able to see the Post with the modified Leave a comment form or will leave you wondering what went wrong and why although you can see the text field to enter the verification code you cannot see the Capcha image….

OK, the answer to that has to do with whether you are currently logged in to your blog application or not. Why? Remember that we just added some code to our Post Controller that adds a captcha action to the controller that is responsible for displaying the captcha image to the end user. We did not need to implement any code for that action but we still need to be able to access it when we are viewing the page. That means that we need to have enough privileges based on the access control rules to be able to run the captcha action and view the image that it generates. If you are logged in your application then you have all the privileges and therefore can see the image, but as an anonymous user you only have let’s say permissions to the index and view actions of the Post controller. So, in oder for this to work for anonymous users as well you need to modify your accessRules function of the Post controller to look something like this:

[code language=”php”]
public function accessRules()
{
return array(
array(‘allow’, // allow all users to perform ‘index’,’view’ and ‘captcha’ actions
‘actions’=>array(‘index’,’view’,’captcha’),
‘users’=>array(‘*’),
),
array(‘allow’, // allow authenticated user to perform any action
‘users’=>array(‘@’),
),
array(‘deny’, // deny all users
‘users’=>array(‘*’),
),
);
}
[/code]

And, that’s it. You should now have a Captcha verificiation code on your Leave a Comment form of your Yii blog tutorial application!

12 thoughts on “How to add Captcha verification in the comments of the Yii blog demo

  1. Thanks! I also copied Yii’s Contact Captcha like your example too but I had forgotten that I had accessRules() defined and my Captcha image wasn’t showing. Then found your example, whew! It all now works. Don’t think I would have thought of adding the action to the accessRules(). Thanks for including and showing that little tidbit!!!

  2. It’s a so useful explanation such as straightforward, …
    … five minutes and has a catpcha field working out!

    Thanks!

  3. this is the best tutor I have found in this evening about “captcha” in the internet.
    although I have individually fixed my bugs, thanks a lot

Leave a Reply