• 使用Lua GD库动态生成验证码图片(2)


    在前一篇文章中初步的实现了验证码的随机生成,觉得很容易被破解,因此加了一些干扰;

    鹤冲天建议使用表达式作为验证码,即使破解程序识别了验证码,也要计算结果才能通过验证,在一定程度上增加了破解难度。


    因此我对代码进行了重新整理,通过控制运行时配置选项来达到不同效果。

    现在主要做到了:

    (1)字符内容随机(普通字符串或表达式)

    (2)每个字符的字体随机

    (3)每个字符大小随机

    (4)每个字符倾斜角度随机

    (5)干扰线条随机

    除了(4)其他都可以通过配置来控制。


    下面是代码,有详细的注释,就不多说了:

      1 require("gd")
      2 require("lfs")
      3 
      4 -----------------------------------------------------------------------------------------------------------------------------------
      5 --运行配置项
      6 -----------------------------------------------------------------------------------------------------------------------------------
      7 --字体:-1-使用gd.FONT_GIANT字体;1-使用随机字体;其他-使用“fonts”中第一个字体
      8 --字体预先在变量“fonts”中定义;如果fonts没有值,将搜索系统中的所有字体,字体路径在“FONT_PATH”中预定义
      9 FONT=1
     10 
     11 --每个字符字体随机:1-是,其他-否
     12 --仅当“FONT”值为“1”时,本变量起作用
     13 FONT_RANDOM_CHAR=0
     14 
     15 --每个字符字体大小是否随机:1-是,其他-否
     16 --仅当FONT^=-1时起作用
     17 FONT_SIZE_RANDOM=1
     18 
     19 --是否增加线条干扰:1-是;其他-否
     20 XLINE_FALG=1
     21 
     22 --干扰线条的最多条数
     23 --仅当“XLINE_FALG”的值为“是”是,本变量起作用
     24 XLINE_LIMIT=6
     25 
     26 --验证码类型:TEXT-字符串;EXPRESSION-表达式
     27 MARK_TYPE="TEXT"
     28 --MARK_TYPE="EXPRESSION"
     29 
     30 --字符个数:仅当“MARK_TYPE”=“TEXT”时,本变量起作用
     31 TEXT_NUM=6
     32 
     33 --表达式项数限制(最多不超过EXPRESSION_ITEMS项):仅当“MARK_TYPE”=“EXPRESSION”时,本变量起作用
     34 EXPRESSION_ITEMS=3
     35 
     36 --生成验证码个数
     37 MARK_NUM=100000
     38 
     39 
     40 -----------------------------------------------------------------------------------------------------------------------------------
     41 --预定义变量
     42 -----------------------------------------------------------------------------------------------------------------------------------
     43 --词典
     44 dict={'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','1','2','3','4','5','6','7','8','9','0'}
     45 numbers={"1","2","3","4","5","6","7","8","9"}--表达式可使用数字,排除0
     46 operators={"+","-","*"}--表达式可使用运算符,不支持“/”
     47 
     48 --随机种子,防止通过获取系统时间得到随机数种子,直接计算出验证码
     49 math.randomseed(os.time())
     50 
     51 --大小
     52 IMG_WIDTH=100
     53 IMG_HEIGHT=40
     54 
     55 --颜色
     56 im2 = gd.createTrueColor(IMG_WIDTH,IMG_HEIGHT)
     57 fg = im2:colorAllocate(129,32,28)--前景色
     58 bg = im2:colorAllocate(216,235,238)--背景色
     59 
     60 --字体
     61 FONT_PATH="C:/WINDOWS/Fonts/"--系统字体路径
     62 fonts={}
     63 --fonts={"courbd.ttf","courbi.ttf","DejaVuMonoSans.ttf","DejaVuMonoSansBold.ttf","DejaVuMonoSansBoldOblique.ttf","DejaVuMonoSansOblique.ttf","lucon.ttf","monosbi.ttf","nina.ttf","simhei.ttf","simkai.ttf","swissci.ttf","tahomabd.ttf","timesbd.ttf","timesbi.ttf","timesi.ttf","trebuc.ttf","trebucit.ttf"}
     64 font_size={14,15,16,17,18,19,20}--随机字体大小
     65 
     66 --生成的随机码
     67 stringmark=""
     68 
     69 -----------------------------------------------------------------------------------------------------------------------------------
     70 --功能函数
     71 -----------------------------------------------------------------------------------------------------------------------------------
     72 --初始化:创建图片、设置背景
     73 function init()
     74     im2 = gd.createTrueColor(IMG_WIDTH, IMG_HEIGHT)
     75     im2:filledRectangle(0,0,IMG_WIDTH,IMG_HEIGHT,bg)
     76     stringmark=""
     77 end
     78 
     79 --查找字体
     80 function searchFont()
     81     if table.getn(fonts)==0 then --没有指定字体,就搜索系统字体
     82         local i=1
     83         for file in lfs.dir(FONT_PATH) do
     84             if string.find(file,".ttf")and not string.find(file,"esri")  then --排除特定字体
     85                 fonts[i]=file
     86                 i=i+1
     87             end
     88         end
     89     end
     90 end
     91 
     92 --生成text字符串
     93 function makeText()
     94     local num=table.getn(dict)
     95     for i=1,TEXT_NUM do
     96         stringmark=stringmark..dict[math.random(num)]
     97     end
     98 end
     99 
    100 --生成表达式字符串
    101 function makeExpression()
    102     local n=math.random(2,3)--表达式项数
    103     local strings={}
    104     for i=1,n*2-1 do--表达式项数+运算符项数
    105         local str=""
    106         if i%2==1 then--数字
    107             local n2=math.random(1,2)
    108             for j=1,n2 do--每个数字最多2位
    109                 str=str..numbers[math.random(9)]
    110             end
    111         else--运算符
    112             str=operators[math.random(3)]
    113         end
    114         strings[i]=str
    115     end 
    116     return strings
    117 end
    118 
    119 --主函数
    120 function doIt()
    121     searchFont()
    122     local numfonts=table.getn(fonts)
    123     if numfonts<1 then
    124         print("没有找到字体!")
    125         return
    126     end
    127 
    128     for i=1,MARK_NUM do
    129         init()
    130         local font=fonts[0];
    131         local fontsize=20;
    132         
    133         if MARK_TYPE=="TEXT" then--普通字符串验证码
    134             makeText()
    135 --            print(stringmark)    
    136             if FONT==-1 then
    137                 im2:string(gd.FONT_GIANT,18,10,stringmark, fg)
    138             else
    139                 for nIndex=1,string.len(stringmark) do
    140                     if FONT==1 then font=fonts[math.random(numfonts)] end
    141                     if FONT_SIZE_RANDOM==1 then fontsize=font_size[math.random(7)] end
    142                     im2:stringFT(fg,FONT_PATH..font,fontsize,math.random()/math.pi,5+(nIndex-1)*1525string.sub(stringmark,nIndex,nIndex))
    143                 end        
    144             end
    145         elseif MARK_TYPE=="EXPRESSION" then--表达式验证码
    146             local strings=makeExpression()
    147             local raise=0
    148             local ncharacter=0 
    149             for j=1,table.getn(strings) do
    150                 if j%2==0 then raise=3 end
    151                 stringmark=stringmark..strings[j]
    152                 if FONT==1 then font=fonts[math.random(numfonts)] end
    153                 if FONT_SIZE_RANDOM==1 then fontsize=font_size[math.random(5)] end          
    154                 im2:stringFT(fg,FONT_PATH..font,fontsize,math.random()/math.pi,5+ncharacter*12+raise, 25, strings[j])
    155                 ncharacter=ncharacter+string.len(strings[j])
    156             end
    157 --            print(stringmark) 
    158 --            value=tonumber(stringmark)
    159 --            print(value)
    160         end
    161         
    162         --  随机线条干扰
    163         if XLINE_FALG==1 then
    164             local xlineNum=math.random(XLINE_LIMIT)
    165             for i=1,xlineNum do
    166                 im2:line(math.random(IMG_WIDTH),math.random(IMG_HEIGHT),math.random(IMG_WIDTH),math.random(IMG_HEIGHT),fg)
    167             end
    168         end
    169 
    170         im2:png("./output/"..font..".png",100)                
    171     end
    172 end
    173 
    174 --start=os.clock()
    175 doIt()
    176 --print(os.clock()-start)


    效果大致如下:

  • 相关阅读:
    pipelinewise 学习二 创建一个简单的pipeline
    pipelinewise 学习一 docker方式安装
    Supercharging your ETL with Airflow and Singer
    ubuntu中使用 alien安装rpm包
    PipelineWise illustrates the power of Singer
    pipelinewise 基于singer 指南的的数据pipeline 工具
    关于singer elt 的几篇很不错的文章
    npkill 一个方便的npm 包清理工具
    kuma docker-compose 环境试用
    kuma 学习四 策略
  • 原文地址:https://www.cnblogs.com/chutianyao/p/1783222.html
Copyright © 2020-2023  润新知