旧版正方教务系统登录验证码识别

默认分类 · 2018-03-22 · 1074 人浏览
旧版正方教务系统登录验证码识别

识别效果

本文以XX大学的正方教务系统验证码为实例

请提前将验证码下载到本地

附件1: model.ini (字模文件,已经提取好,不需修改,放在文章末尾)

原理即将图像进行二值化处理,逐一对每一个像素点进行处理,处理结果非黑即白

业务逻辑

  • 1、首先从网络上下载验证码,存储到本地

  • 2、校验图片信息,确保是gif(因为算法中采用的是gif引擎对图片处理,可根据自身需求自己修改代码中的引擎)

    通过打印图片基本信息,得到以下数组

    Array ( [0] => 60 [1] => 22 [2] => 1 [3] => width="60" height="22" [bits] => 8 [channels] => 3 [mime] => image/gif )
  • 3、将图像进行灰度化处理,这样可以使图像二值化难度降低,示例见下图

  • 4、二值化处理图像
$rgbarray['red'] <= 84 && $rgbarray['green'] <= 80 && $rgbarray['blue'] <= 240

通过观察发现,将图像的RGB控制在(84, 80, 240)以内,打印输出■,否则输出□(存储在数组内)

此时的识别效果最精准

  • 5、对二值化的图像进行分割处理,该验证码排列规律性极强,故分割可以做到精确,将5个数字分割开来,将5个数字的数组分别与model.ini中的字模加以对比
  • 6、对于经常识别出错的数字,我们对其提取特征,二次验证
  • 7、处理结果展示
 Array ( [0] => 60 [1] => 22 [2] => 1 [3] => width="60" height="22" [bits] => 8 [channels] => 3 [mime] => image/gif )

上述过程都放在了DealCode.class.php

<? php
/*
*文件名:DealCode.class.php
*版本:
0.0.1
0.1.0
*时间:
2018年2月15日 14点23分
2018年3月21日 21点09分
*作者:Bill
*功能:识别传来处的理后的*数字*图片,仅适用于XX大学教务处系统的验证码
*/
header('content-type:text/html;charset=utf-8');
class DealCode {

    //图片地址(本地)
    private $imagePath;
    private $origin_code;
    private $code;
    private $model;
    //RGB阈值
    private $rmax;
    private $gmax;
    private $bmax;
    //验证码的类型
    private $type;

    public
    function __construct() {
        self::classify();
    }

    /*
     * 验证码类别分流
     * @param $type
     *
     */
    private
    function classify() {
        //初始化字模
        $config_file_path = 'model.ini';
        $config_info = parse_ini_file($config_file_path, true);
        //筛选验证码类型
        switch ($this - > type) {
            //验证码
            case 0:
                $this - > model = array(
                    0 => $config_info['ahut']['0'],
                    1 => $config_info['ahut']['1'],
                    2 => $config_info['ahut']['2'],
                    3 => $config_info['ahut']['3'],
                    4 => $config_info['ahut']['4'],
                    5 => $config_info['ahut']['5'],
                    6 => $config_info['ahut']['6'],
                    7 => $config_info['ahut']['7'],
                    8 => $config_info['ahut']['8'],
                    9 => $config_info['ahut']['9'],
                    'v5' => $config_info['ahut']['v5'], //数字5特征提取
                    'v6' => $config_info['ahut']['v6'], //数字6特征提取
                    'v7' => $config_info['ahut']['v7'], //数字7特征提取
                    'v8' => $config_info['ahut']['v8'], //数字8特征提取
                );
                //print_r($this->model);
                $this - > code = array(
                    0 => null,
                    1 => null,
                    2 => null,
                    3 => null,
                    4 => null,
                );
                $this - > rmax = 125;
                $this - > gmax = 94;
                $this - > bmax = 222;

                // //调试
                // $this->rmax=125;
                // $this->gmax=100;
                // $this->bmax=255;

                break;

            default:
                echo '没有该学校的识别方法!';
        }
    }

