tobento/app-spam

应用垃圾邮件防护。

1.0.0 2024-08-07 13:55 UTC

This package is auto-updated.

Last update: 2024-09-07 14:07:04 UTC


README

表单垃圾邮件防护,使用验证器检测垃圾邮件。

目录

入门

运行此命令以添加运行中的应用垃圾邮件项目的最新版本。

composer require tobento/app-spam

要求

  • PHP 8.0 或更高版本

文档

应用

如果您使用的是骨架,请查看 App Skeleton

您还可以查看 App 以了解更多关于该应用的信息。

垃圾邮件启动

垃圾邮件启动执行以下操作:

  • 安装和加载垃圾邮件配置文件
  • 实现垃圾邮件接口
use Tobento\App\AppFactory;
use Tobento\App\Spam\DetectorsInterface;

// Create the app
$app = (new AppFactory())->createApp();

// Add directories:
$app->dirs()
    ->dir(realpath(__DIR__.'/../'), 'root')
    ->dir(realpath(__DIR__.'/../app/'), 'app')
    ->dir($app->dir('app').'config', 'config', group: 'config')
    ->dir($app->dir('root').'public', 'public')
    ->dir($app->dir('root').'vendor', 'vendor');

// Adding boots:
$app->boot(\Tobento\App\Spam\Boot\Spam::class);
$app->booting();

// Implemented interfaces:
$detectors = $app->get(DetectorsInterface::class);

// Run the app
$app->run();

垃圾邮件配置

垃圾邮件配置位于默认 App Skeleton 配置位置 app/config/spam.php 文件中,您可以在其中指定应用程序的检测器。

基本用法

渲染检测器

在您的视图文件中,使用 spamDetector 视图宏在表单上渲染检测器。

<form>
    <!-- Using the default -->
    <?= $view->spamDetector()->render($view) ?>
    
    <!-- Or using a specific detector -->
    <?= $view->spamDetector('register')->render($view) ?>
</form>

查看 App View 以了解更多信息。

使用工厂

或者,您也可以指定一个检测器工厂

use Tobento\App\Spam\Factory;

<form>
    <?= $view->spamDetector(new Factory\Honeypot(inputName: 'name'))->render($view) ?>
</form>

查看 可用工厂 以获取其可用检测器工厂的信息。

检测垃圾邮件

为了保护您的表单免受垃圾邮件攻击,请将 ProtectAgainstSpam 中间件添加到您的表单指向的路由中。

use Tobento\App\AppFactory;
use Tobento\App\Spam\Middleware\ProtectAgainstSpam;

$app = (new AppFactory())->createApp();

// Add directories:
$app->dirs()
    ->dir(realpath(__DIR__.'/../'), 'root')
    ->dir(realpath(__DIR__.'/../app/'), 'app')
    ->dir($app->dir('app').'config', 'config', group: 'config')
    ->dir($app->dir('root').'public', 'public')
    ->dir($app->dir('root').'vendor', 'vendor');

// Adding boots:
$app->boot(\Tobento\App\View\Boot\View::class);
$app->boot(\Tobento\App\View\Boot\Form::class);
$app->boot(\Tobento\App\Spam\Boot\Spam::class);
$app->booting();

// Routes:
$app->route('POST', 'register', function() {
    // being spam protected!
    return 'response';
})->middleware([
    ProtectAgainstSpam::class,
    
    // you may specify a specific detector other than the default:
    'detector' => 'register',
    
    // or you may specify a detector factory:
    'detector' => new Factory\Composite(
        new Factory\Named('default'),
        new Factory\WithoutUrl(inputNames: ['message']),
    ),
]);

// Run the app:
$app->run();

查看 可用工厂 以获取其可用检测器工厂的信息。

可用检测器

组合检测器

可以使用 Composite 检测器来组合检测器

use Tobento\App\Spam\Detector;

$detector = new Detector\Composite(
    'default',
    new Detector\Honeypot(name: 'default', inputName: 'hp'),
);

EmailDomain 检测器

EmailDomain 检测器,从指定的黑名单中检测垃圾邮件电子邮件域名。

use Tobento\App\Spam\Detector;

$detector = new Detector\EmailDomain(
    name: 'default',
    inputName: 'email',
    blacklist: ['mail.ru'], // Email domains considered as spam.
    whitelist: ['gmail.com'], // Email domains not considered as spam, exludes from blacklist.
);

您可以考虑创建一个工厂,从文件或其他来源导入被列入黑名单的电子邮件域名。

EmailRemote 检测器

