gf/g/util/gvalid/gvalid.go
2017-12-28 17:28:32 +08:00

380 lines
15 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 通用数据验证工具
// 本来打算取名gvalidator的名字太长了缩写一下
package gvalid
import (
"strings"
"regexp"
"strconv"
"gitee.com/johng/gf/g/os/gtime"
"gitee.com/johng/gf/g/util/gregx"
"gitee.com/johng/gf/g/encoding/gjson"
)
// 默认规则校验错误消息(可以通过接口自定义错误消息)
var defaultMessages = map[string]string {
"required" : "字段不能为空",
"required_if" : "字段不能为空",
"required_with" : "字段不能为空",
"required_with_all" : "字段不能为空",
"date" : "日期格式不正确",
"email" : "邮箱地址格式不正确",
"phone" : "手机号码格式不正确",
"telephone" : "电话号码格式不正确",
"passport" : "账号格式不合法必需以字母开头只能包含字母、数字和下划线长度在6~18之间",
"password" : "密码格式不合法密码格式为任意6-18位的可见字符",
"password2" : "密码格式不合法密码格式为任意6-18位的可见字符必须包含大小写字母和数字",
"password3" : "密码格式不合法密码格式为任意6-18位的可见字符必须包含大小写字母、数字和特殊字符",
"postcode" : "邮政编码不正确",
"id_number" : "身份证号码不正确",
"qq" : "QQ号码格式不正确",
"ip" : "IP地址格式不正确",
"mac" : "MAC地址格式不正确",
"url" : "URL地址格式不正确",
"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" : "字段值不合法",
}
// 检测一条数据的规则其中values参数为非必须参数可以传递所有的校验参数进来进行多参数对比(部分校验规则需要)
func CheckRule(value, rule string, values...map[string]string) map[string]string {
msgs := make(map[string]string)
params := make(map[string]string)
if len(values) > 0 {
params = values[0]
}
items := strings.Split(strings.TrimSpace(rule), "|")
for _, item := range items {
reg, _ := regexp.Compile(`^(\w+):{0,1}(.*)`)
results := reg.FindStringSubmatch(item)
rulekey := results[1]
ruleval := results[2]
match := false
switch rulekey {
// 必须字段
case "required":
match = !(value == "")
break
//// 必须字段(当给定字段值与所给任意值相等时)
//case "required_if":
// array := strings.Split(strings.TrimSpace(ruleval), ",")
// for _, v := range array {
// if strings.Compare(value, strings.TrimSpace(v)) == 0 {
// match = true
// break
// }
// }
// break
//
//// 必须字段(当所给定任意字段值不为空时)
//case "required_with":
// $ruleMatch = false;
// $tmpArray = explode(',', $ruleAttr);
// foreach ($tmpArray as $v) {
//if (!empty(self::$_currentData[$v])) {
//$ruleMatch = true;
//break
//}
//}
// break
//
// // 必须字段(当所给定所有字段值都不为空时)
//case "required_with_all":
// $tmpArray = explode(',', $ruleAttr);
// foreach ($tmpArray as $v) {
//if (empty(self::$_currentData[$v])) {
//$ruleMatch = false;
//break
//}
//}
// break
// 日期格式,需要给定日期格式
case "date":
if _, err := gtime.StrToTime(value, ruleval); err == nil {
match = true
}
break
// // 两字段值应相同(非敏感字符判断,非类型判断)
//case "same":
// $ruleMatch = (isset(self::$_currentData[$ruleAttr]) && $value == self::$_currentData[$ruleAttr]);
// break
//
// // 两字段值不应相同(非敏感字符判断,非类型判断)
//case "different":
// $ruleMatch = (!isset(self::$_currentData[$ruleAttr]) || $value != self::$_currentData[$ruleAttr]);
// break
// 字段值应当在指定范围中
case "in":
array := strings.Split(strings.TrimSpace(ruleval), ",")
for _, v := range array {
if strings.Compare(value, strings.TrimSpace(v)) == 0 {
match = true
break
}
}
break
// 字段值不应当在指定范围中
case "not_in":
match = true
array := strings.Split(strings.TrimSpace(ruleval), ",")
for _, v := range array {
if strings.Compare(value, strings.TrimSpace(v)) == 0 {
match = false
break
}
}
break
// 自定义正则判断
//case "regex":
// $ruleMatch = @preg_match($ruleAttr, $value) ? true : false;
// break
/*
* 验证所给手机号码是否符合手机号的格式.
* 移动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
*/
case "phone":
match = gregx.IsMatchString(`^13[\d]{9}$|^14[5,7]{1}\d{8}$|^15[^4]{1}\d{8}$|^17[0,3,5,6,7,8]{1}\d{8}$|^18[\d]{9}$`, value)
break
/*
* 国内座机电话号码:"XXXX-XXXXXXX"、"XXXX-XXXXXXXX"、"XXX-XXXXXXX"、"XXX-XXXXXXXX"、"XXXXXXX"、"XXXXXXXX"
*/
case "telephone":
match = gregx.IsMatchString(`^((\d{3,4})|\d{3,4}-)?\d{7,8}$`, value)
break
// 腾讯QQ号从10000开始
case "qq":
match = gregx.IsMatchString(`^[1-9][0-9]{4,}$`, value)
break
// 中国邮政编码
case "postcode":
match = gregx.IsMatchString(`^[1-9]\d{5}$`, value)
break
/*
公民身份证号
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{2}$
总:
(^[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{2}$)
*/
case "id_number":
match = gregx.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{2}$)`, value)
break
// 通用帐号规则(字母开头只能包含字母、数字和下划线长度在6~18之间)
case "passport":
match = gregx.IsMatchString(`^[a-zA-Z]{1}\w{5,17}$`, value)
break
// 通用密码(任意可见字符长度在6~18之间)
case "password":
match = gregx.IsMatchString(`^[\w\S]{6,18}$`, value)
break
// 中等强度密码(在弱密码的基础上,必须包含大小写字母和数字)
case "password2":
if gregx.IsMatchString(`^[\w\S]{6,18}$`, value) && gregx.IsMatchString(`[a-z]+`, value) && gregx.IsMatchString(`[A-Z]+`, value) && gregx.IsMatchString(`\d+`, value) {
match = true
}
break
// 强等强度密码(在弱密码的基础上,必须包含大小写字母、数字和特殊字符)
case "password3":
if gregx.IsMatchString(`^[\w\S]{6,18}$`, value) && gregx.IsMatchString(`[a-z]+`, value) && gregx.IsMatchString(`[A-Z]+`, value) && gregx.IsMatchString(`\d+`, value) && gregx.IsMatchString(`\S+`, value) {
match = true
}
break
// 长度范围
case "length":
array := strings.Split(strings.TrimSpace(ruleval), ",")
min := 0
max := 0
if len(array) > 0 {
if v, err := strconv.Atoi(array[0]); err == nil {
min = v
}
}
if len(array) > 1 {
if v, err := strconv.Atoi(array[1]); err == nil {
max = v
}
}
if len(value) >= min && len(value) <= max {
match = true
}
break
// 最小长度
case "min_length":
if min, err := strconv.Atoi(strings.TrimSpace(ruleval)); err == nil {
if len(value) >= min {
match = true
}
}
break
// 最大长度
case "max_length":
if max, err := strconv.Atoi(strings.TrimSpace(ruleval)); err == nil {
if len(value) <= max {
match = true
}
}
break
// 大小范围
case "between":
array := strings.Split(strings.TrimSpace(ruleval), ",")
min := 0
max := 0
if len(array) > 0 {
if v, err := strconv.Atoi(array[0]); err == nil {
min = v
}
}
if len(array) > 1 {
if v, err := strconv.Atoi(array[1]); err == nil {
max = v
}
}
if v, err := strconv.Atoi(value); err == nil {
if v >= min && v <= max {
match = true
}
}
break
// 最小值
case "min":
if min, err := strconv.Atoi(strings.TrimSpace(ruleval)); err == nil {
if v, err := strconv.Atoi(value); err == nil {
if v >= min {
match = true
}
}
}
break
// 最大值
case "max":
if max, err := strconv.Atoi(strings.TrimSpace(ruleval)); err == nil {
if v, err := strconv.Atoi(value); err == nil {
if v <= max {
match = true
}
}
}
break
// json
case "json":
if _, err := gjson.Decode([]byte(value)); err == nil {
match = true
}
break
//// xml
//case "xml":
// $checkResult = @Lib_XmlParser::isXml($value);
// $ruleMatch = ($checkResult !== null && $checkResult !== false);
// break
// 整数
case "integer":
if _, err := strconv.Atoi(value); err == nil {
match = true
}
break
// 小数
case "float":
if _, err := strconv.ParseFloat(value, 10); err == nil {
match = true
}
break
// 布尔值(1,true,on,yes:true | 0,false,off,no,"":false)
case "boolean":
if value != "" && value != "0" && value != "false" && value != "off" && value != "no" {
match = true
}
break
// 邮件
case "email":
match = gregx.IsMatchString(`^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$`, value)
break
// URL
case "url":
match = gregx.IsMatchString(`^(?:([A-Za-z]+):)?(\/{0,3})([0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$`, value)
break
// IP
case "ip":
match = gregx.IsMatchString(`^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$`, value)
break
// MAC地址
case "mac":
match = gregx.IsMatchString(`^([0-9A-Fa-f]{2}-){5}[0-9A-Fa-f]{2}$`, value)
break
default:
msgs[rulekey] = "Invalid rule name:" + rulekey
break
}
// 错误消息整合
if !match {
msgs[rulekey] = defaultMessages[rulekey]
}
}
if len(msgs) > 0 {
return msgs
}
return nil
}