تالار گفتمان nCIS.ir

نسخه‌ی کامل: تغییر ظاهر captcha تولید شده با Yii
شما در حال مشاهده نسخه آرشیو هستید. برای مشاهده نسخه کامل کلیک کنید.
سلام
ابتدا در پوشه components کلاس جدیدی ایجاد میکنیم:
class MyCaptcha extends CCaptchaAction
{
    protected function generateVerifyCode()
    {
 $code = array_merge(range('a', 'z'), range('0', '9'));
 $str = '';
 for($i = 0; $i < 6; $i++) {
 $str .= $code[rand() % count($code)];
 }
        return (string)$str;
    }
}
در فایل siteController.php متد actions را پیدا کرده و نام کلاس جدیدی که ساخته ایم را وارد میکنیم:
public function actions()
 {
 return array(
 'captcha'=>array(
 'class'=>'MyCaptcha',
 'backColor'=>0x0088EE,
 ),
 );
 }
بعد به مسیر Yiiframeworkwebwidgetscaptcha میرویم و فایل CCaptchaAction.php را باز کرده و در متد renderImageGD تغییرات مورد نظرمان را اعمال میکنیم:
protected function renderImageGD($code)
 {
 $image = imagecreatetruecolor($this->width,$this->height);

 $backColor = imagecolorallocate($image,
 (int)($this->foreColor % 0x1000000 / 0x10000),
 (int)($this->foreColor % 0x10000 / 0x100),
 $this->foreColor % 0x100);

 imagefilledrectangle($image,0,0,$this->width,$this->height,$backColor);
 imagecolordeallocate($image,$backColor);

 if($this->transparent)
 imagecolortransparent($image,$backColor);

 $foreColor = imagecolorallocate($image, 210, 240, 255);

        $lineColor = imagecolorallocate($image, 150, 120, 255);

 if($this->fontFile === null)
 $this->fontFile = dirname(__FILE__) . '/comicz.ttf';

 $length = strlen($code);
 $box = imagettfbbox(30,0,$this->fontFile,$code);
 $w = $box[4] - $box[0] + $this->offset * ($length - 1);
 $h = $box[1] - $box[5];
 $scale = min(($this->width - $this->padding * 2) / $w,($this->height - $this->padding * 2) / $h);
 $x = 10;
 $y = round($this->height * 27 / 40);
 for($i = 0; $i < $length; ++$i)
 {
 $fontSize = (int)(rand(30,35) * $scale * 0.8);
 $angle = rand(-10,10);
 $letter = $code[$i];
 $box = imagettftext($image,$fontSize,$angle,$x,$y,$foreColor,$this->fontFile,$letter);
 $x = $box[2] + $this->offset;
 }

 imagecolordeallocate($image,$foreColor);

        // Add lines to the image
        $lineCount= rand(5, 8);
 for($i = 0; $i < $lineCount; $i++) {
 $x1 = rand(10, $w);
 $y1 = rand(10, $h/3);
 $x2 = rand(10, $w/3);
 $y2 = rand(10, $h);
 imageline($image, $x1, $y1, $x2, $y2, $lineColor);
 }

 header('Pragma: public');
 header('Expires: 0');
 header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
 header('Content-Transfer-Encoding: binary');
 header("Content-Type: image/jpeg");
 imagejpeg($image);
 imagedestroy($image);
 }
با تشکر از استاد شهرکی.
بهتره متد renderImageGD رو هم توی کلاس MyCaptcha خودتون تغییر بدین و به کلاسهای اصلی فریمورک دست نزنید.
(17-03-1394، 11:42 ق.ظ)ADMIN نوشته: [ -> ]بهتره متد renderImageGD رو هم توی کلاس MyCaptcha خودتون تغییر بدین و به کلاسهای اصلی فریمورک دست نزنید.

چطور این کار رو انجام بدیم؟
چون در فرمی که captcha رو فراخوانی میکنیم widget با کلاسهای خود Yii ارتباط برقرار میکنه.
نه اینطور نیست. کافیه توی کنترلر تو متد actions کلاس خودتون رو برای کپچا بجای CCaptchaAction معرفی کنید. این کلاس نمونه من که تو مسیر protected/components/CaptchaAction.php ذخیره میکنم:
/**
 * Yii Custom Captcha
 * @author Mohammad Mostafa Shahreki
 * @copyright All rights reserved for Danesh Gostar Motafakker Co.
 * @link http://www.ncis.ir
 */
