From 99f56b9aca239aeecffc47331411a1601cedab81 Mon Sep 17 00:00:00 2001 From: Arandi Lopez Date: Sun, 10 Jan 2021 22:43:22 -0600 Subject: [PATCH] New strict mode, this fixes #9 --- src/ProfaneServiceProvider.php | 19 ++++---- src/ProfaneValidator.php | 54 ++++++++++++++++------- src/Str.php | 5 ++- tests/ProfaneValidatorTest.php | 29 +++++++++++- tests/StrTest.php | 20 +++++++++ tests/Support/ProfaneValidatorBuilder.php | 6 ++- 6 files changed, 104 insertions(+), 29 deletions(-) diff --git a/src/ProfaneServiceProvider.php b/src/ProfaneServiceProvider.php index a1e70c1..181a4fd 100644 --- a/src/ProfaneServiceProvider.php +++ b/src/ProfaneServiceProvider.php @@ -10,21 +10,24 @@ class ProfaneServiceProvider extends ServiceProvider { public function boot() { - $this->loadTranslationsFrom(__DIR__.'/lang', 'laravel-profane'); + $this->loadTranslationsFrom(__DIR__ . '/lang', 'laravel-profane'); $this->publishes([ - __DIR__.'/lang' => resource_path('lang/vendor/laravel-profane'), + __DIR__ . '/lang' => resource_path('lang/vendor/laravel-profane'), ]); + // Rule for caseless content matching Validator::extend('profane', 'LaravelProfane\ProfaneValidator@validate', Lang::get('laravel-profane::validation.profane')); - Validator::replacer('profane', function ($message, $attribute, $rule, $parameters) { + Validator::replacer('profane', function ($message, $attribute) { + return str_replace(':attribute', $attribute, $message); + }); + + // Rule for caseless but strict word matching + Validator::extend('strictly_profane', 'LaravelProfane\ProfaneValidator@validateStrict', Lang::get('laravel-profane::validation.profane')); + + Validator::replacer('strictly_profane', function ($message, $attribute) { return str_replace(':attribute', $attribute, $message); }); } - - public function register() - { - // code... - } } diff --git a/src/ProfaneValidator.php b/src/ProfaneValidator.php index 5edff30..dbc1d2e 100644 --- a/src/ProfaneValidator.php +++ b/src/ProfaneValidator.php @@ -2,27 +2,19 @@ namespace LaravelProfane; -use Illuminate\Contracts\Validation\Validator; - class ProfaneValidator { /** - * [$dictionary description]. - * - * @var [type] + * @var Dictionary */ protected $dictionary; /** - * [$badwords description]. - * * @var array */ protected $badwords = []; /** - * [__construct description]. - * * @param Dictionary $dictionary [description] */ public function __construct(Dictionary $dictionary) @@ -32,25 +24,41 @@ class ProfaneValidator } /** - * Method to extends to Validator. + * Method to extends to Validation Service. * * @param string $attribute - * @param midex $value + * @param mixed $value * @param array $parameters - * @param \Illuminate\Contracts\Validation\Validator $validator [description] * * @return bool */ public function validate($attribute, $value, $parameters) { if ($parameters) { - $this->dictionary->setDictionary($parameters); - $this->badwords = $this->dictionary->getDictionary(); + $this->setDictionary($parameters); } return !$this->isProfane($value); } + /** + * Method to extends to Validation Service for strict word matching. + * + * @param string $attribute + * @param mixed $value + * @param array $parameters + * + * @return bool + */ + public function validateStrict($attribute, $value, $parameters) + { + if ($parameters) { + $this->setDictionary($parameters); + } + + return !$this->isProfane($value, true); + } + /** * Check profanity of text. * @@ -58,11 +66,23 @@ class ProfaneValidator * * @return bool */ - public function isProfane($text) + public function isProfane($text, $strict = false) { return Str::containsCaseless( - Str::removeAccent($text), - $this->badwords + $this->sanitizeText($text), + $this->badwords, + $strict ); } + + private function setDictionary($dictionaries) + { + $this->dictionary->setDictionary($dictionaries); + $this->badwords = $this->dictionary->getDictionary(); + } + + private function sanitizeText($text) + { + return Str::removeAccent(strip_tags($text)); + } } diff --git a/src/Str.php b/src/Str.php index 1a90e75..df88f0a 100644 --- a/src/Str.php +++ b/src/Str.php @@ -13,11 +13,12 @@ class Str * * @return bool */ - public static function containsCaseless($haystack, $needles) + public static function containsCaseless($haystack, $needles, $strict=false) { foreach ((array) $needles as $needle) { $needle = preg_quote($needle); - if ($needle != '' && preg_match("/$needle/iu", $haystack)) { + $regex = $strict ? "/\b$needle\b/iu" : "/$needle/iu"; + if ($needle != '' && preg_match($regex, $haystack)) { return true; } } diff --git a/tests/ProfaneValidatorTest.php b/tests/ProfaneValidatorTest.php index fa24664..95ffb7f 100644 --- a/tests/ProfaneValidatorTest.php +++ b/tests/ProfaneValidatorTest.php @@ -13,6 +13,13 @@ class ProfaneValidatorTest extends TestCase $this->assertFalse($builder->validate(['username', 'culero23', ['es']])); } + public function test_can_not_validate_a_word_with_numbers_in_strict_mode() + { + $builder = new ProfaneValidatorBuilder(); + + $this->assertTrue($builder->validate(['username', 'culero23', ['es']], true)); + } + public function test_can_validate_a_text() { $builder = new ProfaneValidatorBuilder(); @@ -38,6 +45,15 @@ class ProfaneValidatorTest extends TestCase $this->assertTrue($builder->build()->isProfane($word)); } + public function test_can_evaluate_profanity_of_a_sentence_in_strict_mode() + { + $builder = new ProfaneValidatorBuilder(); + + $word = 'fuck you if you read this'; + + $this->assertTrue($builder->build()->isProfane($word), true); + } + public function test_can_evaluate_profanity_of_a_html_string() { $builder = new ProfaneValidatorBuilder(); @@ -56,7 +72,7 @@ class ProfaneValidatorTest extends TestCase $this->assertTrue($builder->build()->isProfane($word)); } - public function test_match_exact_word() + public function test_match_content() { $builder = new ProfaneValidatorBuilder(); @@ -67,6 +83,17 @@ class ProfaneValidatorTest extends TestCase $this->assertTrue($builder->build()->isProfane('sucker96')); } + public function test_match_exact_word_in_strict_mode() + { + $builder = new ProfaneValidatorBuilder(); + + // class is a safe word + $this->assertFalse($builder->build()->isProfane('class', true)); + + // in strict mode this will pass a safe word + $this->assertFalse($builder->build()->isProfane('sucker96', true)); + } + public function test_can_validate_a_bad_word_with_accent() { $builder = new ProfaneValidatorBuilder('sk'); diff --git a/tests/StrTest.php b/tests/StrTest.php index 963e350..38c4295 100644 --- a/tests/StrTest.php +++ b/tests/StrTest.php @@ -21,6 +21,26 @@ class StrTest extends TestCase $this->assertTrue(Str::containsCaseless('Fuck! This class is so bad!', 'fUcK')); } + public function test_text_does_not_contain_match_in_strict_mode() + { + $this->assertFalse(Str::containsCaseless('This class is so bad!', 'ass', true)); + $this->assertFalse(Str::containsCaseless('Theorem Analisys', 'anal', true)); + } + + public function test_text_contains_match_in_strict_mode() + { + $this->assertTrue(Str::containsCaseless('This class is a crap!', 'crap', true)); + $this->assertFalse(Str::containsCaseless('Theorem Analisys', 'anal', true)); + $this->assertFalse(Str::containsCaseless('Sucker69', 'sucker', true)); + } + + public function test_text_contains_match_in_not_strict_mode() + { + $this->assertTrue(Str::containsCaseless('This class is so bad!', 'ass', false)); + $this->assertTrue(Str::containsCaseless('Theorem Analisys', 'anal', false)); + } + + public function test_text_contains_the_same_insensitive_match_from_string() { $this->assertTrue(Str::containsCaseless('Fuck! This class is so bad!', 'Fuck')); diff --git a/tests/Support/ProfaneValidatorBuilder.php b/tests/Support/ProfaneValidatorBuilder.php index e9f50e7..2056197 100644 --- a/tests/Support/ProfaneValidatorBuilder.php +++ b/tests/Support/ProfaneValidatorBuilder.php @@ -31,10 +31,14 @@ class ProfaneValidatorBuilder * * @return [type] [description] */ - public function validate(array $parameters) + public function validate(array $parameters, $strict = false) { list($attribute, $text, $dictionaries) = $parameters; + if ($strict) { + return $this->build()->validateStrict($attribute, $text, $dictionaries); + } + return $this->build()->validate($attribute, $text, $dictionaries); }