Bài 11: Viết thư viện captcha và kiểm tra mã captcha bằng ajax

DOWNLOAD DEMO

Nếu như bạn hay lướt web thì bạn sẽ thấy có những website khi bạn đăng ký thành viên hoặc là gửi thông tin liên hệ thì họ sẽ có những mã code cho bạn nhập vào, những đoạn mã này có mục đích là chống spam vì nó được sinh ra ngẫu nhiên. Những đoạn mã như vậy người ta gọi là mã captcha, hay còn gọi là mã chống spam.

Vậy trong bài này tôi sẽ hướng dẫn các bạn tạo một thư viện captcha bằng php  cho riêng mình, đồng thời học cách sử dụng thư viện captcha, cách hiển thị captcha ra form và sử dụng ajax để validate captcha. Ta bắt đầu nhé.

1. Tạo thư viện captcha bằng php

Công việc đầu tiên là bạn phải tạo một thư viện captcha, đây là thư viện mà tôi viết sẵn nên các bạn xem trực tiếp trên nó nhé, tôi chỉ hướng dẫn cách sư dụng.

Bạn tạo file captcha.php với nội dung sau:

class Captcha 
{
	var $img_width      =   120;
	var $img_height     =   30;	
        
	var $font_path      =   './fonts'; // đường dẫn đên thư mục file text
	var $fonts          =   array();
	var $font_size      =   15;
	
	var $char_set       =   "ABCDEFGHJKLMNPQRSTUVWXYZ2345689";
	var $char_length    =   5;
	
	var $char_color     =   "#880000,#008800,#000088,#888800,#880088,#008888,#000000";
	var $char_colors    =   array();
	
	var $line_count     =   10;
	var $line_color     =   "#DD6666,#66DD66,#6666DD,#DDDD66,#DD66DD,#66DDDD,#666666";
	var $line_colors    =   array();
        
	var $bg_color       =   '#FFFFFF';
	
	// Khởi tạo cấu hình, hàm này sẽ trả về mã code và hiển thị hình
	function get_and_show_image( $override = array() ) 
        {
                // Override lại thong số config
		if( is_array( $override) )
		{
			foreach ( $override as  $key => $value) {
                                if( isset( $this->$key ))
                                        $this->$key = $value;
			}			
		}
                
                // Tạo danh sách colors thành một mảng
		$this->line_colors = preg_split("/,\s*?/", $this->line_color );
		$this->char_colors = preg_split("/,\s*?/", $this->char_color );
		
                // Lấy danh sách fonts trong folder được định nghĩa trong biến font_path
		$this->fonts = $this->collect_files( $this->font_path, "ttf");
                
                // Khởi tạo hình ảnh
		$img = imagecreatetruecolor( $this->img_width, $this->img_height);
		imagefilledrectangle($img, 0, 0, $this->img_width - 1, $this->img_height - 1, $this->gd_color( $this->bg_color ));
		
				
		// Vẽ hình lung tung cho đời nó tươi mát
		for ($i = 0; $i < $this->line_count; $i++){
			imageline($img,
				rand(0, $this->img_width  - 1),
				rand(0, $this->img_height - 1),
				rand(0, $this->img_width  - 1),
				rand(0, $this->img_height - 1),
				$this->gd_color($this->line_colors[rand(0, count($this->line_colors) - 1)])
			);
                }
			
		// Vẽ code lên hình
		$code = "";
		$y = ($this->img_height / 2) + ( $this->font_size / 2);
		
		for ($i = 0; $i < $this->char_length ; $i++) 
                {
			$color = $this->gd_color( $this->char_colors[rand(0, count($this->char_colors) - 1)] );
			$angle = rand(-30, 30);
			$char = substr( $this->char_set, rand(0, strlen($this->char_set) - 1), 1);
			
			$sel_font = $this->fonts[rand(0, count($this->fonts) - 1)];	
                        
			$font = $this->font_path . "/" . $sel_font;
			
			$x = (intval(( $this->img_width / $this->char_length) * $i) + ( $this->font_size / 2));
			$code .= $char;
			
			imagettftext($img, $this->font_size, $angle, $x, $y, $color, $font, $char);
		}
		
                // Hiển thị ảnh
                header('content-type: image/jpg');
                 
		ImageJPeg( $img);
                
		return $code;
	}	
        
        // Chuyển color
	function gd_color($html_color) {
		return preg_match('/^#?([\dA-F]{6})$/i', $html_color, $rgb)
		  ? hexdec($rgb[1]) : false;
	}