class CaptchaAction extends CCaptchaAction
{
    // Configuration
    public $width = 190;
    public $height = 75;
    public $length = 4;
    public $lineCount = 10;
    public $circleCount = 10;
    public $maxRadius = 50;
    public $space = 35;

    public function renderImage($code)
    {
        // Create image
        $im = ImageCreate($this->width, $this->height);
        // Create fixed colors
        $backColor = ImageColorAllocate($im, 255, 255, 255);
        // Asign font
        $font = dirname(__FILE__) . '/snap.ttf';
        // Start position of the text
        $positionX = ($this->width - $this->space * $this->length) / 2;
        // Rotation Direction (1: Anti-clockwise, -1: Clockwise)
        $direction = 1;
        // Fill the image with background color
        ImageFill($im, $this->width / 2, $this->height / 2, $backColor);
        // Write the text in the image using font, rotation, position, etc.
        foreach(str_split($code) as $char) {
            $textColor = ImageColorAllocate($im, rand() % 128, rand() % 128, rand() % 128);
            // Calculate the bounding box of the text
            $fontsize = $this->height * (rand(1, 5) * 0.05 + 0.2);
            $box = ImageTTFBBox($fontsize, 0, $font, $code);
            ImageTTFText($im, $fontsize, (rand() % 30 * $direction), $positionX, ($this->height - $box [5]) / 2, $textColor, $font, $char);
            $direction = -$direction;
            $positionX += $this->space;
        }
        // Add lines to the image
        for($i = 0; $i < $this->lineCount; $i++) {
            $x1 = rand() % $this->width;
            $y1 = rand() % $this->height;
            $x2 = rand() % $this->width;
            $y2 = rand() % $this->height;
            $lineColor = ImageColorAllocate($im, rand() % 128 + 127, rand() % 128 + 127, rand() % 96 + 159);
            ImageLine($im, $x1, $y1, $x2, $y2, $lineColor);
        }
        // Add circles to the image
        for($i = 0; $i < $this->circleCount; $i++) {
            $cx = rand() % $this->width;
            $cy = rand() % $this->height;
            $rx = rand() % $this->maxRadius;
            $ry = rand() % $this->maxRadius;
            $start = rand() % 360;
            $end = rand() % 360;
            $lineColor = ImageColorAllocate($im, rand() % 128 + 127, rand() % 128 + 127, rand() % 96 + 159);
            ImageArc($im, $cx, $cy, $rx, $ry, $start, $end, $lineColor);
        }
        header('Pragma: public');
        header('Expires: 0');
        header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
        header('Content-Transfer-Encoding: binary');
        header('Content-Type: image/png');
        ImagePNG($im);
    }

    protected function generateVerifyCode()
    {
        // Generate random code
        $alpha = range('A', 'Z');
        $code = '';
        for($i = 0; $i < $this->length; $i++) {
            $code .= $alpha [array_rand($alpha)];
        }
        return $code;
    }
}


حالا ببینید چطوری ازش استفاده میکنم:
این متد رو توی کنترلری که میخواین از کپچای خودتون داخلش استفاده کنید بنویسید:
public function actions()
{
    return array(
        'captcha' => array(
            'class' => 'CaptchaAction',
            'length' => 6, // we can set other public fields of our CaptchaAction class here
        ),
    );
}
همونطور که توضیح دادم، میتونید سایر خصوصیات public کلاس CaptchaAction خودتون رو هم برای سفارشی کردن کپچای تولیدی خودتون، اینجا بگذارین. یعنی به کاربر اجازه بدین بدون دستکاری کد شما، کپچای شما رو هم سفارشی کنه. حالا توی ویو اینطوری کپچا رو بارگذاری میکنید:
<?php if(CCaptcha::checkRequirements()): ?>
<div class="form-group">
    <div class="col-sm-3 col-sm-offset-3"><?php $this->widget('CCaptcha', array('buttonLabel' => '<span class="fa fa-rotate-right fa-2x"></span>')); ?></div>
</div><!-- /.form-group -->
<div class="form-group">
    <?php echo $form->labelEx($model, 'verifyCode', array('class' => 'col-sm-3 control-label')); ?>
    <div class="col-sm-3"><?php echo $form->textField($model, 'verifyCode', array('class' => 'form-control')); ?></div>
    <div class="col-sm-6 text-danger"><p><?php echo $form->error($model, 'verifyCode'); ?></p></div>
</div><!-- /.form-group -->
<?php endif; ?>

نکته مهم فقط همونجایی هست که شما ویجت CCaptcha رو میسازین. نمونه تصویری که براتون ساخته میشه رو میگذارم:
[attachment=44]