    /*
     * 载入验证码,必要步骤
     * @param $imagePath
     * @return $number
     */
    function loadVerify($imagePath, $type) {
        $im = imagecreatefromgif($imagePath);
        unlink($imagePath);
        if ($im && imagefilter($im, IMG_FILTER_GRAYSCALE)) {
            // echo 'Image converted to grayscale.';
            imagegif($im, $imagePath);
        } else {
            echo 'Conversion to grayscale failed.';
        }
        $this - > imagePath = $imagePath;
        $this - > type = $type;
    }

    /*
     * 【XX教务处】验证码识别
     * @param $imagePath
     * @return $number
     */
    public
    function OCR_CODE() {
        $codeRes = self::getHec();
        return $codeRes;
    }

    /*
     * 显示二值化的图片
     * @param $imagePath
     * @return 二值化的图片
     */
    public
    function OCR_SHOW() {
        $array = getimagesize($this - > imagePath);
        print_r($array);
        self::visualHec();
    }

    private
    function visualHec() {
        $res = imagecreatefromgif($this - > imagePath);
        //$res = imagecreatefrompng($this->imagePath);
        $size = getimagesize($this - > imagePath);
        echo "<pre>";
        for ($i = 0; $i < $size[1]; ++$i) {
            for ($j = 0; $j < $size[0]; ++$j) {
                $rgb = imagecolorat($res, $j, $i);
                $rgbarray = imagecolorsforindex($res, $rgb);
                // if($j>0 && $j<14){
                //     // if (($rgbarray['red'] ==0 || $rgbarray['red'] <= 52) && $rgbarray['green'] ==0 && ($rgbarray['blue'] <= 205 || $rgbarray['blue'] <= 255)) {     
                //     if ($rgbarray['red'] <= 84 && $rgbarray['green'] <= 80 && $rgbarray['blue'] <= 240) { 
                //         echo "■";
                //     }else{
                //         echo "□";
                //     }
                // }else{
                //     if ($rgbarray['red'] < ($this->rmax) && $rgbarray['green'] < ($this->gmax) && $rgbarray['blue'] < ($this->bmax)) { 
                //         echo "■";
                //     }else{
                //         echo "□";
                //     }
                // }
                if ($rgbarray['red'] < ($this - > rmax) && $rgbarray['green'] < ($this - > gmax) && $rgbarray['blue'] < ($this - > bmax)) {
                    echo "■";
                } else {
                    echo "□";
                }
                // if(
                //     ($rgbarray['red'] == 147 && $rgbarray['green'] == 151 && $rgbarray['blue'] == 150) ||
                //     ($rgbarray['red'] == 204 && $rgbarray['green'] == 203 && $rgbarray['blue'] == 211) ||
                //     ($rgbarray['red'] == 160 && $rgbarray['green'] == 158 && $rgbarray['blue'] == 205) ||
                //     ($rgbarray['red'] == 155 && $rgbarray['green'] == 152 && $rgbarray['blue'] == 195) ||
                //     ($rgbarray['red'] == 163 && $rgbarray['green'] == 151 && $rgbarray['blue'] == 253) ||
                //     ($rgbarray['red'] == 176 && $rgbarray['green'] == 138 && $rgbarray['blue'] == 177)
                // ){
                //     echo "□";
                // }else{
                //     echo "■";
                // }
            }
            echo "<br/>";
        }
        echo "<br/>";
        echo "[完毕]";
        echo "</pre>";
    }