EmailRemote 检测器,使用 PHP 内置函数 getmxrr()checkdnsrr()fsockopen() 来验证电子邮件域名。

use Tobento\App\Spam\Detector;

$detector = new Detector\EmailRemote(
    name: 'default',
    inputName: 'email',
    checkDNS: true,
    checkSMTP: true,
    checkMX: true,
    timeoutInSeconds: 5,
);

Honeypot 检测器

Honeypot 检测器,渲染一个不应包含值的不可见输入元素。如果机器人填写此输入,或从请求中删除输入,则请求将被检测为垃圾邮件。

use Tobento\App\Spam\Detector;

$detector = new Detector\Honeypot(
    name: 'default',
    inputName: 'hp',
);

MinTimePassed 检测器

MinTimePassed 检测器,渲染一个包含时间(作为加密值)的不可见输入元素。如果表单提交速度超过定义的 milliseconds,或从请求中删除输入,则请求将被检测为垃圾邮件。

use Psr\Clock\ClockInterface;
use Tobento\App\Spam\Detector;
use Tobento\Service\Encryption\EncrypterInterface;

$detector = new Detector\MinTimePassed(
    encrypter: $encrypter, // EncrypterInterface
    clock: $clock, // ClockInterface
    name: 'default',
    inputName: 'mtp',
    milliseconds: 1000,
);

您可以通过查看 App Encryption 了解更多相关信息。

Null 检测器

NullDetector 检测器不会将任何请求检测为垃圾邮件。

use Tobento\App\Spam\Detector;

$detector = new Detector\NullDetector(name: 'null');

WithoutUrl 检测器

如果定义的 inputNames 包含 URL,则 WithoutUrl 检测器会将请求检测为垃圾邮件。

use Tobento\App\Spam\Detector;

$detector = new Detector\WithoutUrl(
    name: 'default',
    inputNames: ['message'],
);

可用工厂

组合工厂

Composite 工厂创建一个 组合检测器

use Tobento\App\Spam\Factory;

$factory = new Factory\Composite(
    new Factory\Honeypot(),
);

EmailRemote 工厂

EmailRemote 工厂创建了一个 EmailRemote 检测器

use Tobento\App\Spam\Factory;

$factory = new Factory\EmailRemote(
    inputName: 'email',
    checkDNS: true,
    checkSMTP: true,
    checkMX: true,
    timeoutInSeconds: 5,
);

Honeypot 工厂

Honeypot 工厂创建了一个 Honeypot 检测器

use Tobento\App\Spam\Factory;

$factory = new Factory\Honeypot(
    // you may change the default input name:
    inputName: 'hp',
);

MinTimePassed 工厂

MinTimePassed 工厂创建了一个 MinTimePassed 检测器

use Tobento\App\Spam\Factory;

$factory = new Factory\MinTimePassed(
    // you may change the default input name:
    inputName: 'mtp',
    
    // you may change the default input name:
    milliseconds: 1000,
    
    // you may change the enrypter to be used, otherwise the default is used:
    encrypterName: 'spam',
);

命名工厂

可以使用 Named 工厂从命名检测器创建一个检测器

use Tobento\App\Spam\Factory;

$factory = new Factory\Named(
    detector: 'default',
);

查看 注册命名检测器 部分以了解更多信息。

WithoutUrl 工厂

WithoutUrl 工厂创建了一个 WithoutUrl 检测器

use Tobento\App\Spam\Factory;

$factory = new Factory\WithoutUrl(
    inputNames: ['message'],
);

注册命名检测器

通过配置注册命名检测器

您可以在配置文件 app/config/spam.php 中注册命名检测器

use Tobento\App\Spam\Detector;
use Tobento\App\Spam\DetectorInterface;
use Tobento\App\Spam\Factory;

return [
    // ...
    'detectors' => [
        // using a factory:
        'default' => new Factory\Composite(
            new Factory\Honeypot(inputName: 'hp'),
            new Factory\MinTime(milliseconds: 1000),
        ),
        
        // using a closure:
        'secondary' => static function (string $name): DetectorInterface {
            return new Detector\Composite(
                new Detector\Honeypot(name: $name, inputName: 'hp'),
            );
        },
        
        // using a class instance:
        'null' => new Detector\NullDetector(name: 'null'),
    ],
];

通过引导注册命名检测器

use Tobento\App\Boot;
use Tobento\App\Spam\Boot\Spam;
use Tobento\App\Spam\Detector;
use Tobento\App\Spam\DetectorFactoryInterface;
use Tobento\App\Spam\DetectorsInterface;
use Tobento\App\Spam\Factory;

