danek/datafilter

数据过滤和验证

dev-master 2022-10-25 07:04 UTC

This package is auto-updated.

Last update: 2024-09-25 11:07:08 UTC


README

DataFilter 是一个 PHP 数据验证(清理)模块。

内容

要求

  • PHP 7.1+

通过 Composer 安装

要安装 danek/datafilter 的最新版本,请在 getcomposer.org 上使用 Composer。

composer require danek/datafilter

入门

一个基本示例,它期望两个 POST 参数,都是必需的

<?php

require 'vendor/autoload.php';

// ..

$profile = new \DataFilter\Profile([
    'attributes' => [
        '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 文件中是一个好主意。在运行时,您可以相应地修改加载的配置文件。

验证配置文件

验证配置文件是一组属性,每个属性都有(可能多个)规则。您可以将其视为一个单独的表单,或者视为 Model(ORM..)的通用属性验证。

以下我将展示内联 PHP 方法(见上文)。

结构

$profile = [

    // attribute definitions
    'attibutes' => [
        '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(可选)。

// ..
'attibutes' => [
    'attribName'  => true,
    'attribName2' => false
],
// ..

命名检查函数

有几个预定义的命名函数可以用于。完整列表,请查看 \DataFilter\PredefinedRules\Basic

以下示例显示了一个正则表达式测试和一个最小长度测试。两个属性都是隐式必需的。

 // ..
 'attibutes' => [
     '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'],
'attibutes' => [
    'attribName'  => 'MyTest:foo:bar'
],
// ..

自定义检查函数

可以内联添加自定义检查函数(可以是 Closure 或可调用的数组)

// ..
'attibutes' => [
    'attribName'  => ['\\MyClass', 'myMethod'],
    'attribName2' => function($input, ..) {
       return true;
    }
],
// ..

复杂格式

复杂格式支持对每个属性和规则的严格控制。也可以为每个属性使用多个规则。

'attibutes' => [
    '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 也应该如此。在这种情况下,您将创建一个从 passwordpassword_new 的依赖关系,如下所示

'attibutes' => [

    // the password input
    'password' => [

        // not required itself
        'required' => false,

        // ..
        'dependent' => [
            '*' => ['password_new']
        ]
        //..
   ],

    // default: password_new is optional
    'password_new' => false,
    // ..
]

dependent 的左侧值表示其他属性(右侧数组)所依赖的输入。 * 是一个特殊案例,表示:“在任何输入上”。如果有多个依赖项给出,则在没有其他匹配项的情况下使用 *

此外,还有 dependentRegex,它们的工作方式相同,但左侧有正则表达式。

'attibutes' => [

    // the password input
    'password' => [
        // ..
        'dependentRegex' => [
            '/./' => ['password_new']
        ]
        //..
    ],

    // default: password_new is optional
    'password_new' => false,
    // ..
]

在条件表单部分(例如,如果单选输入切换表单的一部分)的上下文中,依赖关系可能很有用。

使用 JSON

您可以将定义放在 JSON 文件中,并将它们加载到配置文件中。

{
    "attibutes": {
        "someAttrib": true,
        "otherAttrib": {
            "required": false,
            "rules": {
                "isEmail": "Email",
                ...
            }
        },
        ...
    },
    "preFilters": [
        "trim",
        ...
    ],
    ...
}

然后加载定义

$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');
# ..