    private
    function getHec() {
        $m = '';
        $codeRes = '';
        $res = imagecreatefromgif($this - > imagePath);
        //$res = imagecreatefrompng($this->imagePath);
        $size = getimagesize($this - > imagePath);
        //坐标:(j宽度,i高度)
        //第一个字模的矩阵为:宽度0-13,高度所有
        for ($i = 0; $i < $size[1]; ++$i) {
            for ($j = 0; $j < $size[0]; ++$j) {
                $rgb = imagecolorat($res, $j, $i);
                $rgbarray = imagecolorsforindex($res, $rgb);
                // if($j>0 && $j<14){
                //     //if (($rgbarray['red'] ==0 || $rgbarray['red'] <= 52) && $rgbarray['green'] ==0 && ($rgbarray['blue'] <= 205 || $rgbarray['blue'] <= 255)) {
                //     if ($rgbarray['red'] <= 84 && $rgbarray['green'] <= 80 && $rgbarray['blue'] <= 209) { 
                //         $m = "0";
                //     }else{
                //         $m = "1";
                //     }
                // }else{
                //     if ($rgbarray['red'] < ($this->rmax) && $rgbarray['green'] < ($this->gmax) && $rgbarray['blue'] < ($this->bmax)) { 
                //         $m = "0";
                //     }else{
                //         $m = "1";
                //     }
                // }
                if ($rgbarray['red'] < ($this - > rmax) && $rgbarray['green'] < ($this - > gmax) && $rgbarray['blue'] < ($this - > bmax)) {
                    $m = "0";
                } else {
                    $m = "1";
                }
                // if(
                //     ($rgbarray['red'] == 147 && $rgbarray['green'] == 151 && $rgbarray['blue'] == 150) ||
                //     ($rgbarray['red'] == 204 && $rgbarray['green'] == 203 && $rgbarray['blue'] == 211) ||
                //     ($rgbarray['red'] == 160 && $rgbarray['green'] == 158 && $rgbarray['blue'] == 205) ||
                //     ($rgbarray['red'] == 155 && $rgbarray['green'] == 152 && $rgbarray['blue'] == 195) ||
                //     ($rgbarray['red'] == 163 && $rgbarray['green'] == 151 && $rgbarray['blue'] == 253) ||
                //     ($rgbarray['red'] == 176 && $rgbarray['green'] == 138 && $rgbarray['blue'] == 177)
                // ){
                //     $m = "1";
                // }else{
                //     $m = "0";
                // }
                $this - > origin_code[$i][$j] = $m;
            }
        }
        switch ($this - > type) {
            case 0:
                $codeRes = self::ahut_DealCode();
                return $codeRes;
                break;

            case 1:

                break;

            default:

        }
    }

