Passed
Push — 6.0 ( b94f98...cb524c )
by liu
04:38
created

Validate::is()   D

Complexity

Conditions 18
Paths 18

Size

Total Lines 61
Code Lines 46

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 342

Importance

Changes 0
Metric Value
cc 18
eloc 46
nc 18
nop 3
dl 0
loc 61
ccs 0
cts 45
cp 0
crap 342
rs 4.8666
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
// +----------------------------------------------------------------------
1 ignored issue
show
Coding Style introduced by
You must use "/**" style comments for a file comment
Loading history...
3
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
4
// +----------------------------------------------------------------------
5
// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
6
// +----------------------------------------------------------------------
7
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
8
// +----------------------------------------------------------------------
9
// | Author: liu21st <[email protected]>
10
// +----------------------------------------------------------------------
11
declare (strict_types = 1);
12
13
namespace think;
14
15
use Closure;
16
use think\exception\ValidateException;
17
use think\validate\ValidateRule;
18
19
/**
20
 * 数据验证类
21
 */
5 ignored issues
show
Coding Style introduced by
Missing @category tag in class comment
Loading history...
Coding Style introduced by
Missing @package tag in class comment
Loading history...
Coding Style introduced by
Missing @author tag in class comment
Loading history...
Coding Style introduced by
Missing @license tag in class comment
Loading history...
Coding Style introduced by
Missing @link tag in class comment
Loading history...
22
class Validate
23
{
24
    /**
25
     * 自定义验证类型
26
     * @var array
27
     */
28
    protected $type = [];
29
30
    /**
31
     * 验证类型别名
32
     * @var array
33
     */
34
    protected $alias = [
35
        '>' => 'gt', '>=' => 'egt', '<' => 'lt', '<=' => 'elt', '=' => 'eq', 'same' => 'eq',
36
    ];
37
38
    /**
39
     * 当前验证规则
40
     * @var array
41
     */
42
    protected $rule = [];
43
44
    /**
45
     * 验证提示信息
46
     * @var array
47
     */
48
    protected $message = [];
49
50
    /**
51
     * 验证字段描述
52
     * @var array
53
     */
54
    protected $field = [];
55
56
    /**
57
     * 默认规则提示
58
     * @var array
59
     */
60
    protected $typeMsg = [
61
        'require'     => ':attribute require',
62
        'must'        => ':attribute must',
63
        'number'      => ':attribute must be numeric',
64
        'integer'     => ':attribute must be integer',
65
        'float'       => ':attribute must be float',
66
        'boolean'     => ':attribute must be bool',
67
        'email'       => ':attribute not a valid email address',
68
        'mobile'      => ':attribute not a valid mobile',
69
        'array'       => ':attribute must be a array',
70
        'accepted'    => ':attribute must be yes,on or 1',
71
        'date'        => ':attribute not a valid datetime',
72
        'file'        => ':attribute not a valid file',
73
        'image'       => ':attribute not a valid image',
74
        'alpha'       => ':attribute must be alpha',
75
        'alphaNum'    => ':attribute must be alpha-numeric',
76
        'alphaDash'   => ':attribute must be alpha-numeric, dash, underscore',
77
        'activeUrl'   => ':attribute not a valid domain or ip',
78
        'chs'         => ':attribute must be chinese',
79
        'chsAlpha'    => ':attribute must be chinese or alpha',
80
        'chsAlphaNum' => ':attribute must be chinese,alpha-numeric',
81
        'chsDash'     => ':attribute must be chinese,alpha-numeric,underscore, dash',
82
        'url'         => ':attribute not a valid url',
83
        'ip'          => ':attribute not a valid ip',
84
        'dateFormat'  => ':attribute must be dateFormat of :rule',
85
        'in'          => ':attribute must be in :rule',
86
        'notIn'       => ':attribute be notin :rule',
87
        'between'     => ':attribute must between :1 - :2',
88
        'notBetween'  => ':attribute not between :1 - :2',
89
        'length'      => 'size of :attribute must be :rule',
90
        'max'         => 'max size of :attribute must be :rule',
91
        'min'         => 'min size of :attribute must be :rule',
92
        'after'       => ':attribute cannot be less than :rule',
93
        'before'      => ':attribute cannot exceed :rule',
94
        'expire'      => ':attribute not within :rule',
95
        'allowIp'     => 'access IP is not allowed',
96
        'denyIp'      => 'access IP denied',
97
        'confirm'     => ':attribute out of accord with :2',
98
        'different'   => ':attribute cannot be same with :2',
99
        'egt'         => ':attribute must greater than or equal :rule',
100
        'gt'          => ':attribute must greater than :rule',
101
        'elt'         => ':attribute must less than or equal :rule',
102
        'lt'          => ':attribute must less than :rule',
103
        'eq'          => ':attribute must equal :rule',
104
        'unique'      => ':attribute has exists',
105
        'regex'       => ':attribute not conform to the rules',
106
        'method'      => 'invalid Request method',
107
        'token'       => 'invalid token',
108
        'fileSize'    => 'filesize not match',
109
        'fileExt'     => 'extensions to upload is not allowed',
110
        'fileMime'    => 'mimetype to upload is not allowed',
111
    ];
112
113
    /**
114
     * 当前验证场景
115
     * @var string
116
     */
117
    protected $currentScene;
118
119
    /**
120
     * 内置正则验证规则
121
     * @var array
122
     */
123
    protected $defaultRegex = [
124
        'alpha'       => '/^[A-Za-z]+$/',
125
        'alphaNum'    => '/^[A-Za-z0-9]+$/',
126
        'alphaDash'   => '/^[A-Za-z0-9\-\_]+$/',
127
        'chs'         => '/^[\x{4e00}-\x{9fa5}]+$/u',
128
        'chsAlpha'    => '/^[\x{4e00}-\x{9fa5}a-zA-Z]+$/u',
129
        'chsAlphaNum' => '/^[\x{4e00}-\x{9fa5}a-zA-Z0-9]+$/u',
130
        'chsDash'     => '/^[\x{4e00}-\x{9fa5}a-zA-Z0-9\_\-]+$/u',
131
        'mobile'      => '/^1[3-9][0-9]\d{8}$/',
132
        'idCard'      => '/(^[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}$)/',
133
        'zip'         => '/\d{6}/',
134
    ];
135
136
    /**
137
     * Filter_var 规则
138
     * @var array
139
     */
140
    protected $filter = [
141
        'email'   => FILTER_VALIDATE_EMAIL,
142
        'ip'      => [FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6],
143
        'integer' => FILTER_VALIDATE_INT,
144
        'url'     => FILTER_VALIDATE_URL,
145
        'macAddr' => FILTER_VALIDATE_MAC,
146
        'float'   => FILTER_VALIDATE_FLOAT,
147
    ];
148
149
    /**
150
     * 验证场景定义
151
     * @var array
152
     */
153
    protected $scene = [];
154
155
    /**
156
     * 验证失败错误信息
157
     * @var array
158
     */
159
    protected $error = [];
160
161
    /**
162
     * 是否批量验证
163
     * @var bool
164
     */
165
    protected $batch = false;
166
167
    /**
168
     * 验证失败是否抛出异常
169
     * @var bool
170
     */
171
    protected $failException = false;
172
173
    /**
174
     * 场景需要验证的规则
175
     * @var array
176
     */
177
    protected $only = [];
178
179
    /**
180
     * 场景需要移除的验证规则
181
     * @var array
182
     */
183
    protected $remove = [];
184
185
    /**
186
     * 场景需要追加的验证规则
187
     * @var array
188
     */
189
    protected $append = [];
190
191
    /**
192
     * 验证正则定义
193
     * @var array
194
     */
195
    protected $regex = [];
196
197
    /**
198
     * Db对象
199
     * @var Db
200
     */
201
    protected $db;
202
203
    /**
204
     * 语言对象
205
     * @var Lang
206
     */
207
    protected $lang;
208
209
    /**
210
     * 请求对象
211
     * @var Request
212
     */
213
    protected $request;
214
215
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
216
     * @var Closure
217
     */
218
    protected static $maker;
219
220
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
221
     * @var array
222
     */
223
    protected static $extend = [];
224
225
    /**
226
     * 构造方法
227
     * @access public
228
     */
229
    public function __construct()
230
    {
231
        if (static::$maker) {
232
            call_user_func(static::$maker, $this);
233
        }
234
235
        if (!empty(static::$extend)) {
236
            foreach (static::$extend as $extend) {
237
                call_user_func($extend, $this);
238
            }
239
        }
240
    }
241
242
    /**
243
     * 设置扩展注入
244
     * @access public
245
     * @param  Closure $extend
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
246
     * @return void
247
     */
248
    public static function extend(Closure $extend)
249
    {
250
        static::$extend[] = $extend;
251
    }
252
253
    /**
254
     * 设置服务注入
255
     * @access public
256
     * @param  Closure $maker
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
257
     * @return void
258
     */
259
    public static function maker(Closure $maker)
260
    {
261
        static::$maker = $maker;
262
    }
263
264
    /**
265
     * 设置Lang对象
266
     * @access public
267
     * @param  Lang $lang Lang对象
268
     * @return void
269
     */
270
    public function setLang(Lang $lang)
271
    {
272
        $this->lang = $lang;
273
    }
274
275
    /**
276
     * 设置Db对象
277
     * @access public
278
     * @param  Db $db Db对象
279
     * @return void
280
     */
281
    public function setDb(Db $db)
282
    {
283
        $this->db = $db;
284
    }
285
286
    /**
287
     * 设置Request对象
288
     * @access public
289
     * @param  Request $request Request对象
290
     * @return void
291
     */
292
    public function setRequest(Request $request)
293
    {
294
        $this->request = $request;
295
    }
296
297
    /**
298
     * 添加字段验证规则
299
     * @access protected
300
     * @param  string|array  $name  字段名称或者规则数组
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
301
     * @param  mixed         $rule  验证规则或者字段描述信息
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
302
     * @return $this
303
     */
304
    public function rule($name, $rule = '')
305
    {
306
        if (is_array($name)) {
307
            $this->rule = $name + $this->rule;
308
            if (is_array($rule)) {
309
                $this->field = array_merge($this->field, $rule);
310
            }
311
        } else {
312
            $this->rule[$name] = $rule;
313
        }
314
315
        return $this;
316
    }
317
318
    /**
319
     * 注册验证(类型)规则
320
     * @access public
321
     * @param  string   $type  验证规则类型
0 ignored issues
show
Coding Style introduced by
Expected 5 spaces after parameter name; 2 found
Loading history...
322
     * @param  callable $callback callback方法(或闭包)
323
     * @param  string   $message  验证失败提示信息
324
     * @return $this
325
     */
326
    public function register(string $type, callable $callback = null, string $message = null)
327
    {
328
        $this->type[$type] = $callback;
329
330
        if ($message) {
331
            $this->typeMsg[$type] = $message;
332
        }
333
334
        return $this;
335
    }
336
337
    /**
338
     * 设置验证规则的默认提示信息
339
     * @access public
340
     * @param  string|array $type  验证规则类型名称或者数组
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
341
     * @param  string       $msg  验证提示信息
342
     * @return void
343
     */
344
    public function setTypeMsg($type, string $msg = null): void
345
    {
346
        if (is_array($type)) {
347
            $this->typeMsg = array_merge($this->typeMsg, $type);
348
        } else {
349
            $this->typeMsg[$type] = $msg;
350
        }
351
    }
352
353
    /**
354
     * 设置提示信息
355
     * @access public
356
     * @param  array $message 错误信息
357
     * @return Validate
358
     */
359
    public function message(array $message)
360
    {
361
        $this->message = array_merge($this->message, $message);
362
363
        return $this;
364
    }
365
366
    /**
367
     * 设置验证场景
368
     * @access public
369
     * @param  string $name  场景名
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
370
     * @return $this
371
     */
372
    public function scene(string $name)
373
    {
374
        // 设置当前场景
375
        $this->currentScene = $name;
376
377
        return $this;
378
    }
379
380
    /**
381
     * 判断是否存在某个验证场景
382
     * @access public
383
     * @param  string $name 场景名
384
     * @return bool
385
     */
386
    public function hasScene(string $name): bool
387
    {
388
        return isset($this->scene[$name]) || method_exists($this, 'scene' . $name);
389
    }
390
391
    /**
392
     * 设置批量验证
393
     * @access public
394
     * @param  bool $batch  是否批量验证
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
395
     * @return $this
396
     */
397
    public function batch(bool $batch = true)
398
    {
399
        $this->batch = $batch;
400
401
        return $this;
402
    }
403
404
    /**
405
     * 设置验证失败后是否抛出异常
406
     * @access protected
407
     * @param  bool $fail 是否抛出异常
408
     * @return $this
409
     */
410
    public function failException(bool $fail = true)
411
    {
412
        $this->failException = $fail;
413
414
        return $this;
415
    }
416
417
    /**
418
     * 指定需要验证的字段列表
419
     * @access public
420
     * @param  array $fields  字段名
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
421
     * @return $this
422
     */
423
    public function only(array $fields)
424
    {
425
        $this->only = $fields;
426
427
        return $this;
428
    }
429
430
    /**
431
     * 移除某个字段的验证规则
432
     * @access public
433
     * @param  string|array $field  字段名
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
434
     * @param  mixed        $rule   验证规则 true 移除所有规则
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter name; 3 found
Loading history...
435
     * @return $this
436
     */
437
    public function remove($field, $rule = null)
438
    {
439
        if (is_array($field)) {
440
            foreach ($field as $key => $rule) {
441
                if (is_int($key)) {
442
                    $this->remove($rule);
443
                } else {
444
                    $this->remove($key, $rule);
445
                }
446
            }
447
        } else {
448
            if (is_string($rule)) {
449
                $rule = explode('|', $rule);
450
            }
451
452
            $this->remove[$field] = $rule;
453
        }
454
455
        return $this;
456
    }
457
458
    /**
459
     * 追加某个字段的验证规则
460
     * @access public
461
     * @param  string|array $field  字段名
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
462
     * @param  mixed        $rule   验证规则
0 ignored issues
show
Coding Style introduced by
Expected 2 spaces after parameter name; 3 found
Loading history...
463
     * @return $this
464
     */
465
    public function append($field, $rule = null)
466
    {
467
        if (is_array($field)) {
468
            foreach ($field as $key => $rule) {
469
                $this->append($key, $rule);
470
            }
471
        } else {
472
            if (is_string($rule)) {
473
                $rule = explode('|', $rule);
474
            }
475
476
            $this->append[$field] = $rule;
477
        }
478
479
        return $this;
480
    }
481
482
    /**
483
     * 数据自动验证
484
     * @access public
485
     * @param  array $data  数据
486
     * @param  array $rules  验证规则
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
487
     * @return bool
488
     */
489
    public function check(array $data, array $rules = []): bool
490
    {
491
        $this->error = [];
492
493
        if (empty($rules)) {
494
            // 读取验证规则
495
            $rules = $this->rule;
496
        }
497
498
        if ($this->currentScene) {
499
            $this->getScene($this->currentScene);
500
        }
501
502
        foreach ($this->append as $key => $rule) {
503
            if (!isset($rules[$key])) {
504
                $rules[$key] = $rule;
505
            }
506
        }
507
508
        foreach ($rules as $key => $rule) {
509
            // field => 'rule1|rule2...' field => ['rule1','rule2',...]
510
            if (strpos($key, '|')) {
511
                // 字段|描述 用于指定属性名称
512
                list($key, $title) = explode('|', $key);
513
            } else {
514
                $title = $this->field[$key] ?? $key;
515
            }
516
517
            // 场景检测
518
            if (!empty($this->only) && !in_array($key, $this->only)) {
519
                continue;
520
            }
521
522
            // 获取数据 支持二维数组
523
            $value = $this->getDataValue($data, $key);
524
525
            // 字段验证
526
            if ($rule instanceof \Closure) {
527
                $result = call_user_func_array($rule, [$value, $data]);
528
            } elseif ($rule instanceof ValidateRule) {
529
                //  验证因子
530
                $result = $this->checkItem($key, $value, $rule->getRule(), $data, $rule->getTitle() ?: $title, $rule->getMsg());
531
            } else {
532
                $result = $this->checkItem($key, $value, $rule, $data, $title);
533
            }
534
535
            if (true !== $result) {
536
                // 没有返回true 则表示验证失败
537
                if (!empty($this->batch)) {
538
                    // 批量验证
539
                    if (is_array($result)) {
540
                        $this->error = array_merge($this->error, $result);
541
                    } else {
542
                        $this->error[$key] = $result;
543
                    }
544
                } elseif ($this->failException) {
545
                    throw new ValidateException($result);
546
                } else {
547
                    $this->error = $result;
548
                    return false;
549
                }
550
            }
551
        }
552
553
        if (!empty($this->error)) {
554
            if ($this->failException) {
555
                throw new ValidateException($this->error);
556
            }
557
            return false;
558
        }
559
560
        return true;
561
    }
562
563
    /**
564
     * 根据验证规则验证数据
565
     * @access public
566
     * @param  mixed $value 字段值
567
     * @param  mixed $rules 验证规则
568
     * @return bool
569
     */
570
    public function checkRule($value, $rules): bool
571
    {
572
        if ($rules instanceof \Closure) {
573
            return call_user_func_array($rules, [$value]);
574
        } elseif ($rules instanceof ValidateRule) {
575
            $rules = $rules->getRule();
576
        } elseif (is_string($rules)) {
577
            $rules = explode('|', $rules);
578
        }
579
580
        foreach ($rules as $key => $rule) {
581
            if ($rule instanceof \Closure) {
582
                $result = call_user_func_array($rule, [$value]);
583
            } else {
584
                // 判断验证类型
585
                list($type, $rule) = $this->getValidateType($key, $rule);
586
587
                $callback = $this->type[$type] ?? [$this, $type];
588
589
                $result = call_user_func_array($callback, [$value, $rule]);
590
            }
591
592
            if (true !== $result) {
593
                if ($this->failException) {
594
                    throw new ValidateException($result);
595
                }
596
597
                return $result;
598
            }
599
        }
600
601
        return true;
602
    }
603
604
    /**
605
     * 验证单个字段规则
606
     * @access protected
607
     * @param  string $field  字段名
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
608
     * @param  mixed  $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
609
     * @param  mixed  $rules  验证规则
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
610
     * @param  array  $data  数据
611
     * @param  string $title  字段描述
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
612
     * @param  array  $msg  提示信息
0 ignored issues
show
Coding Style introduced by
Expected 3 spaces after parameter name; 2 found
Loading history...
613
     * @return mixed
614
     */
615
    protected function checkItem(string $field, $value, $rules, $data, string $title = '', array $msg = [])
616
    {
617
        if (isset($this->remove[$field]) && true === $this->remove[$field] && empty($this->append[$field])) {
618
            // 字段已经移除 无需验证
619
            return true;
620
        }
621
622
        // 支持多规则验证 require|in:a,b,c|... 或者 ['require','in'=>'a,b,c',...]
623
        if (is_string($rules)) {
624
            $rules = explode('|', $rules);
625
        }
626
627
        if (isset($this->append[$field])) {
628
            // 追加额外的验证规则
629
            $rules = array_unique(array_merge($rules, $this->append[$field]), SORT_REGULAR);
630
        }
631
632
        $i = 0;
633
        foreach ($rules as $key => $rule) {
634
            if ($rule instanceof \Closure) {
635
                $result = call_user_func_array($rule, [$value, $data]);
636
                $info   = is_numeric($key) ? '' : $key;
637
            } else {
638
                // 判断验证类型
639
                list($type, $rule, $info) = $this->getValidateType($key, $rule);
640
641
                if (isset($this->append[$field]) && in_array($info, $this->append[$field])) {
642
643
                } elseif (isset($this->remove[$field]) && in_array($info, $this->remove[$field])) {
644
                    // 规则已经移除
645
                    $i++;
646
                    continue;
647
                }
648
649
                if (isset($this->type[$type])) {
650
                    $result = call_user_func_array($this->type[$type], [$value, $rule, $data, $field, $title]);
651
                } elseif ('must' == $info || 0 === strpos($info, 'require') || (!is_null($value) && '' !== $value)) {
652
                    $result = call_user_func_array([$this, $type], [$value, $rule, $data, $field, $title]);
653
                } else {
654
                    $result = true;
655
                }
656
            }
657
658
            if (false === $result) {
659
                // 验证失败 返回错误信息
660
                if (!empty($msg[$i])) {
661
                    $message = $msg[$i];
662
                    if (is_string($message) && strpos($message, '{%') === 0) {
663
                        $message = $this->lang->get(substr($message, 2, -1));
664
                    }
665
                } else {
666
                    $message = $this->getRuleMsg($field, $title, $info, $rule);
667
                }
668
669
                return $message;
670
            } elseif (true !== $result) {
671
                // 返回自定义错误信息
672
                if (is_string($result) && false !== strpos($result, ':')) {
673
                    $result = str_replace(':attribute', $title, $result);
674
675
                    if (strpos($result, ':rule') && is_scalar($rule)) {
676
                        $result = str_replace(':rule', (string) $rule, $result);
677
                    }
678
                }
679
680
                return $result;
681
            }
682
            $i++;
683
        }
684
685
        return $result;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $result does not seem to be defined for all execution paths leading up to this point.
Loading history...
686
    }
687
688
    /**
689
     * 获取当前验证类型及规则
690
     * @access public
691
     * @param  mixed $key
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
692
     * @param  mixed $rule
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
693
     * @return array
694
     */
695
    protected function getValidateType($key, $rule): array
696
    {
697
        // 判断验证类型
698
        if (!is_numeric($key)) {
699
            if (isset($this->alias[$key])) {
700
                // 判断别名
701
                $key = $this->alias[$key];
702
            }
703
            return [$key, $rule, $key];
704
        }
705
706
        if (strpos($rule, ':')) {
707
            list($type, $rule) = explode(':', $rule, 2);
708
            if (isset($this->alias[$type])) {
709
                // 判断别名
710
                $type = $this->alias[$type];
711
            }
712
            $info = $type;
713
        } elseif (method_exists($this, $rule)) {
714
            $type = $rule;
715
            $info = $rule;
716
            $rule = '';
717
        } else {
718
            $type = 'is';
719
            $info = $rule;
720
        }
721
722
        return [$type, $rule, $info];
723
    }
724
725
    /**
726
     * 验证是否和某个字段的值一致
727
     * @access public
728
     * @param  mixed  $value 字段值
729
     * @param  mixed  $rule  验证规则
730
     * @param  array  $data  数据
731
     * @param  string $field 字段名
732
     * @return bool
733
     */
734
    public function confirm($value, $rule, array $data = [], string $field = ''): bool
735
    {
736
        if ('' == $rule) {
737
            if (strpos($field, '_confirm')) {
738
                $rule = strstr($field, '_confirm', true);
739
            } else {
740
                $rule = $field . '_confirm';
741
            }
742
        }
743
744
        return $this->getDataValue($data, $rule) === $value;
745
    }
746
747
    /**
748
     * 验证是否和某个字段的值是否不同
749
     * @access public
750
     * @param  mixed $value 字段值
751
     * @param  mixed $rule  验证规则
752
     * @param  array $data  数据
753
     * @return bool
754
     */
755
    public function different($value, $rule, array $data = []): bool
756
    {
757
        return $this->getDataValue($data, $rule) != $value;
758
    }
759
760
    /**
761
     * 验证是否大于等于某个值
762
     * @access public
763
     * @param  mixed $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
764
     * @param  mixed $rule  验证规则
765
     * @param  array $data  数据
766
     * @return bool
767
     */
768
    public function egt($value, $rule, array $data = []): bool
769
    {
770
        return $value >= $this->getDataValue($data, $rule);
771
    }
772
773
    /**
774
     * 验证是否大于某个值
775
     * @access public
776
     * @param  mixed $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
777
     * @param  mixed $rule  验证规则
778
     * @param  array $data  数据
779
     * @return bool
780
     */
781
    public function gt($value, $rule, array $data = []): bool
782
    {
783
        return $value > $this->getDataValue($data, $rule);
784
    }
785
786
    /**
787
     * 验证是否小于等于某个值
788
     * @access public
789
     * @param  mixed $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
790
     * @param  mixed $rule  验证规则
791
     * @param  array $data  数据
792
     * @return bool
793
     */
794
    public function elt($value, $rule, array $data = []): bool
795
    {
796
        return $value <= $this->getDataValue($data, $rule);
797
    }
798
799
    /**
800
     * 验证是否小于某个值
801
     * @access public
802
     * @param  mixed $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
803
     * @param  mixed $rule  验证规则
804
     * @param  array $data  数据
805
     * @return bool
806
     */
807
    public function lt($value, $rule, array $data = []): bool
808
    {
809
        return $value < $this->getDataValue($data, $rule);
810
    }
811
812
    /**
813
     * 验证是否等于某个值
814
     * @access public
815
     * @param  mixed $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
816
     * @param  mixed $rule  验证规则
817
     * @return bool
818
     */
819
    public function eq($value, $rule): bool
820
    {
821
        return $value == $rule;
822
    }
823
824
    /**
825
     * 必须验证
826
     * @access public
827
     * @param  mixed $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
828
     * @param  mixed $rule  验证规则
829
     * @return bool
830
     */
831
    public function must($value, $rule = null): bool
832
    {
833
        return !empty($value) || '0' == $value;
834
    }
835
836
    /**
837
     * 验证字段值是否为有效格式
838
     * @access public
839
     * @param  mixed  $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
840
     * @param  string $rule  验证规则
841
     * @param  array  $data  数据
842
     * @return bool
843
     */
844
    public function is($value, string $rule, array $data = []): bool
845
    {
846
        switch (App::parseName($rule, 1, false)) {
847
            case 'require':
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
848
                // 必须
849
                $result = !empty($value) || '0' == $value;
850
                break;
851
            case 'accepted':
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
852
                // 接受
853
                $result = in_array($value, ['1', 'on', 'yes']);
854
                break;
855
            case 'date':
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
856
                // 是否是一个有效日期
857
                $result = false !== strtotime($value);
858
                break;
859
            case 'activeUrl':
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
860
                // 是否为有效的网址
861
                $result = checkdnsrr($value);
862
                break;
863
            case 'boolean':
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
864
            case 'bool':
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
865
                // 是否为布尔值
866
                $result = in_array($value, [true, false, 0, 1, '0', '1'], true);
867
                break;
868
            case 'number':
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
869
                $result = ctype_digit((string) $value);
870
                break;
871
            case 'alphaNum':
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
872
                $result = ctype_alnum($value);
873
                break;
874
            case 'array':
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
875
                // 是否为数组
876
                $result = is_array($value);
877
                break;
878
            case 'file':
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
879
                $result = $value instanceof File;
880
                break;
881
            case 'image':
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
882
                $result = $value instanceof File && in_array($this->getImageType($value->getRealPath()), [1, 2, 3, 6]);
883
                break;
884
            case 'token':
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
885
                $result = $this->token($value, '__token__', $data);
886
                break;
887
            default:
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 8 spaces, found 12
Loading history...
888
                if (isset($this->type[$rule])) {
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
889
                    // 注册的验证规则
890
                    $result = call_user_func_array($this->type[$rule], [$value]);
891
                } elseif (function_exists('ctype_' . $rule)) {
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
892
                    // ctype验证规则
893
                    $ctypeFun = 'ctype_' . $rule;
894
                    $result   = $ctypeFun($value);
895
                } elseif (isset($this->filter[$rule])) {
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
896
                    // Filter_var验证规则
897
                    $result = $this->filter($value, $this->filter[$rule]);
898
                } else {
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
899
                    // 正则验证
900
                    $result = $this->regex($value, $rule);
901
                }
1 ignored issue
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
902
        }
903
904
        return $result;
905
    }
906
907
    // 判断图像类型
908
    protected function getImageType($image)
0 ignored issues
show
Coding Style introduced by
You must use "/**" style comments for a function comment
Loading history...
909
    {
910
        if (function_exists('exif_imagetype')) {
911
            return exif_imagetype($image);
912
        }
913
914
        try {
915
            $info = getimagesize($image);
916
            return $info ? $info[2] : false;
917
        } catch (\Exception $e) {
918
            return false;
919
        }
920
    }
921
922
    /**
923
     * 验证表单令牌
924
     * @access public
925
     * @param  mixed     $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
926
     * @param  mixed     $rule  验证规则
927
     * @param  array     $data  数据
928
     * @return bool
929
     */
930
    public function token($value, string $rule, array $data): bool
931
    {
932
        $rule = !empty($rule) ? $rule : '__token__';
933
        return $this->request->checkToken($rule, $data);
934
    }
935
936
    /**
937
     * 验证是否为合格的域名或者IP 支持A,MX,NS,SOA,PTR,CNAME,AAAA,A6, SRV,NAPTR,TXT 或者 ANY类型
938
     * @access public
939
     * @param  mixed $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
940
     * @param  mixed $rule  验证规则
941
     * @return bool
942
     */
943
    public function activeUrl(string $value, string $rule = 'MX'): bool
944
    {
945
        if (!in_array($rule, ['A', 'MX', 'NS', 'SOA', 'PTR', 'CNAME', 'AAAA', 'A6', 'SRV', 'NAPTR', 'TXT', 'ANY'])) {
946
            $rule = 'MX';
947
        }
948
949
        return checkdnsrr($value, $rule);
950
    }
951
952
    /**
953
     * 验证是否有效IP
954
     * @access public
955
     * @param  mixed $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
956
     * @param  mixed $rule  验证规则 ipv4 ipv6
957
     * @return bool
958
     */
959
    public function ip($value, string $rule = 'ipv4'): bool
960
    {
961
        if (!in_array($rule, ['ipv4', 'ipv6'])) {
962
            $rule = 'ipv4';
963
        }
964
965
        return $this->filter($value, [FILTER_VALIDATE_IP, 'ipv6' == $rule ? FILTER_FLAG_IPV6 : FILTER_FLAG_IPV4]);
966
    }
967
968
    /**
969
     * 验证上传文件后缀
970
     * @access public
971
     * @param  mixed $file  上传文件
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
972
     * @param  mixed $rule  验证规则
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
973
     * @return bool
974
     */
975
    public function fileExt($file, $rule): bool
976
    {
977
        if (is_array($file)) {
978
            foreach ($file as $item) {
979
                if (!($item instanceof File) || !$item->checkExt($rule)) {
980
                    return false;
981
                }
982
            }
983
            return true;
984
        } elseif ($file instanceof File) {
985
            return $file->checkExt($rule);
986
        }
987
988
        return false;
989
    }
990
991
    /**
992
     * 验证上传文件类型
993
     * @access public
994
     * @param  mixed $file  上传文件
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
995
     * @param  mixed $rule  验证规则
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
996
     * @return bool
997
     */
998
    public function fileMime($file, $rule): bool
999
    {
1000
        if (is_array($file)) {
1001
            foreach ($file as $item) {
1002
                if (!($item instanceof File) || !$item->checkMime($rule)) {
1003
                    return false;
1004
                }
1005
            }
1006
            return true;
1007
        } elseif ($file instanceof File) {
1008
            return $file->checkMime($rule);
1009
        }
1010
1011
        return false;
1012
    }
1013
1014
    /**
1015
     * 验证上传文件大小
1016
     * @access public
1017
     * @param  mixed $file  上传文件
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1018
     * @param  mixed $rule  验证规则
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1019
     * @return bool
1020
     */
1021
    public function fileSize($file, $rule): bool
1022
    {
1023
        if (is_array($file)) {
1024
            foreach ($file as $item) {
1025
                if (!($item instanceof File) || !$item->checkSize($rule)) {
1026
                    return false;
1027
                }
1028
            }
1029
            return true;
1030
        } elseif ($file instanceof File) {
1031
            return $file->checkSize($rule);
1032
        }
1033
1034
        return false;
1035
    }
1036
1037
    /**
1038
     * 验证图片的宽高及类型
1039
     * @access public
1040
     * @param  mixed $file  上传文件
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1041
     * @param  mixed $rule  验证规则
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1042
     * @return bool
1043
     */
1044
    public function image($file, $rule): bool
1045
    {
1046
        if (!($file instanceof File)) {
1047
            return false;
1048
        }
1049
1050
        if ($rule) {
1051
            $rule = explode(',', $rule);
1052
1053
            list($width, $height, $type) = getimagesize($file->getRealPath());
1054
1055
            if (isset($rule[2])) {
1056
                $imageType = strtolower($rule[2]);
1057
1058
                if ('jpeg' == $imageType) {
1059
                    $imageType = 'jpg';
1060
                }
1061
1062
                if (image_type_to_extension($type, false) != $imageType) {
1063
                    return false;
1064
                }
1065
            }
1066
1067
            list($w, $h) = $rule;
1068
1069
            return $w == $width && $h == $height;
1070
        }
1071
1072
        return in_array($this->getImageType($file->getRealPath()), [1, 2, 3, 6]);
1073
    }
1074
1075
    /**
1076
     * 验证时间和日期是否符合指定格式
1077
     * @access public
1078
     * @param  mixed $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1079
     * @param  mixed $rule  验证规则
1080
     * @return bool
1081
     */
1082
    public function dateFormat($value, $rule): bool
1083
    {
1084
        $info = date_parse_from_format($rule, $value);
1085
        return 0 == $info['warning_count'] && 0 == $info['error_count'];
1086
    }
1087
1088
    /**
1089
     * 验证是否唯一
1090
     * @access public
1091
     * @param  mixed  $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1092
     * @param  mixed  $rule  验证规则 格式:数据表,字段名,排除ID,主键名
1093
     * @param  array  $data  数据
1094
     * @param  string $field  验证字段名
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1095
     * @return bool
1096
     */
1097
    public function unique($value, $rule, array $data = [], string $field = ''): bool
1098
    {
1099
        if (is_string($rule)) {
1100
            $rule = explode(',', $rule);
1101
        }
1102
1103
        if (false !== strpos($rule[0], '\\')) {
1104
            // 指定模型类
1105
            $db = new $rule[0];
1106
        } else {
1107
            $db = $this->db->name($rule[0]);
0 ignored issues
show
Bug introduced by
The method name() does not exist on think\Db. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1107
            /** @scrutinizer ignore-call */ 
1108
            $db = $this->db->name($rule[0]);
Loading history...
1108
        }
1109
1110
        $key = $rule[1] ?? $field;
1111
        $map = [];
1112
1113
        if (strpos($key, '^')) {
1114
            // 支持多个字段验证
1115
            $fields = explode('^', $key);
1116
            foreach ($fields as $key) {
1117
                if (isset($data[$key])) {
1118
                    $map[] = [$key, '=', $data[$key]];
1119
                }
1120
            }
1121
        } elseif (isset($data[$field])) {
1122
            $map[] = [$key, '=', $data[$field]];
1123
        } else {
1124
            $map = [];
1125
        }
1126
1127
        $pk = !empty($rule[3]) ? $rule[3] : $db->getPk();
1128
1129
        if (is_string($pk)) {
1130
            if (isset($rule[2])) {
1131
                $map[] = [$pk, '<>', $rule[2]];
1132
            } elseif (isset($data[$pk])) {
1133
                $map[] = [$pk, '<>', $data[$pk]];
1134
            }
1135
        }
1136
1137
        if ($db->where($map)->field($pk)->find()) {
1138
            return false;
1139
        }
1140
1141
        return true;
1142
    }
1143
1144
    /**
1145
     * 使用filter_var方式验证
1146
     * @access public
1147
     * @param  mixed $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1148
     * @param  mixed $rule  验证规则
1149
     * @return bool
1150
     */
1151
    public function filter($value, $rule): bool
1152
    {
1153
        if (is_string($rule) && strpos($rule, ',')) {
1154
            list($rule, $param) = explode(',', $rule);
1155
        } elseif (is_array($rule)) {
1156
            $param = $rule[1] ?? null;
1157
            $rule  = $rule[0];
1158
        } else {
1159
            $param = null;
1160
        }
1161
1162
        return false !== filter_var($value, is_int($rule) ? $rule : filter_id($rule), $param);
1163
    }
1164
1165
    /**
1166
     * 验证某个字段等于某个值的时候必须
1167
     * @access public
1168
     * @param  mixed $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1169
     * @param  mixed $rule  验证规则
1170
     * @param  array $data  数据
1171
     * @return bool
1172
     */
1173
    public function requireIf($value, $rule, array $data = []): bool
1174
    {
1175
        list($field, $val) = explode(',', $rule);
1176
1177
        if ($this->getDataValue($data, $field) == $val) {
1178
            return !empty($value) || '0' == $value;
1179
        }
1180
1181
        return true;
1182
    }
1183
1184
    /**
1185
     * 通过回调方法验证某个字段是否必须
1186
     * @access public
1187
     * @param  mixed $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1188
     * @param  mixed $rule  验证规则
1189
     * @param  array $data  数据
1190
     * @return bool
1191
     */
1192
    public function requireCallback($value, $rule, array $data = []): bool
1193
    {
1194
        $result = call_user_func_array([$this, $rule], [$value, $data]);
1195
1196
        if ($result) {
1197
            return !empty($value) || '0' == $value;
1198
        }
1199
1200
        return true;
1201
    }
1202
1203
    /**
1204
     * 验证某个字段有值的情况下必须
1205
     * @access public
1206
     * @param  mixed $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1207
     * @param  mixed $rule  验证规则
1208
     * @param  array $data  数据
1209
     * @return bool
1210
     */
1211
    public function requireWith($value, $rule, array $data = []): bool
1212
    {
1213
        $val = $this->getDataValue($data, $rule);
1214
1215
        if (!empty($val)) {
1216
            return !empty($value) || '0' == $value;
1217
        }
1218
1219
        return true;
1220
    }
1221
1222
    /**
1223
     * 验证某个字段没有值的情况下必须
1224
     * @access public
1225
     * @param  mixed $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1226
     * @param  mixed $rule  验证规则
1227
     * @param  array $data  数据
1228
     * @return bool
1229
     */
1230
    public function requireWithout($value, $rule, array $data = []): bool
1231
    {
1232
        $val = $this->getDataValue($data, $rule);
1233
1234
        if (empty($val)) {
1235
            return !empty($value) || '0' == $value;
1236
        }
1237
1238
        return true;
1239
    }
1240
1241
    /**
1242
     * 验证是否在范围内
1243
     * @access public
1244
     * @param  mixed $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1245
     * @param  mixed $rule  验证规则
1246
     * @return bool
1247
     */
1248
    public function in($value, $rule): bool
1249
    {
1250
        return in_array($value, is_array($rule) ? $rule : explode(',', $rule));
1251
    }
1252
1253
    /**
1254
     * 验证是否不在某个范围
1255
     * @access public
1256
     * @param  mixed $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1257
     * @param  mixed $rule  验证规则
1258
     * @return bool
1259
     */
1260
    public function notIn($value, $rule): bool
1261
    {
1262
        return !in_array($value, is_array($rule) ? $rule : explode(',', $rule));
1263
    }
1264
1265
    /**
1266
     * between验证数据
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
1267
     * @access public
1268
     * @param  mixed $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1269
     * @param  mixed $rule  验证规则
1270
     * @return bool
1271
     */
1272
    public function between($value, $rule): bool
1273
    {
1274
        if (is_string($rule)) {
1275
            $rule = explode(',', $rule);
1276
        }
1277
        list($min, $max) = $rule;
1278
1279
        return $value >= $min && $value <= $max;
1280
    }
1281
1282
    /**
1283
     * 使用notbetween验证数据
1284
     * @access public
1285
     * @param  mixed $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1286
     * @param  mixed $rule  验证规则
1287
     * @return bool
1288
     */
1289
    public function notBetween($value, $rule): bool
1290
    {
1291
        if (is_string($rule)) {
1292
            $rule = explode(',', $rule);
1293
        }
1294
        list($min, $max) = $rule;
1295
1296
        return $value < $min || $value > $max;
1297
    }
1298
1299
    /**
1300
     * 验证数据长度
1301
     * @access public
1302
     * @param  mixed $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1303
     * @param  mixed $rule  验证规则
1304
     * @return bool
1305
     */
1306
    public function length($value, $rule): bool
1307
    {
1308
        if (is_array($value)) {
1309
            $length = count($value);
1310
        } elseif ($value instanceof File) {
1311
            $length = $value->getSize();
1312
        } else {
1313
            $length = mb_strlen((string) $value);
1314
        }
1315
1316
        if (is_string($rule) && strpos($rule, ',')) {
1317
            // 长度区间
1318
            list($min, $max) = explode(',', $rule);
1319
            return $length >= $min && $length <= $max;
1320
        }
1321
1322
        // 指定长度
1323
        return $length == $rule;
1324
    }
1325
1326
    /**
1327
     * 验证数据最大长度
1328
     * @access public
1329
     * @param  mixed $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1330
     * @param  mixed $rule  验证规则
1331
     * @return bool
1332
     */
1333
    public function max($value, $rule): bool
1334
    {
1335
        if (is_array($value)) {
1336
            $length = count($value);
1337
        } elseif ($value instanceof File) {
1338
            $length = $value->getSize();
1339
        } else {
1340
            $length = mb_strlen((string) $value);
1341
        }
1342
1343
        return $length <= $rule;
1344
    }
1345
1346
    /**
1347
     * 验证数据最小长度
1348
     * @access public
1349
     * @param  mixed $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1350
     * @param  mixed $rule  验证规则
1351
     * @return bool
1352
     */
1353
    public function min($value, $rule): bool
1354
    {
1355
        if (is_array($value)) {
1356
            $length = count($value);
1357
        } elseif ($value instanceof File) {
1358
            $length = $value->getSize();
1359
        } else {
1360
            $length = mb_strlen((string) $value);
1361
        }
1362
1363
        return $length >= $rule;
1364
    }
1365
1366
    /**
1367
     * 验证日期
1368
     * @access public
1369
     * @param  mixed $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1370
     * @param  mixed $rule  验证规则
1371
     * @param  array $data  数据
1372
     * @return bool
1373
     */
1374
    public function after($value, $rule, array $data = []): bool
1375
    {
1376
        return strtotime($value) >= strtotime($rule);
1377
    }
1378
1379
    /**
1380
     * 验证日期
1381
     * @access public
1382
     * @param  mixed $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1383
     * @param  mixed $rule  验证规则
1384
     * @param  array $data  数据
1385
     * @return bool
1386
     */
1387
    public function before($value, $rule, array $data = []): bool
1388
    {
1389
        return strtotime($value) <= strtotime($rule);
1390
    }
1391
1392
    /**
1393
     * 验证日期
1394
     * @access public
1395
     * @param  mixed $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1396
     * @param  mixed $rule  验证规则
1397
     * @param  array $data  数据
1398
     * @return bool
1399
     */
1400
    public function afterWith($value, $rule, array $data = []): bool
1401
    {
1402
        $rule = $this->getDataValue($data, $rule);
1403
        return !is_null($rule) && strtotime($value) >= strtotime($rule);
1404
    }
1405
1406
    /**
1407
     * 验证日期
1408
     * @access public
1409
     * @param  mixed $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1410
     * @param  mixed $rule  验证规则
1411
     * @param  array $data  数据
1412
     * @return bool
1413
     */
1414
    public function beforeWith($value, $rule, array $data = []): bool
1415
    {
1416
        $rule = $this->getDataValue($data, $rule);
1417
        return !is_null($rule) && strtotime($value) <= strtotime($rule);
1418
    }
1419
1420
    /**
1421
     * 验证有效期
1422
     * @access public
1423
     * @param  mixed $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1424
     * @param  mixed $rule  验证规则
1425
     * @return bool
1426
     */
1427
    public function expire($value, $rule): bool
1428
    {
1429
        if (is_string($rule)) {
1430
            $rule = explode(',', $rule);
1431
        }
1432
1433
        list($start, $end) = $rule;
1434
1435
        if (!is_numeric($start)) {
1436
            $start = strtotime($start);
1437
        }
1438
1439
        if (!is_numeric($end)) {
1440
            $end = strtotime($end);
1441
        }
1442
1443
        return time() >= $start && time() <= $end;
1444
    }
1445
1446
    /**
1447
     * 验证IP许可
1448
     * @access public
1449
     * @param  mixed $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1450
     * @param  mixed $rule  验证规则
1451
     * @return bool
1452
     */
1453
    public function allowIp($value, $rule): bool
1454
    {
1455
        return in_array($value, is_array($rule) ? $rule : explode(',', $rule));
1456
    }
1457
1458
    /**
1459
     * 验证IP禁用
1460
     * @access public
1461
     * @param  mixed $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1462
     * @param  mixed $rule  验证规则
1463
     * @return bool
1464
     */
1465
    public function denyIp($value, $rule): bool
1466
    {
1467
        return !in_array($value, is_array($rule) ? $rule : explode(',', $rule));
1468
    }
1469
1470
    /**
1471
     * 使用正则验证数据
1472
     * @access public
1473
     * @param  mixed $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1474
     * @param  mixed $rule  验证规则 正则规则或者预定义正则名
1475
     * @return bool
1476
     */
1477
    public function regex($value, $rule): bool
1478
    {
1479
        if (isset($this->regex[$rule])) {
1480
            $rule = $this->regex[$rule];
1481
        } elseif (isset($this->defaultRegex[$rule])) {
1482
            $rule = $this->defaultRegex[$rule];
1483
        }
1484
1485
        if (is_string($rule) && 0 !== strpos($rule, '/') && !preg_match('/\/[imsU]{0,4}$/', $rule)) {
1486
            // 不是正则表达式则两端补上/
1487
            $rule = '/^' . $rule . '$/';
1488
        }
1489
1490
        return is_scalar($value) && 1 === preg_match($rule, (string) $value);
1491
    }
1492
1493
    // 获取错误信息
1494
    public function getError()
0 ignored issues
show
Coding Style introduced by
You must use "/**" style comments for a function comment
Loading history...
1495
    {
1496
        return $this->error;
1497
    }
1498
1499
    /**
1500
     * 获取数据值
1501
     * @access protected
1502
     * @param  array  $data  数据
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1503
     * @param  string $key  数据标识 支持二维
1504
     * @return mixed
1505
     */
1506
    protected function getDataValue(array $data, $key)
1507
    {
1508
        if (is_numeric($key)) {
1509
            $value = $key;
1510
        } elseif (is_string($key) && strpos($key, '.')) {
1511
            // 支持多维数组验证
1512
            foreach (explode('.', $key) as $key) {
0 ignored issues
show
introduced by
$key is overwriting one of the parameters of this function.
Loading history...
1513
                if (!isset($data[$key])) {
1514
                    $value = null;
1515
                    break;
1516
                }
1517
                $value = $data = $data[$key];
1518
            }
1519
        } else {
1520
            $value = $data[$key] ?? null;
1521
        }
1522
1523
        return $value;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $value does not seem to be defined for all execution paths leading up to this point.
Loading history...
1524
    }
1525
1526
    /**
1527
     * 获取验证规则的错误提示信息
1528
     * @access protected
1529
     * @param  string $attribute  字段英文名
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1530
     * @param  string $title  字段描述名
0 ignored issues
show
Coding Style introduced by
Expected 5 spaces after parameter name; 2 found
Loading history...
1531
     * @param  string $type  验证规则名称
0 ignored issues
show
Coding Style introduced by
Expected 6 spaces after parameter name; 2 found
Loading history...
1532
     * @param  mixed  $rule  验证规则数据
0 ignored issues
show
Coding Style introduced by
Expected 6 spaces after parameter name; 2 found
Loading history...
1533
     * @return string
1534
     */
1535
    protected function getRuleMsg(string $attribute, string $title, string $type, $rule): string
1536
    {
1537
        if (isset($this->message[$attribute . '.' . $type])) {
1538
            $msg = $this->message[$attribute . '.' . $type];
1539
        } elseif (isset($this->message[$attribute][$type])) {
1540
            $msg = $this->message[$attribute][$type];
1541
        } elseif (isset($this->message[$attribute])) {
1542
            $msg = $this->message[$attribute];
1543
        } elseif (isset($this->typeMsg[$type])) {
1544
            $msg = $this->typeMsg[$type];
1545
        } elseif (0 === strpos($type, 'require')) {
1546
            $msg = $this->typeMsg['require'];
1547
        } else {
1548
            $msg = $title . $this->lang->get('not conform to the rules');
1549
        }
1550
1551
        if (!is_string($msg)) {
1552
            return $msg;
1553
        }
1554
1555
        if (0 === strpos($msg, '{%')) {
1556
            $msg = $this->lang->get(substr($msg, 2, -1));
1557
        } elseif ($this->lang->has($msg)) {
1558
            $msg = $this->lang->get($msg);
1559
        }
1560
1561
        if (is_scalar($rule) && false !== strpos($msg, ':')) {
1562
            // 变量替换
1563
            if (is_string($rule) && strpos($rule, ',')) {
1564
                $array = array_pad(explode(',', $rule), 3, '');
1565
            } else {
1566
                $array = array_pad([], 3, '');
1567
            }
1568
1569
            $msg = str_replace(
1570
                [':attribute', ':1', ':2', ':3'],
1571
                [$title, $array[0], $array[1], $array[2]],
1572
                $msg);
0 ignored issues
show
Coding Style introduced by
This line of the multi-line function call does not seem to be indented correctly. Expected 12 spaces, but found 16.
Loading history...
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
1573
1574
            if (strpos($msg, ':rule')) {
1575
                $msg = str_replace(':rule', (string) $rule, $msg);
1576
            }
1577
        }
1578
1579
        return $msg;
1580
    }
1581
1582
    /**
1583
     * 获取数据验证的场景
1584
     * @access protected
1585
     * @param  string $scene  验证场景
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1586
     * @return void
1587
     */
1588
    protected function getScene(string $scene): void
1589
    {
1590
        $this->only = $this->append = $this->remove = [];
1591
1592
        if (method_exists($this, 'scene' . $scene)) {
1593
            call_user_func([$this, 'scene' . $scene]);
1594
        } elseif (isset($this->scene[$scene])) {
1595
            // 如果设置了验证适用场景
1596
            $this->only = $this->scene[$scene];
1597
        }
1598
    }
1599
1600
    /**
1601
     * 动态方法 直接调用is方法进行验证
1602
     * @access public
1603
     * @param  string $method  方法名
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1604
     * @param  array $args  调用参数
0 ignored issues
show
Coding Style introduced by
Expected 3 spaces after parameter name; 2 found
Loading history...
1605
     * @return bool
1606
     */
1607
    public function __call($method, $args)
1608
    {
1609
        if ('is' == strtolower(substr($method, 0, 2))) {
1610
            $method = substr($method, 2);
1611
        }
1612
1613
        array_push($args, lcfirst($method));
1614
1615
        return call_user_func_array([$this, 'is'], $args);
1616
    }
1617
}
1618