Yii 2.0 DIY Captcha to custom content

{ Notes }

One year later, after Google index back, the new domain got some special msg and comment, the SPAM. At begin it's just a small number msg a month, but recentlly it's getting worse. So I decide to change the captcha formula to Add and Sub formula. Just hope this change can block some SPAM.

As usuall write down for other people.

 

{ 0. Requirement }

Yii 2.0 Framework displays Captcha like "FEOD" just some letter, it's very easy to recognise, some people may add letter amount or some other stuff, but I want use more special way, the Add and Sub formula, like 18-9.

 

{ 1. SiteController }

    public function actions()
    {
        return [

            ...

            'captcha' => [
                'class' => 'YiilibTools\eeCaptcha', //Explain Later
                'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,
                'transparent' => true,
            ],
        ];
    }

 

{ 2. Model File}

class ContactMsg extends CommonBased
{
    public $verifyCode;

...

    public function rules()
    {
        return [
        
        	...
    
            [['verifyCode'], 'required'],
            ['verifyCode', 'captcha'],
        ];
    }
...

 

{ 3. View File}

<?php $form = ActiveForm::begin(['id' => 'contact-form']); ?>

....

<?= $form->field($model, 'verifyCode')->widget(Captcha::className(), [
    'template' => '<div class="row"><div class="col-lg-1"></div><div class="col-lg-5">{image}</div><div class="col-lg-5">{input}</div></div>',
]) ?>

<?php $form = ActiveForm::end()?>

 

{ 4. YiilibTools/eeCaptcha }

The logic is very simple

  1. eeCaptcha extends CaptchaAction to get all default actions from Yii 2.0 framework
  2. Overwrite generateVerifyCode method to return random integer, here used 10 to 100, be careful, the number we get here is the answer!! Yii 2.0 framework will write it in Session and use for future validate.
  3. Overwrite renderImage method to do some work before render pic.
    1. use random color for display
    2. set styles
    3. generate Add or Sub formula, here we use answer to generate formula.
    4. call and return parent renderImage do image display work.
<?php
namespace YiilibTools;

use yii\captcha\CaptchaAction;

class eeCaptcha extends CaptchaAction{
    
    
    protected function generateVerifyCode()
    {
        
        $code = mt_rand(10, 100);
    
        return $code;
    }
    
    
    protected function renderImage($code)
    {
        //1.rand color
        //color lib
        $colorLib[] = 0x2040A0;
        $colorLib[] = 0x2F4F4F;
        $colorLib[] = 0x483D8B;
        $colorLib[] = 0xCDBE70;
        $colorLib[] = 0xFFB90F;
        $colorLib[] = 0xEE6363;
        $colorLib[] = 0xFF1493;
        
        //get rand color for front
        $index = mt_rand(0, count($colorLib)-1);
        $this->foreColor = $colorLib[$index];
        
        //2.more style here
        $this->padding = 0;
        $this->width = 300;

        
        //3.use min or add
        $another = mt_rand(0, $code);
        if (mt_rand(0, 1)) {
            //+
            $code = $another.' + '.($code-$another);
        }else{
            //-
            $code = ($code+$another).' - '.$another;
        }
        
        return parent::renderImage($code);
    }
    
}

 

{ 5. One More }

If need display some logic question, we can prepare an array(or DB) contained Answer and Question. Then get one random array index for random question, save the index in session, before display image, we use the index load Question content, when validate we use the index find the answer and compare with user input.