ikkez / f3-validation-engine
Cortex 和 PHP Fat-Free 框架的验证引擎
README
这是为 PHP Fat-Free 框架 提供的一个扩展,它提供了一种验证系统,特别适用于验证 Cortex 模型。验证系统基于知名的 GUMP 验证器,当然还有一些额外的功能
- 基于 GUMP 的验证器
- 多级验证
- 在
$fieldConf
中定义 Cortex 验证 - 嵌套数组和依赖验证
- 预验证和后验证过滤器
- 包含 F3 兼容的语言字典
- 基于字段的上下文语言覆盖
- 也可在没有 Cortex 的情况下使用
- 可扩展
目录
安装
使用 composer 安装,只需运行 composer require ikkez/f3-validation-engine
。如果您不使用 composer,请将 src/
文件夹添加到您的 AUTOLOAD
路径中,并单独安装 Wixel/GUMP。
入门
默认情况下,验证引擎是静默的。为了利用验证过程中找到的错误,您需要将一些东西连接起来。这是在 onError
处理器中完成的,在那里您定义如何处理错误。一个示例
$validation = \Validation::instance(); $validation->onError(function($text,$key) { \Base::instance()->set('error.'.$key, $text); \Flash::instance()->addMessage($text,'danger'); });
在上面的示例中,我们注册了一个 onError 处理器,该处理器将错误键设置在 Hive 中,并添加了一条闪存消息到用户会话中。您可以随意全局定义此内容或动态更改 onError 处理器。
为了使错误文本正确显示,您需要加载包含的语言字典。为此,您可以添加 lang 文件夹到您的字典路径,如下所示
LOCALES = app/your/lang/,vendor/ikkez/f3-validation-engine/src/lang,vendor/ikkez/f3-validation-engine/src/lang/ext,
或者您也可以为这个调用一个小助手
\Validation::instance()->loadLang();
这使用了一种优化的加载方法,并且当您将 $ttl
作为第一个参数时,还包括了一些缓存技术。
注意:类似于 \Validation::instance()->loadLang(3600*24);
的缓存需要最新的 F3 边缘版本,否则可能会导致奇怪的词汇问题。至少使用
"bcosca/fatfree-core": "dev-master#b3bc18060f29db864e00bd01b25c99126ecef3d6 as 3.6.6"
验证
要使用验证引擎,您可以选择使用简单数组验证或使用具有预定义字段配置规则的 cortex 映射器。
Cortex 映射器验证
要使用映射器验证,您必须在 $fieldConf
数组中定义验证规则。这可以看起来像这样
protected $fieldConf = [ 'username' => [ 'type' => Schema::DT_VARCHAR128, 'filter' => 'trim', 'validate' => 'required|min_len,10|max_len,128|unique', ], 'email' => [ 'type' => Schema::DT_VARCHAR256, 'filter' => 'trim', 'validate' => 'required|valid_email|email_host', ], ];
要开始验证,您可以使用此方法
$valid = $validation->validateCortexMapper($mapper);
或者将适当的验证特性添加到您的模型类中
namespace Model; class User extends \DB\Cortex { use \Validation\Traits\CortexTrait; // ... }
然后直接在您的模型上调用 $mapper->validate();
。
数据数组验证
如果您只有一个简单数组,并想对某些规则进行验证,您也可以这样做
$data = [ 'username' => 'Jonny', 'email' => 'john.doe@domain.com', ]; $rules = [ 'username' => [ 'filter' => 'trim', 'validate' => 'required|min_len,10|max_len,128|unique', ], 'email' => [ 'filter' => 'trim', 'validate' => 'required|valid_email|email_host', ] ]; $valid = $validation->validate($rules, $data);
验证方法总是返回一个布尔值,以指示数据是否有效(TRUE
)或是否找到任何错误(FALSE
);
规则
验证器
GUMP的默认验证器包括:
required
确保指定的键值存在且不为空valid_email
检查是否为有效的电子邮件地址max_len,n
检查键值长度,确保其长度不超过指定的长度。n = 长度参数。min_len,n
检查键值长度,确保其长度不短于指定的长度。n = 长度参数。exact_len,n
确保键值长度精确匹配指定的长度。n = 长度参数。alpha
确保键值中只包含字母字符(a-z, A-Z)alpha_numeric
确保键值中只包含字母数字字符(a-z, A-Z, 0-9)alpha_dash
确保键值中只包含字母数字字符、破折号和下划线(a-z, A-Z, 0-9, _-)alpha_space
确保键值中只包含字母数字字符和空格(a-z, A-Z, 0-9, \s)numeric
确保只有数字键值integer
确保只有整数键值boolean
检查是否为PHP接受的布尔值,对 "1"、"true"、"on" 和 "yes" 返回 TRUEfloat
检查是否为浮点值valid_url
检查是否为有效的URL或子域url_exists
检查URL是否存在并可访问valid_ip
检查是否为有效的通用IP地址valid_ipv4
检查是否为有效的IPv4地址valid_ipv6
检查是否为有效的IPv4地址guidv4
检查是否为有效的GUID(v4)valid_cc
检查是否为有效的信用卡号码(使用MOD10校验算法)valid_name
检查是否为有效的人类姓名格式contains,n
验证值是否包含在预定义的值集中contains_list,n
验证值是否包含在预定义的值集中。有效的值列表必须以分号分隔的格式提供(例如:value1;value2;value3;..;valuen)。如果发生验证错误,则不会显示有效的值列表(这意味着,错误将只说明输入无效,但不会向用户显示有效集)。doesnt_contain_list,n
验证值是否不包含在预定义的值集中。分号 (;) 分隔,列表不输出。更多信息请参见上述规则。street_address
检查提供的字符串是否是可能的街道地址。1个数字,1个或多个空格,1个或多个字母date
确定提供的输入是否为有效的日期(ISO 8601)min_numeric
确定提供的数值是否高于或等于特定值max_numeric
确定提供的数值是否低于或等于特定值min_age,n
确保字段包含具有最小年龄的日期,例如min_age,18
。输入日期需要与ISO 8601 /strtotime
兼容。starts,n
确保值以特定的字符/字符集开头equalsfield,n
确保提供的字段值等于当前字段值。iban
检查是否为有效的IBANphone_number
验证与以下示例匹配的电话号码:555-555-5555 , 5555425555, 555 555 5555, 1(519) 555-4444, 1 (519) 555-4422, 1-555-555-5555regex
您可以使用以下格式传递自定义正则表达式:'regex,/your-regex/'
valid_json_string
验证字符串是否为有效的JSON格式
其他验证器
empty
检查字段值是否为empty
。notempty
确保字段值不为empty
,不是空字符串,也不是字符串"0"
。notnull
确保字段值不是NULL
。这是一个较宽松的“必填”检查。email_host
检查给定电子邮件地址的MX域名记录。如果主机系统不接受电子邮件,则失败。此验证器仅对有效电子邮件起作用,但不会验证电子邮件地址本身(与valid_email
结合使用)。unique
- Cortex仅支持 -
检查给定的字段值在数据库表中是否唯一(例如用户名)。
过滤器
可以在验证之前使用过滤器来净化输入数据。基本上,过滤器是一个简单的PHP函数,返回一个字符串。
您可以设置在验证之前应用的常规filter
和在之后应用的post_filter
。
'foo' => [ 'filter' => 'trim|base64_decode', 'validate' => 'required|valid_url', 'post_filter' => 'base64_encode', ],
默认GUMP过滤器
sanitize_string
移除脚本标签并编码HTML实体,类似于GUMP::xss_clean();urlencode
编码URL实体htmlencode
编码HTML实体sanitize_email
从电子邮件地址中移除非法字符sanitize_numbers
移除任何非数字字符sanitize_floats
移除任何非浮点字符trim
从字符串的起始和结束处移除空格base64_encode
对输入进行Base64编码base64_decode
对输入进行Base64解码sha1
使用安全的sha1算法对输入进行加密md5
对输入进行MD5编码noise_words
从字符串中移除噪音单词json_encode
创建输入的JSON表示json_decode
解码JSON字符串rmpunctuation
从字符串中移除所有已知标点符号字符basic_tags
从文本中移除所有布局导向的HTML标签,仅留下基本标签whole_number
确保提供的数值以整数形式表示ms_word_characters
将MS Word特殊字符[“”‘’–…]转换为Web安全字符lower_case
转换为小写upper_case
转换为大写slug
创建Web安全的URL别名
其他过滤器
website
如果未指定协议,则将http://
协议添加到URI前面。
验证依赖
您可以选择跳过一条验证规则,并在满足另一个字段的特定条件时才考虑它。
在下面的示例中,当bar = 2
时,foo
才需要。
'foo' => [ 'validate' => 'required', 'validate_depends' => [ 'bar' => 2 ] ]
您还可以使用一些更高级的依赖性检查,如嵌套验证规则。
'foo' => [ 'validate' => 'required', 'validate_depends' => [ 'bar' => ['validate', 'min_numeric,2'] ] ]
当嵌套验证为TRUE
(有效)时,则满足依赖性,并且foo
的验证继续进行,否则将跳过。如果这还不够,您还可以添加一个自定义函数。
'validate_depends' => [ 'bar' => ['call', function($value,$input) { return (bool) $value % 3 }] ]
一个类似F3的调用字符串,如['call', 'Foo->bar']
也是可能的。
验证级别
类似于验证依赖性,您还可以定义验证级别。如果字段上定义了验证级别,则其验证将完全跳过(但是应用过滤器)。
验证级别在您希望在某些步骤中验证记录时很有用,例如,“草稿”在发布之前可能需要较少的验证规则。
您可以像这样定义验证级别
'foo' => [ 'validate_level'=>2, 'validate' => 'required', ]
默认情况下,所有验证都使用level = 0
。要触发此验证规则,您需要调用带有新$level
的validate函数。
$validation->validateCortexMapper($mapper, $level); // OR $validation->validate($rules, $data, $level);
级别检查的默认比较操作符为<=
。因此,级别-2的验证也会触发级别0和级别1的验证规则。如果您只想检查级别-2,还可以设置新的$level_op
参数。
数组验证
如果您在数据或模型中有一个数组字段,您还可以验证某些数组键。
'contact' => [ 'type' => self::DT_JSON, 'validate_array' => [ 'name' => ['validate'=>'required'], 'address' => ['validate'=>'required|street_address'], 'region' => ['validate'=>'required'], 'zip' => ['validate'=>'required'], ] ]
嵌套数组
还可以验证嵌套数组/关联数组数组。
'partners' => [ 'type' => self::DT_JSON, 'validate_nested_array' => [ 'name' => ['validate'=>'required'], 'profession' => ['validate'=>'required'], 'phone' => ['validate'=>'required'], 'image' => ['filter'=>'upload'], ] ]
包含检查
- 正在开发中 -
还可以通过在$fieldConf
(或$rules
数组)中的item
键中简单定义,来定义contains将检查的值(contains
验证器)。
'foo' => [ 'type' => Schema::DT_VARCHAR128, 'item' => [ 'one', 'two', 'three', ] ]
如果值与定义的项目之一不匹配,验证将失败。也可以将一个字符串放入item
,它是一个包含项目的强F3 hive键
。
错误处理
错误信息是从字典文件加载到F3 hive中的。
默认的hive位置在:{PREFIX}error.validation.{type}
这意味着,如果你的PREFIX是ll.
,那么required
验证器的默认文本在ll.error.validation.required
。当然,你也可以在项目的自定义语言文件中覆盖它,但有时你可能只想为模型中的一个字段更改它。这里我们可以使用错误上下文
。
错误上下文
当你验证Cortex模型时,它将自动根据类命名空间有一个上下文。所以当你验证\Model\User
时,错误上下文是error.model.user
。
要覆盖默认的错误消息,针对一个特定字段
和一个特定验证器
,可以在这个上下文中创建一个新的语言键。
[error.model.user] username.required = You Shall Not Pass! username.unique = Doh! It's already taken.
字段名称
大多数错误消息包含一个字段标识符/字段名称,错误属于该字段。默认情况下,此名称由该字段的数组键构建,但这通常不够。为了在错误消息中也有适当的翻译字段名称,系统会根据模型上下文和字段查找语言键。
例如,用户模型中的用户名字段应该标记为
model.user.username.label = 昵称
在此过程中,你也可以考虑占位符标签、帮助文本等,这些都可能适合此架构,并可能改善前端连接。
当你使用validate_array
或validate_nested_array
规则验证数组时,字段标签会移动到条目字段下方的键。例如,当你有一个包含邮编字段的用户模型中的数组地址字段时,标签上下文将是
model.user.address.zip.label = 邮编
默认字段标签
如果你有多个模型上常见的字段,并且不想为每个模型重复定义这些翻译标签,你可以在model.base
中定义一个默认回退标签。
[model.base]
deleted_at.label = deleted at
enabled_from.label = visible from
enabled_until.label = visible until
自定义模型上下文名称转换
默认情况下,模型名称被转换为小写字符串。即此类\Model\BackendUser
被转换为上下文:model.backenduser
。你可以通过设置一个自定义函数来调整此行为。
\Validation::instance()->setStringifyModel(function($mapper) { return implode('.',array_map('lcfirst',explode('\\',get_class($mapper)))); });
此示例将类名转换为model.backendUser
。
前端集成
在设置错误键的onError
处理程序中,例如从样本开始,你可以轻松地使用它们来显示自定义错误消息或向标记添加类。
<div class="uk-card uk-card-default {{ @@error.model.user.username ? 'frame-red' : 'frame-grey' }}"> <div class="uk-card-body"> <h3 class="uk-card-title">{{ @ll.model.user.username.label }}</h3> <div class="uk-margin"> <input class="uk-input {{ @@error.model.user.username ? 'uk-form-danger' : '' }}" type="text" name="username" placeholder="{{ @@ll.model.user.username.placeholder }}"> </div> </div> </div>
如果你喜欢,你也可以根据失败的验证器添加自定义的帮助文本。
例如,添加一个<F3:check if="{{@@error.model.user.username.unique}}">
或为必填验证器添加不同的一个,你可以构建复杂和功能性的表单状态。有关附加的闪存消息,请参阅f3-flash。
自定义错误
如果你想只设置自定义错误消息,请阅读上面的错误上下文
。
如果你需要手动触发错误,因为有些验证部分目前超出了范围,你可以自己进行验证并自行发出错误,如下所示
$valid = $userModel->validate(); if (!$userModel->foo1 && !$userModel->foo2) { \Validation::instance()->emitError('foo','required','model.user.foo'); $valid = false; } if ($valid) { // continue }
emitError(字符串 $field, 字符串 $type, 字符串 | 数组 $context = NULL, 字符串 $fallback = NULL)
要从不同的字段使用错误消息,你可以使用数组作为$context
参数。
\Validation::instance()->emitError('phone_mail_copy','required',[ 'model.employerprofile.phone_mail_copy', // context 'model.employerprofile.phone_mail_orig', // context label ]);
你还可以在自定义错误中使用参数。
if ($f3->get('POST.password') !== $f3->get('POST.password2')) { // The {0} field does not equal {1} field \Validation::instance()->emitError(['password','Password repeat'],'equalsfield','model.user'); }
扩展
扩展系统很简单。要添加一个新的验证器
\Validation::instance()->addValidator('is_one', function($field, $input, $param=NULL) { return $input[$field] === 1; }, 'The field "{0}" must be 1');
也要在error.validation.is_one
中添加新的翻译键,否则只会显示回退文本,或者当没有提供文本时显示上下文。
并且添加一个新的 过滤器
\Validation::instance()->addFilter('nl2br',function($value,$params=NULL) { return nl2br($value); });
您也可以使用 F3 调用字符串
$validator = \Validation::instance(); $validator->addValidator('is_one','App\MyValidators->is_one'); $validator->addFilter('nl2br','App\MyFilters->nl2br');
许可证
GPLv3