mirror of
https://gitee.com/johng/gf.git
synced 2024-11-29 18:57:44 +08:00
improve package gvalid
This commit is contained in:
parent
78ad9d8c2d
commit
993d6e3076
@ -8,6 +8,7 @@
|
||||
package gi18n
|
||||
|
||||
var (
|
||||
// defaultManager is the default i18n instance for package functions.
|
||||
defaultManager = Instance()
|
||||
)
|
||||
|
||||
@ -26,7 +27,7 @@ func SetDelimiters(left, right string) {
|
||||
defaultManager.SetDelimiters(left, right)
|
||||
}
|
||||
|
||||
// T is alias of Translate.
|
||||
// T is alias of Translate for convenience.
|
||||
func T(content string, language ...string) string {
|
||||
return defaultManager.T(content, language...)
|
||||
}
|
||||
@ -36,3 +37,9 @@ func T(content string, language ...string) string {
|
||||
func Translate(content string, language ...string) string {
|
||||
return defaultManager.Translate(content, language...)
|
||||
}
|
||||
|
||||
// GetValue retrieves and returns the configured content for given key and specified language.
|
||||
// It returns an empty string if not found.
|
||||
func GetContent(key string, language ...string) string {
|
||||
return defaultManager.GetContent(key, language...)
|
||||
}
|
||||
|
@ -14,7 +14,8 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
// Instances map.
|
||||
// instances is the instances map for management
|
||||
// for multiple i18n instance by name.
|
||||
instances = gmap.NewStrAnyMap(true)
|
||||
)
|
||||
|
||||
|
@ -43,11 +43,13 @@ type Options struct {
|
||||
}
|
||||
|
||||
var (
|
||||
// defaultDelimiters defines the key variable delimiters.
|
||||
// defaultDelimiters defines the default key variable delimiters.
|
||||
defaultDelimiters = []string{"{#", "}"}
|
||||
)
|
||||
|
||||
// New creates and returns a new i18n manager.
|
||||
// The optional parameter <option> specifies the custom options for i18n manager.
|
||||
// It uses a default one if it's not passed.
|
||||
func New(options ...Options) *Manager {
|
||||
var opts Options
|
||||
if len(options) > 0 {
|
||||
@ -70,20 +72,23 @@ func New(options ...Options) *Manager {
|
||||
return m
|
||||
}
|
||||
|
||||
// DefaultOptions returns the default options for i18n manager.
|
||||
// DefaultOptions creates and returns a default options for i18n manager.
|
||||
func DefaultOptions() Options {
|
||||
path := "i18n"
|
||||
realPath, _ := gfile.Search(path)
|
||||
var (
|
||||
path = "i18n"
|
||||
realPath, _ = gfile.Search(path)
|
||||
)
|
||||
if realPath != "" {
|
||||
path = realPath
|
||||
// To avoid of the source of GF: github.com/gogf/i18n/gi18n
|
||||
// To avoid of the source path of GF: github.com/gogf/i18n/gi18n
|
||||
if gfile.Exists(path + gfile.Separator + "gi18n") {
|
||||
path = ""
|
||||
}
|
||||
}
|
||||
return Options{
|
||||
Path: path,
|
||||
Delimiters: []string{"{#", "}"},
|
||||
Language: "en",
|
||||
Delimiters: defaultDelimiters,
|
||||
}
|
||||
}
|
||||
|
||||
@ -114,7 +119,7 @@ func (m *Manager) SetDelimiters(left, right string) {
|
||||
intlog.Printf(`SetDelimiters: %v`, m.pattern)
|
||||
}
|
||||
|
||||
// T is alias of Translate.
|
||||
// T is alias of Translate for convenience.
|
||||
func (m *Manager) T(content string, language ...string) string {
|
||||
return m.Translate(content, language...)
|
||||
}
|
||||
@ -140,7 +145,9 @@ func (m *Manager) Translate(content string, language ...string) string {
|
||||
return v
|
||||
}
|
||||
// Parse content as variables container.
|
||||
result, _ := gregex.ReplaceStringFuncMatch(m.pattern, content, func(match []string) string {
|
||||
result, _ := gregex.ReplaceStringFuncMatch(
|
||||
m.pattern, content,
|
||||
func(match []string) string {
|
||||
if v, ok := data[match[1]]; ok {
|
||||
return v
|
||||
}
|
||||
@ -150,10 +157,29 @@ func (m *Manager) Translate(content string, language ...string) string {
|
||||
return result
|
||||
}
|
||||
|
||||
// GetValue retrieves and returns the configured content for given key and specified language.
|
||||
// It returns an empty string if not found.
|
||||
func (m *Manager) GetContent(key string, language ...string) string {
|
||||
m.init()
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
transLang := m.options.Language
|
||||
if len(language) > 0 && language[0] != "" {
|
||||
transLang = language[0]
|
||||
} else {
|
||||
transLang = m.options.Language
|
||||
}
|
||||
if data, ok := m.data[transLang]; ok {
|
||||
return data[key]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// init initializes the manager for lazy initialization design.
|
||||
// The i18n manager is only initialized once.
|
||||
func (m *Manager) init() {
|
||||
m.mu.RLock()
|
||||
// If the data is not nil, means it's already initialized.
|
||||
if m.data != nil {
|
||||
m.mu.RUnlock()
|
||||
return
|
||||
@ -165,10 +191,12 @@ func (m *Manager) init() {
|
||||
if gres.Contains(m.options.Path) {
|
||||
files := gres.ScanDirFile(m.options.Path, "*.*", true)
|
||||
if len(files) > 0 {
|
||||
var path string
|
||||
var name string
|
||||
var lang string
|
||||
var array []string
|
||||
var (
|
||||
path string
|
||||
name string
|
||||
lang string
|
||||
array []string
|
||||
)
|
||||
m.data = make(map[string]map[string]string)
|
||||
for _, file := range files {
|
||||
name = file.Name()
|
||||
@ -193,10 +221,18 @@ func (m *Manager) init() {
|
||||
}
|
||||
} else if m.options.Path != "" {
|
||||
files, _ := gfile.ScanDirFile(m.options.Path, "*.*", true)
|
||||
if len(files) > 0 {
|
||||
var path string
|
||||
var lang string
|
||||
var array []string
|
||||
if len(files) == 0 {
|
||||
intlog.Printf(
|
||||
"no i18n files found in configured directory:%s",
|
||||
m.options.Path,
|
||||
)
|
||||
return
|
||||
}
|
||||
var (
|
||||
path string
|
||||
lang string
|
||||
array []string
|
||||
)
|
||||
m.data = make(map[string]map[string]string)
|
||||
for _, file := range files {
|
||||
path = file[len(m.options.Path)+1:]
|
||||
@ -217,7 +253,9 @@ func (m *Manager) init() {
|
||||
glog.Errorf("load i18n file '%s' failed: %v", file, err)
|
||||
}
|
||||
}
|
||||
// Monitor changes of i18n files for hot reload feature.
|
||||
_, _ = gfsnotify.Add(path, func(event *gfsnotify.Event) {
|
||||
// Any changes of i18n files, clear the data.
|
||||
m.mu.Lock()
|
||||
m.data = nil
|
||||
m.mu.Unlock()
|
||||
@ -225,4 +263,3 @@ func (m *Manager) init() {
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,6 @@
|
||||
package gvalid
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/container/gmap"
|
||||
"github.com/gogf/gf/encoding/gjson"
|
||||
"github.com/gogf/gf/net/gipv4"
|
||||
"github.com/gogf/gf/net/gipv6"
|
||||
@ -20,18 +19,17 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
// 单条规则匹配正则
|
||||
// regular expression pattern for single validation rule.
|
||||
gSINGLE_RULE_PATTERN = `^([\w-]+):{0,1}(.*)`
|
||||
)
|
||||
|
||||
var (
|
||||
// 默认错误消息管理对象(并发安全)
|
||||
errorMsgMap = gmap.NewStrStrMap(true)
|
||||
|
||||
// 单规则正则对象,这里使用包内部变量存储,不需要多次解析
|
||||
// regular expression object for single rule
|
||||
// which is compiled just once and of repeatable usage.
|
||||
ruleRegex, _ = regexp.Compile(gSINGLE_RULE_PATTERN)
|
||||
|
||||
// 即使参数为空(nil|"")也需要校验的规则,主要是必需规则及关联规则
|
||||
// mustCheckRulesEvenValueEmpty specifies some rules that must be validated
|
||||
// even the value is empty (nil or empty).
|
||||
mustCheckRulesEvenValueEmpty = map[string]struct{}{
|
||||
"required": {},
|
||||
"required-if": {},
|
||||
@ -46,7 +44,7 @@ var (
|
||||
"not-in": {},
|
||||
"regex": {},
|
||||
}
|
||||
// 所有支持的校验规则
|
||||
// allSupportedRules defines all supported rules that is used for quick checks.
|
||||
allSupportedRules = map[string]struct{}{
|
||||
"required": {},
|
||||
"required-if": {},
|
||||
@ -65,8 +63,8 @@ var (
|
||||
"password2": {},
|
||||
"password3": {},
|
||||
"postcode": {},
|
||||
"id-number": {},
|
||||
"luhn": {},
|
||||
"resident-id": {},
|
||||
"bank-card": {},
|
||||
"qq": {},
|
||||
"ip": {},
|
||||
"ipv4": {},
|
||||
@ -90,7 +88,7 @@ var (
|
||||
"not-in": {},
|
||||
"regex": {},
|
||||
}
|
||||
// 布尔Map
|
||||
// boolMap defines the boolean values.
|
||||
boolMap = map[string]struct{}{
|
||||
"1": {},
|
||||
"true": {},
|
||||
@ -155,59 +153,54 @@ func Check(value interface{}, rules string, msgs interface{}, params ...interfac
|
||||
}
|
||||
}
|
||||
for index := 0; index < len(ruleItems); {
|
||||
item := ruleItems[index]
|
||||
results := ruleRegex.FindStringSubmatch(item)
|
||||
ruleKey := strings.TrimSpace(results[1])
|
||||
ruleVal := strings.TrimSpace(results[2])
|
||||
match := false
|
||||
var (
|
||||
item = ruleItems[index]
|
||||
match = false
|
||||
results = ruleRegex.FindStringSubmatch(item)
|
||||
ruleKey = strings.TrimSpace(results[1])
|
||||
ruleVal = strings.TrimSpace(results[2])
|
||||
)
|
||||
if len(msgArray) > index {
|
||||
customMsgMap[ruleKey] = strings.TrimSpace(msgArray[index])
|
||||
}
|
||||
switch ruleKey {
|
||||
// 必须字段
|
||||
case "required":
|
||||
fallthrough
|
||||
case "required-if":
|
||||
fallthrough
|
||||
case "required-unless":
|
||||
fallthrough
|
||||
case "required-with":
|
||||
fallthrough
|
||||
case "required-with-all":
|
||||
fallthrough
|
||||
case "required-without":
|
||||
fallthrough
|
||||
case "required-without-all":
|
||||
// Required rules.
|
||||
case
|
||||
"required",
|
||||
"required-if",
|
||||
"required-unless",
|
||||
"required-with",
|
||||
"required-with-all",
|
||||
"required-without",
|
||||
"required-without-all":
|
||||
match = checkRequired(val, ruleKey, ruleVal, data)
|
||||
|
||||
// 长度范围
|
||||
case "length":
|
||||
fallthrough
|
||||
case "min-length":
|
||||
fallthrough
|
||||
case "max-length":
|
||||
// Length rules.
|
||||
case
|
||||
"length",
|
||||
"min-length",
|
||||
"max-length":
|
||||
if msg := checkLength(val, ruleKey, ruleVal, customMsgMap); msg != "" {
|
||||
errorMsgs[ruleKey] = msg
|
||||
} else {
|
||||
match = true
|
||||
}
|
||||
// 大小范围
|
||||
case "min":
|
||||
fallthrough
|
||||
case "max":
|
||||
fallthrough
|
||||
case "between":
|
||||
if msg := checkSize(val, ruleKey, ruleVal, customMsgMap); msg != "" {
|
||||
|
||||
// Range rules.
|
||||
case
|
||||
"min",
|
||||
"max",
|
||||
"between":
|
||||
if msg := checkRange(val, ruleKey, ruleVal, customMsgMap); msg != "" {
|
||||
errorMsgs[ruleKey] = msg
|
||||
} else {
|
||||
match = true
|
||||
}
|
||||
|
||||
// 自定义正则判断
|
||||
// Custom regular expression.
|
||||
case "regex":
|
||||
// 需要判断是否被|符号截断,如果是,那么需要进行整合
|
||||
// It here should check the rule as there might be special char '|' in it.
|
||||
for i := index + 1; i < len(ruleItems); i++ {
|
||||
// 判断下一个规则是否合法,不合法那么和当前正则规则进行整合
|
||||
if !gregex.IsMatchString(gSINGLE_RULE_PATTERN, ruleItems[i]) {
|
||||
ruleVal += "|" + ruleItems[i]
|
||||
index++
|
||||
@ -215,26 +208,26 @@ func Check(value interface{}, rules string, msgs interface{}, params ...interfac
|
||||
}
|
||||
match = gregex.IsMatchString(ruleVal, val)
|
||||
|
||||
// 日期格式,
|
||||
// Date rules.
|
||||
case "date":
|
||||
// 使用标准日期格式检查,但是日期之间必须带连接符号
|
||||
// Standard date string, which must contain char '-'.
|
||||
if _, err := gtime.StrToTime(val); err == nil {
|
||||
match = true
|
||||
break
|
||||
}
|
||||
// 检查是否不带日期连接符号的格式
|
||||
// Date that not contains char '-'.
|
||||
if _, err := gtime.StrToTime(val, "Ymd"); err == nil {
|
||||
match = true
|
||||
break
|
||||
}
|
||||
|
||||
// 日期格式,需要给定日期格式
|
||||
// Date rule with specified format.
|
||||
case "date-format":
|
||||
if _, err := gtime.StrToTimeFormat(val, ruleVal); err == nil {
|
||||
match = true
|
||||
}
|
||||
|
||||
// 两字段值应相同(非敏感字符判断,非类型判断)
|
||||
// Values of two fields should be equal as string.
|
||||
case "same":
|
||||
if v, ok := data[ruleVal]; ok {
|
||||
if strings.Compare(val, v) == 0 {
|
||||
@ -242,7 +235,7 @@ func Check(value interface{}, rules string, msgs interface{}, params ...interfac
|
||||
}
|
||||
}
|
||||
|
||||
// 两字段值不应相同(非敏感字符判断,非类型判断)
|
||||
// Values of two fields should not be equal as string.
|
||||
case "different":
|
||||
match = true
|
||||
if v, ok := data[ruleVal]; ok {
|
||||
@ -251,7 +244,7 @@ func Check(value interface{}, rules string, msgs interface{}, params ...interfac
|
||||
}
|
||||
}
|
||||
|
||||
// 字段值应当在指定范围中
|
||||
// Field value should be in range of.
|
||||
case "in":
|
||||
array := strings.Split(ruleVal, ",")
|
||||
for _, v := range array {
|
||||
@ -261,7 +254,7 @@ func Check(value interface{}, rules string, msgs interface{}, params ...interfac
|
||||
}
|
||||
}
|
||||
|
||||
// 字段值不应当在指定范围中
|
||||
// Field value should not be in range of.
|
||||
case "not-in":
|
||||
match = true
|
||||
array := strings.Split(ruleVal, ",")
|
||||
@ -272,104 +265,129 @@ func Check(value interface{}, rules string, msgs interface{}, params ...interfac
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 验证所给手机号码是否符合手机号的格式.
|
||||
* 移动: 134、135、136、137、138、139、150、151、152、157、158、159、182、183、184、187、188、178(4G)、147(上网卡);
|
||||
* 联通: 130、131、132、155、156、185、186、176(4G)、145(上网卡)、175;
|
||||
* 电信: 133、153、180、181、189 、177(4G);
|
||||
* 卫星通信: 1349
|
||||
* 虚拟运营商: 170、173
|
||||
* 2018新增: 16x, 19x
|
||||
*/
|
||||
// Phone format validation.
|
||||
// 1. China Mobile:
|
||||
// 134, 135, 136, 137, 138, 139, 150, 151, 152, 157, 158, 159, 182, 183, 184, 187, 188,
|
||||
// 178(4G), 147(Net);
|
||||
//
|
||||
// 2. China Unicom:
|
||||
// 130, 131, 132, 155, 156, 185, 186 ,176(4G), 145(Net), 175
|
||||
//
|
||||
// 3. China Telecom:
|
||||
// 133, 153, 180, 181, 189, 177(4G)
|
||||
//
|
||||
// 4. Satelite:
|
||||
// 1349
|
||||
//
|
||||
// 5. Virtual:
|
||||
// 170, 173
|
||||
//
|
||||
// 6. 2018:
|
||||
// 16x, 19x
|
||||
case "phone":
|
||||
match = gregex.IsMatchString(`^13[\d]{9}$|^14[5,7]{1}\d{8}$|^15[^4]{1}\d{8}$|^16[\d]{9}$|^17[0,3,5,6,7,8]{1}\d{8}$|^18[\d]{9}$|^19[\d]{9}$`, val)
|
||||
|
||||
// 国内座机电话号码:"XXXX-XXXXXXX"、"XXXX-XXXXXXXX"、"XXX-XXXXXXX"、"XXX-XXXXXXXX"、"XXXXXXX"、"XXXXXXXX"
|
||||
// Telephone number:
|
||||
// "XXXX-XXXXXXX"
|
||||
// "XXXX-XXXXXXXX"
|
||||
// "XXX-XXXXXXX"
|
||||
// "XXX-XXXXXXXX"
|
||||
// "XXXXXXX"
|
||||
// "XXXXXXXX"
|
||||
case "telephone":
|
||||
match = gregex.IsMatchString(`^((\d{3,4})|\d{3,4}-)?\d{7,8}$`, val)
|
||||
|
||||
// 腾讯QQ号,从10000开始
|
||||
// QQ number: from 10000.
|
||||
case "qq":
|
||||
match = gregex.IsMatchString(`^[1-9][0-9]{4,}$`, val)
|
||||
|
||||
// 中国邮政编码
|
||||
// Postcode number.
|
||||
case "postcode":
|
||||
match = gregex.IsMatchString(`^\d{6}$`, val)
|
||||
|
||||
/*
|
||||
公民身份证号
|
||||
xxxxxx yyyy MM dd 375 0 十八位
|
||||
xxxxxx yy MM dd 75 0 十五位
|
||||
// China resident id number.
|
||||
//
|
||||
// xxxxxx yyyy MM dd 375 0 十八位
|
||||
// xxxxxx yy MM dd 75 0 十五位
|
||||
//
|
||||
// 地区: [1-9]\d{5}
|
||||
// 年的前两位:(18|19|([23]\d)) 1800-2399
|
||||
// 年的后两位:\d{2}
|
||||
// 月份: ((0[1-9])|(10|11|12))
|
||||
// 天数: (([0-2][1-9])|10|20|30|31) 闰年不能禁止29+
|
||||
//
|
||||
// 三位顺序码:\d{3}
|
||||
// 两位顺序码:\d{2}
|
||||
// 校验码: [0-9Xx]
|
||||
//
|
||||
// 十八位:^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$
|
||||
// 十五位:^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}$
|
||||
//
|
||||
// 总:
|
||||
// (^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$)|(^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}$)
|
||||
case "resident-id":
|
||||
match = checkResidentId(val)
|
||||
|
||||
地区:[1-9]\d{5}
|
||||
年的前两位:(18|19|([23]\d)) 1800-2399
|
||||
年的后两位:\d{2}
|
||||
月份:((0[1-9])|(10|11|12))
|
||||
天数:(([0-2][1-9])|10|20|30|31) 闰年不能禁止29+
|
||||
|
||||
三位顺序码:\d{3}
|
||||
两位顺序码:\d{2}
|
||||
校验码: [0-9Xx]
|
||||
|
||||
十八位:^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$
|
||||
十五位:^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}$
|
||||
|
||||
总:
|
||||
(^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$)|(^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}$)
|
||||
*/
|
||||
case "id-number":
|
||||
match = checkIDNumber(val)
|
||||
|
||||
// LUHN规则(银行卡号验证规则)
|
||||
case "luhn":
|
||||
// Bank card number using LUHN algorithm.
|
||||
case
|
||||
"luhn",
|
||||
"bank-card":
|
||||
match = checkLuHn(val)
|
||||
|
||||
// Universal passport format rule:
|
||||
// Starting with letter, containing only numbers or underscores, length between 6 and 18
|
||||
// 通用帐号规则(字母开头,只能包含字母、数字和下划线,长度在6~18之间)
|
||||
case "passport":
|
||||
match = gregex.IsMatchString(`^[a-zA-Z]{1}\w{5,17}$`, val)
|
||||
|
||||
// Universal password format rule1:
|
||||
// Containing any visible chars, length between 6 and 18
|
||||
// 通用密码(任意可见字符,长度在6~18之间)
|
||||
case "password":
|
||||
match = gregex.IsMatchString(`^[\w\S]{6,18}$`, val)
|
||||
|
||||
// Universal password format rule2:
|
||||
// Must meet password rule1, must contain lower and upper letters and numbers.
|
||||
// 中等强度密码(在弱密码的基础上,必须包含大小写字母和数字)
|
||||
case "password2":
|
||||
if gregex.IsMatchString(`^[\w\S]{6,18}$`, val) && gregex.IsMatchString(`[a-z]+`, val) && gregex.IsMatchString(`[A-Z]+`, val) && gregex.IsMatchString(`\d+`, val) {
|
||||
match = true
|
||||
}
|
||||
|
||||
// Universal password format rule3:
|
||||
// Must meet password rule1, must contain lower and upper letters, numbers and special chars.
|
||||
// 强等强度密码(在弱密码的基础上,必须包含大小写字母、数字和特殊字符)
|
||||
case "password3":
|
||||
if gregex.IsMatchString(`^[\w\S]{6,18}$`, val) && gregex.IsMatchString(`[a-z]+`, val) && gregex.IsMatchString(`[A-Z]+`, val) && gregex.IsMatchString(`\d+`, val) && gregex.IsMatchString(`[^a-zA-Z0-9]+`, val) {
|
||||
match = true
|
||||
}
|
||||
|
||||
// json
|
||||
// Json.
|
||||
case "json":
|
||||
if _, err := gjson.Decode([]byte(val)); err == nil {
|
||||
match = true
|
||||
}
|
||||
|
||||
// 整数
|
||||
// Integer.
|
||||
case "integer":
|
||||
if _, err := strconv.Atoi(val); err == nil {
|
||||
match = true
|
||||
}
|
||||
|
||||
// 小数
|
||||
// Float.
|
||||
case "float":
|
||||
if _, err := strconv.ParseFloat(val, 10); err == nil {
|
||||
match = true
|
||||
}
|
||||
|
||||
// 布尔值(1,true,on,yes:true | 0,false,off,no,"":false)
|
||||
// Boolean(1,true,on,yes:true | 0,false,off,no,"":false).
|
||||
case "boolean":
|
||||
match = false
|
||||
if _, ok := boolMap[strings.ToLower(val)]; ok {
|
||||
match = true
|
||||
}
|
||||
|
||||
// 邮件
|
||||
// Email.
|
||||
case "email":
|
||||
match = gregex.IsMatchString(`^[a-zA-Z0-9_\-\.]+@[a-zA-Z0-9_\-]+(\.[a-zA-Z0-9_\-]+)+$`, val)
|
||||
|
||||
@ -377,23 +395,23 @@ func Check(value interface{}, rules string, msgs interface{}, params ...interfac
|
||||
case "url":
|
||||
match = gregex.IsMatchString(`(https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]`, val)
|
||||
|
||||
// domain
|
||||
// Domain
|
||||
case "domain":
|
||||
match = gregex.IsMatchString(`^([0-9a-zA-Z][0-9a-zA-Z-]{0,62}\.)+([0-9a-zA-Z][0-9a-zA-Z-]{0,62})\.?$`, val)
|
||||
|
||||
// IP(IPv4/IPv6)
|
||||
// IP(IPv4/IPv6).
|
||||
case "ip":
|
||||
match = gipv4.Validate(val) || gipv6.Validate(val)
|
||||
|
||||
// IPv4
|
||||
// IPv4.
|
||||
case "ipv4":
|
||||
match = gipv4.Validate(val)
|
||||
|
||||
// IPv6
|
||||
// IPv6.
|
||||
case "ipv6":
|
||||
match = gipv6.Validate(val)
|
||||
|
||||
// MAC地址
|
||||
// MAC.
|
||||
case "mac":
|
||||
match = gregex.IsMatchString(`^([0-9A-Fa-f]{2}[\-:]){5}[0-9A-Fa-f]{2}$`, val)
|
||||
|
||||
@ -401,15 +419,15 @@ func Check(value interface{}, rules string, msgs interface{}, params ...interfac
|
||||
errorMsgs[ruleKey] = "Invalid rule name:" + ruleKey
|
||||
}
|
||||
|
||||
// 错误消息整合
|
||||
// Error message handling.
|
||||
if !match {
|
||||
// 不存在则使用默认的错误信息,
|
||||
// 如果在校验过程中已经设置了错误信息,那么这里便不作处理
|
||||
// It does nothing if the error message for this rule
|
||||
// is already set in previous validation.
|
||||
if _, ok := errorMsgs[ruleKey]; !ok {
|
||||
if msg, ok := customMsgMap[ruleKey]; ok {
|
||||
errorMsgs[ruleKey] = msg
|
||||
} else {
|
||||
errorMsgs[ruleKey] = errorMsgMap.Get(ruleKey)
|
||||
errorMsgs[ruleKey] = getDefaultErrorMessageByRule(ruleKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -417,293 +435,9 @@ func Check(value interface{}, rules string, msgs interface{}, params ...interfac
|
||||
}
|
||||
if len(errorMsgs) > 0 {
|
||||
return newError([]string{rules}, ErrorMap{
|
||||
// 单条数值校验没有键名
|
||||
// Single rule validation has no key.
|
||||
"": errorMsgs,
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 判断必须字段
|
||||
func checkRequired(value, ruleKey, ruleVal string, params map[string]string) bool {
|
||||
required := false
|
||||
switch ruleKey {
|
||||
// 必须字段
|
||||
case "required":
|
||||
required = true
|
||||
|
||||
// 必须字段(当任意所给定字段值与所给值相等时)
|
||||
case "required-if":
|
||||
required = false
|
||||
array := strings.Split(ruleVal, ",")
|
||||
// 必须为偶数,才能是键值对匹配
|
||||
if len(array)%2 == 0 {
|
||||
for i := 0; i < len(array); {
|
||||
tk := array[i]
|
||||
tv := array[i+1]
|
||||
if v, ok := params[tk]; ok {
|
||||
if strings.Compare(tv, v) == 0 {
|
||||
required = true
|
||||
break
|
||||
}
|
||||
}
|
||||
i += 2
|
||||
}
|
||||
}
|
||||
|
||||
// 必须字段(当所给定字段值与所给值都不相等时)
|
||||
case "required-unless":
|
||||
required = true
|
||||
array := strings.Split(ruleVal, ",")
|
||||
// 必须为偶数,才能是键值对匹配
|
||||
if len(array)%2 == 0 {
|
||||
for i := 0; i < len(array); {
|
||||
tk := array[i]
|
||||
tv := array[i+1]
|
||||
if v, ok := params[tk]; ok {
|
||||
if strings.Compare(tv, v) == 0 {
|
||||
required = false
|
||||
break
|
||||
}
|
||||
}
|
||||
i += 2
|
||||
}
|
||||
}
|
||||
|
||||
// 必须字段(当所给定任意字段值不为空时)
|
||||
case "required-with":
|
||||
required = false
|
||||
array := strings.Split(ruleVal, ",")
|
||||
for i := 0; i < len(array); i++ {
|
||||
if params[array[i]] != "" {
|
||||
required = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 必须字段(当所给定所有字段值都不为空时)
|
||||
case "required-with-all":
|
||||
required = true
|
||||
array := strings.Split(ruleVal, ",")
|
||||
for i := 0; i < len(array); i++ {
|
||||
if params[array[i]] == "" {
|
||||
required = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 必须字段(当所给定任意字段值为空时)
|
||||
case "required-without":
|
||||
required = false
|
||||
array := strings.Split(ruleVal, ",")
|
||||
for i := 0; i < len(array); i++ {
|
||||
if params[array[i]] == "" {
|
||||
required = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 必须字段(当所给定所有字段值都为空时)
|
||||
case "required-without-all":
|
||||
required = true
|
||||
array := strings.Split(ruleVal, ",")
|
||||
for i := 0; i < len(array); i++ {
|
||||
if params[array[i]] != "" {
|
||||
required = false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if required {
|
||||
return !(value == "")
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// 对字段值长度进行检测
|
||||
func checkLength(value, ruleKey, ruleVal string, customMsgMap map[string]string) string {
|
||||
var (
|
||||
msg = ""
|
||||
runeArray = gconv.Runes(value)
|
||||
valueLen = len(runeArray)
|
||||
)
|
||||
switch ruleKey {
|
||||
// 长度范围
|
||||
case "length":
|
||||
array := strings.Split(ruleVal, ",")
|
||||
min := 0
|
||||
max := 0
|
||||
if len(array) > 0 {
|
||||
if v, err := strconv.Atoi(strings.TrimSpace(array[0])); err == nil {
|
||||
min = v
|
||||
}
|
||||
}
|
||||
if len(array) > 1 {
|
||||
if v, err := strconv.Atoi(strings.TrimSpace(array[1])); err == nil {
|
||||
max = v
|
||||
}
|
||||
}
|
||||
if valueLen < min || valueLen > max {
|
||||
if v, ok := customMsgMap[ruleKey]; !ok {
|
||||
msg = errorMsgMap.Get(ruleKey)
|
||||
} else {
|
||||
msg = v
|
||||
}
|
||||
msg = strings.Replace(msg, ":min", strconv.Itoa(min), -1)
|
||||
msg = strings.Replace(msg, ":max", strconv.Itoa(max), -1)
|
||||
return msg
|
||||
}
|
||||
|
||||
// 最小长度
|
||||
case "min-length":
|
||||
if min, err := strconv.Atoi(ruleVal); err == nil {
|
||||
if valueLen < min {
|
||||
if v, ok := customMsgMap[ruleKey]; !ok {
|
||||
msg = errorMsgMap.Get(ruleKey)
|
||||
} else {
|
||||
msg = v
|
||||
}
|
||||
msg = strings.Replace(msg, ":min", strconv.Itoa(min), -1)
|
||||
}
|
||||
} else {
|
||||
msg = "校验参数[" + ruleVal + "]应当为整数类型"
|
||||
}
|
||||
|
||||
// 最大长度
|
||||
case "max-length":
|
||||
if max, err := strconv.Atoi(ruleVal); err == nil {
|
||||
if valueLen > max {
|
||||
if v, ok := customMsgMap[ruleKey]; !ok {
|
||||
msg = errorMsgMap.Get(ruleKey)
|
||||
} else {
|
||||
msg = v
|
||||
}
|
||||
msg = strings.Replace(msg, ":max", strconv.Itoa(max), -1)
|
||||
}
|
||||
} else {
|
||||
msg = "校验参数[" + ruleVal + "]应当为整数类型"
|
||||
}
|
||||
}
|
||||
return msg
|
||||
}
|
||||
|
||||
// 对字段值大小进行检测
|
||||
func checkSize(value, ruleKey, ruleVal string, customMsgMap map[string]string) string {
|
||||
msg := ""
|
||||
switch ruleKey {
|
||||
// 大小范围
|
||||
case "between":
|
||||
array := strings.Split(ruleVal, ",")
|
||||
min := float64(0)
|
||||
max := float64(0)
|
||||
if len(array) > 0 {
|
||||
if v, err := strconv.ParseFloat(strings.TrimSpace(array[0]), 10); err == nil {
|
||||
min = v
|
||||
}
|
||||
}
|
||||
if len(array) > 1 {
|
||||
if v, err := strconv.ParseFloat(strings.TrimSpace(array[1]), 10); err == nil {
|
||||
max = v
|
||||
}
|
||||
}
|
||||
if v, err := strconv.ParseFloat(value, 10); err == nil {
|
||||
if v < min || v > max {
|
||||
if v, ok := customMsgMap[ruleKey]; !ok {
|
||||
msg = errorMsgMap.Get(ruleKey)
|
||||
} else {
|
||||
msg = v
|
||||
}
|
||||
msg = strings.Replace(msg, ":min", strconv.FormatFloat(min, 'f', -1, 64), -1)
|
||||
msg = strings.Replace(msg, ":max", strconv.FormatFloat(max, 'f', -1, 64), -1)
|
||||
}
|
||||
} else {
|
||||
msg = "输入参数[" + value + "]应当为数字类型"
|
||||
}
|
||||
|
||||
// 最小值
|
||||
case "min":
|
||||
if min, err := strconv.ParseFloat(ruleVal, 10); err == nil {
|
||||
if v, err := strconv.ParseFloat(value, 10); err == nil {
|
||||
if v < min {
|
||||
if v, ok := customMsgMap[ruleKey]; !ok {
|
||||
msg = errorMsgMap.Get(ruleKey)
|
||||
} else {
|
||||
msg = v
|
||||
}
|
||||
msg = strings.Replace(msg, ":min", strconv.FormatFloat(min, 'f', -1, 64), -1)
|
||||
}
|
||||
} else {
|
||||
msg = "输入参数[" + value + "]应当为数字类型"
|
||||
}
|
||||
} else {
|
||||
msg = "校验参数[" + ruleVal + "]应当为数字类型"
|
||||
}
|
||||
|
||||
// 最大值
|
||||
case "max":
|
||||
if max, err := strconv.ParseFloat(ruleVal, 10); err == nil {
|
||||
if v, err := strconv.ParseFloat(value, 10); err == nil {
|
||||
if v > max {
|
||||
if v, ok := customMsgMap[ruleKey]; !ok {
|
||||
msg = errorMsgMap.Get(ruleKey)
|
||||
} else {
|
||||
msg = v
|
||||
}
|
||||
msg = strings.Replace(msg, ":max", strconv.FormatFloat(max, 'f', -1, 64), -1)
|
||||
}
|
||||
} else {
|
||||
msg = "输入参数[" + value + "]应当为数字类型"
|
||||
}
|
||||
} else {
|
||||
msg = "校验参数[" + ruleVal + "]应当为数字类型"
|
||||
}
|
||||
}
|
||||
return msg
|
||||
}
|
||||
|
||||
// 身份证号验证
|
||||
func checkIDNumber(value string) bool {
|
||||
value = strings.ToUpper(strings.TrimSpace(value))
|
||||
// 18位长检测
|
||||
if len(value) != 18 {
|
||||
return false
|
||||
}
|
||||
// 加权因子
|
||||
weightFactor := []int{7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2}
|
||||
// 校验码
|
||||
checkCode := []byte{'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'}
|
||||
last := value[17]
|
||||
num := 0
|
||||
for i := 0; i < 17; i++ {
|
||||
tmp, err := strconv.Atoi(string(value[i]))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
num = num + tmp*weightFactor[i]
|
||||
}
|
||||
if checkCode[num%11] != last {
|
||||
return false
|
||||
}
|
||||
|
||||
return gregex.IsMatchString(`(^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$)|(^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}$)`, value)
|
||||
}
|
||||
|
||||
// LuHn算法验证(银行卡号校验算法)
|
||||
func checkLuHn(value string) bool {
|
||||
var sum = 0
|
||||
var nDigits = len(value)
|
||||
var parity = nDigits % 2
|
||||
|
||||
for i := 0; i < nDigits; i++ {
|
||||
var digit = int(value[i] - 48)
|
||||
if i%2 == parity {
|
||||
digit *= 2
|
||||
if digit > 9 {
|
||||
digit -= 9
|
||||
}
|
||||
}
|
||||
sum += digit
|
||||
}
|
||||
return sum%10 == 0
|
||||
}
|
||||
|
@ -6,6 +6,11 @@
|
||||
|
||||
package gvalid
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/i18n/gi18n"
|
||||
)
|
||||
|
||||
// defaultMessages is the default error messages.
|
||||
var defaultMessages = map[string]string{
|
||||
"required": "The :attribute field is required",
|
||||
@ -20,44 +25,47 @@ var defaultMessages = map[string]string{
|
||||
"email": "The :attribute must be a valid email address",
|
||||
"phone": "The :attribute must be a valid phone number",
|
||||
"telephone": "The :attribute must be a valid telephone number",
|
||||
"passport": "Invalid passport format",
|
||||
"password": "Invalid passport format",
|
||||
"password2": "Invalid passport format",
|
||||
"password3": "Invalid passport format",
|
||||
"postcode": "Invalid postcode format",
|
||||
"id-number": "Invalid id",
|
||||
"luhn": "The :attribute must be a valid bank card number",
|
||||
"passport": "The :attribute value is not a valid passport format",
|
||||
"password": "The :attribute value is not a valid passport format",
|
||||
"password2": "The :attribute value is not a valid passport format",
|
||||
"password3": "The :attribute value is not a valid passport format",
|
||||
"postcode": "The :attribute value is not a valid passport format",
|
||||
"resident-id": "The :attribute value is not a valid resident id number",
|
||||
"bank-card": "The :attribute must be a valid bank card number",
|
||||
"qq": "The :attribute must be a valid QQ number",
|
||||
"ip": "The :attribute must be a valid IP address",
|
||||
"ipv4": "The :attribute must be a valid IPv4 address",
|
||||
"ipv6": "The :attribute must be a valid IPv6 address",
|
||||
"mac": "MAC地址格式不正确",
|
||||
"url": "URL地址格式不正确",
|
||||
"domain": "域名格式不正确",
|
||||
"length": "字段长度为:min到:max个字符",
|
||||
"min-length": "字段最小长度为:min",
|
||||
"max-length": "字段最大长度为:max",
|
||||
"between": "字段大小为:min到:max",
|
||||
"min": "字段最小值为:min",
|
||||
"max": "字段最大值为:max",
|
||||
"json": "字段应当为JSON格式",
|
||||
"xml": "字段应当为XML格式",
|
||||
"array": "字段应当为数组",
|
||||
"integer": "字段应当为整数",
|
||||
"float": "字段应当为浮点数",
|
||||
"boolean": "字段应当为布尔值",
|
||||
"same": "字段值不合法",
|
||||
"different": "字段值不合法",
|
||||
"in": "字段值不合法",
|
||||
"not-in": "字段值不合法",
|
||||
"regex": "字段值不合法",
|
||||
"mac": "The :attribute must be a valid MAC address",
|
||||
"url": "The :attribute must be a valid URL address",
|
||||
"domain": "The :attribute must be a valid domain format",
|
||||
"length": "The :attribute length must be between :min and :max",
|
||||
"min-length": "The :attribute length must be equal or greater than :min",
|
||||
"max-length": "The :attribute length must be equal or lesser than :max",
|
||||
"between": "The :attribute value must be between :min and :max",
|
||||
"min": "The :attribute value must be equal or greater than :min",
|
||||
"max": "The :attribute value must be equal or lesser than :max",
|
||||
"json": "The :attribute must be a valid JSON string",
|
||||
"xml": "The :attribute must be a valid XML string",
|
||||
"array": "The :attribute must be an array",
|
||||
"integer": "The :attribute must be an integer",
|
||||
"float": "The :attribute must be a float",
|
||||
"boolean": "The :attribute field must be true or false",
|
||||
"same": "The :attribute value must be the same as field :other",
|
||||
"different": "The :attribute value must be different from field :other",
|
||||
"in": "The :attribute value is not in acceptable range",
|
||||
"not-in": "The :attribute value is not in acceptable range",
|
||||
"regex": "The :attribute value is invalid",
|
||||
}
|
||||
|
||||
func init() {
|
||||
errorMsgMap.Sets(defaultMessages)
|
||||
// getDefaultErrorMessageByRule retrieves and returns the default error message
|
||||
// for specified rule. It firstly retrieves the message from i18n manager, it returns
|
||||
// from default error messages if it's not found in i18n manager.
|
||||
func getDefaultErrorMessageByRule(rule string) string {
|
||||
i18nKey := fmt.Sprintf(`gf.gvalid.%s`, rule)
|
||||
content := gi18n.GetContent(i18nKey)
|
||||
if content == "" {
|
||||
content = defaultMessages[rule]
|
||||
}
|
||||
|
||||
// SetDefaultErrorMsgs sets the default error messages for package.
|
||||
func SetDefaultErrorMsgs(msgs map[string]string) {
|
||||
errorMsgMap.Sets(msgs)
|
||||
return content
|
||||
}
|
||||
|
80
util/gvalid/gvalid_rule_length.go
Normal file
80
util/gvalid/gvalid_rule_length.go
Normal file
@ -0,0 +1,80 @@
|
||||
// Copyright 2018 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gvalid
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 对字段值长度进行检测
|
||||
func checkLength(value, ruleKey, ruleVal string, customMsgMap map[string]string) string {
|
||||
var (
|
||||
msg = ""
|
||||
runeArray = gconv.Runes(value)
|
||||
valueLen = len(runeArray)
|
||||
)
|
||||
switch ruleKey {
|
||||
// 长度范围
|
||||
case "length":
|
||||
array := strings.Split(ruleVal, ",")
|
||||
min := 0
|
||||
max := 0
|
||||
if len(array) > 0 {
|
||||
if v, err := strconv.Atoi(strings.TrimSpace(array[0])); err == nil {
|
||||
min = v
|
||||
}
|
||||
}
|
||||
if len(array) > 1 {
|
||||
if v, err := strconv.Atoi(strings.TrimSpace(array[1])); err == nil {
|
||||
max = v
|
||||
}
|
||||
}
|
||||
if valueLen < min || valueLen > max {
|
||||
if v, ok := customMsgMap[ruleKey]; !ok {
|
||||
msg = getDefaultErrorMessageByRule(ruleKey)
|
||||
} else {
|
||||
msg = v
|
||||
}
|
||||
msg = strings.Replace(msg, ":min", strconv.Itoa(min), -1)
|
||||
msg = strings.Replace(msg, ":max", strconv.Itoa(max), -1)
|
||||
return msg
|
||||
}
|
||||
|
||||
// 最小长度
|
||||
case "min-length":
|
||||
if min, err := strconv.Atoi(ruleVal); err == nil {
|
||||
if valueLen < min {
|
||||
if v, ok := customMsgMap[ruleKey]; !ok {
|
||||
msg = getDefaultErrorMessageByRule(ruleKey)
|
||||
} else {
|
||||
msg = v
|
||||
}
|
||||
msg = strings.Replace(msg, ":min", strconv.Itoa(min), -1)
|
||||
}
|
||||
} else {
|
||||
msg = "校验参数[" + ruleVal + "]应当为整数类型"
|
||||
}
|
||||
|
||||
// 最大长度
|
||||
case "max-length":
|
||||
if max, err := strconv.Atoi(ruleVal); err == nil {
|
||||
if valueLen > max {
|
||||
if v, ok := customMsgMap[ruleKey]; !ok {
|
||||
msg = getDefaultErrorMessageByRule(ruleKey)
|
||||
} else {
|
||||
msg = v
|
||||
}
|
||||
msg = strings.Replace(msg, ":max", strconv.Itoa(max), -1)
|
||||
}
|
||||
} else {
|
||||
msg = "校验参数[" + ruleVal + "]应当为整数类型"
|
||||
}
|
||||
}
|
||||
return msg
|
||||
}
|
28
util/gvalid/gvalid_rule_luhn.go
Normal file
28
util/gvalid/gvalid_rule_luhn.go
Normal file
@ -0,0 +1,28 @@
|
||||
// Copyright 2018 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gvalid
|
||||
|
||||
// checkLuHn checks value with LUHN algorithm.
|
||||
// It's usually used for bank card number validation.
|
||||
func checkLuHn(value string) bool {
|
||||
var (
|
||||
sum = 0
|
||||
nDigits = len(value)
|
||||
parity = nDigits % 2
|
||||
)
|
||||
for i := 0; i < nDigits; i++ {
|
||||
var digit = int(value[i] - 48)
|
||||
if i%2 == parity {
|
||||
digit *= 2
|
||||
if digit > 9 {
|
||||
digit -= 9
|
||||
}
|
||||
}
|
||||
sum += digit
|
||||
}
|
||||
return sum%10 == 0
|
||||
}
|
86
util/gvalid/gvalid_rule_range.go
Normal file
86
util/gvalid/gvalid_rule_range.go
Normal file
@ -0,0 +1,86 @@
|
||||
// Copyright 2018 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gvalid
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 对字段值大小进行检测
|
||||
func checkRange(value, ruleKey, ruleVal string, customMsgMap map[string]string) string {
|
||||
msg := ""
|
||||
switch ruleKey {
|
||||
// 大小范围
|
||||
case "between":
|
||||
array := strings.Split(ruleVal, ",")
|
||||
min := float64(0)
|
||||
max := float64(0)
|
||||
if len(array) > 0 {
|
||||
if v, err := strconv.ParseFloat(strings.TrimSpace(array[0]), 10); err == nil {
|
||||
min = v
|
||||
}
|
||||
}
|
||||
if len(array) > 1 {
|
||||
if v, err := strconv.ParseFloat(strings.TrimSpace(array[1]), 10); err == nil {
|
||||
max = v
|
||||
}
|
||||
}
|
||||
if v, err := strconv.ParseFloat(value, 10); err == nil {
|
||||
if v < min || v > max {
|
||||
if v, ok := customMsgMap[ruleKey]; !ok {
|
||||
msg = getDefaultErrorMessageByRule(ruleKey)
|
||||
} else {
|
||||
msg = v
|
||||
}
|
||||
msg = strings.Replace(msg, ":min", strconv.FormatFloat(min, 'f', -1, 64), -1)
|
||||
msg = strings.Replace(msg, ":max", strconv.FormatFloat(max, 'f', -1, 64), -1)
|
||||
}
|
||||
} else {
|
||||
msg = "输入参数[" + value + "]应当为数字类型"
|
||||
}
|
||||
|
||||
// 最小值
|
||||
case "min":
|
||||
if min, err := strconv.ParseFloat(ruleVal, 10); err == nil {
|
||||
if v, err := strconv.ParseFloat(value, 10); err == nil {
|
||||
if v < min {
|
||||
if v, ok := customMsgMap[ruleKey]; !ok {
|
||||
msg = getDefaultErrorMessageByRule(ruleKey)
|
||||
} else {
|
||||
msg = v
|
||||
}
|
||||
msg = strings.Replace(msg, ":min", strconv.FormatFloat(min, 'f', -1, 64), -1)
|
||||
}
|
||||
} else {
|
||||
msg = "输入参数[" + value + "]应当为数字类型"
|
||||
}
|
||||
} else {
|
||||
msg = "校验参数[" + ruleVal + "]应当为数字类型"
|
||||
}
|
||||
|
||||
// 最大值
|
||||
case "max":
|
||||
if max, err := strconv.ParseFloat(ruleVal, 10); err == nil {
|
||||
if v, err := strconv.ParseFloat(value, 10); err == nil {
|
||||
if v > max {
|
||||
if v, ok := customMsgMap[ruleKey]; !ok {
|
||||
msg = getDefaultErrorMessageByRule(ruleKey)
|
||||
} else {
|
||||
msg = v
|
||||
}
|
||||
msg = strings.Replace(msg, ":max", strconv.FormatFloat(max, 'f', -1, 64), -1)
|
||||
}
|
||||
} else {
|
||||
msg = "输入参数[" + value + "]应当为数字类型"
|
||||
}
|
||||
} else {
|
||||
msg = "校验参数[" + ruleVal + "]应当为数字类型"
|
||||
}
|
||||
}
|
||||
return msg
|
||||
}
|
108
util/gvalid/gvalid_rule_required.go
Normal file
108
util/gvalid/gvalid_rule_required.go
Normal file
@ -0,0 +1,108 @@
|
||||
// Copyright 2018 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gvalid
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 判断必须字段
|
||||
func checkRequired(value, ruleKey, ruleVal string, params map[string]string) bool {
|
||||
required := false
|
||||
switch ruleKey {
|
||||
// 必须字段
|
||||
case "required":
|
||||
required = true
|
||||
|
||||
// 必须字段(当任意所给定字段值与所给值相等时)
|
||||
case "required-if":
|
||||
required = false
|
||||
array := strings.Split(ruleVal, ",")
|
||||
// 必须为偶数,才能是键值对匹配
|
||||
if len(array)%2 == 0 {
|
||||
for i := 0; i < len(array); {
|
||||
tk := array[i]
|
||||
tv := array[i+1]
|
||||
if v, ok := params[tk]; ok {
|
||||
if strings.Compare(tv, v) == 0 {
|
||||
required = true
|
||||
break
|
||||
}
|
||||
}
|
||||
i += 2
|
||||
}
|
||||
}
|
||||
|
||||
// 必须字段(当所给定字段值与所给值都不相等时)
|
||||
case "required-unless":
|
||||
required = true
|
||||
array := strings.Split(ruleVal, ",")
|
||||
// 必须为偶数,才能是键值对匹配
|
||||
if len(array)%2 == 0 {
|
||||
for i := 0; i < len(array); {
|
||||
tk := array[i]
|
||||
tv := array[i+1]
|
||||
if v, ok := params[tk]; ok {
|
||||
if strings.Compare(tv, v) == 0 {
|
||||
required = false
|
||||
break
|
||||
}
|
||||
}
|
||||
i += 2
|
||||
}
|
||||
}
|
||||
|
||||
// 必须字段(当所给定任意字段值不为空时)
|
||||
case "required-with":
|
||||
required = false
|
||||
array := strings.Split(ruleVal, ",")
|
||||
for i := 0; i < len(array); i++ {
|
||||
if params[array[i]] != "" {
|
||||
required = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 必须字段(当所给定所有字段值都不为空时)
|
||||
case "required-with-all":
|
||||
required = true
|
||||
array := strings.Split(ruleVal, ",")
|
||||
for i := 0; i < len(array); i++ {
|
||||
if params[array[i]] == "" {
|
||||
required = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 必须字段(当所给定任意字段值为空时)
|
||||
case "required-without":
|
||||
required = false
|
||||
array := strings.Split(ruleVal, ",")
|
||||
for i := 0; i < len(array); i++ {
|
||||
if params[array[i]] == "" {
|
||||
required = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 必须字段(当所给定所有字段值都为空时)
|
||||
case "required-without-all":
|
||||
required = true
|
||||
array := strings.Split(ruleVal, ",")
|
||||
for i := 0; i < len(array); i++ {
|
||||
if params[array[i]] != "" {
|
||||
required = false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if required {
|
||||
return !(value == "")
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
58
util/gvalid/gvalid_rule_resident_id.go
Normal file
58
util/gvalid/gvalid_rule_resident_id.go
Normal file
@ -0,0 +1,58 @@
|
||||
// Copyright 2018 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gvalid
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/text/gregex"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// checkResidentId checks whether given id a china resident id number.
|
||||
//
|
||||
// xxxxxx yyyy MM dd 375 0 十八位
|
||||
// xxxxxx yy MM dd 75 0 十五位
|
||||
//
|
||||
// 地区: [1-9]\d{5}
|
||||
// 年的前两位:(18|19|([23]\d)) 1800-2399
|
||||
// 年的后两位:\d{2}
|
||||
// 月份: ((0[1-9])|(10|11|12))
|
||||
// 天数: (([0-2][1-9])|10|20|30|31) 闰年不能禁止29+
|
||||
//
|
||||
// 三位顺序码:\d{3}
|
||||
// 两位顺序码:\d{2}
|
||||
// 校验码: [0-9Xx]
|
||||
//
|
||||
// 十八位:^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$
|
||||
// 十五位:^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}$
|
||||
//
|
||||
// 总:
|
||||
// (^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$)|(^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}$)
|
||||
func checkResidentId(id string) bool {
|
||||
id = strings.ToUpper(strings.TrimSpace(id))
|
||||
if len(id) != 18 {
|
||||
return false
|
||||
}
|
||||
var (
|
||||
weightFactor = []int{7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2}
|
||||
checkCode = []byte{'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'}
|
||||
last = id[17]
|
||||
num = 0
|
||||
)
|
||||
for i := 0; i < 17; i++ {
|
||||
tmp, err := strconv.Atoi(string(id[i]))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
num = num + tmp*weightFactor[i]
|
||||
}
|
||||
if checkCode[num%11] != last {
|
||||
return false
|
||||
}
|
||||
|
||||
return gregex.IsMatchString(`(^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$)|(^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}$)`, id)
|
||||
}
|
Loading…
Reference in New Issue
Block a user