StartMVC开发手册

可以快速上手的开发文档

手册目录

数据验证类

市面上的框架基本都带数据验证功能但基本都只能验证一维数据,现在的接口开发都是基于Restful结构化JSON数据(多维数据),我们这个数据验证支持无限级对象数据验证。

加载验证类

use startmvc\core\Validator;// 引入Validator 类

验证单个数据

Validator内置了很多静态方法可以直接调用

var_dump(Validator::isMobile('12345678901'));
//bool(false)

过滤数据

var_dump(Validator::filterUtf8('Kiss ???? me'));//过滤三字节以上的字符
//string(8) "Kiss me"

常规的数据验证

$data = [
 'username' => 'startmvc',
 'passwd' => 'abc123',
 'age' => 25
];
$rule = [
 'username' => 'required|is_alpha_num|minlen:6',
 'passwd' => 'required|minlen:8',
 'age' => 'required|gte:18|lte:35',
];
$v = new Validator();
if ($v->setRules($rule)->validate($data)) {
 print_r($v->getData());
} else {
 echo $v->getErrorString();
}
//username最小长度为6个字符

自定义TAG和自定义错误提示

上面的demo中返回的错误是由系统自动生成的,可以自定义TAG或者自定义错误提示

自定义TAG 使用单个反引号包裹

$data = [
 'username' => 'startmvc',
 'passwd' => 'abc123',
 'age' => 25
];
$rule = [
 'username' => 'required|is_alpha_num|minlen:6 `用户名`',
 'passwd' => 'required|minlen:8',
 'age' => 'required|gte:18|lte:35',
];
$v = new Validator();
if ($v->setRules($rule)->validate($data)) {
 print_r($v->getData());
} else {
 echo $v->getErrorString();
}
//用户名最小长度为6个字符

自定义错误 使用双反引号包裹

$data = [
 'username' => 'startmvc',
 'passwd' => 'abc123',
 'age' => 25
];
$rule = [
 'username' => 'required|is_alpha_num|minlen:6 ``用户名必须是字母和数字组成哦``',
 'passwd' => 'required|minlen:8',
 'age' => 'required|gte:18|lte:35',
];
$v = new Validator();
if ($v->setRules($rule)->validate($data)) {
 print_r($v->getData());
} else {
 echo $v->getErrorString();
}
//用户名必须是字母和数字组成哦

自动去空格

系统默认开启了字符串去除两端空格,可以使用 $v->setFieldAutoTrim(false); 来关闭

$data = [
 'username' => ' startmvc ',
 'passwd' => 'abc123',
];
$rule = [
 'username' => 'required|minlen:5',
 'passwd' => 'required|minlen:6 `密码`',
];
$v = new Validator();
$v->setFieldAutoTrim(false);
if ($v->setRules($rule)->validate($data)) {
 var_dump($v->getDataByField('username'));
} else {
 echo $v->getErrorString();
}
//string(9) " startmvc "

调用PHP内置函数

任何callable函数都可以被用在规则里面,如下trim和substr

$data = [
 'username' => ' startmvc ',
 'passwd' => 'abc123',
];
$rule = [
 'username' => 'required|trim|substr:0,3',
 'passwd' => 'required|minlen:6 `密码`',
];
$v = new Validator();
$v->setFieldAutoTrim(false);
if ($v->setRules($rule)->validate($data)) {
 var_dump($v->getDataByField('username'));
} else {
 echo $v->getErrorString();
}
//string(3) "sta"

参数位置占位符@@

当前参数传递不是函数第一个参数时需要用@@做占位,如:str_replace:o,a,@@ 把o替换成a

$data = [
 'username' => ' startmvc ',
 'passwd' => 'abc123',
];
$rule = [
 'username' => 'required|trim|str_replace:v,o,@@',
 'passwd' => 'required|minlen:6 `密码`',
];
$v = new Validator();
if ($v->setRules($rule)->validate($data)) {
 var_dump($v->getDataByField('username'));
} else {
 echo $v->getErrorString();
}
//string(7) "startmoc"

自定义验证函数

自定义函数返回布尔值表示验证

$v->setTagMap('is_num', function ($var) {
 return is_numeric($var) ? true : false;
});

自定义函数返回非布尔值表示过滤

$v->setTagMap('filter_num', function ($var) {
 return preg_replace('/[^\d]/', '', $var);
});

完整的例子

$data = [
 'username' => ' startmvc ',
 'qq' => 'abc123bcd456',
];
$rule = [
 'username' => 'required|minlen:5',
 'qq' => 'required|filter_num|minlen:6 `QQ`',
];
$v = new Validator();
$v->setTagMap('filter_num', function ($var) {
 return preg_replace('/[^\d]/', '', $var);
});
if ($v->setRules($rule)->validate($data)) {
 var_dump($v->getDataByField('qq'));
} else {
 echo $v->getErrorString();
}
//string(6) "123456"

