tobento / app-spam
应用垃圾邮件防护。
Requires
- php: >=8.0
- psr/container: ^2.0
- tobento/app: ^1.0.7
- tobento/app-encryption: ^1.0
- tobento/app-http: ^1.0 || ^1.1
- tobento/app-migration: ^1.0
- tobento/app-view: ^1.0
- tobento/service-autowire: ^1.0
Requires (Dev)
- phpunit/phpunit: ^9.5
- tobento/app-event: ^1.0.1
- tobento/app-testing: ^1.0
- tobento/app-validation: ^1.0
- tobento/service-filesystem: ^1.0.5
- vimeo/psalm: ^4.0
Suggests
- tobento/app-validation: To support detecting spam using the validator
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; } }
使用验证器检测垃圾邮件
要求
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 包。