tobento/service-sanitizer

轻松清理数据。

1.0.0 2021-06-30 15:20 UTC

This package is auto-updated.

Last update: 2024-09-29 05:56:41 UTC


README

清理服务提供了一种轻松清理用户输入的方法。

目录

入门

运行以下命令添加清理服务的最新版本。

composer require tobento/service-sanitizer

要求

  • PHP 8.0 或更高版本

亮点

  • 框架无关,适用于任何项目
  • 解耦设计
  • 可扩展
  • 支持嵌套值
  • 自定义过滤器解析

简单示例

以下是一个如何使用清理服务的简单示例。

use Tobento\Service\Sanitizer\Sanitizer;

$sanitizer = new Sanitizer();

// sanitize a single value.
$sanitized = $sanitizer->sanitizing('<p>lorem ipsum</p>', 'cast:string|stripTags|ucwords');

// sanitize multiple values.
$sanitized = $sanitizer->sanitize(
    [
        'name' => 'Thomas',
        'birthday' => '1982-10-30',
        'description' => 'Lorem ipsum',
    ],
    [
        'name' => 'cast:string',
        'birthday' => 'date:Y-m-d:d.m.Y',
        'description' => 'cast:string|stripTags',
    ]
);

文档

清理

单个值

轻松清理单个值。

use Tobento\Service\Sanitizer\Sanitizer;

$sanitizer = new Sanitizer();

$sanitized = $sanitizer->sanitizing('<p>lorem ipsum</p>', 'stripTags|ucwords');

var_dump($sanitized); // string(11) "Lorem Ipsum"

多个值

清理多个值。

use Tobento\Service\Sanitizer\Sanitizer;

$sanitizer = new Sanitizer();

$sanitized = $sanitizer->sanitize(
    [
        'name' => 'Thomas',
        'birthday' => '1982-10-30',
        'description' => 'Lorem ipsum',
    ],
    [
        'name' => 'cast:string',
        'birthday' => 'date:Y-m-d:d.m.Y',
        'description' => 'cast:string|stripTags',
    ]
);

/*Array
(
    [name] => Thomas
    [birthday] => 30.10.1982
    [description] => Lorem ipsum
)*/

嵌套值

如果传入的值包含“嵌套”数据,您可以在过滤器中使用“点”语法指定这些属性

use Tobento\Service\Sanitizer\Sanitizer;

$sanitizer = new Sanitizer();

$sanitized = $sanitizer->sanitize(
    [
        'title' => 'Title',
        'author' => [
            'name' => 'Tom',
            'description' => 'Lorem ipsum',
        ],
    ],
    [
        'name' => 'cast:string',
        'author.name' => 'cast:string',
        'author.description' => 'cast:string|stripTags',
    ]
);

使用数组作为过滤器

根据 FiltersParsers 实现,您可能需要以数组的形式设置过滤器,因为某些参数可能需要解析符号,如“:”。

use Tobento\Service\Sanitizer\Sanitizer;

$sanitizer = new Sanitizer();

$sanitized = $sanitizer->sanitizing(
    '1982-10-30T19:30',
    [
        'date' => ['Y-m-d', 'Y.m.d H:i']
    ]
);

var_dump($sanitized); // string(11) "30.10.1982 19:30"

严格清理

如果使用严格清理,即使数据不存在,也会应用过滤器。

use Tobento\Service\Sanitizer\Sanitizer;

$sanitizer = new Sanitizer();

$sanitized = $sanitizer->sanitize(
    [
        'name' => 'Thomas',
    ],
    [
        'age' => 'cast:int:21',
    ],
    strictSanitation: true,
);

/*Array
(
    [name] => Thomas
    [age] => 21
)*/

仅清理数据

有时可能需要仅获取清理后的数据

use Tobento\Service\Sanitizer\Sanitizer;

$sanitizer = new Sanitizer();

$sanitized = $sanitizer->sanitize(
    [
        'name' => 'Thomas',
    ],
    [
        'age' => 'cast:int:21',
    ],
    strictSanitation: true,
    returnSanitizedOnly: true,
);

/*Array
(
    [age] => 21
)*/

$sanitized = $sanitizer->sanitize(
    [
        'name' => 'Thomas',
    ],
    [
        'age' => 'cast:int:21',
    ],
    strictSanitation: false,
    returnSanitizedOnly: true,
);

/*Array()*/

过滤

默认过滤器

以下是一些开箱即用的过滤器

