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 }