1
头图

[TOC]

Let’s use GO to play with the verification code

Hi, I’m the little magic boy Nezha, defer in GO we shared last time, let’s review it again

  • Shared what defer is
  • A simple illustration of the stack and queue
  • Defer's data structure and implementation principle, specific source code display
  • 3 rules of defer in GO

If the GO for the defer realization of the principle a little bit interested, you are welcome to view the article realization of the principle in GO defer the

Today we will share some GO , let’s grow while playing

Introduction to GO verification code

The verification codes we usually use are roughly divided into these types, let's sort them out:

  • Traditional input form

Enter the numbers, text, letters, etc. on the picture

  • Enter the type of graphic verification code

This is mainly for advertising

  • Pure behavior verification code

For example, swipe as prompted, etc.

  • Icon selection and behavior-assisted verification code

For example, when we buy a train ticket, the verification code, various icons let you choose

  • Click-type graphic verification and behavior assistance

For example, the verification code of a treasure

  • Smart verification code

For example, tap the smart verification code

GO verification code case

Let’s play with the first one today, the one that uses the most verification code.

Will use this verification code library of GO to complete, github.com/dchest/captcha

If we C/C++ like 060d7e2b281bb0, we encapsulate a lot of the underlying processing to achieve it, it is quite tiring, GO is really good, there are many packages used, we can use it, we can also stand On the shoulders of giants, learn the implementation methods in the source code, and learn the design ideas of the big guys.

Install captcha library

You can download it and use it with the following command

go get github.com/dchest/captcha

When we use the captcha GOLAND , we can look at the source directory

Source directory

  • Specific use cases with source code
  • Specific sample pictures
  • Realization of related audio processing
  • Implementation of verification code processing
  • Realization of image processing
  • Realization of random number processing
  • and many more...

Supported languages

The audio currently supported by this library has 4 languages:

  • English
  • Chinese
  • Russian
  • Japanese

Verification code default parameters

The default size of the verification code in the library is width 240 px, height 80 px

image.go in the source code

const (
   // Standard width and height of a captcha image.
   StdWidth  = 240
   StdHeight = 80
   // Maximum absolute skew factor of a single digit.
   maxSkew = 0.7
   // Number of background circles.
   circleCount = 20
)

type Image struct {
   *image.Paletted
   numWidth  int
   numHeight int
   dotSize   int
   rng       siprng
}

The characters contained in the random number

The following are the characters allowed in the verification code id, which can be seen in the source code

random.go in the source package

// idChars are characters allowed in captcha id.
var idChars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")

About audio processing

sounds.go file in the source code

Currently only supports 4 languages "en", "ja", "ru", "zh".

/ NewAudio returns a new audio captcha with the given digits, where each digit
// must be in range 0-9. Digits are pronounced in the given language. If there
// are no sounds for the given language, English is used.
//
// Possible values for lang are "en", "ja", "ru", "zh".
func NewAudio(id string, digits []byte, lang string) *Audio {
   a := new(Audio)

   // Initialize PRNG.
   a.rng.Seed(deriveSeed(audioSeedPurpose, id, digits))

   if sounds, ok := digitSounds[lang]; ok {
      a.digitSounds = sounds
   } else {
      a.digitSounds = digitSounds["en"]
   }
   numsnd := make([][]byte, len(digits))
   nsdur := 0
   for i, n := range digits {
      snd := a.randomizedDigitSound(n)
      nsdur += len(snd)
      numsnd[i] = snd
   }
   // Random intervals between digits (including beginning).
   intervals := make([]int, len(digits)+1)
   intdur := 0
   for i := range intervals {
      dur := a.rng.Int(sampleRate, sampleRate*3) // 1 to 3 seconds
      intdur += dur
      intervals[i] = dur
   }
   // Generate background sound.
   bg := a.makeBackgroundSound(a.longestDigitSndLen()*len(digits) + intdur)
   // Create buffer and write audio to it.
   sil := makeSilence(sampleRate / 5)
   bufcap := 3*len(beepSound) + 2*len(sil) + len(bg) + len(endingBeepSound)
   a.body = bytes.NewBuffer(make([]byte, 0, bufcap))
   // Write prelude, three beeps.
   a.body.Write(beepSound)
   a.body.Write(sil)
   a.body.Write(beepSound)
   a.body.Write(sil)
   a.body.Write(beepSound)
   // Write digits.
   pos := intervals[0]
   for i, v := range numsnd {
      mixSound(bg[pos:], v)
      pos += len(v) + intervals[i+1]
   }
   a.body.Write(bg)
   // Write ending (one beep).
   a.body.Write(endingBeepSound)
   return a
}

The data about language is in the digitSounds map

Seeing this, it’s a bit like doing font parsing and data parsing in embedded