    public function ahut_DealCode() {
        for ($p = 5; $p < 17; $p++) {
            for ($q = 5; $q < 14; $q++) {
                $this - > code[0] = $this - > code[0].$this - > origin_code[$p][$q];
            }
        }

        for ($p = 5; $p < 17; $p++) {
            for ($q = 14; $q < 23; $q++) {
                $this - > code[1] = $this - > code[1].$this - > origin_code[$p][$q];
            }
        }

        for ($p = 5; $p < 17; $p++) {
            for ($q = 23; $q < 32; $q++) {
                $this - > code[2] = $this - > code[2].$this - > origin_code[$p][$q];
            }
        }

        for ($p = 5; $p < 17; $p++) {
            for ($q = 32; $q < 41; $q++) {
                $this - > code[3] = $this - > code[3].$this - > origin_code[$p][$q];
            }
        }

        for ($p = 5; $p < 17; $p++) {
            for ($q = 41; $q < 50; $q++) {
                $this - > code[4] = $this - > code[4].$this - > origin_code[$p][$q];
            }
        }

        // echo "<pre>";
        // print_r($this->code);
        // echo "<pre/>";

        /*
         * 算法优化
         * 对于没有识别出来的,不到达指定匹配程度的数字进行降匹配率限制操作
         */
        $codeArr = array(
            0 => '-1',
            1 => '-1',
            2 => '-1',
            3 => '-1',
            4 => '-1',
        );
        $codeRes = '';
        // for($i=0;$i<5;++$i){
        //     foreach($this->model as $key=>$value){
        //         similar_text($this->code[$i],$value,$percent);
        //         //if($percent>87.97){
        //         if($percent>87){
        //             //echo '第'.$i.'个数字的识别结果是:'.$key."<br/>";
        //             //$codeRes=$codeRes.$key;
        //             $codeArr[$i]=$key;
        //             break;
        //         }
        //     }
        // }
        /*校验验证码位数,是否全部识别出来,没有识别出来的,降低匹配率限制
            匹配率,选出匹配率最高的*/

        //初始化单字符匹配率
        $percent = 0;
        //初始化单字符最大匹配程度存储变量
        $p = 0;
        //初始化相似度
        $sim = array(
            0 => 0,
            1 => 0,
            2 => 0,
            3 => 0,
            4 => 0,
            5 => 0,
            6 => 0,
            7 => 0,
            8 => 0,
            9 => 0,
        );
        for ($i = 0; $i < 5; $i++) {
            //++代码兼容性
            if ($codeArr[$i] == '-1') {
                foreach($this - > model as $key => $value) {
                        similar_text($this - > code[$i], $value, $percent);
                        $sim[$key] = $percent;
                    }
                    //筛选出匹配程度最大的
                    //筛选出来的键名$p就是验证码对应的数字;
                $p = array_search(max($sim), $sim);
                //$p=(string)$p;
                /*
                             识别进化
                             对于上述的算法,会造成机器5、6不分,7、8不分,因此识别到5/6/7/8的数字时,要进一步对这四个数字的局部特征进行进一步比对
                             根据2018年3月21日实验发现,仅仅是在,
                                识别图片8=>数字7,暂时没有发现识别图片7=>数字8,这是单向的,8=>7
                                识别图片6=>数字5,暂时没有发现识别图片5=>数字6,这是单向的,6=>5
                                因此在识别结果为6/8的时候,再次进行校验,比对特征区域,通过则输出6/8,否则输出5/7
                                对于上述的算法,识别到6/8的数字时,要进一步对这2个数字的局部特征进行进一步比对
                             另外发现,验证码前部图片识别失败率明显高于后部,初步判定原因可能是底色分离问题导致
                            */
                if ($p == '6') {
                    $vp = substr($this - > code[$i], 63, 71);
                    similar_text($this - > model['v5'], $vp, $vpPercentA);
                    similar_text($this - > model['v6'], $vp, $vpPercentB);
                    //if($vpPercent<77.777777777778){
                    if ($vpPercentA > $vpPercentB) {
                        $p = '5';
                    }
                }
                if ($p == '8') {
                    $vp = substr($this - > code[$i], 45, 62);
                    similar_text($this - > model['v7'], $vp, $vpPercentA);
                    similar_text($this - > model['v8'], $vp, $vpPercentB);
                    //if($vpPercent<50){
                    if ($vpPercentA > $vpPercentB) {
                        $p = '7';
                    }
                }
                $codeArr[$i] = $p;
            }
        }
        $codeRes = $codeArr[0].$codeArr[1].$codeArr[2].$codeArr[3].$codeArr[4];
        return $codeRes;
    }

}
  • 调用方法
<? php
header('content-type:text/html;charset=utf-8');
set_time_limit(300);

// CURL下载验证码
function CURL($url, $headers, $method, $data, $showHeaders) {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_HEADER, $showHeaders);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_NOBODY, false);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
    curl_setopt($ch, CURLOPT_COOKIEFILE, dirname(__FILE__).
        "/cookie");
    curl_setopt($ch, CURLOPT_COOKIEJAR, dirname(__FILE__).
        "/cookie");
    if ($method == 'POST') {
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
    }
    $result = curl_exec($ch);
    curl_close($ch);
    return $result;
}