class SpamDetectorsBoot extends Boot
{
    public const BOOT = [
        // you may ensure the spam boot.
        Spam::class,
    ];
    
    public function boot()
    {
        // you may use the app on method to add only if requested:
        $app->on(
            DetectorsInterface::class,
            static function(DetectorsInterface $detectors) {
                $detectors->add(
                    name: 'null',
                    detector: new Detector\NullDetector(), // DetectorInterface|DetectorFactoryInterface
                );
            }
        );
    }
}

手动检测垃圾邮件

引导 spam 后,将 DetectorsInterface 注入任何服务或控制器。

use Psr\Http\Message\ServerRequestInterface;
use Tobento\App\Spam\DetectorsInterface;
use Tobento\App\Spam\Exception\SpamDetectedException;

class SpamService
{
    public function isSpam(ServerRequestInterface $request, DetectorsInterface $detectors): bool
    {
        try {
            $detectors->get('name')->detect($request);
        } catch (SpamDetectedException $e) {
            return true;
        }
        
        return false;
    }
}

从值检测垃圾邮件

use Psr\Http\Message\ServerRequestInterface;
use Tobento\App\Spam\DetectorsInterface;
use Tobento\App\Spam\Exception\SpamDetectedException;

class SpamService
{
    public function isSpam(mixed $value, DetectorsInterface $detectors): bool
    {
        try {
            $detectors->get('name')->detectFromValue($value);
        } catch (SpamDetectedException $e) {
            return true;
        }
        
        return false;
    }
}

使用验证器检测垃圾邮件

要求

需要 App Validation

composer require tobento/app-validation

此外,如果您想支持类似于 spam:detector_name 的字符串定义规则,可以引导 ValidationSpamRule 引导

use Tobento\App\AppFactory;

// Create the app
$app = (new AppFactory())->createApp();

// Adding boots
$app->boot(\Tobento\App\Spam\Boot\ValidationSpamRule::class);
$app->boot(\Tobento\App\Spam\Boot\Spam::class);

// Run the app
$app->run();

否则,您需要引导验证器引导

use Tobento\App\AppFactory;

// Create the app
$app = (new AppFactory())->createApp();

// Adding boots
$app->boot(\Tobento\App\Validation\Boot\Validator::class);
$app->boot(\Tobento\App\Spam\Boot\Spam::class);

// Run the app
$app->run();

垃圾邮件规则

use Tobento\App\Spam\Factory;
use Tobento\App\Spam\Validation\SpamRule;

$validation = $validator->validating(
    value: 'foo@example.com',
    rules: [
        // using a detector name:
        new SpamRule(
            detector: 'email',
            
            // you may specify a custom error message:
            errorMessage: 'Custom error message',
        ),
        
        // using a detector factory:
        new SpamRule(detector: new Factory\Named('email')),
        
        // or if booted the ValidationSpamRule::class:
        'spam:email',
        
        // or with multiple detector names:
        'spam:emailRemote:emailDomain',
    ],
);

跳过验证

您可以使用 skipValidation 参数在某些条件下跳过验证

$validation = $validator->validating(
    value: 'foo',
    rules: [
        // skips validation:
        new SpamRule(detector: 'email', skipValidation: true),
        
        // does not skip validation:
        new SpamRule(detector: 'email', skipValidation: false),
        
        // skips validation:
        new SpamRule(detector: 'email', skipValidation: fn (mixed $value): bool => $value === 'foo'),
    ],
);

Http 垃圾邮件错误处理器启动

http 错误处理器引导执行以下操作

  • 处理 Tobento\App\Spam\Exception\SpamDetectedException::class 异常。

引导由 Spam Boot 自动加载。

use Tobento\App\AppFactory;

// Create the app
$app = (new AppFactory())->createApp();

// Adding boots
// $app->boot(\Tobento\App\Spam\Boot\HttpSpamErrorHandler::class); // not needed to boot!
$app->boot(\Tobento\App\Spam\Boot\Spam::class);

// Run the app
$app->run();

如果检测到垃圾邮件,错误处理器将返回一个 422 Unprocessable Entity HTTP 响应。

您可以为处理垃圾邮件异常以适应您的应用程序而创建一个自定义的 具有更高优先级的错误处理器,优先级为 3000,如 Tobento\App\Spam\Boot\HttpSpamErrorHandler::class 所定义。

事件

可用事件

支持的事件

简单地,安装 App Event 包。

致谢