github.com/sohaha/zlsgo@v1.7.13-0.20240501141223-10dd1a906f76/zvalid/rule.go (about)

     1  package zvalid
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"strconv"
     7  	"strings"
     8  	"unicode"
     9  
    10  	"golang.org/x/crypto/bcrypt"
    11  
    12  	"github.com/sohaha/zlsgo/zjson"
    13  	"github.com/sohaha/zlsgo/zstring"
    14  )
    15  
    16  // Regex regular expression match
    17  func (v Engine) Regex(pattern string, customError ...string) Engine {
    18  	return pushQueue(&v, func(v *Engine) *Engine {
    19  		if ignore(v) {
    20  			return v
    21  		}
    22  		if !zstring.RegexMatch(pattern, v.value) {
    23  			v.err = setError(v, "格式不正确", customError...)
    24  		}
    25  		return v
    26  	})
    27  }
    28  
    29  // IsBool boolean value
    30  func (v Engine) IsBool(customError ...string) Engine {
    31  	return pushQueue(&v, func(v *Engine) *Engine {
    32  		if ignore(v) {
    33  			return v
    34  		}
    35  		if _, err := strconv.ParseBool(v.value); err != nil {
    36  			v.err = setError(v, "必须是布尔值", customError...)
    37  		}
    38  		return v
    39  	})
    40  }
    41  
    42  // IsLower lowerCase letters
    43  func (v Engine) IsLower(customError ...string) Engine {
    44  	return pushQueue(&v, func(v *Engine) *Engine {
    45  		if ignore(v) {
    46  			return v
    47  		}
    48  		for _, rv := range v.value {
    49  			if !unicode.IsLower(rv) {
    50  				v.err = setError(v, "必须是小写字母", customError...)
    51  				return v
    52  			}
    53  		}
    54  		return v
    55  	})
    56  }
    57  
    58  // IsUpper uppercase letter
    59  func (v Engine) IsUpper(customError ...string) Engine {
    60  	return pushQueue(&v, func(v *Engine) *Engine {
    61  		if ignore(v) {
    62  			return v
    63  		}
    64  		for _, rv := range v.value {
    65  			if !unicode.IsUpper(rv) {
    66  				v.err = setError(v, "必须是大写字母", customError...)
    67  				return v
    68  			}
    69  		}
    70  		return v
    71  	})
    72  }
    73  
    74  // IsLetter uppercase and lowercase letters
    75  func (v Engine) IsLetter(customError ...string) Engine {
    76  	return pushQueue(&v, func(v *Engine) *Engine {
    77  		if ignore(v) {
    78  			return v
    79  		}
    80  		for _, rv := range v.value {
    81  			if !unicode.IsLetter(rv) {
    82  				v.err = setError(v, "必须是字母", customError...)
    83  				return v
    84  			}
    85  		}
    86  		return v
    87  	})
    88  }
    89  
    90  // IsNumber is number
    91  func (v Engine) IsNumber(customError ...string) Engine {
    92  	return pushQueue(&v, func(v *Engine) *Engine {
    93  		if ignore(v) {
    94  			return v
    95  		}
    96  		if _, err := strconv.ParseFloat(v.value, 64); err != nil {
    97  			v.err = setError(v, "必须是数字", customError...)
    98  		}
    99  		return v
   100  	})
   101  }
   102  
   103  // IsInteger is integer
   104  func (v Engine) IsInteger(customError ...string) Engine {
   105  	return pushQueue(&v, func(v *Engine) *Engine {
   106  		if ignore(v) {
   107  			return v
   108  		}
   109  		if _, err := strconv.Atoi(v.value); err != nil {
   110  			v.err = setError(v, "必须是整数", customError...)
   111  		}
   112  		return v
   113  	})
   114  }
   115  
   116  // IsLowerOrDigit lowercase letters or numbers
   117  func (v Engine) IsLowerOrDigit(customError ...string) Engine {
   118  	return pushQueue(&v, func(v *Engine) *Engine {
   119  		if ignore(v) {
   120  			return v
   121  		}
   122  		for _, rv := range v.value {
   123  			if !unicode.IsLower(rv) && !unicode.IsDigit(rv) {
   124  				v.err = setError(v, "必须是小写字母或数字", customError...)
   125  				return v
   126  			}
   127  		}
   128  		return v
   129  	})
   130  }
   131  
   132  // IsUpperOrDigit uppercase letters or numbers
   133  func (v Engine) IsUpperOrDigit(customError ...string) Engine {
   134  	return pushQueue(&v, func(v *Engine) *Engine {
   135  		if ignore(v) {
   136  			return v
   137  		}
   138  		for _, rv := range v.value {
   139  			if !unicode.IsUpper(rv) && !unicode.IsDigit(rv) {
   140  				v.err = setError(v, "必须是大写字母或数字", customError...)
   141  				return v
   142  			}
   143  		}
   144  		return v
   145  	})
   146  }
   147  
   148  // IsLetterOrDigit letters or numbers
   149  func (v Engine) IsLetterOrDigit(customError ...string) Engine {
   150  	return pushQueue(&v, func(v *Engine) *Engine {
   151  		if ignore(v) {
   152  			return v
   153  		}
   154  		for _, rv := range v.value {
   155  			if !unicode.IsLetter(rv) && !unicode.IsDigit(rv) {
   156  				v.err = setError(v, "必须是字母或数字", customError...)
   157  				return v
   158  			}
   159  		}
   160  		return v
   161  	})
   162  }
   163  
   164  // IsChinese chinese character
   165  func (v Engine) IsChinese(customError ...string) Engine {
   166  	return pushQueue(&v, func(v *Engine) *Engine {
   167  		if ignore(v) {
   168  			return v
   169  		}
   170  		for _, rv := range v.value {
   171  			if !unicode.Is(unicode.Scripts["Han"], rv) {
   172  				v.err = setError(v, "必须是中文", customError...)
   173  				return v
   174  			}
   175  		}
   176  		return v
   177  	})
   178  }
   179  
   180  // IsMobile chinese mobile
   181  func (v Engine) IsMobile(customError ...string) Engine {
   182  	return pushQueue(&v, func(v *Engine) *Engine {
   183  		if ignore(v) {
   184  			return v
   185  		}
   186  		if !zstring.RegexMatch(`^1[\d]{10}$`, v.value) {
   187  			v.err = setError(v, "格式不正确", customError...)
   188  			return v
   189  		}
   190  
   191  		return v
   192  	})
   193  }
   194  
   195  // IsMail email address
   196  func (v Engine) IsMail(customError ...string) Engine {
   197  	return pushQueue(&v, func(v *Engine) *Engine {
   198  		if ignore(v) {
   199  			return v
   200  		}
   201  		errMsg := setError(v, "格式不正确", customError...)
   202  		emailSlice := strings.Split(v.value, "@")
   203  		if len(emailSlice) != 2 {
   204  			v.err = errMsg
   205  			return v
   206  		}
   207  		if emailSlice[0] == "" || emailSlice[1] == "" {
   208  			v.err = errMsg
   209  			return v
   210  		}
   211  
   212  		for k, rv := range emailSlice[0] {
   213  			if k == 0 && !unicode.IsLetter(rv) && !unicode.IsDigit(rv) {
   214  				v.err = errMsg
   215  				return v
   216  			} else if !unicode.IsLetter(rv) && !unicode.IsDigit(rv) && rv != '@' && rv != '.' && rv != '_' && rv != '-' {
   217  				v.err = errMsg
   218  				return v
   219  			}
   220  		}
   221  
   222  		domainSlice := strings.Split(emailSlice[1], ".")
   223  		if len(domainSlice) < 2 {
   224  			v.err = errMsg
   225  			return v
   226  		}
   227  		domainSliceLen := len(domainSlice)
   228  		for i := 0; i < domainSliceLen; i++ {
   229  			for k, rv := range domainSlice[i] {
   230  				if i != domainSliceLen-1 && k == 0 && !unicode.IsLetter(rv) && !unicode.IsDigit(rv) {
   231  					v.err = errMsg
   232  					return v
   233  				} else if !unicode.IsLetter(rv) && !unicode.IsDigit(rv) && rv != '.' && rv != '_' && rv != '-' {
   234  					v.err = errMsg
   235  					return v
   236  				} else if i == domainSliceLen-1 && !unicode.IsLetter(rv) {
   237  					v.err = errMsg
   238  					return v
   239  				}
   240  			}
   241  		}
   242  
   243  		return v
   244  	})
   245  }
   246  
   247  // IsURL links
   248  func (v Engine) IsURL(customError ...string) Engine {
   249  	return pushQueue(&v, func(v *Engine) *Engine {
   250  		if ignore(v) {
   251  			return v
   252  		}
   253  		if len(v.value) < 10 || !(strings.HasPrefix(v.value, "https://") || strings.HasPrefix(v.value, "http://")) {
   254  			v.err = setError(v, "格式不正确", customError...)
   255  			return v
   256  		}
   257  		return v
   258  	})
   259  }
   260  
   261  // IsIP ipv4 v6 address
   262  func (v Engine) IsIP(customError ...string) Engine {
   263  	return pushQueue(&v, func(v *Engine) *Engine {
   264  		if ignore(v) {
   265  			return v
   266  		}
   267  		if net.ParseIP(v.value) == nil {
   268  			v.err = setError(v, "格式不正确", customError...)
   269  			return v
   270  		}
   271  
   272  		return v
   273  	})
   274  }
   275  
   276  // IsJSON valid json format
   277  func (v Engine) IsJSON(customError ...string) Engine {
   278  	return pushQueue(&v, func(v *Engine) *Engine {
   279  		if ignore(v) {
   280  			return v
   281  		}
   282  		if !zjson.Valid(v.value) {
   283  			v.err = setError(v, "格式不正确", customError...)
   284  			return v
   285  		}
   286  		return v
   287  	})
   288  }
   289  
   290  // IsChineseIDNumber mainland china id number
   291  func (v Engine) IsChineseIDNumber(customError ...string) Engine {
   292  	return pushQueue(&v, func(v *Engine) *Engine {
   293  		if ignore(v) {
   294  			return v
   295  		}
   296  		var idV int
   297  		if len(v.value) < 18 {
   298  			v.err = setError(v, "格式不正确", customError...)
   299  			return v
   300  		}
   301  		if v.value[17:] == "X" {
   302  			idV = 88
   303  		} else {
   304  			var err error
   305  			if idV, err = strconv.Atoi(v.value[17:]); err != nil {
   306  				v.err = setError(v, "格式不正确", customError...)
   307  				return v
   308  			}
   309  		}
   310  
   311  		var verify int
   312  		id := v.value[:17]
   313  		arr := make([]int, 17)
   314  		for i := 0; i < 17; i++ {
   315  			arr[i], v.err = strconv.Atoi(string(id[i]))
   316  			if v.err != nil {
   317  				return v
   318  			}
   319  		}
   320  		wi := [17]int{7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2}
   321  		var res int
   322  		for i := 0; i < 17; i++ {
   323  			res += arr[i] * wi[i]
   324  		}
   325  		verify = res % 11
   326  
   327  		var temp int
   328  		a18 := [11]int{1, 0, 88 /* 'X' */, 9, 8, 7, 6, 5, 4, 3, 2}
   329  		for i := 0; i < 11; i++ {
   330  			if i == verify {
   331  				temp = a18[i]
   332  				break
   333  			}
   334  		}
   335  		if temp != idV {
   336  			v.err = setError(v, "格式不正确", customError...)
   337  			return v
   338  		}
   339  
   340  		return v
   341  	})
   342  }
   343  
   344  // MinLength minimum length
   345  func (v Engine) MinLength(min int, customError ...string) Engine {
   346  	return pushQueue(&v, func(v *Engine) *Engine {
   347  		if ignore(v) {
   348  			return v
   349  		}
   350  		if len(v.value) < min {
   351  			v.err = setError(v, "长度不能小于"+strconv.Itoa(min)+"个字符", customError...)
   352  		}
   353  		return v
   354  	})
   355  }
   356  
   357  // MinUTF8Length utf8 encoding minimum length
   358  func (v Engine) MinUTF8Length(min int, customError ...string) Engine {
   359  	return pushQueue(&v, func(v *Engine) *Engine {
   360  		if !ignore(v) && zstring.Len(v.value) < min {
   361  			v.err = setError(v, "长度不能小于"+strconv.Itoa(min)+"个字符", customError...)
   362  		}
   363  		return v
   364  	})
   365  }
   366  
   367  // MaxLength the maximum length
   368  func (v Engine) MaxLength(max int, customError ...string) Engine {
   369  	return pushQueue(&v, func(v *Engine) *Engine {
   370  		if !ignore(v) && len(v.value) > max {
   371  			v.err = setError(v, "长度不能大于"+strconv.Itoa(max)+"个字符", customError...)
   372  		}
   373  		return v
   374  	})
   375  }
   376  
   377  // MaxUTF8Length utf8 encoding maximum length
   378  func (v Engine) MaxUTF8Length(max int, customError ...string) Engine {
   379  	return pushQueue(&v, func(v *Engine) *Engine {
   380  		if !ignore(v) && zstring.Len(v.value) > max {
   381  			v.err = setError(v, "长度不能大于"+strconv.Itoa(max)+"个字符", customError...)
   382  		}
   383  		return v
   384  	})
   385  }
   386  
   387  // MinInt minimum integer value
   388  func (v Engine) MinInt(min int, customError ...string) Engine {
   389  	return pushQueue(&v, func(v *Engine) *Engine {
   390  		if ignore(v) {
   391  			return v
   392  		}
   393  		if v.valueInt == 0 {
   394  			i, err := strconv.Atoi(v.value)
   395  			if err != nil {
   396  				v.err = setError(v, "检查失败,不能小于"+strconv.Itoa(min), customError...)
   397  				return v
   398  			}
   399  			v.valueInt = i
   400  		}
   401  		if v.valueInt < min {
   402  			v.err = setError(v, "不能小于"+strconv.Itoa(min), customError...)
   403  			return v
   404  		}
   405  		return v
   406  	})
   407  }
   408  
   409  // MaxInt maximum integer value
   410  func (v Engine) MaxInt(max int, customError ...string) Engine {
   411  	return pushQueue(&v, func(v *Engine) *Engine {
   412  		if ignore(v) {
   413  			return v
   414  		}
   415  		if v.valueInt == 0 {
   416  			var err error
   417  			v.valueInt, err = strconv.Atoi(v.value)
   418  			if err != nil {
   419  				v.err = setError(v, "检查失败,不能大于"+strconv.Itoa(max), customError...)
   420  				return v
   421  			}
   422  		}
   423  		if v.valueInt > max {
   424  			v.err = setError(v, "不能大于"+strconv.Itoa(max), customError...)
   425  			return v
   426  		}
   427  		return v
   428  	})
   429  }
   430  
   431  // MinFloat minimum floating point value
   432  func (v Engine) MinFloat(min float64, customError ...string) Engine {
   433  	return pushQueue(&v, func(v *Engine) *Engine {
   434  		if ignore(v) {
   435  			return v
   436  		}
   437  		if v.valueFloat == 0 {
   438  			var err error
   439  			v.valueFloat, err = strconv.ParseFloat(v.value, 64)
   440  			if err != nil {
   441  				v.err = setError(v, "检查失败,不能小于"+fmt.Sprint(min), customError...)
   442  				return v
   443  			}
   444  		}
   445  
   446  		if v.valueFloat < min {
   447  			v.err = setError(v, "不能小于"+fmt.Sprint(min), customError...)
   448  			return v
   449  		}
   450  		return v
   451  	})
   452  }
   453  
   454  // MaxFloat maximum floating point value
   455  func (v Engine) MaxFloat(max float64, customError ...string) Engine {
   456  	return pushQueue(&v, func(v *Engine) *Engine {
   457  		if ignore(v) {
   458  			return v
   459  		}
   460  		if v.valueFloat == 0 {
   461  			var err error
   462  			v.valueFloat, err = strconv.ParseFloat(v.value, 64)
   463  			if err != nil {
   464  				v.err = setError(v, "检查失败,不能大于"+fmt.Sprint(max), customError...)
   465  				return v
   466  			}
   467  		}
   468  		if v.valueFloat > max {
   469  			v.err = setError(v, "不能大于"+fmt.Sprint(max), customError...)
   470  			return v
   471  		}
   472  		return v
   473  	})
   474  }
   475  
   476  // EnumString allow only values ​​in []string
   477  func (v Engine) EnumString(slice []string, customError ...string) Engine {
   478  	return pushQueue(&v, func(v *Engine) *Engine {
   479  		if ignore(v) {
   480  			return v
   481  		}
   482  		for k := range slice {
   483  			if slice[k] == v.value {
   484  				return v
   485  			}
   486  		}
   487  		v.err = setError(v, "不在允许的范围", customError...)
   488  		return v
   489  	})
   490  }
   491  
   492  // EnumInt allow only values ​​in []int
   493  func (v Engine) EnumInt(i []int, customError ...string) Engine {
   494  	return pushQueue(&v, func(v *Engine) *Engine {
   495  		if ignore(v) {
   496  			return v
   497  		}
   498  		value, err := strconv.Atoi(v.value)
   499  		if err != nil {
   500  			v.err = setError(v, err.Error(), customError...)
   501  			return v
   502  		}
   503  		v.valueInt = value
   504  		for k := range i {
   505  			if value == i[k] {
   506  				return v
   507  			}
   508  		}
   509  		v.err = setError(v, "不在允许的范围", customError...)
   510  		return v
   511  	})
   512  }
   513  
   514  // EnumFloat64 allow only values ​​in []float64
   515  func (v Engine) EnumFloat64(f []float64, customError ...string) Engine {
   516  	return pushQueue(&v, func(v *Engine) *Engine {
   517  		if ignore(v) {
   518  			return v
   519  		}
   520  		if v.valueFloat == 0 {
   521  			var err error
   522  			v.valueFloat, err = strconv.ParseFloat(v.value, 64)
   523  			if err != nil {
   524  				v.err = setError(v, err.Error(), customError...)
   525  				return v
   526  			}
   527  		}
   528  		for k := range f {
   529  			if v.valueFloat == f[k] {
   530  				return v
   531  			}
   532  		}
   533  		v.err = setError(v, "不在允许的范围", customError...)
   534  		return v
   535  	})
   536  }
   537  
   538  // CheckPassword check encrypt password
   539  func (v Engine) CheckPassword(password string, customError ...string) Engine {
   540  	return pushQueue(&v, func(v *Engine) *Engine {
   541  		if err := bcrypt.CompareHashAndPassword(zstring.String2Bytes(password), zstring.String2Bytes(v.value)); err != nil {
   542  			v.err = setError(v, "不匹配", customError...)
   543  		}
   544  		return v
   545  	})
   546  }