zoukankan      html  css  js  c++  java
  • 红马版验证码实现(中文+变形+噪点)

    为了应付越来越多的自动发帖机、恶意攻击等情形,验证码技术在大量的网站上得到使用。我在近期开发一个注册网站的时候,也使用了这一技术。当然,我并不想完完全全自己重新实现,而是参考了网上能够找到的实现,做了若干改进而已。下面谈谈我的实现。
        补两张图片:
          
        首先看验证码图片输出页的代码:

    <%@ Page Language="C#" %>

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

    <script runat="server">
        
    protected void Page_Load(object sender, EventArgs e)
        {
            VryImgGen gen 
    = new VryImgGen();
            
    string verifyCode = gen.CreateVerifyCode(51);
            Session[
    "VerifyCode"= verifyCode.ToUpper();
            System.Drawing.Bitmap bitmap 
    = gen.CreateImage(verifyCode);
            System.IO.MemoryStream ms 
    = new System.IO.MemoryStream();
            bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
            Response.Clear();
            Response.ContentType 
    = "image/Png";
            Response.BinaryWrite(ms.GetBuffer());
            bitmap.Dispose();
            ms.Dispose();
            ms.Close();
            Response.End();
        }
    </script>

        功能很简单,初始化一个验证码生成对象,生成图片。然后保存到一个MemoryStream里。得到字节流,输出字节流。验证码的数据是保存在Session中的,这是最简单的方法。或者可以加密储存在cookie里,也是可以的。

        再来看看验证码生成对象:

    using System;
    using System.Data;
    using System.Configuration;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Web.UI.HtmlControls;
    using System.Drawing;
    using System.Text;

    /// <summary>
    /// Summary description for VryImgGen
    /// </summary>
    public partial class VryImgGen
    {
        
        
    /// <summary>
        
    /// 供验证码生成汉字时选取的汉字集,若为空则按照《GB2312简体中文编码表》编码规则构造汉字
        
    /// </summary>
        public static string ChineseChars = String.Empty;

        
    /// <summary>
        
    /// 英文与数字串
        
    /// </summary>
        protected static readonly string EnglishOrNumChars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
       
        
    public VryImgGen()
        {
            rnd 
    = new Random(unchecked((int)DateTime.Now.Ticks));
        }

        
    /// <summary>
        
    /// 全局随机数生成器
        
    /// </summary>
        private Random rnd;
        
        
    int length = 5;
        
    /// <summary>
        
    /// 验证码长度(默认6个验证码的长度)
        
    /// </summary>
        public int Length
        {
            
    get { return length; }
            
    set { length = value; }
        }
            
        
    int fontSize = 18;
        
    /// <summary>
        
    /// 验证码字体大小(为了显示扭曲效果,默认30像素,可以自行修改)
        
    /// </summary>
        public int FontSize
        {
            
    get { return fontSize; }
            
    set { fontSize = value; }
        }   
        
        
    int padding = 4;
        
    /// <summary>
        
    /// 边框补(默认4像素)
        
    /// </summary>
        public int Padding
        {
            
    get { return padding; }
            
    set { padding = value; }
        }   
        
        
    bool chaos = true;
        
    /// <summary>
        
    /// 是否输出燥点(默认输出)
        
    /// </summary>
        public bool Chaos
        {
            
    get { return chaos; }
            
    set { chaos = value; }
        }   
            
        Color chaosColor 
    = Color.LightGray;
        
    /// <summary>
        
    /// 输出燥点的颜色(默认灰色)
        
    /// </summary>
        public Color ChaosColor
        {
            
    get { return chaosColor; }
            
    set { chaosColor = value; }
        }
        
        Color backgroundColor 
    = Color.White;
        
    /// <summary>
        
    /// 自定义背景色(默认白色)
        
    /// </summary>
        public Color BackgroundColor
        {
            
    get { return backgroundColor; }
            
    set { backgroundColor = value; }
        }   
            
        Color[] colors 
    = { Color.Black, Color.Red, Color.DarkBlue, Color.Green, Color.Orange, Color.Brown, Color.DarkCyan, Color.Purple };
        
    /// <summary>
        
    /// 自定义随机颜色数组
        
    /// </summary>
        public Color[] Colors
        {
            
    get { return colors; }
            
    set { colors = value; }
        }
      
        
    string[] fonts = { "Arial""Georgia" };
        
    /// <summary>
        
    /// 自定义字体数组
        
    /// </summary>
        public string[] Fonts
        {
            
    get { return fonts; }
            
    set { fonts = value; }
        }   

        
    #region 产生波形滤镜效果

        
    private const double PI = 3.1415926535897932384626433832795;
        
    private const double PI2 = 6.283185307179586476925286766559;

        
    /// <summary>
        
    /// 正弦曲线Wave扭曲图片(Edit By 51aspx.com)
        
    /// </summary>
        
    /// <param name="srcBmp">图片路径</param>
        
    /// <param name="bXDir">如果扭曲则选择为True</param>
        
    /// <param name="nMultValue">波形的幅度倍数,越大扭曲的程度越高,一般为3</param>
        
    /// <param name="dPhase">波形的起始相位,取值区间[0-2*PI)</param>
        
    /// <returns></returns>
        public System.Drawing.Bitmap TwistImage(Bitmap srcBmp, bool bXDir, double dMultValue, double dPhase)
        {
            System.Drawing.Bitmap destBmp 
    = new Bitmap(srcBmp.Width, srcBmp.Height);

            
    // 将位图背景填充为白色
            System.Drawing.Graphics graph = System.Drawing.Graphics.FromImage(destBmp);
            graph.FillRectangle(
    new SolidBrush(System.Drawing.Color.White), 00, destBmp.Width, destBmp.Height);
            graph.Dispose();

            
    double dBaseAxisLen = bXDir ? (double)destBmp.Height : (double)destBmp.Width;

            
    for (int i = 0; i < destBmp.Width; i++)
            {
                
    for (int j = 0; j < destBmp.Height; j++)
                {
                    
    double dx = 0;
                    dx 
    = bXDir ? (PI2 * (double)j) / dBaseAxisLen : (PI2 * (double)i) / dBaseAxisLen;
                    dx 
    += dPhase;
                    
    double dy = Math.Sin(dx);

                    
    // 取得当前点的颜色
                    int nOldX = 0, nOldY = 0;
                    nOldX 
    = bXDir ? i + (int)(dy * dMultValue) : i;
                    nOldY 
    = bXDir ? j : j + (int)(dy * dMultValue);

                    System.Drawing.Color color 
    = srcBmp.GetPixel(i, j);
                    
    if (nOldX >= 0 && nOldX < destBmp.Width
                     
    && nOldY >= 0 && nOldY < destBmp.Height)
                    {
                        destBmp.SetPixel(nOldX, nOldY, color);
                    }
                }
            }

            
    return destBmp;
        }



        
    #endregion
       
        
    /// <summary>
        
    /// 生成校验码图片
        
    /// </summary>
        
    /// <param name="code">验证码</param>
        
    /// <returns></returns>
        public Bitmap CreateImage(string code)
        {
            
    int fSize = FontSize;
            
    int fWidth = fSize + Padding;

            
    int imageWidth = (int)(code.Length * fWidth) + 4 + Padding * 2;
            
    int imageHeight = fSize * 2 + Padding * 2;

            System.Drawing.Bitmap image 
    = new System.Drawing.Bitmap(imageWidth, imageHeight);

            Graphics g 
    = Graphics.FromImage(image);

            g.Clear(BackgroundColor);

            
    //给背景添加随机生成的燥点
            if (this.Chaos)
            {

                Pen pen 
    = new Pen(ChaosColor, 0);
                
    int c = Length * 10;

                
    for (int i = 0; i < c; i++)
                {
                    
    int x = rnd.Next(image.Width);
                    
    int y = rnd.Next(image.Height);

                    g.DrawRectangle(pen, x, y, 
    11);
                }
            }

            
    int left = 0, top = 0, top1 = 1, top2 = 1;

            
    int n1 = (imageHeight - FontSize - Padding * 2);
            
    int n2 = n1 / 4;
            top1 
    = n2;
            top2 
    = n2 * 2;

            Font f;
            Brush b;

            
    int cindex, findex;

            
    //随机字体和颜色的验证码字符
            for (int i = 0; i < code.Length; i++)
            {
                cindex 
    = rnd.Next(Colors.Length - 1);
                findex 
    = rnd.Next(Fonts.Length - 1);

                f 
    = new System.Drawing.Font(Fonts[findex], fSize, System.Drawing.FontStyle.Bold);
                b 
    = new System.Drawing.SolidBrush(Colors[cindex]);

                
    if (i % 2 == 1)
                {
                    top 
    = top2;
                }
                
    else
                {
                    top 
    = top1;
                }

                left 
    = i * fWidth;

                g.DrawString(code.Substring(i, 
    1), f, b, left, top);
            }

            
    //画一个边框 边框颜色为Color.Gainsboro
            g.DrawRectangle(new Pen(Color.Gainsboro, 0), 00, image.Width - 1, image.Height - 1);
            g.Dispose();

            
    //产生波形(Add By 51aspx.com)
            image = TwistImage(image, true84);

            
    return image;
        }
                
        
    /// <summary>
        
    /// 生成随机字符码
        
    /// </summary>
        
    /// <param name="codeLen">字符串长度</param>
        
    /// <param name="zhCharsCount">中文字符数</param>
        
    /// <returns></returns>
        public string CreateVerifyCode(int codeLen, int zhCharsCount)
        {
            
    char[] chs = new char[codeLen];

            
    int index;
            
    for (int i = 0; i < zhCharsCount; i++)
            {
                index 
    = rnd.Next(0, codeLen);
                
    if (chs[index] == '\0')
                    chs[index] 
    = CreateZhChar();
                
    else
                    
    --i;
            }
            
    for (int i = 0; i < codeLen; i++)
            {
                
    if (chs[i] == '\0')
                    chs[i] 
    = CreateEnOrNumChar();
            }

            
    return new string(chs, 0, chs.Length);
        }

        
    /// <summary>
        
    /// 生成默认长度5的随机字符码
        
    /// </summary>
        
    /// <returns></returns>
        public string CreateVerifyCode()
        {
            
    return CreateVerifyCode(Length, 0);
        }
        
        
    /// <summary>
        
    /// 生成英文或数字字符
        
    /// </summary>
        
    /// <returns></returns>
        protected char CreateEnOrNumChar()
        {
            
    return EnglishOrNumChars[rnd.Next(0, EnglishOrNumChars.Length)];
        }

        
    /// <summary>
        
    /// 生成汉字字符
        
    /// </summary>
        
    /// <returns></returns>
        protected char CreateZhChar()
        {
            
    //若提供了汉字集,查询汉字集选取汉字
            if (ChineseChars.Length > 0)
            {
                
    return ChineseChars[rnd.Next(0, ChineseChars.Length)];
            }
            
    //若没有提供汉字集,则根据《GB2312简体中文编码表》编码规则构造汉字
            else
            {
                
    byte[] bytes = new byte[2];

                
    //第一个字节值在0xb0, 0xf7之间
                bytes[0= (byte)rnd.Next(0xb00xf8);
                
    //第二个字节值在0xa1, 0xfe之间
                bytes[1= (byte)rnd.Next(0xa10xff);

                
    //根据汉字编码的字节数组解码出中文汉字
                string str1 = Encoding.GetEncoding("gb2312").GetString(bytes);

                
    return str1[0];
            }
        }
    }

        这里面大量使用了51aspx.com的代码,在此表示感谢。这里的主要改进在于支持生成中英文混合的验证码。中文的生成有两种方式,一是根据《GB2312简体中文编码表》编码规则构造汉字,二是从一个选定的中文字符集合中随即选取汉字。实现很简单,参考函数protected char CreateZhChar(),在此不赘述。

        最后说一下验证码的使用,下面是一个例子:  

    <img src="VerifyCode.aspx" id="valiCode" alt="验证码" />
    <title="刷新验证码" href="#" onclick="javascript:document.getElementById('valiCode').src='VerifyCode.aspx?id='+Math.random();return false;">看不清,换张图片?</a>

        这里有个小技巧,就是在刷新验证码的使用,验证码的URL后面用了随机参数以欺骗浏览器重新请求。

    源代码
    2500常用汉字
    498常用汉字

  • 相关阅读:
    CodeForces 219D Choosing Capital for Treeland (树形DP)
    POJ 3162 Walking Race (树的直径,单调队列)
    POJ 2152 Fire (树形DP,经典)
    POJ 1741 Tree (树的分治,树的重心)
    POJ 1655 Balancing Act (树的重心,常规)
    HDU 2196 Computer (树形DP)
    HDU 1520 Anniversary party (树形DP,入门)
    寒门子弟
    JQuery选择器(转)
    (四)Web应用开发---系统架构图
  • 原文地址:https://www.cnblogs.com/dsliang/p/1857638.html
Copyright © 2011-2022 走看看