        // Lấy danh sách file theo phần mở rộng (ext)
	function collect_files($dir, $ext) 
        {
		if (false !== ($dir = opendir($dir))) 
                {
			$files = array();

			while (false !== ($file = readdir($dir)))
				if (preg_match("/\\.$ext\$/i", $file))
					$files[] = $file;

			return $files;

		}
                return false;
	}
}

Trong thư viện captcha này bạn cần cấu hình những thông số như sau:

  • Thuộc tính $font_path là nơi chứa những file font chữ của captcha
  • Thuộc tính $img_width là chiều dài của hình ảnh trả về
  • Thuộc tính $img_height là chiều cao của hình ảnh trả về 
  • Thuộc tính $char_length là chiều dài của mã code captcha
  • Thuộc tính $bg_color là mã màu của background, mặc định là màu trắng (FFFFFF),
  • Thuộc tính $font_size là kích thước của chữ in trên hình captcha

Cấu trúc folder sẽ có dạng như sau:

Ở đây bạn chỉ cần chú ý đến folder fonts, đây là folder chứa những file font chữ của captcha,

2. Tạo file hiển thị hình ảnh captcha bằng php

Trong bước này ta sẽ hiển thị hình ảnh captcha thông qua một file PHP, ở file này sẽ import file captcha.php, khởi tạo đối tượng captcha và lưu vào SESSION nhằm mục đích dùng để validate khi người dùng submit form.

Bạn tạo file image.php với nội dung như sau:

<?php session_start();

require("captcha.php");
$captcha = new Captcha();
$code = $captcha->get_and_show_image();

// Lưu code session
$_SESSION['captcha_code'] = $code;

?>

Bước này rất đơn giản, quan trọng nhất là ở đoạn code lưu SESSION, nếu ta không lưu thì ta sẽ không biết được mã code hiện tại là bao nhiêu để validate.

3. Tạo form liên hệ hiển thị captcha

Bây giờ tôi sẽ tạo form liên hệ, và để đơn giản tôi chỉ hiển thị một form đơn giản với một nội dung duy nhất đó là content. Bạn tạo file index.php với nội dung như sau:

<!DOCTYPE html>
<html>
    <head>
        <title></title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <script language="javascript" src="http://code.jquery.com/jquery-2.0.0.min.js"></script>
    </head>
    <body style="width: 500px; margin: 0px auto;">
        <form id="mainform" method="post" action="">
            <table border="1" cellspacing="0" cellpadding="5">
                <tr>
                    <td>Nội dung</td>
                    <td><textarea id="content" cols="40" rows="5"></textarea></td>
                </tr>
                <tr>
                    <td>Captcha</td>
                    <td>
                        <img src="image.php" id="img-captcha"/>
                        <input type="button" value="Reload" onclick="$('#img-captcha').attr('src', 'image.php?rand=' + Math.random())" /> <br/>
                        <input type="text" id="captcha" value="" />
                    </td>
                </tr>
                <tr>
                    <td>Captcha</td>
                    <td>
                        <input id="submit" type="submit" value="Lưu" />
                    </td>
                </tr>
            </table>
        </form>
        <script language="javascript">
            $(document).ready(function(){
                $('#submit').click(function()
                {
                    // Lấy dự liệu
                    var data = {
                        content : $('#content').val(),
                        captcha : $('#captcha').val()
                    };
                    
                    // Validate
                    if ($.trim(data.content) == ''){
                        alert('Bạn chưa nhập nội dung');
                    }
                    else if ($.trim(data.captcha) == ''){
                        alert('Bạn chưa nhập captcha');
                    }
                    else{
                        
                        $.ajax({
                            type : 'POST',
                            dataType : 'json',
                            url : 'ajax_validate.php',
                            data : data,
                            success : function (result){
                                if (!result.hasOwnProperty('error')){
                                    alert('Kết quả trả về không phù hợp');
                                }
                                else if (result['error'] == 'success'){
                                    $('#mainform').submit();
                                    alert('Kiểm tra thành công');
                                }
                                else{
                                    if (result['content'] != ''){
                                        alert(result['content']);
                                    }
                                    
                                    if (result['captcha'] != ''){
                                        alert(result['captcha']);
                                    }
                                }
                            },
                            error : function (){
                                alert('Có lỗi xảy ra trong quá trình xử lý');
                            }
                        });
                    }
                    return false;
                });
            });
        </script>
    </body>