⚠️ 一些过滤器(如 stripTags)如果类型不是字符串,则返回原始值。因此,您可能需要添加 cast:string 过滤器。

自定义默认过滤器

如果您想设置自己的默认过滤器,可以按以下方式操作

use Tobento\Service\Sanitizer\Sanitizer;
use Tobento\Service\Sanitizer\SanitizerInterface;
use Tobento\Service\Sanitizer\FiltersInterface;

class CustomDefaultFilters implements FiltersInterface
{
    /**
     * Add the filters to the sanitizer.
     *
     * @param SanitizerInterface $sanitizer
     * @return void
     */
    public function addFilters(SanitizerInterface $sanitizer): void
    {
        $sanitizer->addFilter('cast', new \Tobento\Service\Sanitizer\Filter\Cast());        
    }    
}

$sanitizer = new Sanitizer(new CustomDefaultFilters());

添加过滤器

您可以通过以下方式添加自己的过滤器。如果相同的过滤器键已经存在,它将覆盖该过滤器。

use Tobento\Service\Sanitizer\Sanitizer;
use Tobento\Service\Sanitizer\FilterInterface;

$sanitizer = new Sanitizer();

// By a callable.
$sanitizer->addFilter('trim', function(mixed $value, array $parameters): mixed
{
    return is_string($value) ? trim($value) : $value;
});

// By a class implementing the FilterInterface.
class TrimFilter implements FilterInterface
{    
    /**
     * Apply the filter.
     * 
     * @param mixed $value The value to sanitize
     * @param array $parameters The parameters set on the sanitation 'filter:foo:bar'
     *
     * @throws FilterException If filter cannot handle sanitation
     *
     * @return mixed The sanitized value
     */
    public function apply(mixed $value, array $parameters = []): mixed
    {
        return is_string($value) ? trim($value) : $value;
    }
}

$sanitizer->addFilter('trim', new TrimFilter());

关于 FilterIf 的说明

"filterIf" 过滤器仅在值匹配给定的条件时应用过滤器。

use Tobento\Service\Sanitizer\Sanitizer;

$sanitizer = new Sanitizer();

$sanitized = $sanitizer->sanitize(
    [
        'country' => 'CH',
        'phone' => '+41 76 123 45 67',
    ],
    [
        // filter phone only if country value is "CH"
        'phone' => 'filterIf:country:CH|digit',
    ],
    returnSanitizedOnly: true,
);

var_dump($sanitized);
// array(1) { ["phone"]=> string(11) "41761234567" }

您可以通过扩展 FilterIf 类轻松添加更多 FilterIf 条件

use Tobento\Service\Sanitizer\Sanitizer;
use Tobento\Service\Sanitizer\Filter\FilterIf;
use Tobento\Service\Collection\Collection;

// Filter only if the attributes defined are present.
class FilterIfPresent extends FilterIf
{    
    /**
     * Apply the filter.
     * 
     * @param mixed $value The value to sanitize
     * @param array $parameters The parameters set on the sanitation 'filter:foo:bar'
     *
     * @throws FilterException If filter cannot handle sanitation
     *
     * @return mixed The sanitized value
     */
    public function apply(mixed $value, array $parameters = []): mixed
    {
        // extract value and data.
        [$value, $data] = $value;
        
        if (! $data instanceof Collection)
        {
            return false;
        }
        
        return $data->has($parameters);
    }
}

$sanitizer = new Sanitizer();
$sanitizer->addFilter('filterIfPresent', new FilterIfPresent());

$sanitized = $sanitizer->sanitize(
    [
        'country' => 'CH',
        'locale' => 'de-CH',
        'phone' => '+41 76 123 45 67',
    ],
    [
        // filter phone only if country and locale is present.
        'phone' => 'filterIfPresent:country:locale|digit',
    ]
);

/*Array
(
    [country] => CH
    [locale] => de-CH
    [phone] => 41761234567
)*/

解析过滤器

您可以更改清理时解析过滤器的行为。

use Tobento\Service\Sanitizer\Sanitizer;
use Tobento\Service\Sanitizer\FiltersParserInterface;
use Tobento\Service\Sanitizer\ParsedFilter;

class CustomParser implements FiltersParserInterface
{    
    /**
     * Parses the filters.
     * 
     * @param string|array
     * @return array The parsed filters [ParsedFilter, ...]
     */
    public function parse(string|array $filters): array
    {
        // do your parsing strategy
        $parsedFilters = [];
        
        return $parsedFilters;
    }
}

$sanitizer = new Sanitizer(filtersParser: new CustomParser());

致谢