两个字段值必须相同(same用法)

一般用在密码和重复密码比较的场景

$data = [
 'username' => 'startmvc',
 'passwd' => 'abc123',
 'repasswd' => 'abc12',
];
$rule = [
 'username' => 'required|is_alpha_num|minlen:5',
 'passwd' => 'required|minlen:6 `密码`',
 'repasswd' => 'required|same:passwd ``密码必须和重复密码一致``',
];
$v = new Validator();
if ($v->setRules($rule)->validate($data)) {
 print_r($v->getData());
} else {
 echo $v->getErrorString();
}
//密码必须和重复密码一致

无限级数据验证

$data = [
 'username' => 'abc123',
 'mobile' => '13345678901',
 'attr' => [
 'sex' => 0,
 'age' => 28,
 'shoe' => [
 'brand' => 'NB',
 'size' => 41,
 ]
 ],
];
$rule = [
 'username' => 'required|minlen:6',
 'mobile' => 'required|is_mobile',
 'attr' => [
 'sex' => 'required|in:0,1,2',
 'age' => 'required|gte:18|lte:35',
 'shoe' => [
 'brand' => 'required',
 'size' => 'required|gte:18|lte:45',
 ]
 ]
];
$v = new Validator();
if ($v->setRules($rule)->validate($data)) {
 print_r($v->getData());
} else {
 echo $v->getErrorString();
}
//Array
//(
// [username] => abc123
// [mobile] => 13345678901
// [attr] => Array
// (
// [sex] => 0
// [age] => 28
// [shoe] => Array
// (
// [brand] => NB
// [size] => 41
// )
//
// )
//
//)

注意:无限级数据规则设置支持对象无限级 但不支持数组,如下数据结构

$data = [
 'username' => 'abc123',
 'mobile' => '13345678901',
 'address' => [
 ['provice' => '北京', 'city' => '北京'],
 ['provice' => '江苏', 'city' => '浙江'],
 ],
];

解决办法:使用setTagMap来设置定义函数迭代验证

失败处理方式 setFailFast()

默认 true 为快速失败:遇到首个字段校验失败立即中止,getError() 只包含第一个失败字段的错误(与旧版行为一致)。

传入 false 则收集全部错误:逐字段继续校验,getError() 一次返回所有失败字段(每个字段只记录首个失败规则),适合表单场景一次点亮全部红框。

$data = [
 'username' => 'a',
 'email' => 'not-an-email',
];
$rule = [
 'username' => 'required|minlen:3`用户名`',
 'email' => 'required|is_email`邮箱`',
];

// 默认:快速失败
$v = new Validator();
$v->setRules($rule)->validate($data);
print_r($v->getError());
//Array
//(
// [username] => 用户名最小长度为3个字符
//)

// 收集全部错误
$v = new Validator();
$v->setFailFast(false)->setRules($rule)->validate($data);
print_r($v->getError());
//Array
//(
// [username] => 用户名最小长度为3个字符
// [email] => 邮箱地址错误
//)

也可直接设置公有属性 $v->failFast = false;。
注意:无论哪种方式,校验失败时 getData() / getAllData() 均返回空。

获取错误

获取字符格式的错误

...
echo $v->getErrorString();
//密码必须和重复密码一致

获取数组形式的错误

...
print_r($v->getError());
//Array
//(
// [repasswd] => 密码必须和重复密码一致
//)

获取结果数据

获取所有数据 含未验证字段 $v->getAllData()

$data = [
 'username' => 'startmvc',
 'age' => '123s',
 'hobby' => 'sport',
];
$rule = [
 'username' => 'required|minlen:5',
 'age' => 'required|intval',
];
$v = new Validator();
if ($v->setRules($rule)->validate($data)) {
 print_r($v->getAllData());
} else {
 print_r($v->getError());
}
//Array
//(
// [username] => startmvc
// [age] => 123
// [hobby] => sport
//)

获取已设置验证规则的数据 不含未验证字段 $v->getData()

注意:当字段未设置required属性且未传递该字段时 结果不含该字段

$data = [
 'username' => 'startmvc',
 'age' => '123s',
 'hobby' => 'sport',
];
$rule = [
 'username' => 'required|minlen:5',
 'age' => 'required|intval',
];
$v = new Validator();
if ($v->setRules($rule)->validate($data)) {
 print_r($v->getData());
} else {
 print_r($v->getError());
}
//Array
//(
// [username] => startmvc
// [age] => 123
//)

获取某个字段的值 支持链式结构 foo.bar

