mizmoz / validate
受React Prop Types启发的验证
Requires
- php: >=8.3
- ext-intl: >=1.1
- ext-json: >=1.2
- guzzlehttp/guzzle: ^7.9
- symfony/console: ^7.0
Requires (Dev)
- mockery/mockery: ^1.4
- phpstan/phpstan: ^1.12
- phpunit/phpunit: ^9.5
README
为PHP 7提供的验证,旨在减少冗余。
随着时间的推移,我们使用过很多不同的验证库,但我对它们都不甚满意。
主要目标是创建一个可以处理复杂项、解析它们并生成自身良好描述的验证器。梦想是创建一个可以处理REST API数据、向用户发送有用的错误消息以及端点的良好描述的验证器。这将是Mizmoz API的界面。
目录
入门
Composer安装
API其实非常新,很可能会有所变化。
composer require mizmoz/validate
保持资源更新
如果你使用IsEmailDisposable验证器,请确保你使用的是最新的可丢弃电子邮件主机名列表。
最佳实践是创建一个cron作业,执行以下更新。
php bin/mizmoz update
在资源文件夹中查看示例cron文件,应放置在/etc/cron.d。
基本验证
Validate::isString()->validate('Hello there!'); // true Validate::isObject()->validate(new DateTime); // true Validate::isArray()->validate([]); // true Validate::isArray()->validate(new ObjectWithToArray); // true Validate::isOneOf(['on', 'off'])->validate('on'); // true Validate::isOneOf(['on', 'off'])->validate('oops'); // false // Validate a value and return it's object $result = Validate::isObjectOfType(DateTime::class)->validate('2016-01-01 00:00:00'); $result->isValid(); // true $result->getValue(); // DateTime 2016-01-01 00:00:00
将验证器解析为新值
$result = Validate::isSame('me') ->toValue(\User::current()->userId) ->validate($userId); // get the user id $userId = $result->getValue();
更复杂和有用的示例
// Validate a set of items $result = Validate::set([ 'name' => Validate::isString() ->setDescription('Subscriber name') ->isRequired(), 'email' => Validate::isEmail() ->isRequired(), 'sendNewsletter' => Validate::isBoolean() ->setDescription('Subscribe the email address to the newsletter?') ->setDefault(false) ])->validate($_POST); // Get the sanitised data as an array. $values = $result->getValue();
验证ACL
虽然目前没有ACL验证器(它们可能以后会提供)。可以在你的应用程序中返回或抛出异常。这样,你可以使用一组标准的异常来处理ACL失败。例如,我们在API上使用验证,并捕获AclException来显示错误消息。
// Add custom validator ValidateFactory::setHelper('aclOwner', function () { // add your custom validator return new IsOwner(); }); Validate::aclAuthenticated(\User::current())->validate(\User::get(1));
测试
可以使用ValidatorFactory::mock()方法来模拟任何验证器或解析器。
模拟非常简单,只需通过调用模拟对象的方法来设置返回的Result对象。
# Setup the Mock of isString $mock = ValidatorFactory::mock('isString') ->valid(false) ->value('fail-value') ->message('boo'); Validator::isString()->validate('hello')->isValid(); // false as we've overriden the result # Reset the container ValidatorFactory::unMock('isString'); # ... or using the original mock $mock->unMock(); # You can also make a mock go away after it's called by adding `once()` when setting it up ValidatorFactory::mock('isString') // ... extra setup ->once();
获取传递给模拟对象参数
# return an array with the param names and the called method either __constructor, validate or resolve $mock->getCallArguments();
验证器
IsArray
检查值是否为数组
(new IsArray()) ->validate([1, 2, 3]); // true
IsArrayOf
检查数组是否只包含提供的值。对于允许多个值的枚举很有用。对于只有一个值,设置IsOneOf
$validate = (new IsArrayOf(['yes', 'no', 'maybe'])); $validate->validate(['yes']); // pass $validate->validate(['no']); // pass $validate->validate(['yes', 'no']); // pass $validate->validate(['definitely']); // fail
IsArrayOfShape
与IsShape相同,但$value必须是数组。
IsArrayOfType
检查数组是否只包含特定类型的项
针对单个类型进行检查
$validate = (new IsArrayOfType( new IsString() )); $validate->validate(['Hello']); // pass $validate->validate([1, 'World']); // fail
针对多个类型进行检查
$validate = (new IsArrayOfType([ new IsString(), new IsInteger(), ])); $validate->validate(['Hello']); // pass $validate->validate([1, 'World']); // pass
IsBoolean
检查值是否为布尔类型,即1、'1'、true、'true'、0、'0'、false、'false'。
(new IsBoolean()) ->validate(true); // true
IsDate
检查值是否是格式正确的有效日期。
$options
string format- 值期望的日期格式bool setValueToDateTime- 当日期有效时,将值从结果设置到值。bool strict- 使用严格模式将强制空字符串失败
(new IsDate()) ->validate('2016-01-01'); // true (new IsDate(['format' => 'd/m/Y'])) ->validate('01/01/2016'); // true
IsEmailDisposable
检查值是否是类似guerillamail.com的可丢弃电子邮件地址
(new IsEmailDisposable()) ->validate('bob@guerillamail.com'); // true
IsEmail
检查值是否是有效的电子邮件地址
(new IsEmail()) ->validate('support@mizmoz.com'); // true
不允许可丢弃电子邮件地址
(new IsEmail(['allowDisposable' => false]))
IsFilter
过滤器是一个很酷的字符串解析辅助工具。
基本哈希标签及其用法示例
我们使用过滤器将列名映射到状态等事物上。只支持@tag和#tag,其他任何内容都将作为纯文本返回过滤器键中。
$validate = new IsFilter([ '#active|#deleted' => 'userStatus' ]); $result = $validate->validate('#deleted')->getValue(); // returns ['userStatus' => ['delete'], 'filter' => ''] $model = User::create(); foreach ($result as $column => $value) { // we have some magic attached to our models for filtering also but you get the idea of how this can be used ;) $model->where($column, $value); } $model->fetch();
特殊的:isInteger标记
$validate = new IsFilter([ '@:isInteger' => 'userId' ]); $result = $validate->validate('@123 @456')->getValue(); // returns returns ['userId' => [123, 456], 'filter' => '']
过滤值中删除了所有标签
$validate = new IsFilter([ '#subscribed' => 'userStatus' ]); $result = $validate->validate('Bob')->getValue(); // returns ['filter' => 'Bob'] // or with tags $result = $validate->validate('Bob #subscribed')->getValue(); // returns ['userStatus' => ['subscribed'], 'filter' => 'Bob']
当没有标签时使用*作为默认标签
// active is marked as the default $validate = new IsFilter([ '#active*|#inactive' => 'status' ]); $validate->validate('')->getValue(); // returns ['status' => ['active']] // Or with a filter $validate->validate('Bob')->getValue(); // returns ['status' => ['active'], 'filter' => 'Bob']
默认标签适用于定义的组,因此您可以拥有其他没有默认值的标签
// active is marked as the default $validate = new IsFilter([ '#active*|#inactive' => 'status', '#admin|#user' => 'role', ]); $validate->validate('')->getValue(); // returns ['status' => ['active']] // Or with a tag $validate->validate('#admin')->getValue(); // returns ['status' => ['active'], 'role' => ['admin']]
IsInteger
检查值是否为整数
bool $strict - 设置为严格模式以只允许整数,不允许数字字符串或浮点数。
(new IsInteger()) ->validate(1); // valid
IsNumeric
检查值是否为数字
(new IsNumeric()) ->validate(1); // valid (new IsNumeric()) ->validate('100'); // valid
IsObject
IsOneOf
IsOneOfType
IsReCaptcha
验证reCAPTCHA响应
(new IsReCaptcha($secret)) ->validate($response);
IsRequired
IsSame
IsShape
检查值是否具有特定的形状,有时用例子解释会更简单...
(new IsShape([ 'name' => new IsString(), 'age' => new IsInteger(), ]))->validate([ 'name' => 'Bob', 'age' => 45, ]); // valid
形状可以嵌套以验证形状的形状。
使用Validate::set()提供辅助函数以返回形状的优美描述。
$validate = Validate::set([ 'name' => Validate::isString() ->setDescription('Full name') ->isRequired(), ]); // return an array describing the set / shape. $validate->getDescription();
IsString
检查值是否为字符串
(new IsString) ->validate('Hello world'); // valid
路线图
待办事项列表
- 正式化API
- OpenAPI格式的可选描述:[https://github.com/OAI/OpenAPI-Specification](https://github.com/OAI/OpenAPI-Specification)
- 将验证器作为ReactJS组件创建。从Chain解析描述以形成组件。
- 为所有剩余的验证器添加文档...这里列出的验证器还有很多,所以请务必查看src/Validator目录。
- 添加更多验证器!
任务
- 为isOneOfType创建描述
通用
允许正匹配或负匹配。可能如下所示
// Positive match Validate::is()->email(); // Negative match Validate::not()->email();
验证器
IsPassword
检查字符串是否满足密码的要求。
- 最小长度
- 大写字母
- 小写字母
- 特殊字符
- 数字
解析器
ToHash
使用各种技术创建给定数据的散列。MD5、SHA1、password_hash等。
生成API发布版本
在Mizmoz,我们已使用验证器链在JSON中生成我们的API模式。
下一步将是通过比较新旧API端点来创建新版本或发布。这将使我们能够为每个更改创建离散的版本,并有助于通过突出显示每个更改来编制文档。我们甚至可以更进一步,当默认值等更改时突出显示API的破坏性更改。