?>
< h3 > 针对XX大学教务处系统的验证码的识别 < /h3> < ul >
    < li > 本识别系统针对XX大学教务处系统的验证码的识别 < /li> < li > 识别率99.99 % < /li> < li > 没有接入第三方图像识别API < /li> < li > 作者: Bill < /li> < li > 2018 年3月22日 15 点04分 < /li> < li > 刷新页面以便于从XX大学教务处系统重新获取验证码并识别, 每次获取10个验证码 < /li> < /ul> < table cellspacing = "0"
cellpadding = "5"
border = "1" >
    < tr >
    < td > # < /td> < td > 验证码 < /td> < td > 识别结果 < /td> < td > 操作时间 < /td> < td > 识别耗时 < /td> < /tr> <? php
    //Config
    //////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////
    //说明,这个count是请求验证码的次数,根据实际需要,自行设置///////////
$count = 10; ////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

include("DealCode.class.php");
for ($k = 0; $k < $count; ++$k) {

    $img = CURL("http://211.70.149.135:88/CheckCode.aspx", array(
            "Cache-Control: max-age=0",
            "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
            "Accept-Language: zh-CN,zh;q=0.9",
            "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36",
            "Upgrade-Insecure-Requests: 1",
            "Host: 211.70.149.135:88",
            "Proxy-Connection: keep-alive"
        ),
        "GET",
        "",
        false
    );
    // 用了一个订单号的算法生成唯一文件名
    @
    date_default_timezone_set("PRC");
    //订购日期
    $a = array();
    $order_date = date('Y-m-d');
    //订单号码主体(YYYYMMDDHHIISSNNNNNNNN)
    $order_id_main = date('YmdHis').rand(10000000, 99999999);
    //订单号码主体长度
    $order_id_len = strlen($order_id_main);
    $order_id_sum = 0;
    for ($i = 0; $i < $order_id_len; $i++) {
        $order_id_sum += (int)(substr($order_id_main, $i, 1));
    }
    //唯一订单号码(YYYYMMDDHHIISSNNNNNNNNCC)
    $order_id = $order_id_main.str_pad((100 - $order_id_sum % 100) % 100, 2, '0', STR_PAD_LEFT);

    file_put_contents('zf/'.$order_id.
        '.jpg', $img);

    //sleep(1);

    $p = new DealCode();

    $t1 = microtime(true);

    $p - > loadVerify('zf/'.$order_id.
        '.jpg', 0);

    $codeRes = $p - > OCR_CODE();
    $show = $p - > OCR_SHOW();
    $t2 = microtime(true); ?>
    < tr >
        < td > <? php echo $k + 1; ?> < /td> < td > < img src = "<?php 
    echo 'zf/'.$order_id.
    '.jpg';
    // unlink('zf/'.$order_id.'.jpg'); 
    ?> "/></td> < td > <? php echo "识别结果:".$codeRes; ?> < /td> < td > <? php echo date('y-m-d h:i:s'); ?> < /td> < td > <? php echo '耗时:'.(($t2 - $t1) * 1000).
    'ms'; ?> < /td> < /tr> <? php
    // echo "<br/>";
    // $p->OCR_SHOW();

    //销毁对象和缓存
    unset($p);
}

?>

< /table>
  • 附件:model.ini
[ahut]
0 = 110000111100000011000110001001111001001111001001111001001111001001111001001111001000110001100000011110000111
1 = 111100111111000111110000111100100111101100111111100111111100111111100111111100111111100111111100111111100111
2 = 110000111100000011000111001001111001111111001111110011111100011111000111110001111100111111000000001000000001
3 = 110000011100000001001111001111111001111000011111000011111110001111111001001111001000110001100000011110000111
4 = 111110011111100011111100011111000011110010011110010011100110011001110011000000001000000001111110011111110011
5 = 100000011100000011100111111000111111000000111000000011001110001111111001001111001000110001100000011110000111
6 = 110000011100000001100111001001111111001000111000000011000110001001111001001111001100111001100000011110000111
7 = 000000001000000001111110011111100111111100111111001111111001111111001111110001111110011111110011111110011111
8 = 110000111100000011001111001001111001001111001100000011100000011001111001001111001001111001100000011110000111
9 = 110000111100000011001110011001111001001111001000110001100000001110001001111111001001110011000000011100000111
v5 = 111111001
v6 = 001111001
v7 = 111001111111001111
v8 = 100000011100000011

