fishfin/php-valigator

独立的PHP类,用于数据清理和验证

1.0.4 2021-03-11 12:55 UTC

This package is auto-updated.

Last update: 2024-09-11 21:07:35 UTC


README

极简主义爱好者们,欢呼吧!Valigator是一个独立的PHP类,用于数据清理和验证。它没有库依赖,实现了程序员友好的过滤器语法,并且非常灵活。它只是一个单独的类文件,包含它,你就可以开始了!

Valigator,嗯?

PHP API框架正在快速发展。它们非常简洁,快速,并且比功能强大但有时笨拙的大型框架更受欢迎。为了在API框架和项目中实现验证,必须安装大型供应商源,这会增加代码库的不必要增加和复杂性。Valigator就是为了解决这个问题而创建的。没有什么可以阻止你在非API项目中使用Valigator。向前走吧,你会喜欢的!

Valigator清单
  ✓ PHP (5.5.*, 5.6.*, 7.*)
  ✓ Stand-alone
  ✓ Data Sanitization
  ✓ Data Validation
  ✓ Simple
  ✓ Flexible
  ✓ Programmer-friendly

PS:Slim Framework 3很棒!

又一个Vali[dg]ator

也许吧。也许不是。是的,Valigator从一些好的,不,伟大的东西中汲取了灵感,并添加了自己的好东西。只是为了吸引你的兴趣:过滤器别名、多个参数、自定义标签、自定义验证错误消息等等。

Valigator的结构

