33// +----------------------------------------------------------------------
44// | ThinkPHP [ WE CAN DO IT JUST THINK ]
55// +----------------------------------------------------------------------
6- // | Copyright (c) 2006~2023 http://thinkphp.cn All rights reserved.
6+ // | Copyright (c) 2006~2025 http://thinkphp.cn All rights reserved.
77// +----------------------------------------------------------------------
88// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
99// +----------------------------------------------------------------------
@@ -241,6 +241,24 @@ class Validate
241241 */
242242 protected $ regex = [];
243243
244+ /**
245+ * Db对象
246+ * @var Db
247+ */
248+ protected $ db ;
249+
250+ /**
251+ * 语言对象
252+ * @var Lang
253+ */
254+ protected $ lang ;
255+
256+ /**
257+ * 请求对象
258+ * @var Request
259+ */
260+ protected $ request ;
261+
244262 /**
245263 * @var Closure[]
246264 */
@@ -270,6 +288,39 @@ public static function maker(Closure $maker)
270288 static ::$ maker [] = $ maker ;
271289 }
272290
291+ /**
292+ * 设置Lang对象
293+ * @access public
294+ * @param Lang $lang Lang对象
295+ * @return void
296+ */
297+ public function setLang ($ lang )
298+ {
299+ $ this ->lang = $ lang ;
300+ }
301+
302+ /**
303+ * 设置Db对象
304+ * @access public
305+ * @param Db $db Db对象
306+ * @return void
307+ */
308+ public function setDb ($ db )
309+ {
310+ $ this ->db = $ db ;
311+ }
312+
313+ /**
314+ * 设置Request对象
315+ * @access public
316+ * @param Request $request Request对象
317+ * @return void
318+ */
319+ public function setRequest ($ request )
320+ {
321+ $ this ->request = $ request ;
322+ }
323+
273324 /**
274325 * 添加字段验证规则
275326 * @access protected
@@ -591,7 +642,7 @@ public function check(array $data, array | string $rules = []): bool
591642 $ rules = $ this ->getGroupRules ($ rules );
592643 // 分组独立检测
593644 if ($ rules instanceof Closure) {
594- return $ rules (new self )
645+ return $ rules (new self () )
595646 ->alias ($ this ->alias )
596647 ->batch ($ this ->batch )
597648 ->failException ($ this ->failException )
@@ -600,13 +651,13 @@ public function check(array $data, array | string $rules = []): bool
600651 }
601652
602653 if ($ rules instanceof Validate) {
603- $ rules = $ rules ->getRules ();
654+ $ rules = $ rules ->getRules ();
604655 }
605656
606657 if ($ this ->currentScene ) {
607658 $ this ->getScene ($ this ->currentScene );
608659 }
609-
660+
610661 foreach ($ this ->append as $ key => $ rule ) {
611662 if (!isset ($ rules [$ key ])) {
612663 $ rules [$ key ] = $ rule ;
@@ -647,8 +698,8 @@ public function check(array $data, array | string $rules = []): bool
647698 /**
648699 * 验证字段规则
649700 * @access protected
650- * @param string $field 字段名
651- * @param mixed $rule 验证规则
701+ * @param string $key 字段名
702+ * @param mixed $rule 验证规则
652703 * @param array $data 数据
653704 * @param string $title 字段描述
654705 * @return bool
@@ -664,7 +715,7 @@ protected function checkItems($key, $rule, $data, $title): bool
664715 $ items = $ rule ->getRules ();
665716 if ($ items instanceof Closure) {
666717 // 获取验证集的规则
667- $ items = $ items (new self )->getRule ();
718+ $ items = $ items (new self () )->getRule ();
668719 }
669720 // 验证集的错误信息
670721 foreach ($ rule ->getMessage () as $ name => $ message ) {
@@ -833,7 +884,7 @@ protected function checkItem(string $field, $value, $rules, $data, string $title
833884 continue ;
834885 }
835886
836- if ('must ' == $ type || str_starts_with ($ type , 'require ' ) || in_array ($ type , $ this ->must ) || (!is_null ($ value ) && '' !== $ value )) {
887+ if ('must ' == $ type || str_starts_with ($ type , 'require ' ) || in_array ($ field , $ this ->must ) || (!is_null ($ value ) && '' !== $ value )) {
837888 $ result = call_user_func_array ($ callback , [$ value , $ rule , $ data , $ field , $ title ]);
838889 } else {
839890 $ result = true ;
@@ -844,6 +895,9 @@ protected function checkItem(string $field, $value, $rules, $data, string $title
844895 // 验证失败 返回错误信息
845896 if (!empty ($ msg [$ i ])) {
846897 $ message = $ msg [$ i ];
898+ if (is_string ($ message ) && str_starts_with ($ message , '{% ' )) {
899+ $ message = $ this ->lang ->get (substr ($ message , 2 , -1 ));
900+ }
847901 } else {
848902 $ message = $ this ->getRuleMsg ($ field , $ title , $ type , $ rule );
849903 }
@@ -1092,6 +1146,23 @@ protected function getImageType($image)
10921146 }
10931147 }
10941148
1149+ /**
1150+ * 验证表单令牌
1151+ * @access public
1152+ * @param mixed $value 字段值
1153+ * @param mixed $rule 验证规则
1154+ * @param array $data 数据
1155+ * @return bool
1156+ */
1157+ public function token ($ value , string $ rule , array $ data ): bool
1158+ {
1159+ if ($ this ->request ) {
1160+ $ rule = !empty ($ rule ) ? $ rule : '__token__ ' ;
1161+ return $ this ->request ->checkToken ($ rule , $ data );
1162+ }
1163+ return true ;
1164+ }
1165+
10951166 /**
10961167 * 验证是否为合格的域名或者IP 支持A,MX,NS,SOA,PTR,CNAME,AAAA,A6, SRV,NAPTR,TXT 或者 ANY类型
10971168 * @access public
@@ -1321,9 +1392,76 @@ public function image($file, $rule): bool
13211392 public function dateFormat ($ value , $ rule ): bool
13221393 {
13231394 $ info = date_parse_from_format ($ rule , $ value );
1395+ if (strlen ((string ) $ info ['year ' ]) != 4 && strpos ($ rule , 'Y ' ) !== false ) {
1396+ return false ;
1397+ }
13241398 return 0 == $ info ['warning_count ' ] && 0 == $ info ['error_count ' ];
13251399 }
13261400
1401+ /**
1402+ * 验证是否唯一
1403+ * @access public
1404+ * @param mixed $value 字段值
1405+ * @param mixed $rule 验证规则 格式:数据表,字段名,排除ID,主键名
1406+ * @param array $data 数据
1407+ * @param string $field 验证字段名
1408+ * @return bool
1409+ */
1410+ public function unique ($ value , $ rule , array $ data = [], string $ field = '' ): bool
1411+ {
1412+ if (!$ this ->db ) {
1413+ return true ;
1414+ }
1415+
1416+ if (is_string ($ rule )) {
1417+ $ rule = explode (', ' , $ rule );
1418+ }
1419+
1420+ if (str_contains ($ rule [0 ], '\\' )) {
1421+ // 指定模型类
1422+ $ db = new $ rule [0 ]();
1423+ } else {
1424+ $ db = $ this ->db ->name ($ rule [0 ]);
1425+ }
1426+
1427+ $ key = $ rule [1 ] ?? $ field ;
1428+ $ map = [];
1429+
1430+ if (str_contains ($ key , '^ ' )) {
1431+ // 支持多个字段验证
1432+ $ fields = explode ('^ ' , $ key );
1433+ foreach ($ fields as $ key ) {
1434+ if (isset ($ data [$ key ])) {
1435+ $ map [] = [$ key , '= ' , $ data [$ key ]];
1436+ }
1437+ }
1438+ } elseif (strpos ($ key , '= ' )) {
1439+ // 支持复杂验证
1440+ parse_str ($ key , $ array );
1441+ foreach ($ array as $ k => $ val ) {
1442+ $ map [] = [$ k , '= ' , $ data [$ k ] ?? $ val ];
1443+ }
1444+ } elseif (isset ($ data [$ field ])) {
1445+ $ map [] = [$ key , '= ' , $ data [$ field ]];
1446+ }
1447+
1448+ $ pk = !empty ($ rule [3 ]) ? $ rule [3 ] : $ db ->getPk ();
1449+
1450+ if (is_string ($ pk )) {
1451+ if (isset ($ rule [2 ])) {
1452+ $ map [] = [$ pk , '<> ' , $ rule [2 ]];
1453+ } elseif (isset ($ data [$ pk ])) {
1454+ $ map [] = [$ pk , '<> ' , $ data [$ pk ]];
1455+ }
1456+ }
1457+
1458+ if ($ db ->where ($ map )->field ($ pk )->find ()) {
1459+ return false ;
1460+ }
1461+
1462+ return true ;
1463+ }
1464+
13271465 /**
13281466 * 使用filter_var方式验证
13291467 * @access public
@@ -1760,7 +1898,7 @@ public function regex($value, $rule): bool
17601898 * 获取内置正则验证规则
17611899 * @access public
17621900 * @param string $rule 验证规则 正则规则或者预定义正则名
1763- * @return bool
1901+ * @return string
17641902 */
17651903 protected function getDefaultRegexRule (string $ rule ): string
17661904 {
@@ -1878,7 +2016,7 @@ protected function getRuleMsg(string $attribute, string $title, string $type, $r
18782016 } elseif (str_starts_with ($ type , 'require ' )) {
18792017 $ msg = $ this ->typeMsg ['require ' ];
18802018 } else {
1881- $ msg = $ title . ' 规则不符 ' ;
2019+ $ msg = $ title . ( $ this -> lang ? $ this -> lang -> get ( ' not conform to the rules ' ) : ' 规则不符 ') ;
18822020 }
18832021
18842022 if (is_array ($ msg )) {
@@ -1898,6 +2036,14 @@ protected function getRuleMsg(string $attribute, string $title, string $type, $r
18982036 */
18992037 protected function parseErrorMsg (string $ msg , $ rule , string $ title )
19002038 {
2039+ if ($ this ->lang ) {
2040+ if (str_starts_with ($ msg , '{% ' )) {
2041+ $ msg = $ this ->lang ->get (substr ($ msg , 2 , -1 ));
2042+ } elseif ($ this ->lang ->has ($ msg )) {
2043+ $ msg = $ this ->lang ->get ($ msg );
2044+ }
2045+ }
2046+
19012047 if (is_array ($ msg )) {
19022048 return $ this ->errorMsgIsArray ($ msg , $ rule , $ title );
19032049 }
@@ -1974,10 +2120,10 @@ protected function getGroupRules(string $group)
19742120 {
19752121 $ method = 'rules ' . Str::studly ($ group );
19762122 if (method_exists ($ this , $ method )) {
1977- $ validate = call_user_func_array ([$ this , $ method ], [new self ]);
2123+ $ validate = call_user_func_array ([$ this , $ method ], [new self () ]);
19782124 return $ validate ->alias ($ this ->alias )
1979- ->batch ($ this ->batch )
1980- ->failException ($ this ->failException );
2125+ ->batch ($ this ->batch )
2126+ ->failException ($ this ->failException );
19812127 }
19822128 return $ this ->group [$ group ] ?? [];
19832129 }
0 commit comments