49.垃圾内容检测机制(一)
- 本系列文章为
laracasts.com
的系列视频教程——Let's Build A Forum with Laravel and TDD 的学习笔记。若喜欢该系列视频,可去该网站订阅后下载该系列视频, 支持正版 ;- 视频源码地址:github.com/laracasts/Lets-Build-a-...;
- 本项目为一个 forum(论坛)项目,与本站的第二本实战教程 《Laravel 教程 - Web 开发实战进阶》 类似,可互相参照。
本节说明
- 对应视频教程第 49 小节:Spam Detection
本节内容
在开始本节内容之前,我们先来完成应该在上一节完成的工作:运行全部测试。
测试报错,因为我们需要进行以下修改:
forum\resources\views\threads\index.blade.php
.
.
<h4 class="flex">
<a href="{{ $thread->path() }}">
@if(auth()->check() && $thread->hasUpdatesFor(auth()->user()))
<strong>
{{ $thread->title }}
</strong>
@else
{{ $thread->title }}
@endif
</a>
</h4>
.
.
在上一节中,我们使用了$thread->hasUpdatesFor(auth()->user())
。但是我们忘记考虑未登录用户的情形,所以产生了报错。修复后再次运行全部测试:
现在正式开始本节内容。本节我们将开始构建一系列垃圾探测器,用来过滤垃圾回复、话题等内容。对于一个论坛而言,这些几乎是不可避免的问题,我们将从关键字检测开始。首先我们新建一个测试:
forum\tests\Feature\ParticipateInForumTest.php
.
.
/** @test */
public function replies_contain_spam_may_not_be_created()
{
$this->signIn();
$thread = create('App\Thread');
$reply = make('App\Reply',[
'body' => 'something forbidden'
]);
$this->expectException(\Exception::class);
$this->post($thread->path() . '/replies',$reply->toArray());
}
}
为了让测试通过,我们 Hard Codeing 一下:
forum\app\Http\Controllers\RepliesController.php
.
.
public function store($channelId,Thread $thread)
{
$this->validate(request(),['body' => 'required']);
if(stripos(request('body'),'something forbidden') !== false){
throw new \Exception('Your reply contains spam.');
}
$reply = $thread->addReply([
'body' => request('body'),
'user_id' => auth()->id(),
]);
if(request()->expectsJson()){
return $reply->load('owner');
}
return back()->with('flash','Your reply has been left.');
}
.
.
运行测试:
虽然测试通过了,但是我们都知道以上的代码只是权宜之计,因为我们的关键词检测必然要求是可扩展的。接下来我们来新建一个测试文件:
forum\tests\Unit\SpamTest.php
<?php
namespace Tests\Unit;
use Tests\TestCase;
use App\Spam;
class SpamTest extends TestCase
{
/** @test */
public function it_validates_spam()
{
$spam = new Spam();
$this->assertFalse($spam->detect('Innocent reply here.'));
}
}
我们建立的第一个测试十分简单,它仅仅测试是否会进行关键词检测。为了通过测试,我们还需要Spam
类文件以及detect
方法:
forum\app\Spam.php
<?php
namespace App;
class Spam
{
public function detect($body)
{
$this->detectInvalidKeywords($body);
return false;
}
public function detectInvalidKeywords($body)
{
$invalidKeywords = [
'something forbidden'
];
foreach ($invalidKeywords as $invalidKeyword){
if(stripos($body,$invalidKeyword) !== false){
throw new \Exception('Your reply contains spam.');
}
}
}
}
在detect
中,我们调用detectInvalidKeywords()
方法检测关键词:如果有配置好的关键词,则抛出异常;否则,返回false
。我们来测试一下:
现在我们可以修改检测关键词的代码:
forum\app\Http\Controllers\RepliesController.php
.
.
public function store($channelId,Thread $thread,Spam $spam)
{
$this->validate(request(),['body' => 'required']);
$spam->detect(request('body'));
$reply = $thread->addReply([
'body' => request('body'),
'user_id' => auth()->id(),
]);
if(request()->expectsJson()){
return $reply->load('owner');
}
return back()->with('flash','Your reply has been left.');
}
.
.
注:别忘了顶部
Spam
的引用。
再次运行一下我们上一个测试:
测试通过。我们将在下一节进行一些更深入地探讨。