术语

  • 字段
    映射到过滤器的数据的名称。通常是POST请求中的变量名称。字段可以映射到零个、一个或多个清理过滤器。字段可以映射到零个、一个或多个验证过滤器。区分大小写。例如,loginIdloginid不相同。

  • 运行过滤器的字段的值。通常是映射到POST请求中的变量名称。除非通过运行在其上的过滤器使其不区分大小写,否则区分大小写。例如,email过滤器不在乎传递的值是大小写字母。
  • 过滤器
    一些人称之为规则,Valigator更愿意称之为过滤器。因为存在清理过滤器和验证过滤器,所以很简单。不区分大小写。例如,误将required误写成Required没有任何区别。
  • 参数
    传递给过滤器的参数。您可以向过滤器传递零个、一个或多个参数。不区分大小写,除非需要过滤器使其区分大小写。例如,startswith过滤器可以验证字段值是否以作为区分大小写参数传递的字符开头。
  • 清理
    清理过滤器简称为“清理”。清理从不失败,因此从不发出任何错误消息。
  • 验证
    而验证过滤器简称为“验证”。验证要么通过要么失败。如果失败,它将发出一个错误消息。
  • 标签
    程序员可以设置的字段的可读标签。如果没有设置,标签默认为字段变量名称的大写单词。例如,字段loginId默认将标记为Login Id(很酷,不是吗!),但可以被程序员重命名为已注册登录 ID。以下模式的变量名称会自动检测:snake_casecamelCasePascalCasetrain-case。一些默认标签示例
  • token变为Token
  • project_title变为Project Title
  • book-1变为Book 1
  • debitCardNumber变为Debit Card Number
  • FAQAnswer6变为FAQ Answer 6
  • SuspenseAccount#变为Suspense Account #
  • errormsg
    验证产生的错误消息(每个验证一个)。程序员可以根据字段和验证自定义错误消息。错误消息可能包含一些特殊标签,这些标签将被动态替换
  • {field}{label} 将被替换为字段的标签
  • {fieldlineage}{labellineage} 将被替换为完整字段层次结构的标签(反向顺序,例如 Node 3 of Node 2 of Node 1
  • {fieldlineagef}{labellineagef} 将被替换为完整字段层次结构的标签(正向顺序,例如 Node 1.Node 2.Node 3
  • {value} 将被替换为字段的值
  • {filter} 将被替换为过滤器的名称
  • {args}{parms} 将被替换为连接的参数字符串
  • {arg1}、...、{argn}{parm1}、...、{parmn} 如果存在,将被替换为过滤器的单独参数(注意没有 {arg0}{parm0}

齿轮和轮子

让我们用一个例子来更容易地从这里开始。假设我们想要验证以下字段

  • loginId:必填,且必须是电子邮件ID
  • name:必填,且必须是一个名字
  • creditCardNumber:非必填,但如果提供,必须是有效的信用卡号码
  • billAddressPINCode:非必填,但如果提供,必须是一个6位数字
  • shipAddressPINCode:非必填,但如果提供,必须是一个6位数字

是的,你已经注意到了,驼峰命名法只是我的偏好。

现在假设我们正在一个数组中接收以下数据(如果你没有以数组的形式接收数据,你需要创建一个数组)

<?php
// iteration 1
$inputData = [
  'salutation' => 'Mr.',                               // we aren't interested in validating this
  'loginId' => '',                                     // invalid data as it is empty
                                                       // notice that 'name' is missing
  'creditCardNumber' => '0001-0001-0001-ABCD',         // not a valid credit card number
                                                       // notice that 'billAddressPINCode' is missing
                                                       // notice that 'shipAddressPINCode' is missing
];

现在根据我们有的数据验证要求创建过滤器,并添加一些其他有用的东西。请阅读代码注释中的重要说明。

<?php
$myFilters = [
  'loginId:"Retail User ID"' => [                      // overrides default label 'Login Id'
    'sanitizations' => 'trim',                         // 'trim' is a popular filter, works exactly
                                                       // like the PHP in-built trim()
    'validations' => 'required|email',                 // multiple validation filters
  ],
  'name:"Full Name"' => [                              // overrides default 'Name'
    'sanitization' => 'trim',                          // singular 'sanitization' works too
    'validation' => 'required|personname',             // singular 'validation' works too
  ],
  'creditCardNumber' => [
                                                       // label defaults to 'Credit Card Number'
    'sanitizations' => 'trim|numeric',                 // multiple sanitization filters
    'validations' => 'creditcard',                     // if present, must be credit card number
  ],
  'billAddressPINCode:"PIN Code (Billing)"|shipAddressPINCode:"PIN Code (Shipping)"' => [
                                                       // overrides default labels for Address PIN Codes
                                                       // no sanitization filters here
    'validations' => 'numeric|exactlen:6',             // if present, must be numeric of exactly 6
                                                       // characters length
  ],
];

// Important Notes:
//  1. 'loginId', 'name', 'creditCardNumber', 'billAddressPINCode' and 'shipAddressPINCode' are our
//     **fields** of interest
//  2. Field names are case-sensitive: 'loginId' is not the same as 'loginid'
//  3. Fields running  same sanitizations and validations need not be listed separately, they can
//     be concatenated together with the pipe (|) delimiter
//  4. Important understanding about filters:
//     a. Sanitization filters will modify input, and will never emit errors
//     b. Validation filters will never modify input, but can emit errors
//  5. The order of running filters is as follows:
//     a. All sanitizations first (if they exist) in order: 'loginId' to 'billAddressPINCode'
//     b. Then all validations (if they exist) in order:  'loginId' to 'billAddressPINCode'
//  6. If there are validation errors, they will be reported in exactly the same order, so
//     if you want some errors to be reported higher than the others, place the field higher
//  7. You can use the following keywords interchangeably, whatever makes you comfortable:
//     a. 'sanitization' <=> 'sanitizations'
//     b. 'validation' <=> 'validations'
//  8. Multiple filters can be set for each field, for sanitizations or validations, the
//     delimiter is '|'. Filters are run in the same order from left to right. Output of first
//     sanitization filter is passed to the second one, output of second to the third and so on.
//     Output of sanitization is sent to validation filters.
//  9. For most validation filters except 'required', if input is absent or empty, validation
//     will pass. Simply add 'required' filter to the beginning of validation filters if the
//     value must be present.

现在让我们运行验证器

<?php
require 'Valigator.php';                               // point to the right path, or autoload

$myValigator = new \Fishfin\Valigator($myFilters);

$validationResults = $myValigator->run($inputData);    // run() does sanitizations, then validations

if ($validationResults === FALSE) {                    // at least one validation failed
  $myValidationErrorsArray = $myValigator->getValidationErrors();
} else {                                               // all validations passed
  $sanitizedInputData = $validationResults;
}

// For iteration 1, following will be the results:
// $validationResults:
//   FALSE
// $myValidationErrorsArray:
//   ["Retail User ID is required",
//    "Full Name is required",
//    "Credit Card Number does not contain a valid credit card number"]

让我们尝试使用稍作修改的输入进行下一轮迭代。

<?php
require 'Valigator.php';                               // for brevity, we will not show this in next
                                                       // iteration
// iteration 2
$inputData = [
  'salutation' => 'Mr.',                               // still not interested in validating this
  'loginId' => 'user',                                 // still not okay, not an email
  'name' => 'Ruskin Bond 5',                           // what's a numeric doing in a name?
  'creditCardNumber' => '0001-0001-0001-0001',         // does not satisfy credit card last digit logic
  'billAddressPINCode' => 'A123456',                   // not a numeric, not 6 digits
  'shipAddressPINCode' => '987654',                    // looks good
];

$myValigator = new \Fishfin\Valigator($myFilters);     // block start
                                                       // for brevity, we will not show this block in next
$validationResults = $myValigator->run($inputData);    // iteration

if ($validationResults === FALSE) {
  $myValidationErrorsArray = $myValigator->getValidationErrors();
} else {
  $sanitizedInputData = $validationResults;
}                                                      // block end

// Results for iteration 2:
// $validationResults:
//   FALSE
// $myValidationErrorsArray:
//   ["Retail User ID is not a valid email address",
//    "Full Name does not seem to contain a person's name",
//    "Credit Card Number does not contain a valid credit card number",
//    "PIN Code (Billing) may only contain numeric characters",
//    "PIN Code (Billing) must be exactly 6 characters long"]
// Nice, yeah?

现在是第3轮迭代的时间

<?php
// iteration 3
$inputData = [
  'salutation' => 'Mr.',                               // whatever
  'loginId' => 'user@example.com',                     // looks okay now
  'name' => 'Ruskin Bond ',                            // notice additional blank at the end
  'creditCardNumber' => '4111=1111=1111=1111',         // is actually a valid sample Visa CC number
                                                       // notice '=' symbol instead of hyphens or blanks
  'billAddressPINCode' => '1234567',                   // not 6 digits
  'shipAddressPINCode' => '987654',                    // is good
];

// Results:
// $validationResults:
//   FALSE
// $myValidationErrorsArray:
//   ["PIN Code (Billing) must be exactly 6 characters long"]
// No error on credit card number, because it was sanitized for numbers! More on this later.

最后...

<?php
// iteration 4
$inputData = [
  'salutation' => 'Mr.',
  'loginId' => 'user@example.com',
  'name' => 'Ruskin Bond ',
  'creditCardNumber' => '4111=1111=1111=1111',
  'billAddressPINCode' => '123456',                    // looks good now
  'shipAddressPINCode' => '987654',
];

// Results:
// $validationResults:
//   TRUE
// $sanitizedInputData:
//   {"salutation":"Mr.",
//    "loginId":"user@example.com",
//    "name":"Ruskin Bond",
//    "creditCardNumber":"4111111111111111",
//    "billAddressPINCode":"123456",
//    "shipAddressPINCode":"987654"}
// Did you notice the name was sanitized by removing leading and trailing blanks? That was because
// of the 'trim' sanitization. Notice how '=' was removed because of the 'numeric' sanitization.
// All validations passed this time, phew!

铃铛和哨子

现在你已经熟悉了基础知识,让我们继续一些高级内容。它是高级的,但不用担心,语义非常简单!

多个过滤器

你已经知道如何运行多个过滤器:管道符号 '|'。

'filter1|filter2|filter3'

过滤器的参数

所有冒号后面的位置参数,由逗号分隔,能有多简单?

'filter1:arg1,arg2,arg3'

如果你是程序员,你会知道位置参数的预期内容。那就是你的线索。

验证过滤器的自定义错误消息

如果数据不符合过滤器,验证过滤器会发出默认错误消息。如果你不喜欢默认消息,请创建自己的!在参数之后,放一个分号,然后开始你的自定义错误消息,用单引号或双引号。

'filter1:arg1,arg2;"My very own validation error message!"'
'filter2;\'And I\'ll change this one\'s too!\''

注意filter2没有参数,所以不需要冒号。如果错误消息本身不包含任何特殊字符,如单引号、双引号、冒号或分号,那么你可能甚至不需要加引号!

带有特殊标签的自定义错误消息

如果你喜欢自定义错误消息,你会更喜欢这个。在验证错误消息中,{field}{value}{filter}{args}{arg1} ... {argn} 都是特殊标签。

'filter1:arg1,arg2;"{field} with value {value} failed filter {filter} with attributes {args}"'
'filter2:arg1,arg2;"Maybe {field} didn't like {filter} with that parameter {arg2}"'

为了好玩,假设验证过滤器被命名为 'wildfur',参数为 'yellow,striped'。假设它运行的字段是 'animal',其标签为 'Animal'(可以是自动设置或显式使用 'label' 键)且字段的值为 'cheetah'。

'wildfur:yellow,striped;"{field} with value {value} may not have liked {filter} with attributes {args}, especially {arg2}"'

将发出错误消息

'Animal with value cheetah may not have liked wildfur with attributes yellow, striped, especially striped'

注释单个过滤器

只需用一个斜杠注释掉一个过滤器,以便它不运行。我保证这将非常有用,特别是在调试时。

'/filter1:arg1f1;"This filter will not run"|filter2:arg1f2;"This filter will run"'

跳过过滤器块

在过滤器列表中使用特殊关键字 'skip'。

'filter1|skip|filter2:;"Skipping this and all after"|filter3:;"Skipping this too"'
'filter1|skip:all|filter2:;"Skipping this and all after"|filter3:;"Skipping this too"'
'filter1:;"Will run"|skip:2|filter2:"Skipping first"|filter3:;"Skipping second"|filter4:;"Will run"'

skipskip:all 意思相同,随便你用哪个。

流行过滤器别名

一些流行的过滤器和一些参数有别名,因为不同的程序员以不同的名称记住它们,这就是你看到的编程怪癖。

  • alphabetalphabetic 相同
  • booleanbool 相同
  • integerint 相同
  • numericnumnumber 相同
  • stringstr 相同
    此列表将根据流行反馈进行更新。

过滤器大全

清理过滤器

  • basichtmltags 删除所有HTML标签,除了基本标签如 <a><b><blockquote><br><code><dd><dl><em><hr><h1><h2><h3><h4><h5><h6><i><img><label><li><p><span><strong><sub><sup><ul>
  • email 从电子邮件ID中删除所有非法字符。
  • float 从浮点数中删除所有非法字符。
  • htmlencode 将HTML字符转换为它们的HTML实体,例如,将 & 转换为 &#38;,将 ' 转换为 &#39;,将 " 转换为 &#34;,将 < 转换为 &#60;,将 > 转换为 &#62;

验证过滤器

详细文档正在编制中,但到目前为止已经足够让你轻松开始!PHP类已准备好投入生产。