datafilter / datafilter
数据过滤和验证
Requires
- php: >=5.3.0
This package is not auto-updated.
Last update: 2020-01-18 05:52:51 UTC
README
DataFilter 是一个 PHP 的数据验证(净化)模块。
编写此模块的动机主要源于需要有一个通用的验证模块,该模块既不与任何类型的 ORM 逻辑交织,也不与控制器(在 MVC 术语中)逻辑交织。
第二个目标是创建一个可以通过元语言(JSON、YAML 等)配置的验证规则,无需“内联”规则定义 - 简而言之:将验证规则与业务逻辑分离。
需要 PHP 5.3(尽管示例中使用的语法是 5.4 数组符号)。
通过 Composer 安装
创建一个最小的 composer.json
{
"require": {
"datafilter/datafilter": "dev-master"
}
}
运行 composer update 或 install
composer.phar install --dev
入门
一个基本示例,期望两个 POST 参数,都是必需的
<?php
require 'vendor/autoload.php';
// ..
$profile = new \DataFilter\Profile([
'attribs' => [
'username' => true,
'password' => true
]
]);
if ($profile->check($_POST)) {
$data = $profile->getLastResult()->getValidData();
}
else {
error_log("Failed, required params not given");
}
深入
配置文件是 DataFilter 验证和过滤(也是净化)的核心。创建这些配置文件有三种可能的方法:使用内联 PHP 定义、使用元语言(如 JSON)编写的外部定义或使用编程方法在运行时编写定义。
根据您的验证问题的复杂程度,我认为使用内联 PHP 定义或将配置文件放入 JSON 文件中是个好主意。在运行时,您可以相应地修改加载的配置文件。
验证配置文件
验证配置文件是一组具有(可能多个)规则的属性。您可以将其视为单个表单,也可以视为模型(ORM)的一般属性验证。
以下将展示内联 PHP 方法(见上文)。
结构
$profile = [
// attribute definitions
'attribs' => [
'attributeName' => [
// rule definitions
],
// list of attributes and rules
],
// overwrite default invalid error message
'errorTemplate' => "Attribute :attrib: violated rule :rule:",
// overwrite default missing error message
'missingTemplate' => "Attribute :attrib: is missing",
// custom rule classes
'ruleClasses' => [
"\\MyRuleClass",
// ..
],
// custom filter classes
'filterClasses' => [
"\\MyFilterClass",
// ..
],
// custom, global pre-filters (before validating)
'preFilters' => [
function($in) {
return $in;
},
"namedFilter",
["\\SomeClass", "someMethod"],
// ..
],
// custom, global pre-filters (after validating, only on valids)
'postFilters' => [
function($in) {
return $in;
},
"namedFilter",
["\\SomeClass", "someMethod",
// ..
]
];
规则格式
简单(必需、可选)
最简单的规则格式是 true
(必需)或 false
(可选)。
// ..
'attribs' => [
'attribName' => true,
'attribName2' => false
],
// ..
命名检查函数
有一些预定义的命名函数可以使用。完整列表请参阅 \DataFilter\PredefinedRules\Basic
。
以下示例显示了正则表达式测试和最小长度测试。这两个属性都是隐式必需的。
// ..
'attribs' => [
'attribName' => 'Regex:/^a[0-9]+',
'attribName2' => 'MinLen:5'
],
// ..
包含预定义规则的类可以添加。它们必须实现返回函数引用的公共、静态方法
class MyClass {
public static function ruleMyTest($arg1, $arg2) {
return function ($input, \DataFilter\Rule $rule = null, \DataFilter\Attribute $attrib = null, \DataFilter\Profile $profile = null) {
return true;
}
}
}
自定义类需要注册,并可以使用方法名称使用
// ..
'ruleClasses' => ['\\MyClass'],
'attribs' => [
'attribName' => 'MyTest:foo:bar'
],
// ..
自定义检查函数
可以内联添加自定义检查函数(可以是 Closure 或可调用数组)
// ..
'attribs' => [
'attribName' => ['\\MyClass', 'myMethod'],
'attribName2' => function($input, ..) {
return true;
}
],
// ..
复杂格式
复杂格式支持对每个属性和规则进行严格控制。也可以为每个属性使用多个规则。
'attribs' => [
'attribName' => [
// whether required
'required' => true,
// whether any (first) positive rule match validates argument (default: false)
'matchAny' => false,
// default value is set if attribute NOT given (empty input is still given!). Implies optional (not required)
'default' => null,
// default missing error text
'missing' => 'This attribute is missing',
// whether skip all (global and local) filters (default: false)
'noFilter' => false,
// list of ules
'rules' => [
'ruleName' => [
// either a Closure (or callable array or a named function)
'constraint' => $constraint,
// custom error message if rule fails
'error' => 'On error show this message',
// whether ignore this rule on empty input
'skipEmpty' => false,
// whether this rule sets the result valid and stops further rules
'sufficient' => false
]
],
// dependencies: see explanation below
'dependent' => [
'onSomeInput' => ['otherField1', 'otherField2']
]
]
]
属性依赖关系
依赖关系可以通过常见的密码案例来解释。假设您有一个表单,其中包含一个名为 password
的输入和一个名为 password_new
的输入。如果提供了 password
,则应同时提供 password_new
。在这种情况下,您可以创建从 password
到 password_new
的依赖关系,如下所示
'attribs' => [
// the password input
'password' => [
// not required itself
'required' => false,
// ..
'dependent' => [
'*' => ['password_new']
]
//..
],
// default: password_new is optional
'password_new' => false,
// ..
]
dependent
的左侧值代表其他属性(右侧数组)所依赖的输入。 *
是一个特殊情况,表示:“任何输入”。如果提供了多个依赖关系,而输入没有其他匹配项时,则使用 *
。
此外,还有 dependentRegex
,它的工作方式相同,但在左侧使用正则表达式。
'attribs' => [
// the password input
'password' => [
// ..
'dependentRegex' => [
'/./' => ['password_new']
]
//..
],
// default: password_new is optional
'password_new' => false,
// ..
]
依赖关系可以在条件表单部分的情况下很有用(例如,如果一个单选输入开关表单的一部分开或关)。
使用 JSON
您可以将定义放入 JSON 文件中,并将它们加载到配置文件中。
def.json:
{
"attribs": {
"someAttrib": true,
"otherAttrib": {
"required": false,
"rules": {
"isEmail": "Email",
...
}
},
...
},
"preFilters" => [ ... ],
...
}
然后加载定义
$profile = \DataFilter\Profile::loadJson("def.json");
当然,使用 JSON 文件外部化的定义的问题是无法使用可调用函数(function() {..}
)。然而,使用下面的程序化方法,您可以在运行时添加这些规则/过滤器。
程序化
此选项应主要用于在需要时修改预定义配置文件。您也可以从头创建完整的配置文件,但据我看来,这只会使代码混乱。
// creating
$profile = new \DataFilter\Profile();
$profile->setAttrib('email');
$email = $profile->getAttrib('email');
$email->setRule('checkMail', 'Email');
$email->setRule('checkSomething', function($in) {
return strlen($in) > 4 && preg_match('/aaa/', $in);
});
$email->addPostFilters([
function($in){
return ucfirst($in);
}
]);
# ..
// manipulating
$profile = \DataFilter\Profile::fromJson("def.json");
$email = $profile->getAttrib('email');
# ..