1 Star 0 Fork 13

齐泽西/validate

forked from gookit/validate 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
validators.go 30.91 KB
一键复制 编辑 原始数据 按行查看 历史
inhere 提交于 2020-06-21 22:39 . add some method and more tests
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293
package validate
import (
"bytes"
"encoding/json"
"net"
"net/url"
"reflect"
"regexp"
"strconv"
"strings"
"time"
"unicode/utf8"
"github.com/gookit/goutil/fsutil"
"github.com/gookit/goutil/mathutil"
"github.com/gookit/goutil/strutil"
)
// Basic regular expressions for validating strings.
// (there are from package "asaskevich/govalidator")
const (
Email = "^(((([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+(\\.([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+)*)|((\\x22)((((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(([\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(\\([\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}]))))*(((\\x20|\\x09)*(\\x0d\\x0a))?(\\x20|\\x09)+)?(\\x22)))@((([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])([a-zA-Z]|\\d|-|\\.|_|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*([a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.)+(([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])([a-zA-Z]|\\d|-|_|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*([a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.?$"
UUID3 = "^[0-9a-f]{8}-[0-9a-f]{4}-3[0-9a-f]{3}-[0-9a-f]{4}-[0-9a-f]{12}$"
UUID4 = "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"
UUID5 = "^[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"
UUID = "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
Int = "^(?:[-+]?(?:0|[1-9][0-9]*))$"
Float = "^(?:[-+]?(?:[0-9]+))?(?:\\.[0-9]*)?(?:[eE][\\+\\-]?(?:[0-9]+))?$"
RGBColor = "^rgb\\(\\s*(0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*,\\s*(0|[1-9]\\d?|1\\d\\d?|2[0-4]\\d|25[0-5])\\s*\\)$"
FullWidth = "[^\u0020-\u007E\uFF61-\uFF9F\uFFA0-\uFFDC\uFFE8-\uFFEE0-9a-zA-Z]"
HalfWidth = "[\u0020-\u007E\uFF61-\uFF9F\uFFA0-\uFFDC\uFFE8-\uFFEE0-9a-zA-Z]"
Base64 = "^(?:[A-Za-z0-9+\\/]{4})*(?:[A-Za-z0-9+\\/]{2}==|[A-Za-z0-9+\\/]{3}=|[A-Za-z0-9+\\/]{4})$"
Latitude = "^[-+]?([1-8]?\\d(\\.\\d+)?|90(\\.0+)?)$"
Longitude = "^[-+]?(180(\\.0+)?|((1[0-7]\\d)|([1-9]?\\d))(\\.\\d+)?)$"
DNSName = `^([a-zA-Z0-9_]{1}[a-zA-Z0-9_-]{0,62}){1}(\.[a-zA-Z0-9_]{1}[a-zA-Z0-9_-]{0,62})*[\._]?$`
FullURL = `^(?:ftp|tcp|udp|wss?|https?):\/\/[\w\.\/#=?&]+$`
URLSchema = `((ftp|tcp|udp|wss?|https?):\/\/)`
URLUsername = `(\S+(:\S*)?@)`
URLPath = `((\/|\?|#)[^\s]*)`
URLPort = `(:(\d{1,5}))`
URLIP = `([1-9]\d?|1\d\d|2[01]\d|22[0-3])(\.(1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.([0-9]\d?|1\d\d|2[0-4]\d|25[0-4]))`
URLSubdomain = `((www\.)|([a-zA-Z0-9]+([-_\.]?[a-zA-Z0-9])*[a-zA-Z0-9]\.[a-zA-Z0-9]+))`
WinPath = `^[a-zA-Z]:\\(?:[^\\/:*?"<>|\r\n]+\\)*[^\\/:*?"<>|\r\n]*$`
UnixPath = `^(/[^/\x00]*)+/?$`
)
// some string regexp. (it is from package "asaskevich/govalidator")
var (
// rxUser = regexp.MustCompile("^[a-zA-Z0-9!#$%&'*+/=?^_`{|}~.-]+$")
// rxHostname = regexp.MustCompile("^[^\\s]+\\.[^\\s]+$")
// rxUserDot = regexp.MustCompile("(^[.]{1})|([.]{1}$)|([.]{2,})")
rxEmail = regexp.MustCompile(Email)
rxISBN10 = regexp.MustCompile("^(?:[0-9]{9}X|[0-9]{10})$")
rxISBN13 = regexp.MustCompile("^(?:[0-9]{13})$")
rxUUID3 = regexp.MustCompile(UUID3)
rxUUID4 = regexp.MustCompile(UUID4)
rxUUID5 = regexp.MustCompile(UUID5)
rxUUID = regexp.MustCompile(UUID)
rxAlpha = regexp.MustCompile("^[a-zA-Z]+$")
rxAlphaNum = regexp.MustCompile("^[a-zA-Z0-9]+$")
rxAlphaDash = regexp.MustCompile(`^(?:[\w-]+)$`)
rxNumber = regexp.MustCompile("^[0-9]+$")
rxInt = regexp.MustCompile(Int)
rxFloat = regexp.MustCompile(Float)
rxCnMobile = regexp.MustCompile(`^1\d{10}$`)
rxHexColor = regexp.MustCompile("^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$")
rxRGBColor = regexp.MustCompile(RGBColor)
rxASCII = regexp.MustCompile("^[\x00-\x7F]+$")
// --
rxHexadecimal = regexp.MustCompile("^[0-9a-fA-F]+$")
rxPrintableASCII = regexp.MustCompile("^[\x20-\x7E]+$")
rxMultiByte = regexp.MustCompile("[^\x00-\x7F]")
// rxFullWidth = regexp.MustCompile(FullWidth)
// rxHalfWidth = regexp.MustCompile(HalfWidth)
rxBase64 = regexp.MustCompile(Base64)
rxDataURI = regexp.MustCompile(`^data:.+/(.+);base64,(?:.+)`)
rxLatitude = regexp.MustCompile(Latitude)
rxLongitude = regexp.MustCompile(Longitude)
rxDNSName = regexp.MustCompile(DNSName)
rxFullURL = regexp.MustCompile(FullURL)
rxURLSchema = regexp.MustCompile(URLSchema)
// rxSSN = regexp.MustCompile(`^\d{3}[- ]?\d{2}[- ]?\d{4}$`)
rxWinPath = regexp.MustCompile(WinPath)
rxUnixPath = regexp.MustCompile(UnixPath)
// --
rxHasLowerCase = regexp.MustCompile(".*[[:lower:]]")
rxHasUpperCase = regexp.MustCompile(".*[[:upper:]]")
)
/*************************************************************
* global validators
*************************************************************/
type funcMeta struct {
fv reflect.Value
name string
// readonly cache
numIn int
numOut int
// is internal built in validator
isInternal bool
// last arg is like "... interface{}"
isVariadic bool
}
func (fm *funcMeta) checkArgNum(argNum int, name string) {
// last arg is like "... interface{}"
if fm.isVariadic {
if argNum+1 < fm.numIn {
panicf("not enough parameters for validator '%s'!", name)
}
} else if argNum != fm.numIn {
panicf(
"the number of parameters given does not match the required. validator '%s', want %d, given %d",
name,
fm.numIn,
argNum,
)
}
}
func newFuncMeta(name string, isInternal bool, fv reflect.Value) *funcMeta {
fm := &funcMeta{fv: fv, name: name, isInternal: isInternal}
ft := fv.Type()
fm.numIn = ft.NumIn() // arg num of the func
fm.numOut = ft.NumOut() // return arg num of the func
fm.isVariadic = ft.IsVariadic()
return fm
}
// ValidatorName get real validator name.
func ValidatorName(name string) string {
if rName, ok := validatorAliases[name]; ok {
return rName
}
return name
}
// AddValidators to the global validators map
func AddValidators(m map[string]interface{}) {
for name, checkFunc := range m {
AddValidator(name, checkFunc)
}
}
// AddValidator to the pkg. checkFunc must return a bool
// Usage:
// v.AddValidator("myFunc", func(val interface{}) bool {
// // do validate val ...
// return true
// })
func AddValidator(name string, checkFunc interface{}) {
fv := checkValidatorFunc(name, checkFunc)
validators[name] = 2 // custom
validatorValues[name] = fv
validatorMetas[name] = newFuncMeta(name, false, fv)
}
// Validators get all validator names
func Validators() map[string]int {
return validators
}
/*************************************************************
* context validators:
* - field value compare
* - requiredXXX
*************************************************************/
// Required field val check
func (v *Validation) Required(field string, val interface{}) bool {
// check file
fd, ok := v.data.(*FormData)
if ok && fd.HasFile(field) {
return true
}
// check value
return !IsEmpty(val)
}
// RequiredIf field under validation must be present and not empty if the anotherField field is equal to any value.
func (v *Validation) RequiredIf(field string, val interface{}, kvs ...string) bool {
// format error
if len(kvs) < 2 {
return false
}
dstField, args := kvs[0], kvs[1:]
if dstVal, has := v.Get(dstField); has {
if Enum(dstVal, args) {
return NotEqual(val, nil) && NotEqual(val, "")
}
}
return true
}
// RequiredUnless field under validation must be present and not empty unless the anotherField field is equal to any value.
func (v *Validation) RequiredUnless(_ string, val interface{}, kvs ...string) bool {
// format error
if len(kvs) < 2 {
return false
}
dstField, args := kvs[0], kvs[1:]
if dstVal, has := v.Get(dstField); has {
if !Enum(dstVal, args) {
return NotEqual(val, nil) && NotEqual(val, "")
}
}
// fields in values
return true
}
// RequiredWith field under validation must be present and not empty only if any of the other specified fields are present.
func (v *Validation) RequiredWith(_ string, val interface{}, kvs ...string) bool {
// format error
if len(kvs) == 0 {
return false
}
for idx := range kvs {
if _, has := v.Get(kvs[idx]); has {
return NotEqual(val, nil) && NotEqual(val, "")
}
}
// all fields not exist
return true
}
// RequiredWithAll field under validation must be present and not empty only if all of the other specified fields are present.
func (v *Validation) RequiredWithAll(_ string, val interface{}, kvs ...string) bool {
// format error
if len(kvs) == 0 {
return false
}
for idx := range kvs {
if _, has := v.Get(kvs[idx]); !has {
// if any field does not exist, not continue.
return true
}
}
// all fields exist
return NotEqual(val, nil) && NotEqual(val, "")
}
// RequiredWithout field under validation must be present and not empty only when any of the other specified fields are not present.
func (v *Validation) RequiredWithout(_ string, val interface{}, kvs ...string) bool {
// format error
if len(kvs) == 0 {
return false
}
for idx := range kvs {
if _, has := v.Get(kvs[idx]); !has {
return NotEqual(val, nil) && NotEqual(val, "")
}
}
// all fields exist
return true
}
// RequiredWithoutAll field under validation must be present and not empty only when any of the other specified fields are not present.
func (v *Validation) RequiredWithoutAll(_ string, val interface{}, kvs ...string) bool {
// format error
if len(kvs) == 0 {
return false
}
for idx := range kvs {
if _, has := v.Get(kvs[idx]); has {
// if any field exist, not continue.
return true
}
}
// all fields exist
return NotEqual(val, nil) && NotEqual(val, "")
}
// EqField value should EQ the dst field value
func (v *Validation) EqField(val interface{}, dstField string) bool {
// get dst field value.
dstVal, has := v.Get(dstField)
if !has {
return false
}
// return val == dstVal
return IsEqual(val, dstVal)
}
// NeField value should not equal the dst field value
func (v *Validation) NeField(val interface{}, dstField string) bool {
// get dst field value.
dstVal, has := v.Get(dstField)
if !has {
return false
}
// return val != dstVal
return !IsEqual(val, dstVal)
}
// GtField value should GT the dst field value
func (v *Validation) GtField(val interface{}, dstField string) bool {
// get dst field value.
dstVal, has := v.Get(dstField)
if !has {
return false
}
return valueCompare(val, dstVal, "gt")
}
// GteField value should GTE the dst field value
func (v *Validation) GteField(val interface{}, dstField string) bool {
// get dst field value.
dstVal, has := v.Get(dstField)
if !has {
return false
}
return valueCompare(val, dstVal, "gte")
}
// LtField value should LT the dst field value
func (v *Validation) LtField(val interface{}, dstField string) bool {
// get dst field value.
dstVal, has := v.Get(dstField)
if !has {
return false
}
return valueCompare(val, dstVal, "lt")
}
// LteField value should LTE the dst field value(for int, string)
func (v *Validation) LteField(val interface{}, dstField string) bool {
// get dst field value.
dstVal, has := v.Get(dstField)
if !has {
return false
}
return valueCompare(val, dstVal, "lte")
}
/*************************************************************
* context validators:
* - file validators
*************************************************************/
const fileValidators = "|isFile|isImage|inMimeTypes|"
var (
imageMimeTypes = map[string]string{
"bmp": "image/bmp",
"gif": "image/gif",
"ief": "image/ief",
"jpg": "image/jpeg",
// "jpe": "image/jpeg",
"jpeg": "image/jpeg",
"png": "image/png",
"svg": "image/svg+xml",
"ico": "image/x-icon",
"webp": "image/webp",
}
)
func isFileValidator(name string) bool {
return strings.Contains(fileValidators, "|"+name+"|")
}
// IsFormFile check field is uploaded file
func (v *Validation) IsFormFile(fd *FormData, field string) (ok bool) {
if fh := fd.GetFile(field); fh != nil {
_, err := fh.Open()
if err == nil {
return true
}
}
return false
}
// IsFormImage check field is uploaded image file.
// Usage:
// v.AddRule("avatar", "image")
// v.AddRule("avatar", "image", "jpg", "png", "gif") // set ext limit
func (v *Validation) IsFormImage(fd *FormData, field string, exts ...string) (ok bool) {
mime := fd.FileMimeType(field)
if mime == "" {
return
}
var fileExt string
for ext, imgMime := range imageMimeTypes {
if imgMime == mime {
fileExt = ext
ok = true
break
}
}
// don't limit mime type
if len(exts) == 0 {
return ok // only check is an image
}
return Enum(fileExt, exts)
}
// InMimeTypes check field is uploaded file and mime type is in the mimeTypes.
// Usage:
// v.AddRule("video", "mimeTypes", "video/avi", "video/mpeg", "video/quicktime")
func (v *Validation) InMimeTypes(fd *FormData, field, mimeType string, moreTypes ...string) bool {
mime := fd.FileMimeType(field)
if mime == "" {
return false
}
mimeTypes := append(moreTypes, mimeType)
return Enum(mime, mimeTypes)
}
/*************************************************************
* global: basic validators
*************************************************************/
// IsEmpty of the value
func IsEmpty(val interface{}) bool {
if val == nil {
return true
}
if s, ok := val.(string); ok {
return s == ""
}
return ValueIsEmpty(reflect.ValueOf(val))
}
// Contains check that the specified string, list(array, slice) or map contains the
// specified substring or element.
//
// Notice: list check value exist. map check key exist.
func Contains(s, sub interface{}) bool {
ok, found := includeElement(s, sub)
// ok == false: 's' could not be applied builtin len()
// found == false: 's' does not contain 'sub'
return ok && found
}
// NotContains check that the specified string, list(array, slice) or map does NOT contain the
// specified substring or element.
//
// Notice: list check value exist. map check key exist.
func NotContains(s, sub interface{}) bool {
ok, found := includeElement(s, sub)
// ok == false: could not be applied builtin len()
// found == true: 's' contain 'sub'
return ok && !found
}
/*************************************************************
* global: type validators
*************************************************************/
// IsUint check, allow: intX, uintX, string
func IsUint(val interface{}) bool {
switch typVal := val.(type) {
case int:
return typVal >= 0
case int8:
return typVal >= 0
case int16:
return typVal >= 0
case int32:
return typVal >= 0
case int64:
return typVal >= 0
case uint, uint8, uint16, uint32, uint64:
return true
case string:
_, err := strconv.ParseUint(typVal, 10, 32)
return err == nil
}
return false
}
// IsBool check. allow: bool, string.
func IsBool(val interface{}) bool {
if _, ok := val.(bool); ok {
return true
}
if typVal, ok := val.(string); ok {
_, err := strutil.ToBool(typVal)
return err == nil
}
return false
}
// IsFloat check. allow: floatX, string
func IsFloat(val interface{}) bool {
if val == nil {
return false
}
switch rv := val.(type) {
case float32, float64:
return true
case string:
return rv != "" && rxFloat.MatchString(rv)
}
return false
}
// IsArray check
func IsArray(val interface{}) (ok bool) {
if val == nil {
return false
}
rv := reflect.ValueOf(val)
if rv.Kind() == reflect.Ptr {
rv = rv.Elem()
}
return rv.Kind() == reflect.Array
}
// IsSlice check
func IsSlice(val interface{}) (ok bool) {
if val == nil {
return false
}
rv := reflect.ValueOf(val)
if rv.Kind() == reflect.Ptr {
rv = rv.Elem()
}
return rv.Kind() == reflect.Slice
}
// IsInts is int slice check
func IsInts(val interface{}) bool {
if val == nil {
return false
}
switch val.(type) {
case []int, []int8, []int16, []int32, []int64, []uint, []uint8, []uint16, []uint32, []uint64:
return true
}
return false
}
// IsStrings is string slice check
func IsStrings(val interface{}) (ok bool) {
if val == nil {
return false
}
_, ok = val.([]string)
return
}
// IsMap check
func IsMap(val interface{}) (ok bool) {
if val == nil {
return false
}
var rv reflect.Value
if rv, ok = val.(reflect.Value); !ok {
rv = reflect.ValueOf(val)
}
if rv.Kind() == reflect.Ptr {
rv = rv.Elem()
}
return rv.Kind() == reflect.Map
}
// IsInt check, and support length check
func IsInt(val interface{}, minAndMax ...int64) (ok bool) {
if val == nil {
return false
}
intVal, err := valueToInt64(val, true)
if err != nil {
return false
}
argLn := len(minAndMax)
if argLn == 0 { // only check type
return true
}
// value check
minVal := minAndMax[0]
if argLn == 1 { // only min length check.
return intVal >= minVal
}
maxVal := minAndMax[1]
// min and max length check
return intVal >= minVal && intVal <= maxVal
}
// IsString check and support length check.
// Usage:
// ok := IsString(val)
// ok := IsString(val, 5) // with min len check
// ok := IsString(val, 5, 12) // with min and max len check
func IsString(val interface{}, minAndMaxLen ...int) (ok bool) {
if val == nil {
return false
}
argLn := len(minAndMaxLen)
str, isStr := val.(string)
// only check type
if argLn == 0 {
return isStr
}
if !isStr {
return false
}
// length check
strLen := len(str)
minLen := minAndMaxLen[0]
// only min length check.
if argLn == 1 {
return strLen >= minLen
}
// min and max length check
maxLen := minAndMaxLen[1]
return strLen >= minLen && strLen <= maxLen
}
/*************************************************************
* global: string validators
*************************************************************/
// HasWhitespace check. eg "10"
func HasWhitespace(s string) bool {
return s != "" && strings.ContainsRune(s, ' ')
}
// IsIntString check. eg "10"
func IsIntString(s string) bool {
return s != "" && rxInt.MatchString(s)
}
// IsASCII string.
func IsASCII(s string) bool {
return s != "" && rxASCII.MatchString(s)
}
// IsPrintableASCII string.
func IsPrintableASCII(s string) bool {
return s != "" && rxPrintableASCII.MatchString(s)
}
// IsBase64 string.
func IsBase64(s string) bool {
return s != "" && rxBase64.MatchString(s)
}
// IsLatitude string.
func IsLatitude(s string) bool {
return s != "" && rxLatitude.MatchString(s)
}
// IsLongitude string.
func IsLongitude(s string) bool {
return s != "" && rxLongitude.MatchString(s)
}
// IsDNSName string.
func IsDNSName(s string) bool {
return s != "" && rxDNSName.MatchString(s)
}
// HasURLSchema string.
func HasURLSchema(s string) bool {
return s != "" && rxURLSchema.MatchString(s)
}
// IsFullURL string.
func IsFullURL(s string) bool {
return s != "" && rxFullURL.MatchString(s)
}
// IsURL string.
func IsURL(s string) bool {
if s == "" {
return false
}
_, err := url.Parse(s)
return err == nil
}
// IsDataURI string.
// data:[<mime type>] ( [;charset=<charset>] ) [;base64],码内容
// eg. "data:image/gif;base64,R0lGODlhA..."
func IsDataURI(s string) bool {
return s != "" && rxDataURI.MatchString(s)
}
// IsMultiByte string.
func IsMultiByte(s string) bool {
return s != "" && rxMultiByte.MatchString(s)
}
// IsISBN10 string.
func IsISBN10(s string) bool {
return s != "" && rxISBN10.MatchString(s)
}
// IsISBN13 string.
func IsISBN13(s string) bool {
return s != "" && rxISBN13.MatchString(s)
}
// IsHexadecimal string.
func IsHexadecimal(s string) bool {
return s != "" && rxHexadecimal.MatchString(s)
}
// IsCnMobile string.
func IsCnMobile(s string) bool {
return s != "" && rxCnMobile.MatchString(s)
}
// IsHexColor string.
func IsHexColor(s string) bool {
return s != "" && rxHexColor.MatchString(s)
}
// IsRGBColor string.
func IsRGBColor(s string) bool {
return s != "" && rxRGBColor.MatchString(s)
}
// IsAlpha string.
func IsAlpha(s string) bool {
return s != "" && rxAlpha.MatchString(s)
}
// IsAlphaNum string.
func IsAlphaNum(s string) bool {
return s != "" && rxAlphaNum.MatchString(s)
}
// IsAlphaDash string.
func IsAlphaDash(s string) bool {
return s != "" && rxAlphaDash.MatchString(s)
}
// IsNumber string. should >= 0
func IsNumber(v interface{}) bool {
if s, err := strutil.ToString(v); err == nil {
return s != "" && rxNumber.MatchString(s)
}
return false
}
// IsNumeric is string/int number. should >= 0
func IsNumeric(v interface{}) bool {
if s, err := strutil.ToString(v); err == nil {
return s != "" && rxNumber.MatchString(s)
}
return false
}
// IsStringNumber is string number. should >= 0
func IsStringNumber(s string) bool {
return s != "" && rxNumber.MatchString(s)
}
// IsEmail check
func IsEmail(s string) bool {
return s != "" && rxEmail.MatchString(s)
}
// IsUUID string
func IsUUID(s string) bool {
return s != "" && rxUUID.MatchString(s)
}
// IsUUID3 string
func IsUUID3(s string) bool {
return s != "" && rxUUID3.MatchString(s)
}
// IsUUID4 string
func IsUUID4(s string) bool {
return s != "" && rxUUID4.MatchString(s)
}
// IsUUID5 string
func IsUUID5(s string) bool {
return s != "" && rxUUID5.MatchString(s)
}
// IsIP is the validation function for validating if the field's value is a valid v4 or v6 IP address.
func IsIP(s string) bool {
// ip := net.ParseIP(s)
return s != "" && net.ParseIP(s) != nil
}
// IsIPv4 is the validation function for validating if a value is a valid v4 IP address.
func IsIPv4(s string) bool {
if s == "" {
return false
}
ip := net.ParseIP(s)
return ip != nil && ip.To4() != nil
}
// IsIPv6 is the validation function for validating if the field's value is a valid v6 IP address.
func IsIPv6(s string) bool {
ip := net.ParseIP(s)
return ip != nil && ip.To4() == nil
}
// IsMAC is the validation function for validating if the field's value is a valid MAC address.
func IsMAC(s string) bool {
if s == "" {
return false
}
_, err := net.ParseMAC(s)
return err == nil
}
// IsCIDRv4 is the validation function for validating if the field's value is a valid v4 CIDR address.
func IsCIDRv4(s string) bool {
if s == "" {
return false
}
ip, _, err := net.ParseCIDR(s)
return err == nil && ip.To4() != nil
}
// IsCIDRv6 is the validation function for validating if the field's value is a valid v6 CIDR address.
func IsCIDRv6(s string) bool {
if s == "" {
return false
}
ip, _, err := net.ParseCIDR(s)
return err == nil && ip.To4() == nil
}
// IsCIDR is the validation function for validating if the field's value is a valid v4 or v6 CIDR address.
func IsCIDR(s string) bool {
if s == "" {
return false
}
_, _, err := net.ParseCIDR(s)
return err == nil
}
// IsJSON check if the string is valid JSON (note: uses json.Unmarshal).
func IsJSON(s string) bool {
if s == "" {
return false
}
var js json.RawMessage
return Unmarshal([]byte(s), &js) == nil
}
// HasLowerCase check string has lower case
func HasLowerCase(s string) bool {
if s == "" {
return false
}
return rxHasLowerCase.MatchString(s)
}
// HasUpperCase check string has upper case
func HasUpperCase(s string) bool {
if s == "" {
return false
}
return rxHasUpperCase.MatchString(s)
}
// StartsWith check string is starts with sub-string
func StartsWith(s, sub string) bool {
if s == "" {
return false
}
return strings.HasPrefix(s, sub)
}
// EndsWith check string is ends with sub-string
func EndsWith(s, sub string) bool {
if s == "" {
return false
}
return strings.HasSuffix(s, sub)
}
// StringContains check string is contains sub-string
func StringContains(s, sub string) bool {
if s == "" {
return false
}
return strings.Contains(s, sub)
}
// Regexp match value string
func Regexp(str string, pattern string) bool {
ok, _ := regexp.MatchString(pattern, str)
return ok
}
/*************************************************************
* global: filesystem validators
*************************************************************/
// PathExists reports whether the named file or directory exists.
func PathExists(path string) bool {
return fsutil.PathExists(path)
}
// IsFilePath path is an local filepath
func IsFilePath(path string) bool {
return fsutil.IsFile(path)
}
// IsDirPath path is an local dir path
func IsDirPath(path string) bool {
return fsutil.IsDir(path)
}
// IsWinPath string
func IsWinPath(s string) bool {
return s != "" && rxWinPath.MatchString(s)
}
// IsUnixPath string
func IsUnixPath(s string) bool {
return s != "" && rxUnixPath.MatchString(s)
}
/*************************************************************
* global: compare validators
*************************************************************/
// IsEqual check two value is equals.
// Support:
// bool, int(X), uint(X), string, float(X) AND slice, array, map
func IsEqual(val, wantVal interface{}) bool {
// check is nil
if val == nil || wantVal == nil {
return val == wantVal
}
sv := reflect.ValueOf(val)
wv := reflect.ValueOf(wantVal)
// don't compare func, struct
if sv.Kind() == reflect.Func || sv.Kind() == reflect.Struct {
return false
}
if wv.Kind() == reflect.Func || wv.Kind() == reflect.Struct {
return false
}
// compare basic type: bool, int(X), uint(X), string, float(X)
equal, err := eq(sv, wv)
// is not an basic type, eg: slice, array, map ...
if err != nil {
expBt, ok := val.([]byte)
if !ok {
return reflect.DeepEqual(val, wantVal)
}
actBt, ok := wantVal.([]byte)
if !ok {
return false
}
if expBt == nil || actBt == nil {
return expBt == nil && actBt == nil
}
return bytes.Equal(expBt, actBt)
}
return equal
}
// NotEqual check
func NotEqual(val, wantVal interface{}) bool {
return !IsEqual(val, wantVal)
}
// IntEqual check
func IntEqual(val interface{}, wantVal int64) bool {
// intVal, isInt := IntVal(val)
intVal, err := mathutil.Int64(val)
if err != nil {
return false
}
return intVal == wantVal
}
// Gt check value greater dst value. only check for: int(X), uint(X), float(X)
func Gt(val interface{}, dstVal int64) bool {
intVal, err := mathutil.Int64(val)
if err != nil {
return false
}
return intVal > dstVal
}
// Min check value greater or equal dst value, alias `Gte`.
// only check for: int(X), uint(X), float(X).
func Min(val interface{}, min int64) bool {
intVal, err := mathutil.Int64(val)
if err != nil {
return false
}
return intVal >= min
}
// Lt less than dst value. only check for: int(X), uint(X), float(X).
func Lt(val interface{}, dstVal int64) bool {
intVal, err := mathutil.Int64(val)
if err != nil {
return false
}
return intVal < dstVal
}
// Max less than or equal dst value, alias `Lte`. check for: int(X), uint(X), float(X).
func Max(val interface{}, max int64) bool {
intVal, err := mathutil.Int64(val)
if err != nil {
return false
}
return intVal <= max
}
// Between int value in the given range.
func Between(val interface{}, min, max int64) bool {
intVal, err := mathutil.Int64(val)
if err != nil {
return false
}
return intVal >= min && intVal <= max
}
/*************************************************************
* global: array, slice, map validators
*************************************************************/
// Enum value(int(X),string) should be in the given enum(strings, ints, uints).
func Enum(val, enum interface{}) bool {
if val == nil || enum == nil {
return false
}
// if is string value
if strVal, ok := val.(string); ok {
if ss, ok := enum.([]string); ok {
for _, strItem := range ss {
if strVal == strItem { // exists
return true
}
}
}
return false
}
// as int value
intVal, err := mathutil.Int64(val)
if err != nil {
return false
}
if int64s, ok := toInt64Slice(enum); ok {
for _, i64 := range int64s {
if intVal == i64 { // exists
return true
}
}
}
return false
}
// NotIn value should be not in the given enum(strings, ints, uints).
func NotIn(val, enum interface{}) bool {
return false == Enum(val, enum)
}
/*************************************************************
* global: length validators
*************************************************************/
// Length equal check for string, array, slice, map
func Length(val interface{}, wantLen int) bool {
ln := CalcLength(val)
if ln == -1 {
return false
}
return ln == wantLen
}
// MinLength check for string, array, slice, map
func MinLength(val interface{}, minLen int) bool {
ln := CalcLength(val)
if ln == -1 {
return false
}
return ln >= minLen
}
// MaxLength check for string, array, slice, map
func MaxLength(val interface{}, maxLen int) bool {
ln := CalcLength(val)
if ln == -1 {
return false
}
return ln <= maxLen
}
// ByteLength check string's length
func ByteLength(str string, minLen int, maxLen ...int) bool {
strLen := len(str)
// only min length check.
if len(maxLen) == 0 {
return strLen >= minLen
}
// min and max length check
return strLen >= minLen && strLen <= maxLen[0]
}
// RuneLength check string's length (including multi byte strings)
func RuneLength(val interface{}, minLen int, maxLen ...int) bool {
str, isString := val.(string)
if !isString {
return false
}
// strLen := len([]rune(str))
strLen := utf8.RuneCountInString(str)
// only min length check.
if len(maxLen) == 0 {
return strLen >= minLen
}
// min and max length check
return strLen >= minLen && strLen <= maxLen[0]
}
// StringLength check string's length (including multi byte strings)
func StringLength(val interface{}, minLen int, maxLen ...int) bool {
return RuneLength(val, minLen, maxLen...)
}
/*************************************************************
* global: date/time validators
*************************************************************/
// IsDate check value is an date string.
func IsDate(srcDate string) bool {
_, err := strutil.ToTime(srcDate)
return err == nil
}
// DateFormat check
func DateFormat(s string, layout string) bool {
_, err := time.Parse(layout, s)
return err == nil
}
// DateEquals check.
// Usage:
// DateEquals(val, "2017-05-12")
// func DateEquals(srcDate, dstDate string) bool {
// return false
// }
// BeforeDate check
func BeforeDate(srcDate, dstDate string) bool {
st, err := strutil.ToTime(srcDate)
if err != nil {
return false
}
dt, err := strutil.ToTime(dstDate)
if err != nil {
return false
}
return st.Before(dt)
}
// BeforeOrEqualDate check
func BeforeOrEqualDate(srcDate, dstDate string) bool {
st, err := strutil.ToTime(srcDate)
if err != nil {
return false
}
dt, err := strutil.ToTime(dstDate)
if err != nil {
return false
}
return st.Before(dt) || st.Equal(dt)
}
// AfterOrEqualDate check
func AfterOrEqualDate(srcDate, dstDate string) bool {
st, err := strutil.ToTime(srcDate)
if err != nil {
return false
}
dt, err := strutil.ToTime(dstDate)
if err != nil {
return false
}
return st.After(dt) || st.Equal(dt)
}
// AfterDate check
func AfterDate(srcDate, dstDate string) bool {
st, err := strutil.ToTime(srcDate)
if err != nil {
return false
}
dt, err := strutil.ToTime(dstDate)
if err != nil {
return false
}
return st.After(dt)
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/qizexi/validate.git
git@gitee.com:qizexi/validate.git
qizexi
validate
validate
master

搜索帮助