;注释
;6的特征是在初始矩阵中的第8行
;8的特征是在初始矩阵中的第6-7行


  1. Umrqbr 昨天

    buy cheap generic nizoral - order generic lotrisone buy sporanox 100 mg for sale

  2. Xthbiz 昨天

    semaglutide online buy - buy glucovance without a prescription order DDAVP without prescription

  3. Ltwbbt 前天

    order terbinafine 250mg generic - diflucan drug buy grifulvin v pills

  4. [url=https://valtrexmedication.com/]valtrex over counter[/url]

  5. Qhjrgl 4 天前

    buy glycomet generic - precose 25mg generic precose cheap

  6. Iyrfoe 5 天前

    repaglinide 1mg sale - order generic empagliflozin 25mg jardiance 25mg uk

  7. Jvcxxe 7 天前

    glyburide us - pill dapagliflozin 10mg forxiga uk

  8. [url=https://valtrexv.com/]valtrex without prescription com[/url]

  9. [url=https://prednisoneo.com/]prednisone 1 tablet[/url]

  10. Csojnl 8 天前

    depo-medrol us - cost astelin 10 ml order azelastine 10 ml sprayers

  11. Rcskax 9 天前

    desloratadine 5mg for sale - order albuterol online cheap ventolin inhaler

  12. [url=http://happyfamilystorerx.online/]legitimate canadian mail order pharmacy[/url]

  13. Arfykx 11 天前

    order albuterol 4mg generic - purchase fluticasone sale buy theo-24 Cr for sale

  14. Dbxyzs 11 天前

    ivermectin 12mg for people - doryx online order cefaclor oral

  15. Rmlbwc 14 天前

    buy azithromycin no prescription - buy zithromax 500mg ciprofloxacin 500mg oral

  16. Anciwx 15 天前

    clindamycin brand - buy generic chloromycetin over the counter order chloramphenicol

  17. Uypwpf 20 天前

    buy augmentin 1000mg pill - buy trimethoprim online cipro oral

  18. Qaofnp 20 天前

    amoxil for sale - buy cefuroxime pills cipro price

  19. Cbxnof 24 天前

    buy atarax 10mg without prescription - atarax over the counter where can i buy amitriptyline

  20. Qoceqi 24 天前

    buy clomipramine 25mg - abilify 30mg brand buy generic doxepin

  21. Epjqsz 26 天前

    buy seroquel no prescription - eskalith over the counter order eskalith for sale

  22. Aydfsn 27 天前

    order clozaril 50mg online cheap - frumil 5 mg brand famotidine drug

  23. Perfcw 29 天前

    buy retrovir pills - zyloprim 300mg canada brand zyloprim

  24. Ysmrny 29 天前

    glycomet 1000mg drug - order lincomycin generic cheap lincomycin

  25. Fnxvol 03-23

    furosemide 100mg oral - furosemide 100mg cost buy captopril for sale

  26. Wkxesi 03-18

    buy ciplox pills - cheap doryx sale order erythromycin pills

  27. Emepro 03-17

    flagyl 200mg us - oxytetracycline buy online buy generic zithromax

  28. Huwium 03-15

    order generic cipro 500mg - order myambutol online cheap buy amoxiclav pills

  29. Ulfrrg 03-15

    buy cipro paypal - keflex 500mg price augmentin 1000mg cheap

  30. Gngnea 03-13

    order atorvastatin 40mg pills lipitor 40mg tablet order lipitor 40mg pills

Theme Jasmine by Kent Liao And Bill

本站由提供云存储服务