Completed
Push — 6.0 ( fa435c...32cf92 )
by liu
02:57
created

Validate   F

Complexity

Total Complexity 242

Size/Duplication

Total Lines 1489
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
eloc 515
dl 0
loc 1489
ccs 0
cts 463
cp 0
rs 2
c 0
b 0
f 0
wmc 242

60 Methods

Rating   Name   Duplication   Size   Complexity  
A getValidateType() 0 24 5
A different() 0 3 1
A hasScene() 0 3 2
A append() 0 15 4
A __make() 0 7 1
A elt() 0 3 1
A confirm() 0 11 3
A setTypeMsg() 0 6 2
A setDb() 0 3 1
A only() 0 5 1
A failException() 0 5 1
A extend() 0 9 2
A setLang() 0 3 1
B checkRule() 0 32 8
A scene() 0 6 1
A must() 0 3 2
F check() 0 72 18
A egt() 0 3 1
A message() 0 9 2
A remove() 0 19 5
A lt() 0 3 1
F checkItem() 0 71 27
A eq() 0 3 1
A gt() 0 3 1
A rule() 0 12 3
A batch() 0 5 1
A getScene() 0 9 3
A __call() 0 9 2
A notBetween() 0 8 3
A notIn() 0 3 2
A after() 0 3 1
A requireIf() 0 9 3
A ip() 0 7 3
A activeUrl() 0 7 2
A in() 0 3 2
C is() 0 58 17
A allowIp() 0 3 2
A requireCallback() 0 9 3
A expire() 0 17 5
A beforeWith() 0 4 2
A min() 0 11 3
A before() 0 3 1
A fileSize() 0 14 6
B image() 0 29 7
A between() 0 8 3
A fileMime() 0 14 6
C getRuleMsg() 0 45 14
A length() 0 18 5
A filter() 0 12 5
A regex() 0 14 6
A fileExt() 0 14 6
A getImageType() 0 11 4
A requireWith() 0 9 3
C unique() 0 45 12
A getError() 0 3 1
A afterWith() 0 4 2
A max() 0 11 3
A getDataValue() 0 18 5
A denyIp() 0 3 2
A dateFormat() 0 4 2

How to fix   Complexity   

Complex Class

Complex classes like Validate often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Validate, and based on these observations, apply Extract Interface, too.

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

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

1017
            /** @scrutinizer ignore-call */ 
1018
            $db = Db::name($rule[0]);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1018
        }
1019
1020
        $key = $rule[1] ?? $field;
1021
        $map = [];
1022
1023
        if (strpos($key, '^')) {
1024
            // 支持多个字段验证
1025
            $fields = explode('^', $key);
1026
            foreach ($fields as $key) {
1027
                if (isset($data[$key])) {
1028
                    $map[] = [$key, '=', $data[$key]];
1029
                }
1030
            }
1031
        } elseif (isset($data[$field])) {
1032
            $map[] = [$key, '=', $data[$field]];
1033
        } else {
1034
            $map = [];
1035
        }
1036
1037
        $pk = !empty($rule[3]) ? $rule[3] : $db->getPk();
1038
1039
        if (is_string($pk)) {
1040
            if (isset($rule[2])) {
1041
                $map[] = [$pk, '<>', $rule[2]];
1042
            } elseif (isset($data[$pk])) {
1043
                $map[] = [$pk, '<>', $data[$pk]];
1044
            }
1045
        }
1046
1047
        if ($db->where($map)->field($pk)->find()) {
1048
            return false;
1049
        }
1050
1051
        return true;
1052
    }
1053
1054
    /**
1055
     * 使用filter_var方式验证
1056
     * @access public
1057
     * @param  mixed     $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1058
     * @param  mixed     $rule  验证规则
1059
     * @return bool
1060
     */
1061
    public function filter($value, $rule): bool
