1 Star 0 Fork 0

w0rdyyp / validator

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
baked_in.go 52.67 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001
package validator
import (
"bytes"
"context"
"crypto/sha256"
"fmt"
"net"
"net/url"
"os"
"reflect"
"strconv"
"strings"
"sync"
"time"
"unicode/utf8"
urn "github.com/leodido/go-urn"
)
// Func accepts a FieldLevel interface for all validation needs. The return
// value should be true when validation succeeds.
type Func func(fl FieldLevel) bool
// FuncCtx accepts a context.Context and FieldLevel interface for all
// validation needs. The return value should be true when validation succeeds.
type FuncCtx func(ctx context.Context, fl FieldLevel) bool
// wrapFunc wraps noramal Func makes it compatible with FuncCtx
func wrapFunc(fn Func) FuncCtx {
if fn == nil {
return nil // be sure not to wrap a bad function.
}
return func(ctx context.Context, fl FieldLevel) bool {
return fn(fl)
}
}
var (
restrictedTags = map[string]struct{}{
diveTag: {},
keysTag: {},
endKeysTag: {},
structOnlyTag: {},
omitempty: {},
skipValidationTag: {},
utf8HexComma: {},
utf8Pipe: {},
noStructLevelTag: {},
requiredTag: {},
isdefault: {},
}
// BakedInAliasValidators is a default mapping of a single validation tag that
// defines a common or complex set of validation(s) to simplify
// adding validation to structs.
bakedInAliases = map[string]string{
"iscolor": "hexcolor|rgb|rgba|hsl|hsla",
}
// BakedInValidators is the default map of ValidationFunc
// you can add, remove or even replace items to suite your needs,
// or even disregard and use your own map if so desired.
bakedInValidators = map[string]Func{
"required": hasValue,
"required_with": requiredWith,
"required_with_all": requiredWithAll,
"required_without": requiredWithout,
"required_without_all": requiredWithoutAll,
"isdefault": isDefault,
"len": hasLengthOf,
"min": hasMinOf,
"max": hasMaxOf,
"eq": isEq,
"ne": isNe,
"lt": isLt,
"lte": isLte,
"gt": isGt,
"gte": isGte,
"eqfield": isEqField,
"eqcsfield": isEqCrossStructField,
"necsfield": isNeCrossStructField,
"gtcsfield": isGtCrossStructField,
"gtecsfield": isGteCrossStructField,
"ltcsfield": isLtCrossStructField,
"ltecsfield": isLteCrossStructField,
"nefield": isNeField,
"gtefield": isGteField,
"gtfield": isGtField,
"ltefield": isLteField,
"ltfield": isLtField,
"fieldcontains": fieldContains,
"fieldexcludes": fieldExcludes,
"alpha": isAlpha,
"alphanum": isAlphanum,
"alphaunicode": isAlphaUnicode,
"alphanumunicode": isAlphanumUnicode,
"numeric": isNumeric,
"number": isNumber,
"hexadecimal": isHexadecimal,
"hexcolor": isHEXColor,
"rgb": isRGB,
"rgba": isRGBA,
"hsl": isHSL,
"hsla": isHSLA,
"e164": isE164,
"email": isEmail,
"url": isURL,
"uri": isURI,
"urn_rfc2141": isUrnRFC2141, // RFC 2141
"file": isFile,
"base64": isBase64,
"base64url": isBase64URL,
"contains": contains,
"containsany": containsAny,
"containsrune": containsRune,
"excludes": excludes,
"excludesall": excludesAll,
"excludesrune": excludesRune,
"startswith": startsWith,
"endswith": endsWith,
"isbn": isISBN,
"isbn10": isISBN10,
"isbn13": isISBN13,
"eth_addr": isEthereumAddress,
"btc_addr": isBitcoinAddress,
"btc_addr_bech32": isBitcoinBech32Address,
"uuid": isUUID,
"uuid3": isUUID3,
"uuid4": isUUID4,
"uuid5": isUUID5,
"uuid_rfc4122": isUUIDRFC4122,
"uuid3_rfc4122": isUUID3RFC4122,
"uuid4_rfc4122": isUUID4RFC4122,
"uuid5_rfc4122": isUUID5RFC4122,
"ascii": isASCII,
"printascii": isPrintableASCII,
"multibyte": hasMultiByteCharacter,
"datauri": isDataURI,
"latitude": isLatitude,
"longitude": isLongitude,
"ssn": isSSN,
"ipv4": isIPv4,
"ipv6": isIPv6,
"ip": isIP,
"cidrv4": isCIDRv4,
"cidrv6": isCIDRv6,
"cidr": isCIDR,
"tcp4_addr": isTCP4AddrResolvable,
"tcp6_addr": isTCP6AddrResolvable,
"tcp_addr": isTCPAddrResolvable,
"udp4_addr": isUDP4AddrResolvable,
"udp6_addr": isUDP6AddrResolvable,
"udp_addr": isUDPAddrResolvable,
"ip4_addr": isIP4AddrResolvable,
"ip6_addr": isIP6AddrResolvable,
"ip_addr": isIPAddrResolvable,
"unix_addr": isUnixAddrResolvable,
"mac": isMAC,
"hostname": isHostnameRFC952, // RFC 952
"hostname_rfc1123": isHostnameRFC1123, // RFC 1123
"fqdn": isFQDN,
"unique": isUnique,
"oneof": isOneOf,
"html": isHTML,
"html_encoded": isHTMLEncoded,
"url_encoded": isURLEncoded,
"dir": isDir,
}
)
var oneofValsCache = map[string][]string{}
var oneofValsCacheRWLock = sync.RWMutex{}
func parseOneOfParam2(s string) []string {
oneofValsCacheRWLock.RLock()
vals, ok := oneofValsCache[s]
oneofValsCacheRWLock.RUnlock()
if !ok {
oneofValsCacheRWLock.Lock()
vals = strings.Fields(s)
oneofValsCache[s] = vals
oneofValsCacheRWLock.Unlock()
}
return vals
}
func isURLEncoded(fl FieldLevel) bool {
return uRLEncodedRegex.MatchString(fl.Field().String())
}
func isHTMLEncoded(fl FieldLevel) bool {
return hTMLEncodedRegex.MatchString(fl.Field().String())
}
func isHTML(fl FieldLevel) bool {
return hTMLRegex.MatchString(fl.Field().String())
}
func isOneOf(fl FieldLevel) bool {
vals := parseOneOfParam2(fl.Param())
field := fl.Field()
var v string
switch field.Kind() {
case reflect.String:
v = field.String()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
v = strconv.FormatInt(field.Int(), 10)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
v = strconv.FormatUint(field.Uint(), 10)
default:
panic(fmt.Sprintf("Bad field type %T", field.Interface()))
}
for i := 0; i < len(vals); i++ {
if vals[i] == v {
return true
}
}
return false
}
// isUnique is the validation function for validating if each array|slice|map value is unique
func isUnique(fl FieldLevel) bool {
field := fl.Field()
param := fl.Param()
v := reflect.ValueOf(struct{}{})
switch field.Kind() {
case reflect.Slice, reflect.Array:
if param == "" {
m := reflect.MakeMap(reflect.MapOf(field.Type().Elem(), v.Type()))
for i := 0; i < field.Len(); i++ {
m.SetMapIndex(field.Index(i), v)
}
return field.Len() == m.Len()
}
sf, ok := field.Type().Elem().FieldByName(param)
if !ok {
panic(fmt.Sprintf("Bad field name %s", param))
}
m := reflect.MakeMap(reflect.MapOf(sf.Type, v.Type()))
for i := 0; i < field.Len(); i++ {
m.SetMapIndex(field.Index(i).FieldByName(param), v)
}
return field.Len() == m.Len()
case reflect.Map:
m := reflect.MakeMap(reflect.MapOf(field.Type().Elem(), v.Type()))
for _, k := range field.MapKeys() {
m.SetMapIndex(field.MapIndex(k), v)
}
return field.Len() == m.Len()
default:
panic(fmt.Sprintf("Bad field type %T", field.Interface()))
}
}
// IsMAC is the validation function for validating if the field's value is a valid MAC address.
func isMAC(fl FieldLevel) bool {
_, err := net.ParseMAC(fl.Field().String())
return err == nil
}
// IsCIDRv4 is the validation function for validating if the field's value is a valid v4 CIDR address.
func isCIDRv4(fl FieldLevel) bool {
ip, _, err := net.ParseCIDR(fl.Field().String())
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(fl FieldLevel) bool {
ip, _, err := net.ParseCIDR(fl.Field().String())
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(fl FieldLevel) bool {
_, _, err := net.ParseCIDR(fl.Field().String())
return err == nil
}
// IsIPv4 is the validation function for validating if a value is a valid v4 IP address.
func isIPv4(fl FieldLevel) bool {
ip := net.ParseIP(fl.Field().String())
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(fl FieldLevel) bool {
ip := net.ParseIP(fl.Field().String())
return ip != nil && ip.To4() == nil
}
// IsIP is the validation function for validating if the field's value is a valid v4 or v6 IP address.
func isIP(fl FieldLevel) bool {
ip := net.ParseIP(fl.Field().String())
return ip != nil
}
// IsSSN is the validation function for validating if the field's value is a valid SSN.
func isSSN(fl FieldLevel) bool {
field := fl.Field()
if field.Len() != 11 {
return false
}
return sSNRegex.MatchString(field.String())
}
// IsLongitude is the validation function for validating if the field's value is a valid longitude coordinate.
func isLongitude(fl FieldLevel) bool {
field := fl.Field()
var v string
switch field.Kind() {
case reflect.String:
v = field.String()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
v = strconv.FormatInt(field.Int(), 10)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
v = strconv.FormatUint(field.Uint(), 10)
case reflect.Float32:
v = strconv.FormatFloat(field.Float(), 'f', -1, 32)
case reflect.Float64:
v = strconv.FormatFloat(field.Float(), 'f', -1, 64)
default:
panic(fmt.Sprintf("Bad field type %T", field.Interface()))
}
return longitudeRegex.MatchString(v)
}
// IsLatitude is the validation function for validating if the field's value is a valid latitude coordinate.
func isLatitude(fl FieldLevel) bool {
field := fl.Field()
var v string
switch field.Kind() {
case reflect.String:
v = field.String()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
v = strconv.FormatInt(field.Int(), 10)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
v = strconv.FormatUint(field.Uint(), 10)
case reflect.Float32:
v = strconv.FormatFloat(field.Float(), 'f', -1, 32)
case reflect.Float64:
v = strconv.FormatFloat(field.Float(), 'f', -1, 64)
default:
panic(fmt.Sprintf("Bad field type %T", field.Interface()))
}
return latitudeRegex.MatchString(v)
}
// IsDataURI is the validation function for validating if the field's value is a valid data URI.
func isDataURI(fl FieldLevel) bool {
uri := strings.SplitN(fl.Field().String(), ",", 2)
if len(uri) != 2 {
return false
}
if !dataURIRegex.MatchString(uri[0]) {
return false
}
return base64Regex.MatchString(uri[1])
}
// HasMultiByteCharacter is the validation function for validating if the field's value has a multi byte character.
func hasMultiByteCharacter(fl FieldLevel) bool {
field := fl.Field()
if field.Len() == 0 {
return true
}
return multibyteRegex.MatchString(field.String())
}
// IsPrintableASCII is the validation function for validating if the field's value is a valid printable ASCII character.
func isPrintableASCII(fl FieldLevel) bool {
return printableASCIIRegex.MatchString(fl.Field().String())
}
// IsASCII is the validation function for validating if the field's value is a valid ASCII character.
func isASCII(fl FieldLevel) bool {
return aSCIIRegex.MatchString(fl.Field().String())
}
// IsUUID5 is the validation function for validating if the field's value is a valid v5 UUID.
func isUUID5(fl FieldLevel) bool {
return uUID5Regex.MatchString(fl.Field().String())
}
// IsUUID4 is the validation function for validating if the field's value is a valid v4 UUID.
func isUUID4(fl FieldLevel) bool {
return uUID4Regex.MatchString(fl.Field().String())
}
// IsUUID3 is the validation function for validating if the field's value is a valid v3 UUID.
func isUUID3(fl FieldLevel) bool {
return uUID3Regex.MatchString(fl.Field().String())
}
// IsUUID is the validation function for validating if the field's value is a valid UUID of any version.
func isUUID(fl FieldLevel) bool {
return uUIDRegex.MatchString(fl.Field().String())
}
// IsUUID5RFC4122 is the validation function for validating if the field's value is a valid RFC4122 v5 UUID.
func isUUID5RFC4122(fl FieldLevel) bool {
return uUID5RFC4122Regex.MatchString(fl.Field().String())
}
// IsUUID4RFC4122 is the validation function for validating if the field's value is a valid RFC4122 v4 UUID.
func isUUID4RFC4122(fl FieldLevel) bool {
return uUID4RFC4122Regex.MatchString(fl.Field().String())
}
// IsUUID3RFC4122 is the validation function for validating if the field's value is a valid RFC4122 v3 UUID.
func isUUID3RFC4122(fl FieldLevel) bool {
return uUID3RFC4122Regex.MatchString(fl.Field().String())
}
// IsUUIDRFC4122 is the validation function for validating if the field's value is a valid RFC4122 UUID of any version.
func isUUIDRFC4122(fl FieldLevel) bool {
return uUIDRFC4122Regex.MatchString(fl.Field().String())
}
// IsISBN is the validation function for validating if the field's value is a valid v10 or v13 ISBN.
func isISBN(fl FieldLevel) bool {
return isISBN10(fl) || isISBN13(fl)
}
// IsISBN13 is the validation function for validating if the field's value is a valid v13 ISBN.
func isISBN13(fl FieldLevel) bool {
s := strings.Replace(strings.Replace(fl.Field().String(), "-", "", 4), " ", "", 4)
if !iSBN13Regex.MatchString(s) {
return false
}
var checksum int32
var i int32
factor := []int32{1, 3}
for i = 0; i < 12; i++ {
checksum += factor[i%2] * int32(s[i]-'0')
}
return (int32(s[12]-'0'))-((10-(checksum%10))%10) == 0
}
// IsISBN10 is the validation function for validating if the field's value is a valid v10 ISBN.
func isISBN10(fl FieldLevel) bool {
s := strings.Replace(strings.Replace(fl.Field().String(), "-", "", 3), " ", "", 3)
if !iSBN10Regex.MatchString(s) {
return false
}
var checksum int32
var i int32
for i = 0; i < 9; i++ {
checksum += (i + 1) * int32(s[i]-'0')
}
if s[9] == 'X' {
checksum += 10 * 10
} else {
checksum += 10 * int32(s[9]-'0')
}
return checksum%11 == 0
}
// IsEthereumAddress is the validation function for validating if the field's value is a valid ethereum address based currently only on the format
func isEthereumAddress(fl FieldLevel) bool {
address := fl.Field().String()
if !ethAddressRegex.MatchString(address) {
return false
}
if ethaddressRegexUpper.MatchString(address) || ethAddressRegexLower.MatchString(address) {
return true
}
// checksum validation is blocked by https://github.com/golang/crypto/pull/28
return true
}
// IsBitcoinAddress is the validation function for validating if the field's value is a valid btc address
func isBitcoinAddress(fl FieldLevel) bool {
address := fl.Field().String()
if !btcAddressRegex.MatchString(address) {
return false
}
alphabet := []byte("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz")
decode := [25]byte{}
for _, n := range []byte(address) {
d := bytes.IndexByte(alphabet, n)
for i := 24; i >= 0; i-- {
d += 58 * int(decode[i])
decode[i] = byte(d % 256)
d /= 256
}
}
h := sha256.New()
_, _ = h.Write(decode[:21])
d := h.Sum([]byte{})
h = sha256.New()
_, _ = h.Write(d)
validchecksum := [4]byte{}
computedchecksum := [4]byte{}
copy(computedchecksum[:], h.Sum(d[:0]))
copy(validchecksum[:], decode[21:])
return validchecksum == computedchecksum
}
// IsBitcoinBech32Address is the validation function for validating if the field's value is a valid bech32 btc address
func isBitcoinBech32Address(fl FieldLevel) bool {
address := fl.Field().String()
if !btcLowerAddressRegexBech32.MatchString(address) && !btcUpperAddressRegexBech32.MatchString(address) {
return false
}
am := len(address) % 8
if am == 0 || am == 3 || am == 5 {
return false
}
address = strings.ToLower(address)
alphabet := "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
hr := []int{3, 3, 0, 2, 3} // the human readable part will always be bc
addr := address[3:]
dp := make([]int, 0, len(addr))
for _, c := range addr {
dp = append(dp, strings.IndexRune(alphabet, c))
}
ver := dp[0]
if ver < 0 || ver > 16 {
return false
}
if ver == 0 {
if len(address) != 42 && len(address) != 62 {
return false
}
}
values := append(hr, dp...)
GEN := []int{0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3}
p := 1
for _, v := range values {
b := p >> 25
p = (p&0x1ffffff)<<5 ^ v
for i := 0; i < 5; i++ {
if (b>>uint(i))&1 == 1 {
p ^= GEN[i]
}
}
}
if p != 1 {
return false
}
b := uint(0)
acc := 0
mv := (1 << 5) - 1
var sw []int
for _, v := range dp[1 : len(dp)-6] {
acc = (acc << 5) | v
b += 5
for b >= 8 {
b -= 8
sw = append(sw, (acc>>b)&mv)
}
}
if len(sw) < 2 || len(sw) > 40 {
return false
}
return true
}
// ExcludesRune is the validation function for validating that the field's value does not contain the rune specified within the param.
func excludesRune(fl FieldLevel) bool {
return !containsRune(fl)
}
// ExcludesAll is the validation function for validating that the field's value does not contain any of the characters specified within the param.
func excludesAll(fl FieldLevel) bool {
return !containsAny(fl)
}
// Excludes is the validation function for validating that the field's value does not contain the text specified within the param.
func excludes(fl FieldLevel) bool {
return !contains(fl)
}
// ContainsRune is the validation function for validating that the field's value contains the rune specified within the param.
func containsRune(fl FieldLevel) bool {
r, _ := utf8.DecodeRuneInString(fl.Param())
return strings.ContainsRune(fl.Field().String(), r)
}
// ContainsAny is the validation function for validating that the field's value contains any of the characters specified within the param.
func containsAny(fl FieldLevel) bool {
return strings.ContainsAny(fl.Field().String(), fl.Param())
}
// Contains is the validation function for validating that the field's value contains the text specified within the param.
func contains(fl FieldLevel) bool {
return strings.Contains(fl.Field().String(), fl.Param())
}
// StartsWith is the validation function for validating that the field's value starts with the text specified within the param.
func startsWith(fl FieldLevel) bool {
return strings.HasPrefix(fl.Field().String(), fl.Param())
}
// EndsWith is the validation function for validating that the field's value ends with the text specified within the param.
func endsWith(fl FieldLevel) bool {
return strings.HasSuffix(fl.Field().String(), fl.Param())
}
// FieldContains is the validation function for validating if the current field's value contains the field specified by the param's value.
func fieldContains(fl FieldLevel) bool {
field := fl.Field()
currentField, _, ok := fl.GetStructFieldOK()
if !ok {
return false
}
return strings.Contains(field.String(), currentField.String())
}
// FieldExcludes is the validation function for validating if the current field's value excludes the field specified by the param's value.
func fieldExcludes(fl FieldLevel) bool {
field := fl.Field()
currentField, _, ok := fl.GetStructFieldOK()
if !ok {
return true
}
return !strings.Contains(field.String(), currentField.String())
}
// IsNeField is the validation function for validating if the current field's value is not equal to the field specified by the param's value.
func isNeField(fl FieldLevel) bool {
field := fl.Field()
kind := field.Kind()
currentField, currentKind, ok := fl.GetStructFieldOK()
if !ok || currentKind != kind {
return true
}
switch kind {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return field.Int() != currentField.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return field.Uint() != currentField.Uint()
case reflect.Float32, reflect.Float64:
return field.Float() != currentField.Float()
case reflect.Slice, reflect.Map, reflect.Array:
return int64(field.Len()) != int64(currentField.Len())
case reflect.Struct:
fieldType := field.Type()
// Not Same underlying type i.e. struct and time
if fieldType != currentField.Type() {
return true
}
if fieldType == timeType {
t := currentField.Interface().(time.Time)
fieldTime := field.Interface().(time.Time)
return !fieldTime.Equal(t)
}
}
// default reflect.String:
return field.String() != currentField.String()
}
// IsNe is the validation function for validating that the field's value does not equal the provided param value.
func isNe(fl FieldLevel) bool {
return !isEq(fl)
}
// IsLteCrossStructField is the validation function for validating if the current field's value is less than or equal to the field, within a separate struct, specified by the param's value.
func isLteCrossStructField(fl FieldLevel) bool {
field := fl.Field()
kind := field.Kind()
topField, topKind, ok := fl.GetStructFieldOK()
if !ok || topKind != kind {
return false
}
switch kind {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return field.Int() <= topField.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return field.Uint() <= topField.Uint()
case reflect.Float32, reflect.Float64:
return field.Float() <= topField.Float()
case reflect.Slice, reflect.Map, reflect.Array:
return int64(field.Len()) <= int64(topField.Len())
case reflect.Struct:
fieldType := field.Type()
// Not Same underlying type i.e. struct and time
if fieldType != topField.Type() {
return false
}
if fieldType == timeType {
fieldTime := field.Interface().(time.Time)
topTime := topField.Interface().(time.Time)
return fieldTime.Before(topTime) || fieldTime.Equal(topTime)
}
}
// default reflect.String:
return field.String() <= topField.String()
}
// IsLtCrossStructField is the validation function for validating if the current field's value is less than the field, within a separate struct, specified by the param's value.
// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
func isLtCrossStructField(fl FieldLevel) bool {
field := fl.Field()
kind := field.Kind()
topField, topKind, ok := fl.GetStructFieldOK()
if !ok || topKind != kind {
return false
}
switch kind {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return field.Int() < topField.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return field.Uint() < topField.Uint()
case reflect.Float32, reflect.Float64:
return field.Float() < topField.Float()
case reflect.Slice, reflect.Map, reflect.Array:
return int64(field.Len()) < int64(topField.Len())
case reflect.Struct:
fieldType := field.Type()
// Not Same underlying type i.e. struct and time
if fieldType != topField.Type() {
return false
}
if fieldType == timeType {
fieldTime := field.Interface().(time.Time)
topTime := topField.Interface().(time.Time)
return fieldTime.Before(topTime)
}
}
// default reflect.String:
return field.String() < topField.String()
}
// IsGteCrossStructField is the validation function for validating if the current field's value is greater than or equal to the field, within a separate struct, specified by the param's value.
func isGteCrossStructField(fl FieldLevel) bool {
field := fl.Field()
kind := field.Kind()
topField, topKind, ok := fl.GetStructFieldOK()
if !ok || topKind != kind {
return false
}
switch kind {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return field.Int() >= topField.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return field.Uint() >= topField.Uint()
case reflect.Float32, reflect.Float64:
return field.Float() >= topField.Float()
case reflect.Slice, reflect.Map, reflect.Array:
return int64(field.Len()) >= int64(topField.Len())
case reflect.Struct:
fieldType := field.Type()
// Not Same underlying type i.e. struct and time
if fieldType != topField.Type() {
return false
}
if fieldType == timeType {
fieldTime := field.Interface().(time.Time)
topTime := topField.Interface().(time.Time)
return fieldTime.After(topTime) || fieldTime.Equal(topTime)
}
}
// default reflect.String:
return field.String() >= topField.String()
}
// IsGtCrossStructField is the validation function for validating if the current field's value is greater than the field, within a separate struct, specified by the param's value.
func isGtCrossStructField(fl FieldLevel) bool {
field := fl.Field()
kind := field.Kind()
topField, topKind, ok := fl.GetStructFieldOK()
if !ok || topKind != kind {
return false
}
switch kind {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return field.Int() > topField.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return field.Uint() > topField.Uint()
case reflect.Float32, reflect.Float64:
return field.Float() > topField.Float()
case reflect.Slice, reflect.Map, reflect.Array:
return int64(field.Len()) > int64(topField.Len())
case reflect.Struct:
fieldType := field.Type()
// Not Same underlying type i.e. struct and time
if fieldType != topField.Type() {
return false
}
if fieldType == timeType {
fieldTime := field.Interface().(time.Time)
topTime := topField.Interface().(time.Time)
return fieldTime.After(topTime)
}
}
// default reflect.String:
return field.String() > topField.String()
}
// IsNeCrossStructField is the validation function for validating that the current field's value is not equal to the field, within a separate struct, specified by the param's value.
func isNeCrossStructField(fl FieldLevel) bool {
field := fl.Field()
kind := field.Kind()
topField, currentKind, ok := fl.GetStructFieldOK()
if !ok || currentKind != kind {
return true
}
switch kind {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return topField.Int() != field.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return topField.Uint() != field.Uint()
case reflect.Float32, reflect.Float64:
return topField.Float() != field.Float()
case reflect.Slice, reflect.Map, reflect.Array:
return int64(topField.Len()) != int64(field.Len())
case reflect.Struct:
fieldType := field.Type()
// Not Same underlying type i.e. struct and time
if fieldType != topField.Type() {
return true
}
if fieldType == timeType {
t := field.Interface().(time.Time)
fieldTime := topField.Interface().(time.Time)
return !fieldTime.Equal(t)
}
}
// default reflect.String:
return topField.String() != field.String()
}
// IsEqCrossStructField is the validation function for validating that the current field's value is equal to the field, within a separate struct, specified by the param's value.
func isEqCrossStructField(fl FieldLevel) bool {
field := fl.Field()
kind := field.Kind()
topField, topKind, ok := fl.GetStructFieldOK()
if !ok || topKind != kind {
return false
}
switch kind {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return topField.Int() == field.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return topField.Uint() == field.Uint()
case reflect.Float32, reflect.Float64:
return topField.Float() == field.Float()
case reflect.Slice, reflect.Map, reflect.Array:
return int64(topField.Len()) == int64(field.Len())
case reflect.Struct:
fieldType := field.Type()
// Not Same underlying type i.e. struct and time
if fieldType != topField.Type() {
return false
}
if fieldType == timeType {
t := field.Interface().(time.Time)
fieldTime := topField.Interface().(time.Time)
return fieldTime.Equal(t)
}
}
// default reflect.String:
return topField.String() == field.String()
}
// IsEqField is the validation function for validating if the current field's value is equal to the field specified by the param's value.
func isEqField(fl FieldLevel) bool {
field := fl.Field()
kind := field.Kind()
currentField, currentKind, ok := fl.GetStructFieldOK()
if !ok || currentKind != kind {
return false
}
switch kind {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return field.Int() == currentField.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return field.Uint() == currentField.Uint()
case reflect.Float32, reflect.Float64:
return field.Float() == currentField.Float()
case reflect.Slice, reflect.Map, reflect.Array:
return int64(field.Len()) == int64(currentField.Len())
case reflect.Struct:
fieldType := field.Type()
// Not Same underlying type i.e. struct and time
if fieldType != currentField.Type() {
return false
}
if fieldType == timeType {
t := currentField.Interface().(time.Time)
fieldTime := field.Interface().(time.Time)
return fieldTime.Equal(t)
}
}
// default reflect.String:
return field.String() == currentField.String()
}
// IsEq is the validation function for validating if the current field's value is equal to the param's value.
func isEq(fl FieldLevel) bool {
field := fl.Field()
param := fl.Param()
switch field.Kind() {
case reflect.String:
return field.String() == param
case reflect.Slice, reflect.Map, reflect.Array:
p := asInt(param)
return int64(field.Len()) == p
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
p := asInt(param)
return field.Int() == p
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
p := asUint(param)
return field.Uint() == p
case reflect.Float32, reflect.Float64:
p := asFloat(param)
return field.Float() == p
}
panic(fmt.Sprintf("Bad field type %T", field.Interface()))
}
// IsBase64 is the validation function for validating if the current field's value is a valid base 64.
func isBase64(fl FieldLevel) bool {
return base64Regex.MatchString(fl.Field().String())
}
// IsBase64URL is the validation function for validating if the current field's value is a valid base64 URL safe string.
func isBase64URL(fl FieldLevel) bool {
return base64URLRegex.MatchString(fl.Field().String())
}
// IsURI is the validation function for validating if the current field's value is a valid URI.
func isURI(fl FieldLevel) bool {
field := fl.Field()
switch field.Kind() {
case reflect.String:
s := field.String()
// checks needed as of Go 1.6 because of change https://github.com/golang/go/commit/617c93ce740c3c3cc28cdd1a0d712be183d0b328#diff-6c2d018290e298803c0c9419d8739885L195
// emulate browser and strip the '#' suffix prior to validation. see issue-#237
if i := strings.Index(s, "#"); i > -1 {
s = s[:i]
}
if len(s) == 0 {
return false
}
_, err := url.ParseRequestURI(s)
return err == nil
}
panic(fmt.Sprintf("Bad field type %T", field.Interface()))
}
// IsURL is the validation function for validating if the current field's value is a valid URL.
func isURL(fl FieldLevel) bool {
field := fl.Field()
switch field.Kind() {
case reflect.String:
var i int
s := field.String()
// checks needed as of Go 1.6 because of change https://github.com/golang/go/commit/617c93ce740c3c3cc28cdd1a0d712be183d0b328#diff-6c2d018290e298803c0c9419d8739885L195
// emulate browser and strip the '#' suffix prior to validation. see issue-#237
if i = strings.Index(s, "#"); i > -1 {
s = s[:i]
}
if len(s) == 0 {
return false
}
url, err := url.ParseRequestURI(s)
if err != nil || url.Scheme == "" {
return false
}
return err == nil
}
panic(fmt.Sprintf("Bad field type %T", field.Interface()))
}
// isUrnRFC2141 is the validation function for validating if the current field's value is a valid URN as per RFC 2141.
func isUrnRFC2141(fl FieldLevel) bool {
field := fl.Field()
switch field.Kind() {
case reflect.String:
str := field.String()
_, match := urn.Parse([]byte(str))
return match
}
panic(fmt.Sprintf("Bad field type %T", field.Interface()))
}
// IsFile is the validation function for validating if the current field's value is a valid file path.
func isFile(fl FieldLevel) bool {
field := fl.Field()
switch field.Kind() {
case reflect.String:
fileInfo, err := os.Stat(field.String())
if err != nil {
return false
}
return !fileInfo.IsDir()
}
panic(fmt.Sprintf("Bad field type %T", field.Interface()))
}
// IsE164 is the validation function for validating if the current field's value is a valid e.164 formatted phone number.
func isE164(fl FieldLevel) bool {
return e164Regex.MatchString(fl.Field().String())
}
// IsEmail is the validation function for validating if the current field's value is a valid email address.
func isEmail(fl FieldLevel) bool {
return emailRegex.MatchString(fl.Field().String())
}
// IsHSLA is the validation function for validating if the current field's value is a valid HSLA color.
func isHSLA(fl FieldLevel) bool {
return hslaRegex.MatchString(fl.Field().String())
}
// IsHSL is the validation function for validating if the current field's value is a valid HSL color.
func isHSL(fl FieldLevel) bool {
return hslRegex.MatchString(fl.Field().String())
}
// IsRGBA is the validation function for validating if the current field's value is a valid RGBA color.
func isRGBA(fl FieldLevel) bool {
return rgbaRegex.MatchString(fl.Field().String())
}
// IsRGB is the validation function for validating if the current field's value is a valid RGB color.
func isRGB(fl FieldLevel) bool {
return rgbRegex.MatchString(fl.Field().String())
}
// IsHEXColor is the validation function for validating if the current field's value is a valid HEX color.
func isHEXColor(fl FieldLevel) bool {
return hexcolorRegex.MatchString(fl.Field().String())
}
// IsHexadecimal is the validation function for validating if the current field's value is a valid hexadecimal.
func isHexadecimal(fl FieldLevel) bool {
return hexadecimalRegex.MatchString(fl.Field().String())
}
// IsNumber is the validation function for validating if the current field's value is a valid number.
func isNumber(fl FieldLevel) bool {
switch fl.Field().Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.Float32, reflect.Float64:
return true
default:
return numberRegex.MatchString(fl.Field().String())
}
}
// IsNumeric is the validation function for validating if the current field's value is a valid numeric value.
func isNumeric(fl FieldLevel) bool {
switch fl.Field().Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.Float32, reflect.Float64:
return true
default:
return numericRegex.MatchString(fl.Field().String())
}
}
// IsAlphanum is the validation function for validating if the current field's value is a valid alphanumeric value.
func isAlphanum(fl FieldLevel) bool {
return alphaNumericRegex.MatchString(fl.Field().String())
}
// IsAlpha is the validation function for validating if the current field's value is a valid alpha value.
func isAlpha(fl FieldLevel) bool {
return alphaRegex.MatchString(fl.Field().String())
}
// IsAlphanumUnicode is the validation function for validating if the current field's value is a valid alphanumeric unicode value.
func isAlphanumUnicode(fl FieldLevel) bool {
return alphaUnicodeNumericRegex.MatchString(fl.Field().String())
}
// IsAlphaUnicode is the validation function for validating if the current field's value is a valid alpha unicode value.
func isAlphaUnicode(fl FieldLevel) bool {
return alphaUnicodeRegex.MatchString(fl.Field().String())
}
// isDefault is the opposite of required aka hasValue
func isDefault(fl FieldLevel) bool {
return !hasValue(fl)
}
// HasValue is the validation function for validating if the current field's value is not the default static value.
func hasValue(fl FieldLevel) bool {
field := fl.Field()
switch field.Kind() {
case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func:
return !field.IsNil()
default:
if fl.(*validate).fldIsPointer && field.Interface() != nil {
return true
}
return field.IsValid() && field.Interface() != reflect.Zero(field.Type()).Interface()
}
}
// requireCheckField is a func for check field kind
func requireCheckFieldKind(fl FieldLevel, param string, defaultNotFoundValue bool) bool {
field := fl.Field()
kind := field.Kind()
var nullable, found bool
if len(param) > 0 {
field, kind, nullable, found = fl.GetStructFieldOKAdvanced2(fl.Parent(), param)
if !found {
return defaultNotFoundValue
}
}
switch kind {
case reflect.Invalid:
return defaultNotFoundValue
case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func:
return field.IsNil()
default:
if nullable && field.Interface() != nil {
return false
}
return field.IsValid() && field.Interface() == reflect.Zero(field.Type()).Interface()
}
}
// RequiredWith is the validation function
// The field under validation must be present and not empty only if any of the other specified fields are present.
func requiredWith(fl FieldLevel) bool {
params := parseOneOfParam2(fl.Param())
for _, param := range params {
if !requireCheckFieldKind(fl, param, true) {
return hasValue(fl)
}
}
return true
}
// RequiredWithAll is the validation function
// The field under validation must be present and not empty only if all of the other specified fields are present.
func requiredWithAll(fl FieldLevel) bool {
params := parseOneOfParam2(fl.Param())
for _, param := range params {
if requireCheckFieldKind(fl, param, true) {
return true
}
}
return hasValue(fl)
}
// RequiredWithout is the validation function
// The field under validation must be present and not empty only when any of the other specified fields are not present.
func requiredWithout(fl FieldLevel) bool {
if requireCheckFieldKind(fl, strings.TrimSpace(fl.Param()), true) {
return hasValue(fl)
}
return true
}
// RequiredWithoutAll is the validation function
// The field under validation must be present and not empty only when all of the other specified fields are not present.
func requiredWithoutAll(fl FieldLevel) bool {
params := parseOneOfParam2(fl.Param())
for _, param := range params {
if !requireCheckFieldKind(fl, param, true) {
return true
}
}
return hasValue(fl)
}
// IsGteField is the validation function for validating if the current field's value is greater than or equal to the field specified by the param's value.
func isGteField(fl FieldLevel) bool {
field := fl.Field()
kind := field.Kind()
currentField, currentKind, ok := fl.GetStructFieldOK()
if !ok || currentKind != kind {
return false
}
switch kind {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return field.Int() >= currentField.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return field.Uint() >= currentField.Uint()
case reflect.Float32, reflect.Float64:
return field.Float() >= currentField.Float()
case reflect.Struct:
fieldType := field.Type()
// Not Same underlying type i.e. struct and time
if fieldType != currentField.Type() {
return false
}
if fieldType == timeType {
t := currentField.Interface().(time.Time)
fieldTime := field.Interface().(time.Time)
return fieldTime.After(t) || fieldTime.Equal(t)
}
}
// default reflect.String
return len(field.String()) >= len(currentField.String())
}
// IsGtField is the validation function for validating if the current field's value is greater than the field specified by the param's value.
func isGtField(fl FieldLevel) bool {
field := fl.Field()
kind := field.Kind()
currentField, currentKind, ok := fl.GetStructFieldOK()
if !ok || currentKind != kind {
return false
}
switch kind {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return field.Int() > currentField.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return field.Uint() > currentField.Uint()
case reflect.Float32, reflect.Float64:
return field.Float() > currentField.Float()
case reflect.Struct:
fieldType := field.Type()
// Not Same underlying type i.e. struct and time
if fieldType != currentField.Type() {
return false
}
if fieldType == timeType {
t := currentField.Interface().(time.Time)
fieldTime := field.Interface().(time.Time)
return fieldTime.After(t)
}
}
// default reflect.String
return len(field.String()) > len(currentField.String())
}
// IsGte is the validation function for validating if the current field's value is greater than or equal to the param's value.
func isGte(fl FieldLevel) bool {
field := fl.Field()
param := fl.Param()
switch field.Kind() {
case reflect.String:
p := asInt(param)
return int64(utf8.RuneCountInString(field.String())) >= p
case reflect.Slice, reflect.Map, reflect.Array:
p := asInt(param)
return int64(field.Len()) >= p
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
p := asInt(param)
return field.Int() >= p
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
p := asUint(param)
return field.Uint() >= p
case reflect.Float32, reflect.Float64:
p := asFloat(param)
return field.Float() >= p
case reflect.Struct:
if field.Type() == timeType {
now := time.Now().UTC()
t := field.Interface().(time.Time)
return t.After(now) || t.Equal(now)
}
}
panic(fmt.Sprintf("Bad field type %T", field.Interface()))
}
// IsGt is the validation function for validating if the current field's value is greater than the param's value.
func isGt(fl FieldLevel) bool {
field := fl.Field()
param := fl.Param()
switch field.Kind() {
case reflect.String:
p := asInt(param)
return int64(utf8.RuneCountInString(field.String())) > p
case reflect.Slice, reflect.Map, reflect.Array:
p := asInt(param)
return int64(field.Len()) > p
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
p := asInt(param)
return field.Int() > p
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
p := asUint(param)
return field.Uint() > p
case reflect.Float32, reflect.Float64:
p := asFloat(param)
return field.Float() > p
case reflect.Struct:
if field.Type() == timeType {
return field.Interface().(time.Time).After(time.Now().UTC())
}
}
panic(fmt.Sprintf("Bad field type %T", field.Interface()))
}
// HasLengthOf is the validation function for validating if the current field's value is equal to the param's value.
func hasLengthOf(fl FieldLevel) bool {
field := fl.Field()
param := fl.Param()
switch field.Kind() {
case reflect.String:
p := asInt(param)
return int64(utf8.RuneCountInString(field.String())) == p
case reflect.Slice, reflect.Map, reflect.Array:
p := asInt(param)
return int64(field.Len()) == p
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
p := asInt(param)
return field.Int() == p
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
p := asUint(param)
return field.Uint() == p
case reflect.Float32, reflect.Float64:
p := asFloat(param)
return field.Float() == p
}
panic(fmt.Sprintf("Bad field type %T", field.Interface()))
}
// HasMinOf is the validation function for validating if the current field's value is greater than or equal to the param's value.
func hasMinOf(fl FieldLevel) bool {
return isGte(fl)
}
// IsLteField is the validation function for validating if the current field's value is less than or equal to the field specified by the param's value.
func isLteField(fl FieldLevel) bool {
field := fl.Field()
kind := field.Kind()
currentField, currentKind, ok := fl.GetStructFieldOK()
if !ok || currentKind != kind {
return false
}
switch kind {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return field.Int() <= currentField.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return field.Uint() <= currentField.Uint()
case reflect.Float32, reflect.Float64:
return field.Float() <= currentField.Float()
case reflect.Struct:
fieldType := field.Type()
// Not Same underlying type i.e. struct and time
if fieldType != currentField.Type() {
return false
}
if fieldType == timeType {
t := currentField.Interface().(time.Time)
fieldTime := field.Interface().(time.Time)
return fieldTime.Before(t) || fieldTime.Equal(t)
}
}
// default reflect.String
return len(field.String()) <= len(currentField.String())
}
// IsLtField is the validation function for validating if the current field's value is less than the field specified by the param's value.
func isLtField(fl FieldLevel) bool {
field := fl.Field()
kind := field.Kind()
currentField, currentKind, ok := fl.GetStructFieldOK()
if !ok || currentKind != kind {
return false
}
switch kind {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return field.Int() < currentField.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return field.Uint() < currentField.Uint()
case reflect.Float32, reflect.Float64:
return field.Float() < currentField.Float()
case reflect.Struct:
fieldType := field.Type()
// Not Same underlying type i.e. struct and time
if fieldType != currentField.Type() {
return false
}
if fieldType == timeType {
t := currentField.Interface().(time.Time)
fieldTime := field.Interface().(time.Time)
return fieldTime.Before(t)
}
}
// default reflect.String
return len(field.String()) < len(currentField.String())
}
// IsLte is the validation function for validating if the current field's value is less than or equal to the param's value.
func isLte(fl FieldLevel) bool {
field := fl.Field()
param := fl.Param()
switch field.Kind() {
case reflect.String:
p := asInt(param)
return int64(utf8.RuneCountInString(field.String())) <= p
case reflect.Slice, reflect.Map, reflect.Array:
p := asInt(param)
return int64(field.Len()) <= p
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
p := asInt(param)
return field.Int() <= p
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
p := asUint(param)
return field.Uint() <= p
case reflect.Float32, reflect.Float64:
p := asFloat(param)
return field.Float() <= p
case reflect.Struct:
if field.Type() == timeType {
now := time.Now().UTC()
t := field.Interface().(time.Time)
return t.Before(now) || t.Equal(now)
}
}
panic(fmt.Sprintf("Bad field type %T", field.Interface()))
}
// IsLt is the validation function for validating if the current field's value is less than the param's value.
func isLt(fl FieldLevel) bool {
field := fl.Field()
param := fl.Param()
switch field.Kind() {
case reflect.String:
p := asInt(param)
return int64(utf8.RuneCountInString(field.String())) < p
case reflect.Slice, reflect.Map, reflect.Array:
p := asInt(param)
return int64(field.Len()) < p
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
p := asInt(param)
return field.Int() < p
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
p := asUint(param)
return field.Uint() < p
case reflect.Float32, reflect.Float64:
p := asFloat(param)
return field.Float() < p
case reflect.Struct:
if field.Type() == timeType {
return field.Interface().(time.Time).Before(time.Now().UTC())
}
}
panic(fmt.Sprintf("Bad field type %T", field.Interface()))
}
// HasMaxOf is the validation function for validating if the current field's value is less than or equal to the param's value.
func hasMaxOf(fl FieldLevel) bool {
return isLte(fl)
}
// IsTCP4AddrResolvable is the validation function for validating if the field's value is a resolvable tcp4 address.
func isTCP4AddrResolvable(fl FieldLevel) bool {
if !isIP4Addr(fl) {
return false
}
_, err := net.ResolveTCPAddr("tcp4", fl.Field().String())
return err == nil
}
// IsTCP6AddrResolvable is the validation function for validating if the field's value is a resolvable tcp6 address.
func isTCP6AddrResolvable(fl FieldLevel) bool {
if !isIP6Addr(fl) {
return false
}
_, err := net.ResolveTCPAddr("tcp6", fl.Field().String())
return err == nil
}
// IsTCPAddrResolvable is the validation function for validating if the field's value is a resolvable tcp address.
func isTCPAddrResolvable(fl FieldLevel) bool {
if !isIP4Addr(fl) && !isIP6Addr(fl) {
return false
}
_, err := net.ResolveTCPAddr("tcp", fl.Field().String())
return err == nil
}
// IsUDP4AddrResolvable is the validation function for validating if the field's value is a resolvable udp4 address.
func isUDP4AddrResolvable(fl FieldLevel) bool {
if !isIP4Addr(fl) {
return false
}
_, err := net.ResolveUDPAddr("udp4", fl.Field().String())
return err == nil
}
// IsUDP6AddrResolvable is the validation function for validating if the field's value is a resolvable udp6 address.
func isUDP6AddrResolvable(fl FieldLevel) bool {
if !isIP6Addr(fl) {
return false
}
_, err := net.ResolveUDPAddr("udp6", fl.Field().String())
return err == nil
}
// IsUDPAddrResolvable is the validation function for validating if the field's value is a resolvable udp address.
func isUDPAddrResolvable(fl FieldLevel) bool {
if !isIP4Addr(fl) && !isIP6Addr(fl) {
return false
}
_, err := net.ResolveUDPAddr("udp", fl.Field().String())
return err == nil
}
// IsIP4AddrResolvable is the validation function for validating if the field's value is a resolvable ip4 address.
func isIP4AddrResolvable(fl FieldLevel) bool {
if !isIPv4(fl) {
return false
}
_, err := net.ResolveIPAddr("ip4", fl.Field().String())
return err == nil
}
// IsIP6AddrResolvable is the validation function for validating if the field's value is a resolvable ip6 address.
func isIP6AddrResolvable(fl FieldLevel) bool {
if !isIPv6(fl) {
return false
}
_, err := net.ResolveIPAddr("ip6", fl.Field().String())
return err == nil
}
// IsIPAddrResolvable is the validation function for validating if the field's value is a resolvable ip address.
func isIPAddrResolvable(fl FieldLevel) bool {
if !isIP(fl) {
return false
}
_, err := net.ResolveIPAddr("ip", fl.Field().String())
return err == nil
}
// IsUnixAddrResolvable is the validation function for validating if the field's value is a resolvable unix address.
func isUnixAddrResolvable(fl FieldLevel) bool {
_, err := net.ResolveUnixAddr("unix", fl.Field().String())
return err == nil
}
func isIP4Addr(fl FieldLevel) bool {
val := fl.Field().String()
if idx := strings.LastIndex(val, ":"); idx != -1 {
val = val[0:idx]
}
ip := net.ParseIP(val)
return ip != nil && ip.To4() != nil
}
func isIP6Addr(fl FieldLevel) bool {
val := fl.Field().String()
if idx := strings.LastIndex(val, ":"); idx != -1 {
if idx != 0 && val[idx-1:idx] == "]" {
val = val[1 : idx-1]
}
}
ip := net.ParseIP(val)
return ip != nil && ip.To4() == nil
}
func isHostnameRFC952(fl FieldLevel) bool {
return hostnameRegexRFC952.MatchString(fl.Field().String())
}
func isHostnameRFC1123(fl FieldLevel) bool {
return hostnameRegexRFC1123.MatchString(fl.Field().String())
}
func isFQDN(fl FieldLevel) bool {
val := fl.Field().String()
if val == "" {
return false
}
if val[len(val)-1] == '.' {
val = val[0 : len(val)-1]
}
return strings.ContainsAny(val, ".") &&
hostnameRegexRFC952.MatchString(val)
}
// IsDir is the validation function for validating if the current field's value is a valid directory.
func isDir(fl FieldLevel) bool {
field := fl.Field()
if field.Kind() == reflect.String {
fileInfo, err := os.Stat(field.String())
if err != nil {
return false
}
return fileInfo.IsDir()
}
panic(fmt.Sprintf("Bad field type %T", field.Interface()))
}
1
https://gitee.com/wordyyp/validator.git
git@gitee.com:wordyyp/validator.git
wordyyp
validator
validator
v9.31.0

搜索帮助