var digitSounds = map[string][][]byte{
    "en": [][]byte{
        { // 0
            0x80, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80,
            ...
        },
    "ru": [][]byte{
        { // 0
             0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7f, 0x7e,
            ...
        },
    "zh": [][]byte{
        { // 0
            0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80,
            ...
        },
    "ja": [][]byte{
        { // 0
             0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x83,
            ...
        }, 

Start the demonstration of the case

my_captcha.html implemented as follows

For the time being about the language of audio, I wrote 2 2 languages

  • English
  • Chinese
<!doctype html>
<head>
    <title>GO 简单制作验证码案例</title>
    <style>
        input{
            margin-top: 30px;
        }
    </style>
</head>
<body>
<script>

    // 设置语言
    function setSrcQuery(e, q) {
        var src = e.src;
        var p = src.indexOf('?');
        if (p >= 0) {
            src = src.substr(0, p);
        }
        e.src = src + "?" + q
    }

    // 播放音频
    function playAudio() {
        var le = document.getElementById("lang");
        var lang = le.options[le.selectedIndex].value;
        var e = document.getElementById('audio')
        setSrcQuery(e, "lang=" + lang)
        e.style.display = 'block';
        e.autoplay = 'true';
        return false;
    }

    // 切换语言
    function changeLang() {
        var e = document.getElementById('audio')
        if (e.style.display == 'block') {
            playAudio();
        }
    }

    // 重新加载
    function reload() {
        setSrcQuery(document.getElementById('image'), "reload=" + (new Date()).getTime());
        setSrcQuery(document.getElementById('audio'), (new Date()).getTime());
        return false;
    }
</script>
<div align="center" >
    <select id="lang" onchange="changeLang()">
        <option value="en">英文</option>
        <option value="zh">中文</option>
    </select>
</div>

<form action="/processCapcha" method=post align="center">
    <p>请输入你在下面的图片中看到的数字:</p>
    <p><img id=image src="/captcha/{{.CaptchaId}}.png" alt="Captcha image"></p>
    <a href="#" onclick="reload()">重新加载</a>   |   <a href="#" onclick="playAudio()">播放音频验证码</a>

    <audio id=audio controls style="display:none" src="/captcha/{{.CaptchaId}}.wav" preload=none>
        You browser doesn't support audio.
        <a href="/captcha/download/{{.CaptchaId}}.wav">下载文件</a> to play it in the external player.
    </audio>

    <input type=hidden name=captchaId value="{{.CaptchaId}}" align=center><br>
    <input name=captchaSolution align=center>
    <input type=submit value=Submit>
</form>

main.go

  • Show verification code
  • Process the verification code and display the result
  • Reload verification code
  • Play verification code audio
package main

import (
    "github.com/dchest/captcha"
    "io"
    "io/ioutil"
    "log"
    "net/http"
    "text/template"
)

const filePath = "./my_captcha.html"
// 读取 html 文件
func readHtml() string {
    var bytes []byte
    var err error
    if bytes, err = ioutil.ReadFile(filePath); err != nil {
        log.Fatalf("ioutil.ReadFile error filePath =  %s , err :"+filePath, err)
        return ""
    }

    return string(bytes)
}

// 读取html 文件,转成template.Template 指针
var formTemplate = template.Must(template.New("myCaptcha").Parse(readHtml()))

// 显示验证码
func showCaptcha(w http.ResponseWriter, r *http.Request) {
    if r.URL.Path != "/" {
        http.NotFound(w, r)
        return
    }
    d := struct {
        CaptchaId string
    }{
        captcha.New(),
    }
    // Execute将解析后的模板应用到指定的数据对象,并将输出写入wr
    if err := formTemplate.Execute(w, &d); err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
    }
}

// 处理验证码,跳转结果页面
func resultPage(w http.ResponseWriter, r *http.Request) {

    w.Header().Set("Content-Type", "text/html; charset=utf-8")

    if !captcha.VerifyString(r.FormValue("captchaId"), r.FormValue("captchaSolution")) {
        io.WriteString(w, "错误的验证码,请重新输入\n")
    } else {
        io.WriteString(w, "验证吗正确,你很棒哦!!\n")
    }
    io.WriteString(w, "<br><a href='/'>再试一下</a>")
}

func main() {

    // 简单设置log参数
    log.SetFlags(log.Lshortfile | log.LstdFlags)

    http.HandleFunc("/", showCaptcha)
    http.HandleFunc("/processCapcha", resultPage)
    
    http.Handle("/captcha/", captcha.Server(captcha.StdWidth, captcha.StdHeight))

    log.Println("starting server : 8888")

    if err := http.ListenAndServe("localhost:8888", nil); err != nil {
        log.Fatal(err)
    }
}

The width and height of the above code is like this

StdWidth  = 240
StdHeight = 80

The HandleFunc looks like this. I shared it when I introduced gin before. You can look back at the article and let us explore the net/http code flow

// HandleFunc registers the handler function for the given pattern
    // in the DefaultServeMux.
    // The documentation for ServeMux explains how patterns are matched.
    func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
        DefaultServeMux.HandleFunc(pattern, handler)
    }

Actual effect of verification code

click to play the audio verification code, you can see this effect

The audio will play different voices according to the language we choose, and read the numbers on the picture

to sum up

  • Sorting out the types of verification codes
  • Installation of verification code library
  • Source code introduction of verification code library
  • Practice, coding
  • Verification code performance display

Welcome to like, follow, favorite

Friends, your support and encouragement are my motivation to keep sharing and improve quality

Okay, that's it for this time, How to use GOLANG to send mail next time

Technology is open, and our mindset should be more open. Embrace the change, live toward the sun, and work hard to move forward.

I am little magic boy , welcome to like and follow the collection, see you next time~


阿兵云原生
192 声望38 粉丝