1062
    {
1063
        if (is_string($rule) && strpos($rule, ',')) {
1064
            list($rule, $param) = explode(',', $rule);
1065
        } elseif (is_array($rule)) {
1066
            $param = $rule[1] ?? null;
1067
            $rule  = $rule[0];
1068
        } else {
1069
            $param = null;
1070
        }
1071
1072
        return false !== filter_var($value, is_int($rule) ? $rule : filter_id($rule), $param);
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
     * @param  array     $data  数据
1081
     * @return bool
1082
     */
1083
    public function requireIf($value, $rule, array $data = []): bool
1084
    {
1085
        list($field, $val) = explode(',', $rule);
1086
1087
        if ($this->getDataValue($data, $field) == $val) {
1088
            return !empty($value) || '0' == $value;
1089
        }
1090
1091
        return true;
1092
    }
1093
1094
    /**
1095
     * 通过回调方法验证某个字段是否必须
1096
     * @access public
1097
     * @param  mixed     $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1098
     * @param  mixed     $rule  验证规则
1099
     * @param  array     $data  数据
1100
     * @return bool
1101
     */
1102
    public function requireCallback($value, $rule, array $data = []): bool
1103
    {
1104
        $result = call_user_func_array([$this, $rule], [$value, $data]);
1105
1106
        if ($result) {
1107
            return !empty($value) || '0' == $value;
1108
        }
1109
1110
        return true;
1111
    }
1112
1113
    /**
1114
     * 验证某个字段有值的情况下必须
1115
     * @access public
1116
     * @param  mixed     $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1117
     * @param  mixed     $rule  验证规则
1118
     * @param  array     $data  数据
1119
     * @return bool
1120
     */
1121
    public function requireWith($value, $rule, array $data = []): bool
1122
    {
1123
        $val = $this->getDataValue($data, $rule);
1124
1125
        if (!empty($val)) {
1126
            return !empty($value) || '0' == $value;
1127
        }
1128
1129
        return true;
1130
    }
1131
1132
    /**
1133
     * 验证是否在范围内
1134
     * @access public
1135
     * @param  mixed     $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1136
     * @param  mixed     $rule  验证规则
1137
     * @return bool
1138
     */
1139
    public function in($value, $rule): bool
1140
    {
1141
        return in_array($value, is_array($rule) ? $rule : explode(',', $rule));
1142
    }
1143
1144
    /**
1145
     * 验证是否不在某个范围
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 notIn($value, $rule): bool
1152
    {
1153
        return !in_array($value, is_array($rule) ? $rule : explode(',', $rule));
1154
    }
1155
1156
    /**
1157
     * between验证数据
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
1158
     * @access public
1159
     * @param  mixed     $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1160
     * @param  mixed     $rule  验证规则
1161
     * @return bool
1162
     */
1163
    public function between($value, $rule): bool
1164
    {
1165
        if (is_string($rule)) {
1166
            $rule = explode(',', $rule);
1167
        }
1168
        list($min, $max) = $rule;
1169
1170
        return $value >= $min && $value <= $max;
1171
    }
1172
1173
    /**
1174
     * 使用notbetween验证数据
1175
     * @access public
1176
     * @param  mixed     $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1177
     * @param  mixed     $rule  验证规则
1178
     * @return bool
1179
     */
1180
    public function notBetween($value, $rule): bool
1181
    {
1182
        if (is_string($rule)) {
1183
            $rule = explode(',', $rule);
1184
        }
1185
        list($min, $max) = $rule;
1186
1187
        return $value < $min || $value > $max;
1188
    }
1189
1190
    /**
1191
     * 验证数据长度
1192
     * @access public
1193
     * @param  mixed     $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1194
     * @param  mixed     $rule  验证规则
1195
     * @return bool
1196
     */
1197
    public function length($value, $rule): bool
1198
    {
1199
        if (is_array($value)) {
1200
            $length = count($value);
1201
        } elseif ($value instanceof File) {
1202
            $length = $value->getSize();
1203
        } else {
1204
            $length = mb_strlen((string) $value);
1205
        }
1206
1207
        if (strpos($rule, ',')) {
1208
            // 长度区间
1209
            list($min, $max) = explode(',', $rule);
1210
            return $length >= $min && $length <= $max;
1211
        }
1212
1213
        // 指定长度
1214
        return $length == $rule;
1215
    }
1216
1217
    /**
1218
     * 验证数据最大长度
1219
     * @access public
1220
     * @param  mixed     $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1221
     * @param  mixed     $rule  验证规则
1222
     * @return bool
1223
     */
1224
    public function max($value, $rule): bool
1225
    {
1226
        if (is_array($value)) {
1227
            $length = count($value);
1228
        } elseif ($value instanceof File) {
1229
            $length = $value->getSize();
1230
        } else {
1231
            $length = mb_strlen((string) $value);
1232
        }
1233
1234
        return $length <= $rule;
1235
    }
1236
1237
    /**
1238
     * 验证数据最小长度
1239
     * @access public
1240
     * @param  mixed     $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1241
     * @param  mixed     $rule  验证规则
1242
     * @return bool
1243
     */
1244
    public function min($value, $rule): bool
1245
    {
1246
        if (is_array($value)) {
1247
            $length = count($value);
1248
        } elseif ($value instanceof File) {
1249
            $length = $value->getSize();
1250
        } else {
1251
            $length = mb_strlen((string) $value);
1252
        }
1253
1254
        return $length >= $rule;
1255
    }
1256
1257
    /**
1258
     * 验证日期
1259
     * @access public
1260
     * @param  mixed     $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1261
     * @param  mixed     $rule  验证规则
1262
     * @param  array     $data  数据
1263
     * @return bool
1264
     */
1265
    public function after($value, $rule, array $data = []): bool
1266
    {
1267
        return strtotime($value) >= strtotime($rule);
1268
    }
1269
1270
    /**
1271
     * 验证日期
1272
     * @access public
1273
     * @param  mixed     $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1274
     * @param  mixed     $rule  验证规则
1275
     * @param  array     $data  数据
1276
     * @return bool
1277
     */
1278
    public function before($value, $rule, array $data = []): bool
1279
    {
1280
        return strtotime($value) <= strtotime($rule);
1281
    }
1282
1283
    /**
1284
     * 验证日期
1285
     * @access public
1286
     * @param  mixed     $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1287
     * @param  mixed     $rule  验证规则
1288
     * @param  array     $data  数据
1289
     * @return bool
1290
     */
1291
    public function afterWith($value, $rule, array $data = []): bool
1292
    {
1293
        $rule = $this->getDataValue($data, $rule);
1294
        return !is_null($rule) && strtotime($value) >= strtotime($rule);
1295
    }
1296
1297
    /**
1298
     * 验证日期
1299
     * @access public
1300
     * @param  mixed     $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1301
     * @param  mixed     $rule  验证规则
1302
     * @param  array     $data  数据
1303
     * @return bool
1304
     */
1305
    public function beforeWith($value, $rule, array $data = []): bool
1306
    {
1307
        $rule = $this->getDataValue($data, $rule);
1308
        return !is_null($rule) && strtotime($value) <= strtotime($rule);
1309
    }
1310
1311
    /**
1312
     * 验证有效期
1313
     * @access public
1314
     * @param  mixed     $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1315
     * @param  mixed     $rule  验证规则
1316
     * @return bool
1317
     */
1318
    public function expire($value, $rule): bool
1319
    {
1320
        if (is_string($rule)) {
1321
            $rule = explode(',', $rule);
1322
        }
1323
1324
        list($start, $end) = $rule;
1325
1326
        if (!is_numeric($start)) {
1327
            $start = strtotime($start);
1328
        }
1329
1330
        if (!is_numeric($end)) {
1331
            $end = strtotime($end);
1332
        }
1333
1334
        return $_SERVER['REQUEST_TIME'] >= $start && $_SERVER['REQUEST_TIME'] <= $end;
1335
    }
1336
1337
    /**
1338
     * 验证IP许可
1339
     * @access public
1340
     * @param  string    $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1341
     * @param  mixed     $rule  验证规则
1342
     * @return bool
1343
     */
1344
    public function allowIp($value, $rule): bool
1345
    {
1346
        return in_array($value, is_array($rule) ? $rule : explode(',', $rule));
1347
    }
1348
1349
    /**
1350
     * 验证IP禁用
1351
     * @access public
1352
     * @param  string    $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1353
     * @param  mixed     $rule  验证规则
1354
     * @return bool
1355
     */
1356
    public function denyIp($value, $rule): bool
1357
    {
1358
        return !in_array($value, is_array($rule) ? $rule : explode(',', $rule));
1359
    }
1360
1361
    /**
1362
     * 使用正则验证数据
1363
     * @access public
1364
     * @param  mixed     $value  字段值
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1365
     * @param  mixed     $rule  验证规则 正则规则或者预定义正则名
1366
     * @return bool
1367
     */
1368
    public function regex($value, $rule): bool
1369
    {
1370
        if (isset($this->regex[$rule])) {
1371
            $rule = $this->regex[$rule];
1372
        } elseif (isset($this->defaultRegex[$rule])) {
1373
            $rule = $this->defaultRegex[$rule];
1374
        }
1375
1376
        if (0 !== strpos($rule, '/') && !preg_match('/\/[imsU]{0,4}$/', $rule)) {
1377
            // 不是正则表达式则两端补上/
1378
            $rule = '/^' . $rule . '$/';
1379
        }
1380
1381
        return is_scalar($value) && 1 === preg_match($rule, (string) $value);
1382
    }
1383
1384
    // 获取错误信息
1385
    public function getError()
0 ignored issues
show
Coding Style introduced by
You must use "/**" style comments for a function comment
Loading history...
1386
    {
1387
        return $this->error;
1388
    }
1389
1390
    /**
1391
     * 获取数据值
1392
     * @access protected
1393
     * @param  array     $data  数据
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1394
     * @param  string    $key  数据标识 支持二维
1395
     * @return mixed
1396
     */
1397
    protected function getDataValue(array $data, $key)
1398
    {
1399
        if (is_numeric($key)) {
1400
            $value = $key;
1401
        } elseif (strpos($key, '.')) {
1402
            // 支持多维数组验证
1403
            foreach (explode('.', $key) as $key) {
0 ignored issues
show
introduced by
$key is overwriting one of the parameters of this function.
Loading history...
1404
                if (!isset($data[$key])) {
1405
                    $value = null;
1406
                    break;
1407
                }
1408
                $value = $data = $data[$key];
1409
            }
1410
        } else {
1411
            $value = $data[$key] ?? null;
1412
        }
1413
1414
        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...
1415
    }
1416
1417
    /**
1418
     * 获取验证规则的错误提示信息
1419
     * @access protected
1420
     * @param  string    $attribute  字段英文名
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1421
     * @param  string    $title  字段描述名
0 ignored issues
show
Coding Style introduced by
Expected 5 spaces after parameter name; 2 found
Loading history...
1422
     * @param  string    $type  验证规则名称
0 ignored issues
show
Coding Style introduced by
Expected 6 spaces after parameter name; 2 found
Loading history...
1423
     * @param  mixed     $rule  验证规则数据
0 ignored issues
show
Coding Style introduced by
Expected 6 spaces after parameter name; 2 found
Loading history...
1424
     * @return string
1425
     */
1426
    protected function getRuleMsg(string $attribute, string $title, string $type, $rule): string
1427
    {
1428
        if (isset($this->message[$attribute . '.' . $type])) {
1429
            $msg = $this->message[$attribute . '.' . $type];
1430
        } elseif (isset($this->message[$attribute][$type])) {
1431
            $msg = $this->message[$attribute][$type];
1432
        } elseif (isset($this->message[$attribute])) {
1433
            $msg = $this->message[$attribute];
1434
        } elseif (isset($this->typeMsg[$type])) {
1435
            $msg = $this->typeMsg[$type];
1436
        } elseif (0 === strpos($type, 'require')) {
1437
            $msg = $this->typeMsg['require'];
1438
        } else {
1439
            $msg = $title . $this->lang->get('not conform to the rules');
1440
        }
1441
1442
        if (!is_string($msg)) {
1443
            return $msg;
1444
        }
1445
1446
        if (0 === strpos($msg, '{%')) {
1447
            $msg = $this->lang->get(substr($msg, 2, -1));
1448
        } elseif ($this->lang->has($msg)) {
1449
            $msg = $this->lang->get($msg);
1450
        }
1451
1452
        if (is_scalar($rule) && false !== strpos($msg, ':')) {
1453
            // 变量替换
1454
            if (is_string($rule) && strpos($rule, ',')) {
1455
                $array = array_pad(explode(',', $rule), 3, '');
1456
            } else {
1457
                $array = array_pad([], 3, '');
1458
            }
1459
1460
            $msg = str_replace(
1461
                [':attribute', ':1', ':2', ':3'],
1462
                [$title, $array[0], $array[1], $array[2]],
1463
                $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...
1464
1465
            if (strpos($msg, ':rule')) {
1466
                $msg = str_replace(':rule', (string) $rule, $msg);
1467
            }
1468
        }
1469
1470
        return $msg;
1471
    }
1472
1473
    /**
1474
     * 获取数据验证的场景
1475
     * @access protected
1476
     * @param  string $scene  验证场景
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1477
     * @return void
1478
     */
1479
    protected function getScene(string $scene): void
1480
    {
1481
        $this->only = $this->append = $this->remove = [];
1482
1483
        if (method_exists($this, 'scene' . $scene)) {
1484
            call_user_func([$this, 'scene' . $scene]);
1485
        } elseif (isset($this->scene[$scene])) {
1486
            // 如果设置了验证适用场景
1487
            $this->only = $this->scene[$scene];
1488
        }
1489
    }
1490
1491
    /**
1492
     * 动态方法 直接调用is方法进行验证
1493
     * @access public
1494
     * @param  string $method  方法名
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after parameter name; 2 found
Loading history...
1495
     * @param  array $args  调用参数
0 ignored issues
show
Coding Style introduced by
Expected 3 spaces after parameter name; 2 found
Loading history...
1496
     * @return bool
1497
     */
1498
    public function __call($method, $args)
1499
    {
1500
        if ('is' == strtolower(substr($method, 0, 2))) {
1501
            $method = substr($method, 2);
1502
        }
1503
1504
        array_push($args, lcfirst($method));
1505
1506
        return call_user_func_array([$this, 'is'], $args);
1507
    }
1508
}
1509