</html>

Trong đó đoạn code dưới đây dùng để hiển thị captcha nên trong src của thẻ image tôi có trỏ đên file captcha.php. Và mỗi lần click vào button reload  tôi sẽ thay thông số random trên SRC của thẻ captcha với mục đích load lại hình ảnh, vì nếu không làm vậy thì bộ nhớ của trình duyệt sẽ ko gọi đến server để đổi code.

<tr>
    <td>Captcha</td>
    <td>
        <img src="image.php" id="img-captcha"/>
        <input type="button" value="Reload" onclick="$('#img-captcha').attr('src', 'image.php?rand=' + Math.random())" /> <br/>
        <input type="text" id="captcha" value="" />
    </td>
</tr>

Đoạn code dưới đây dùng để gửi ajax kiểm tra thông tin người dùng nhập vào:

$(document).ready(function(){
    $('#submit').click(function()
    {
        // Lấy dự liệu
        var data = {
            content : $('#content').val(),
            captcha : $('#captcha').val()
        };

        // Validate
        if ($.trim(data.content) == ''){
            alert('Bạn chưa nhập nội dung');
        }
        else if ($.trim(data.captcha) == ''){
            alert('Bạn chưa nhập captcha');
        }
        else{

            $.ajax({
                type : 'POST',
                dataType : 'json',
                url : 'ajax_validate.php',
                data : data,
                success : function (result){
                    if (!result.hasOwnProperty('error')){
                        alert('Kết quả trả về không phù hợp');
                    }
                    else if (result['error'] == 'success'){
                        $('#mainform').submit();
                        alert('Kiểm tra thành công');
                    }
                    else{
                        if (result['content'] != ''){
                            alert(result['content']);
                        }

                        if (result['captcha'] != ''){
                            alert(result['captcha']);
                        }
                    }
                },
                error : function (){
                    alert('Có lỗi xảy ra trong quá trình xử lý');
                }
            });
        }
        return false;
    });
});

4. Tạo trang nhận request ajax kiểm tra mã captcha bằng php

Bước này ta sẽ tạo một file ajax_validate.php, nội dung của file này sẽ lấy dữ liệu từ đoạn code gửi ajax bên file index.php

session_start();

// Lấy thông tin
$content = isset($_POST['content']) ? $_POST['content'] : false;
$captcha = isset($_POST['captcha']) ? $_POST['captcha'] : false;

// Biến lưu kết quả trả về
$error = array(
    'error'     => 'success',
    'content'   => '',
    'captcha'   => ''
);

// Kiểm tra content
if (!$content){
    $error['content'] = 'Bạn chưa nhập nội dung';
    $error['error'] = 'error';
}

// Kiểm tra captcha
if (!$captcha){
    $error['captcha'] = 'Bạn chưa nhập captcha';
    $error['error'] = 'error';
}
else if (!isset($_SESSION['captcha_code']) || $_SESSION['captcha_code'] != trim($captcha)) {
    $error['captcha'] = 'Captcha bạn nhập không đúng';
    $error['error'] = 'error';
}

// Trả kết quả cho client
die (json_encode($error));

Trong file này bạn chỉ cần chú ý đến những đoạn code comment mà tôi dùng để kiểm tra mã captcha. Vì ở file image.php tôi lưu code vào SESSION nên ở đây tôi sẽ kiểm tra và gọi session để so sánh thông số rồi trả về kết quả

Chạy lên ta ta sẽ có như hình ảnh dưới đây:

5. Lời kết

Bài này mình chỉ muốn giới thiệu thư viện captcha và cách sử dụng nó như hiển thị captcha, reload capcha,... đồng thời hướng dẫn các bạn cách sử dụng Ajax để validate form. Vì bài khá đơn giản nên mình không sử dụng database để lưu trữ.

Hãy để lại link bài viết gốc khi chia sẻ bài viết này, mình sẽ report DMCA với những website lấy nội dung mà không để nguồn hoặc copy bài với số lượng lớn.

Nguồn: freetuts.net

Profile photo of adminTheHalfHeart

TheHalfHeart

Có sở thích viết tuts nên đã từng tham gia viết ở một số diễn đàn, đến năm 2014 mới có điều kiện sáng lập ra freetuts.net. Sinh năm 90 và có 1 vợ 2 con, thích ca hát và lập trình.

ĐĂNG BÌNH LUẬN: Đăng câu hỏi trên Group Facebook để được hỗ trợ nhanh nhất.