$data = [
 'username' => 'abc123',
 'mobile' => '13345678901',
 'attr' => [
 'sex' => 0,
 'age' => 28,
 'shoe' => [
 'brand' => 'NB',
 'size' => 41,
 ]
 ],
];
$rule = [
 'username' => 'required|minlen:6',
 'mobile' => 'required|is_mobile',
 'attr' => [
 'sex' => 'required|in:0,1,2',
 'age' => 'required|gte:18|lte:35',
 'shoe' => [
 'brand' => 'required',
 'size' => 'required|gte:18|lte:45',
 ]
 ]
];
$v = new Validator();
if ($v->setRules($rule)->validate($data)) {
 var_dump($v->getDataByField('mobile'));
 var_dump($v->getDataByField('attr.shoe.brand'));
} else {
 echo $v->getErrorString();
}
//string(11) "13345678901"
//string(2) "NB"

独立字段过滤 filter()

只保留白名单内的字段,其余字段(含表单中被注入的附加字段)一律剔除。与验证解耦,无需设置任何规则即可使用,常用于防止批量赋值攻击。

$data = [
 'username' => 'tom',
 'email' => 'tom@example.com',
 'is_admin' => 1, // 表单中被注入的字段
];

$data = Validator::filter($data, ['username', 'email']);
// ['username' => 'tom', 'email' => 'tom@example.com'] is_admin 已被剔除
仅处理顶层字段;白名单中的字段在数据里不存在时安静跳过,不报错。

独立数据填充 fill()

写入前的数据准备:自动填充默认值、调用函数转换值,并支持按场景(insert / update)分组。

$data = Validator::fill($data, [
 'status' => 1, // 标量:仅字段缺失或为 null 时填充
 'name' => 'trim', // 函数名:一律调用并覆盖
 'password' => function ($v) {
 return $v === null ? null : password_hash($v, PASSWORD_DEFAULT);
 },
 'insert' => ['reg_ip' => 'get_ip'], // 场景组:仅 $scene = 'insert' 时生效
], 'insert');
规则形式行为
标量值(如 1、'abc')仅当字段缺失或值为 null 时填充,不覆盖已有值(0 / false / 空串均视为已有值)
可调用值(函数名 / 闭包)一律调用,参数为当前字段值(字段缺失时为 null);返回 null 则放弃写入该字段
'insert' / 'update' 键场景组,仅当第三个参数 $scene 与键名一致时应用;不传 $scene 时场景组不生效
可调用值必须能单参调用(trim / md5 / strtoupper / 闭包);password_hash 这类多必参函数请用闭包包一层。

两者可组合成完整的写入前管道(模型层的「三大自动」即由此驱动):

use startmvc\core\Validator;

$data = Validator::filter($data, ['username', 'email', 'status']); // 1. 过滤
$data = Validator::fill($data, ['status' => 1]); // 2. 填充

$v = new Validator();
if (!$v->setRules([ // 3. 验证
 'username' => 'required|minlen:3`用户名`',
 'email' => 'required|is_email`邮箱`',
])->validate($data)) {
 echo $v->getErrorString();
 return;
}

db('users')->insert($data); // 全程不需要模型
快速失败:首个字段校验失败即中止,getError() 只包含第一个失败字段的错误。
结果数据:验证通过后用 getData() 取「仅规则字段」的白名单数据,用 getAllData() 取「含未验证字段」的全量数据。
内置规则TAG列表
required
len
minlen
maxlen
width
minwidth
maxwidth
gt 
lt 
gte
lte
eq
neq
in
nin
same
is_mobile
is_email
is_idcard
is_ip
is_url
is_array
is_float 
is_int
is_numeric
is_string
is_natural
is_natural_no_zero
is_hanzi 
is_mongoid 
is_alpha
is_alpha_num
is_alpha_num_dash
<b>内置函数列表<br></b>
public function required($var): bool
public function same($var, $compare_var): bool
public static function len($var, $len): bool
public static function minlen($var, $len): bool
public static function maxlen($var, $len): bool
public static function width($var, $len): bool
public static function minwidth($var, $len): bool
public static function maxwidth($var, $len): bool
public static function isMobile($var): bool
public static function isEmail($var): bool
public static function isIp($var, $type = 'ipv4'): bool
public static function isUrl($var): bool
public static function isIdcard($var): bool //是否为身份证号码
public static function isNatural($var): bool
public static function isNaturalNoZero($var): bool
public static function isHanzi($var): bool //是否汉字
public static function isMongoid($var): bool
public static function isAlpha($var): bool
public static function isAlphaNum($var): bool
public static function isAlphaNumDash($var): bool
public static function gt($var, $min): bool
public static function lt($var, $max): bool
public static function gte($var, $min): bool
public static function lte($var, $max): bool
public static function eq($var, $obj): bool
public static function neq($var, $obj): bool
public static function in($var, ...$set): bool
public static function nin($var, ...$set): bool
public static function filterUtf8($var): string //过滤3字节以上的字符