├── .gitignore ├── .styleci.yml ├── .travis.yml ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── composer.json ├── phpunit.xml ├── src ├── Dictionary.php ├── ProfaneServiceProvider.php ├── ProfaneValidator.php ├── Str.php ├── dict │ ├── de.php │ ├── en.php │ ├── es-cl.php │ ├── es.php │ ├── fil.php │ ├── fr-ca.php │ ├── fr.php │ ├── gr.php │ ├── id.php │ ├── it.php │ ├── ml.php │ ├── nl.php │ ├── pt-br.php │ ├── ro-md.php │ ├── ro.php │ ├── ru.php │ ├── sk.php │ ├── sr-rs.php │ └── zh-tw.php └── lang │ ├── de │ └── validation.php │ ├── en │ └── validation.php │ ├── es-cl │ └── validation.php │ ├── es │ └── validation.php │ ├── fr │ └── validation.php │ ├── gr │ └── validation.php │ ├── id │ └── validation.php │ ├── it │ └── validation.php │ ├── ml │ └── validation.php │ ├── nl │ └── validation.php │ ├── pt-br │ └── validation.php │ ├── ro-md │ └── validation.php │ ├── ro │ └── validation.php │ ├── sk │ └── validation.php │ ├── sr-rs │ └── validation.php │ └── zh-tw │ └── validation.php └── tests ├── DictionaryTest.php ├── ProfaneValidatorTest.php ├── StrTest.php ├── Support └── ProfaneValidatorBuilder.php └── TestCase.php /.gitignore: -------------------------------------------------------------------------------- 1 | vendor 2 | .idea 3 | composer.lock -------------------------------------------------------------------------------- /.styleci.yml: -------------------------------------------------------------------------------- 1 | preset: recommended 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 8.0 5 | - 7.4 6 | - 7.3 7 | - 7.2 8 | 9 | env: 10 | matrix: 11 | - COMPOSER_FLAGS="--prefer-lowest" 12 | - COMPOSER_FLAGS="" 13 | 14 | before_install: 15 | - travis_retry composer self-update 16 | 17 | install: 18 | - travis_retry composer update --prefer-source $PREFER_LOWEST 19 | 20 | script: 21 | - phpunit 22 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Hi! 2 | Thanks to contribute in this project. **Changes and contributions must be added as pull request** 3 | 4 | ## Add a new dictionary 5 | 6 | You can help to make this project better by adding a new dictionary of swear words in your native language. The dictionary file MUST follow this points: 7 | 8 | 1. It must be a `.php` file in `src/dict` 9 | 2. Its filename must be a valid language code, check [here](https://www.science.co.il/language/Locale-codes.php) 10 | 3. It must return an array with your swear words 11 | 4. You MUST use array brackets declaration instead of `array()` function. 12 | 5. Each word must be in a single line 13 | 6. Each word must be single quoted 14 | 7. Each word MUST NOT contains accents 15 | 16 | ### Example 17 | 18 | ```php 19 | 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Laravel Profanity Validator 2 | 3 | [![Latest Stable Version](https://poser.pugx.org/arandilopez/laravel-profane/v/stable)](https://packagist.org/packages/arandilopez/laravel-profane) 4 | [![Total Downloads](https://poser.pugx.org/arandilopez/laravel-profane/downloads)](https://packagist.org/packages/arandilopez/laravel-profane) 5 | [![License](https://poser.pugx.org/arandilopez/laravel-profane/license)](https://packagist.org/packages/arandilopez/laravel-profane) 6 | [![Daily Downloads](https://poser.pugx.org/arandilopez/laravel-profane/d/daily)](https://packagist.org/packages/arandilopez/laravel-profane) 7 | [![composer.lock](https://poser.pugx.org/arandilopez/laravel-profane/composerlock)](https://packagist.org/packages/arandilopez/laravel-profane) 8 | ![](https://travis-ci.org/arandilopez/laravel-profane.svg?branch=master) 9 | [![StyleCI](https://styleci.io/repos/63648834/shield?branch=master)](https://styleci.io/repos/63648834) 10 | 11 | I made this package to perform a validation for swearwords using Laravel validation service. 12 | 13 | ## Installation 14 | 15 | Install via composer 16 | 17 | ```shell 18 | composer require arandilopez/laravel-profane 19 | ``` 20 | 21 | ## Configuration 22 | 23 | Add the `ProfaneServiceProvider` class in your `config/app.php` file. 24 | 25 | ```php 26 | [ 31 | // ... 32 | LaravelProfane\ProfaneServiceProvider::class, 33 | ]; 34 | 35 | // ... 36 | ]; 37 | ``` 38 | 39 | Publish vendor lang files if you need to replace by your own. 40 | 41 | ```shell 42 | php artisan vendor:publish 43 | ``` 44 | 45 | ## Usage 46 | 47 | This package register a custom validator. You can use in your controller's `validate` function. 48 | 49 | ```php 50 | validate($request, [ 57 | 'username' => 'required|profane' 58 | ]); 59 | 60 | // ... 61 | } 62 | } 63 | ``` 64 | 65 | The validator will load the default locale in your `config/app.php` file configuration which by is `en`. **If your locale is not supported, please [post an issue for this project](https://github.com/arandilopez/laravel-profane/issues)** 66 | 67 | If you want to use others dictionaries you can pass them as parameters in the validator. 68 | 69 | ```php 70 | validate($request, [ 77 | 'username' => 'required|profane:es,en' 78 | ]); 79 | 80 | // ... 81 | } 82 | } 83 | ``` 84 | 85 | You can also send as parameter a path of a file which is a dictionary in order to replace the default dictionary or **add a new non supported locale**. 86 | 87 | ```php 88 | validate($request, [ 95 | 'username' => 'required|profane:es,en,'.resource_path('lang/fr/dict.php') 96 | ]); 97 | 98 | // ... 99 | } 100 | } 101 | ``` 102 | 103 | #### Strict validation 104 | 105 | Now you can strictly validate the exact profane word in the content. 106 | 107 | ```php 108 | validate($request, [ 115 | 'username' => 'required|strictly_profane:es,en' 116 | ]); 117 | 118 | // ... 119 | } 120 | } 121 | ``` 122 | 123 | This fixes known issues when you get a error in validation for words like `class` or `analysis`, as they include `ass` and `anal` respectively, but fails the validation for content like `sucker69`. 124 | 125 | ## Getting Help 126 | 127 | If you're stuck getting something to work, or need to report a bug, please [post an issue in the Github Issues for this project](https://github.com/arandilopez/laravel-profane/issues). 128 | 129 | ## Contributing 130 | 131 | If you're interesting in contributing code to this project, clone it by running: 132 | 133 | ```shell 134 | git clone git@github.com:arandilopez/laravel-profane.git 135 | ``` 136 | 137 | Please read the [CONTRIBUTING](CONTRIBUTING.md) file. 138 | 139 | Pull requests are welcome, but please make sure you provide unit tests to cover your changes. **You can help to add and support more locales!** 140 | 141 | _Thanks to [@dorianneto](https://github.com/dorianneto) for his contributions._ 142 | 143 | ### Supported Locales 144 | 145 | - English ( provided by [@arandilopez](https://github.com/arandilopez) ) 146 | - Spanish ( provided by [@arandilopez](https://github.com/arandilopez) and [@xDidier901](https://github.com/xDidier901)) 147 | - Italian ( provided by [@aletundo](https://github.com/aletundo) ) 148 | - Brazilian Portuguese ( provided by [@ianrodriguesbr](https://github.com/ianrodriguesbr) and [@LeonardoTeixeira](https://github.com/LeonardoTeixeira)) 149 | - Traditional Chinese ( provided by [@Nationalcat](https://github.com/Nationalcat) ) 150 | - Slovak ( provided by [@kotass](https://github.com/kotass) ) 151 | - Dutch (Netherlands) ( provided by [@Cannonb4ll](https://github.com/Cannonb4ll) and [@WouterVanmulken](https://github.com/WouterVanmulken)) 152 | - Greek ( provided by [@siokas](https://github.com/siokas) ) 153 | - Malayalam ( provided by [@abinodh](https://github.com/abinodh) ) 154 | - Russian ( provided by [@alex2sat](https://github.com/alex2sat) ) 155 | - Serbian ( provided by [@Djuki](https://github.com/Djuki) ) 156 | - Filipino ( provided by [@credocleo](https://github.com/credocleo) ) 157 | - Romanian ( provided by [@rchioreanu](https://github.com/rchioreanu) ) 158 | - Indonesian ( provided by [@rizasaputra](https://github.com/rizasaputra) ) 159 | 160 | ## License 161 | 162 | This project is open-sourced software licensed under the [MIT license](http://opensource.org/licenses/MIT). 163 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "arandilopez/laravel-profane", 3 | "description": "Laravel Profanity Valitador", 4 | "license": "MIT", 5 | "authors": [ 6 | { 7 | "name": "Arandi Lopez", 8 | "email": "arandilopez.93@gmail.com" 9 | } 10 | ], 11 | "autoload": { 12 | "psr-4": { 13 | "LaravelProfane\\": "src/", 14 | "LaravelProfaneTests\\": "tests/" 15 | } 16 | }, 17 | "minimum-stability": "stable", 18 | "require": { 19 | "illuminate/support": ">=5.2|^6.0|^7.0|^8.0" 20 | }, 21 | "require-dev": { 22 | "phpunit/phpunit": "^8.0|^8.5", 23 | "mockery/mockery": "^1.3" 24 | }, 25 | "extra": { 26 | "laravel": { 27 | "providers": ["LaravelProfane\\ProfaneServiceProvider"] 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | tests 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/Dictionary.php: -------------------------------------------------------------------------------- 1 | setDictionary($dictionary ?: $locale); 28 | } 29 | 30 | /** 31 | * [getDictionary description]. 32 | * 33 | * @return [type] [description] 34 | */ 35 | public function getDictionary() 36 | { 37 | return $this->dictionary; 38 | } 39 | 40 | /** 41 | * Set the dictionary to use. 42 | * 43 | * @param array|string $dictionary 44 | */ 45 | public function setDictionary($dictionary) 46 | { 47 | $this->dictionary = $this->readDictionary($dictionary); 48 | } 49 | 50 | /** 51 | * [readDictionary description]. 52 | * 53 | * @param [type] $dictionary [description] 54 | * 55 | * @return [type] [description] 56 | */ 57 | protected function readDictionary($dictionary) 58 | { 59 | $words = []; 60 | $baseDictPath = $this->getBaseDictPath(); 61 | if (is_array($dictionary)) { 62 | foreach ($dictionary as $file) { 63 | if (file_exists($baseDictPath.$file.'.php')) { 64 | $dict = include $baseDictPath.$file.'.php'; 65 | $words = array_merge($words, $dict); 66 | } else { 67 | // if the file isn't in the dict directory, 68 | // it's probably a custom user library 69 | $dict = include $file; 70 | $words = array_merge($words, $dict); 71 | } 72 | } 73 | // just a single string, not an array 74 | } elseif (is_string($dictionary)) { 75 | if (file_exists($baseDictPath.$dictionary.'.php')) { 76 | $dict = include $baseDictPath.$dictionary.'.php'; 77 | $words = array_merge($words, $dict); 78 | } else { 79 | if (file_exists($dictionary)) { 80 | $dict = include $dictionary; 81 | $words = array_merge($words, $dict); 82 | } // else nothing is merged 83 | } 84 | } 85 | 86 | return $words; 87 | } 88 | 89 | /** 90 | * [getBaseDictPath description]. 91 | * 92 | * @return [type] [description] 93 | */ 94 | protected function getBaseDictPath() 95 | { 96 | return property_exists($this, 'baseDictPath') ? $this->baseDictPath : __DIR__.DIRECTORY_SEPARATOR.'dict/'; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/ProfaneServiceProvider.php: -------------------------------------------------------------------------------- 1 | loadTranslationsFrom(__DIR__.'/lang', 'laravel-profane'); 14 | 15 | $this->publishes([ 16 | __DIR__.'/lang' => resource_path('lang/vendor/laravel-profane'), 17 | ]); 18 | 19 | // Rule for caseless content matching 20 | Validator::extend('profane', 'LaravelProfane\ProfaneValidator@validate', Lang::get('laravel-profane::validation.profane')); 21 | 22 | Validator::replacer('profane', function ($message, $attribute) { 23 | return str_replace(':attribute', $attribute, $message); 24 | }); 25 | 26 | // Rule for caseless but strict word matching 27 | Validator::extend('strictly_profane', 'LaravelProfane\ProfaneValidator@validateStrict', Lang::get('laravel-profane::validation.profane')); 28 | 29 | Validator::replacer('strictly_profane', function ($message, $attribute) { 30 | return str_replace(':attribute', $attribute, $message); 31 | }); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/ProfaneValidator.php: -------------------------------------------------------------------------------- 1 | dictionary = $dictionary; 23 | $this->badwords = $dictionary->getDictionary(); 24 | } 25 | 26 | /** 27 | * Method to extends to Validation Service. 28 | * 29 | * @param string $attribute 30 | * @param mixed $value 31 | * @param array $parameters 32 | * 33 | * @return bool 34 | */ 35 | public function validate($attribute, $value, $parameters) 36 | { 37 | if ($parameters) { 38 | $this->setDictionary($parameters); 39 | } 40 | 41 | return !$this->isProfane($value); 42 | } 43 | 44 | /** 45 | * Method to extends to Validation Service for strict word matching. 46 | * 47 | * @param string $attribute 48 | * @param mixed $value 49 | * @param array $parameters 50 | * 51 | * @return bool 52 | */ 53 | public function validateStrict($attribute, $value, $parameters) 54 | { 55 | if ($parameters) { 56 | $this->setDictionary($parameters); 57 | } 58 | 59 | return !$this->isProfane($value, true); 60 | } 61 | 62 | /** 63 | * Check profanity of text. 64 | * 65 | * @param string $text 66 | * 67 | * @return bool 68 | */ 69 | public function isProfane($text, $strict = false) 70 | { 71 | return Str::containsCaseless( 72 | $this->sanitizeText($text), 73 | $this->badwords, 74 | $strict 75 | ); 76 | } 77 | 78 | private function setDictionary($dictionaries) 79 | { 80 | $this->dictionary->setDictionary($dictionaries); 81 | $this->badwords = $this->dictionary->getDictionary(); 82 | } 83 | 84 | private function sanitizeText($text) 85 | { 86 | return Str::removeAccent(strip_tags($text)); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/Str.php: -------------------------------------------------------------------------------- 1 | '-', 'Ь' => '-', 'Ъ' => '-', 'ь' => '-', 40 | 'Ă' => 'A', 'Ą' => 'A', 'À' => 'A', 'Ã' => 'A', 'Á' => 'A', 'Æ' => 'A', 'Â' => 'A', 'Å' => 'A', 'Ä' => 'Ae', 41 | 'Þ' => 'B', 42 | 'Ć' => 'C', 'ץ' => 'C', 'Ç' => 'C', 43 | 'È' => 'E', 'Ę' => 'E', 'É' => 'E', 'Ë' => 'E', 'Ê' => 'E', 44 | 'Ğ' => 'G', 45 | 'İ' => 'I', 'Ï' => 'I', 'Î' => 'I', 'Í' => 'I', 'Ì' => 'I', 46 | 'Ł' => 'L', 47 | 'Ñ' => 'N', 'Ń' => 'N', 48 | 'Ø' => 'O', 'Ó' => 'O', 'Ò' => 'O', 'Ô' => 'O', 'Õ' => 'O', 'Ö' => 'Oe', 49 | 'Ş' => 'S', 'Ś' => 'S', 'Ș' => 'S', 'Š' => 'S', 50 | 'Ț' => 'T', 51 | 'Ù' => 'U', 'Û' => 'U', 'Ú' => 'U', 'Ü' => 'Ue', 52 | 'Ý' => 'Y', 53 | 'Ź' => 'Z', 'Ž' => 'Z', 'Ż' => 'Z', 54 | 'â' => 'a', 'ǎ' => 'a', 'ą' => 'a', 'á' => 'a', 'ă' => 'a', 'ã' => 'a', 'Ǎ' => 'a', 'а' => 'a', 'А' => 'a', 'å' => 'a', 'à' => 'a', 'א' => 'a', 'Ǻ' => 'a', 'Ā' => 'a', 'ǻ' => 'a', 'ā' => 'a', 'ä' => 'ae', 'æ' => 'ae', 'Ǽ' => 'ae', 'ǽ' => 'ae', 55 | 'б' => 'b', 'ב' => 'b', 'Б' => 'b', 'þ' => 'b', 56 | 'ĉ' => 'c', 'Ĉ' => 'c', 'Ċ' => 'c', 'ć' => 'c', 'ç' => 'c', 'ц' => 'c', 'צ' => 'c', 'ċ' => 'c', 'Ц' => 'c', 'Č' => 'c', 'č' => 'c', 'Ч' => 'ch', 'ч' => 'ch', 57 | 'ד' => 'd', 'ď' => 'd', 'Đ' => 'd', 'Ď' => 'd', 'đ' => 'd', 'д' => 'd', 'Д' => 'D', 'ð' => 'd', 58 | 'є' => 'e', 'ע' => 'e', 'е' => 'e', 'Е' => 'e', 'Ə' => 'e', 'ę' => 'e', 'ĕ' => 'e', 'ē' => 'e', 'Ē' => 'e', 'Ė' => 'e', 'ė' => 'e', 'ě' => 'e', 'Ě' => 'e', 'Є' => 'e', 'Ĕ' => 'e', 'ê' => 'e', 'ə' => 'e', 'è' => 'e', 'ë' => 'e', 'é' => 'e', 59 | 'ф' => 'f', 'ƒ' => 'f', 'Ф' => 'f', 60 | 'ġ' => 'g', 'Ģ' => 'g', 'Ġ' => 'g', 'Ĝ' => 'g', 'Г' => 'g', 'г' => 'g', 'ĝ' => 'g', 'ğ' => 'g', 'ג' => 'g', 'Ґ' => 'g', 'ґ' => 'g', 'ģ' => 'g', 61 | 'ח' => 'h', 'ħ' => 'h', 'Х' => 'h', 'Ħ' => 'h', 'Ĥ' => 'h', 'ĥ' => 'h', 'х' => 'h', 'ה' => 'h', 62 | 'î' => 'i', 'ï' => 'i', 'í' => 'i', 'ì' => 'i', 'į' => 'i', 'ĭ' => 'i', 'ı' => 'i', 'Ĭ' => 'i', 'И' => 'i', 'ĩ' => 'i', 'ǐ' => 'i', 'Ĩ' => 'i', 'Ǐ' => 'i', 'и' => 'i', 'Į' => 'i', 'י' => 'i', 'Ї' => 'i', 'Ī' => 'i', 'І' => 'i', 'ї' => 'i', 'і' => 'i', 'ī' => 'i', 'ij' => 'ij', 'IJ' => 'ij', 63 | 'й' => 'j', 'Й' => 'j', 'Ĵ' => 'j', 'ĵ' => 'j', 'я' => 'ja', 'Я' => 'ja', 'Э' => 'je', 'э' => 'je', 'ё' => 'jo', 'Ё' => 'jo', 'ю' => 'ju', 'Ю' => 'ju', 64 | 'ĸ' => 'k', 'כ' => 'k', 'Ķ' => 'k', 'К' => 'k', 'к' => 'k', 'ķ' => 'k', 'ך' => 'k', 65 | 'Ŀ' => 'l', 'ŀ' => 'l', 'Л' => 'l', 'ł' => 'l', 'ļ' => 'l', 'ĺ' => 'l', 'Ĺ' => 'l', 'Ļ' => 'l', 'л' => 'l', 'Ľ' => 'l', 'ľ' => 'l', 'ל' => 'l', 66 | 'מ' => 'm', 'М' => 'm', 'ם' => 'm', 'м' => 'm', 67 | // 'ñ'=>'n', // for spanish cono != coño 68 | 'н' => 'n', 'Ņ' => 'n', 'ן' => 'n', 'ŋ' => 'n', 'נ' => 'n', 'Н' => 'n', 'ń' => 'n', 69 | 'Ŋ' => 'n', 'ņ' => 'n', 'ʼn' => 'n', 'Ň' => 'n', 'ň' => 'n', 70 | 'о' => 'o', 'О' => 'o', 'ő' => 'o', 'õ' => 'o', 'ô' => 'o', 'Ő' => 'o', 'ŏ' => 'o', 'Ŏ' => 'o', 'Ō' => 'o', 'ō' => 'o', 'ø' => 'o', 'ǿ' => 'o', 'ǒ' => 'o', 'ò' => 'o', 'Ǿ' => 'o', 'Ǒ' => 'o', 'ơ' => 'o', 'ó' => 'o', 'Ơ' => 'o', 'œ' => 'oe', 'Œ' => 'oe', 'ö' => 'oe', 71 | 'פ' => 'p', 'ף' => 'p', 'п' => 'p', 'П' => 'p', 72 | 'ק' => 'q', 73 | 'ŕ' => 'r', 'ř' => 'r', 'Ř' => 'r', 'ŗ' => 'r', 'Ŗ' => 'r', 'ר' => 'r', 'Ŕ' => 'r', 'Р' => 'r', 'р' => 'r', 74 | 'ș' => 's', 'с' => 's', 'Ŝ' => 's', 'š' => 's', 'ś' => 's', 'ס' => 's', 'ş' => 's', 'С' => 's', 'ŝ' => 's', 'Щ' => 'sch', 'щ' => 'sch', 'ш' => 'sh', 'Ш' => 'sh', 'ß' => 'ss', 75 | 'т' => 't', 'ט' => 't', 'ŧ' => 't', 'ת' => 't', 'ť' => 't', 'ţ' => 't', 'Ţ' => 't', 'Т' => 't', 'ț' => 't', 'Ŧ' => 't', 'Ť' => 't', '™' => 'tm', 76 | 'ū' => 'u', 'у' => 'u', 'Ũ' => 'u', 'ũ' => 'u', 'Ư' => 'u', 'ư' => 'u', 'Ū' => 'u', 'Ǔ' => 'u', 'ų' => 'u', 'Ų' => 'u', 'ŭ' => 'u', 'Ŭ' => 'u', 'Ů' => 'u', 'ů' => 'u', 'ű' => 'u', 'Ű' => 'u', 'Ǖ' => 'u', 'ǔ' => 'u', 'Ǜ' => 'u', 'ù' => 'u', 'ú' => 'u', 'û' => 'u', 'У' => 'u', 'ǚ' => 'u', 'ǜ' => 'u', 'Ǚ' => 'u', 'Ǘ' => 'u', 'ǖ' => 'u', 'ǘ' => 'u', 'ü' => 'ue', 77 | 'в' => 'v', 'ו' => 'v', 'В' => 'v', 78 | 'ש' => 'w', 'ŵ' => 'w', 'Ŵ' => 'w', 79 | 'ы' => 'y', 'ŷ' => 'y', 'ý' => 'y', 'ÿ' => 'y', 'Ÿ' => 'y', 'Ŷ' => 'y', 80 | 'Ы' => 'y', 'ž' => 'z', 'З' => 'z', 'з' => 'z', 'ź' => 'z', 'ז' => 'z', 'ż' => 'z', 'ſ' => 'z', 'Ж' => 'zh', 'ж' => 'zh', 'ά' => 'α', 'έ' => 'ε', 'ή' => 'η', 'ί' => 'ι', 'ό' => 'ο', 'ύ' => 'υ', 'ώ' => 'ω', 81 | ]; 82 | 83 | return strtr($string, $replace); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/dict/de.php: -------------------------------------------------------------------------------- 1 | 'Das :attribute enthält vulgäre Wörter', 5 | ]; 6 | -------------------------------------------------------------------------------- /src/lang/en/validation.php: -------------------------------------------------------------------------------- 1 | 'The :attribute contains vulgar content', 5 | ]; 6 | -------------------------------------------------------------------------------- /src/lang/es-cl/validation.php: -------------------------------------------------------------------------------- 1 | 'El :attribute contiene palabras vulgares', 5 | ]; 6 | -------------------------------------------------------------------------------- /src/lang/es/validation.php: -------------------------------------------------------------------------------- 1 | 'El :attribute contiene palabras vulgares', 5 | ]; 6 | -------------------------------------------------------------------------------- /src/lang/fr/validation.php: -------------------------------------------------------------------------------- 1 | 'Le champ :attribute comporte du contenu vulgaire', 5 | ]; 6 | -------------------------------------------------------------------------------- /src/lang/gr/validation.php: -------------------------------------------------------------------------------- 1 | 'Στο πεδίο :attribute εμπεριέχονται χυδαίες εκφράσεις', 5 | ]; 6 | -------------------------------------------------------------------------------- /src/lang/id/validation.php: -------------------------------------------------------------------------------- 1 | ':attribute mengandung konten yang vulgar', 5 | ]; 6 | -------------------------------------------------------------------------------- /src/lang/it/validation.php: -------------------------------------------------------------------------------- 1 | 'Il campo :attribute contiene parole volgari o offensive', 5 | ]; 6 | -------------------------------------------------------------------------------- /src/lang/ml/validation.php: -------------------------------------------------------------------------------- 1 | 'ഈ :attribute നകത്തു മ്ലേച്ഛമായ ഭാഷ ഉണ്ട്', 5 | ]; 6 | -------------------------------------------------------------------------------- /src/lang/nl/validation.php: -------------------------------------------------------------------------------- 1 | 'Het :attribute veld bevat vulgaire inhoud', 5 | ]; 6 | -------------------------------------------------------------------------------- /src/lang/pt-br/validation.php: -------------------------------------------------------------------------------- 1 | 'O campo :attribute contém palavras vulgares', 5 | ]; 6 | -------------------------------------------------------------------------------- /src/lang/ro-md/validation.php: -------------------------------------------------------------------------------- 1 | ':attribute are un continut vulgar', 5 | ]; 6 | -------------------------------------------------------------------------------- /src/lang/ro/validation.php: -------------------------------------------------------------------------------- 1 | ':attribute are un continut vulgar', 5 | ]; 6 | -------------------------------------------------------------------------------- /src/lang/sk/validation.php: -------------------------------------------------------------------------------- 1 | ':attribute obsahuje vulgárny obsah', 5 | ]; 6 | -------------------------------------------------------------------------------- /src/lang/sr-rs/validation.php: -------------------------------------------------------------------------------- 1 | ':attribute sadrži vulgarne reči', 5 | ]; 6 | -------------------------------------------------------------------------------- /src/lang/zh-tw/validation.php: -------------------------------------------------------------------------------- 1 | ':attribute欄位內容包含粗俗用詞,請您修正:)', 5 | ]; 6 | -------------------------------------------------------------------------------- /tests/DictionaryTest.php: -------------------------------------------------------------------------------- 1 | assertEquals($dictionary->getDictionary(), $expected); 16 | } 17 | 18 | public function test_words_from_only_one_file() 19 | { 20 | $dictionary = new Dictionary(__DIR__.'/../src/dict/es.php'); 21 | 22 | $expected = include __DIR__.'/../src/dict/es.php'; 23 | 24 | $this->assertEquals($dictionary->getDictionary(), $expected); 25 | } 26 | 27 | public function test_words_from_locale_array() 28 | { 29 | $dictionary = new Dictionary([ 30 | 'es', 31 | 'gr', 32 | ]); 33 | 34 | $expected = array_merge( 35 | include __DIR__.'/../src/dict/es.php', 36 | include __DIR__.'/../src/dict/gr.php' 37 | ); 38 | 39 | $this->assertEquals($dictionary->getDictionary(), $expected); 40 | } 41 | 42 | public function test_words_from_file_array() 43 | { 44 | $dictionary = new Dictionary([ 45 | __DIR__.'/../src/dict/es.php', 46 | __DIR__.'/../src/dict/gr.php', 47 | __DIR__.'/../src/dict/it.php', 48 | ]); 49 | 50 | $expected = array_merge( 51 | include __DIR__.'/../src/dict/es.php', 52 | include __DIR__.'/../src/dict/gr.php', 53 | include __DIR__.'/../src/dict/it.php' 54 | ); 55 | 56 | $this->assertEquals($dictionary->getDictionary(), $expected); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /tests/ProfaneValidatorTest.php: -------------------------------------------------------------------------------- 1 | assertFalse($builder->validate(['username', 'culero23', ['es']])); 14 | } 15 | 16 | public function test_can_not_validate_a_word_with_numbers_in_strict_mode() 17 | { 18 | $builder = new ProfaneValidatorBuilder(); 19 | 20 | $this->assertTrue($builder->validate(['username', 'culero23', ['es']], true)); 21 | } 22 | 23 | public function test_can_validate_a_text() 24 | { 25 | $builder = new ProfaneValidatorBuilder(); 26 | 27 | $this->assertFalse($builder->validate(['description', 'fck you bitch. 幹!', ['es', 'en', 'zh-tw']])); 28 | } 29 | 30 | public function test_can_evaluate_profanity_of_a_word() 31 | { 32 | $builder = new ProfaneValidatorBuilder(); 33 | 34 | $word = 'fuck'; 35 | 36 | $this->assertTrue($builder->build()->isProfane($word)); 37 | } 38 | 39 | public function test_can_evaluate_profanity_of_a_sentence() 40 | { 41 | $builder = new ProfaneValidatorBuilder(); 42 | 43 | $word = 'fuck you if you read this'; 44 | 45 | $this->assertTrue($builder->build()->isProfane($word)); 46 | } 47 | 48 | public function test_can_evaluate_profanity_of_a_sentence_in_strict_mode() 49 | { 50 | $builder = new ProfaneValidatorBuilder(); 51 | 52 | $word = 'fuck you if you read this'; 53 | 54 | $this->assertTrue($builder->build()->isProfane($word), true); 55 | } 56 | 57 | public function test_can_evaluate_profanity_of_a_html_string() 58 | { 59 | $builder = new ProfaneValidatorBuilder(); 60 | 61 | $word = 'fuck you if you read this.'; 62 | 63 | $this->assertTrue($builder->build()->isProfane($word)); 64 | } 65 | 66 | public function test_can_evaluate_as_caseless_mode() 67 | { 68 | $builder = new ProfaneValidatorBuilder(); 69 | 70 | $word = 'FUCK you BITCH if you read this.'; 71 | 72 | $this->assertTrue($builder->build()->isProfane($word)); 73 | } 74 | 75 | public function test_match_content() 76 | { 77 | $builder = new ProfaneValidatorBuilder(); 78 | 79 | // it thinks class ~= ass 80 | $this->assertTrue($builder->build()->isProfane('class')); 81 | 82 | // but this should be profane 83 | $this->assertTrue($builder->build()->isProfane('sucker96')); 84 | } 85 | 86 | public function test_match_exact_word_in_strict_mode() 87 | { 88 | $builder = new ProfaneValidatorBuilder(); 89 | 90 | // class is a safe word 91 | $this->assertFalse($builder->build()->isProfane('class', true)); 92 | 93 | // in strict mode this will pass a safe word 94 | $this->assertFalse($builder->build()->isProfane('sucker96', true)); 95 | } 96 | 97 | public function test_can_validate_a_bad_word_with_accent() 98 | { 99 | $builder = new ProfaneValidatorBuilder('sk'); 100 | 101 | $word = 'piča'; 102 | 103 | $this->assertTrue($builder->build()->isProfane($word)); 104 | } 105 | 106 | public function test_enie_in_spanish_is_evaluated() 107 | { 108 | $builder = new ProfaneValidatorBuilder('es'); 109 | 110 | // in spanish coño =! cono 111 | $word = 'coño'; 112 | 113 | $this->assertTrue($builder->build()->isProfane($word)); 114 | } 115 | 116 | public function test_can_validate_a_word_in_greek() 117 | { 118 | $this->mockConfigs(); 119 | 120 | $builder = new ProfaneValidatorBuilder('gr'); 121 | 122 | $word = 'μαλάκας'; 123 | 124 | $this->assertTrue($builder->build()->isProfane($word)); 125 | } 126 | 127 | public function test_can_validate_a_text_in_greek() 128 | { 129 | $this->mockConfigs(); 130 | 131 | $builder = new ProfaneValidatorBuilder(); 132 | 133 | $this->assertFalse($builder->validate(['description', 'εισαι πουτανα', ['en', 'gr']])); 134 | } 135 | 136 | public function test_can_validate_a_word_in_french() 137 | { 138 | $this->mockConfigs(); 139 | 140 | $builder = new ProfaneValidatorBuilder(); 141 | 142 | $this->assertFalse($builder->validate(['description', 'Va te faire enculer, sac à merde', ['en', 'fr']])); 143 | } 144 | 145 | public function test_can_validate_a_word_in_french_canadian() 146 | { 147 | $this->mockConfigs(); 148 | 149 | $builder = new ProfaneValidatorBuilder(); 150 | 151 | $this->assertFalse($builder->validate(['description', 'Décrisse gros cave', ['en', 'fr-ca']])); 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /tests/StrTest.php: -------------------------------------------------------------------------------- 1 | assertTrue(Str::containsCaseless('Fuck! This class is so bad!', 'ass')); 12 | } 13 | 14 | public function test_text_contains_insensitive_match_from_array() 15 | { 16 | $this->assertTrue(Str::containsCaseless('Fuck! This class is so bad!', ['fuk', 'fuck'])); 17 | } 18 | 19 | public function test_text_contains_insensitive_match_from_string() 20 | { 21 | $this->assertTrue(Str::containsCaseless('Fuck! This class is so bad!', 'fUcK')); 22 | } 23 | 24 | public function test_text_does_not_contain_match_in_strict_mode() 25 | { 26 | $this->assertFalse(Str::containsCaseless('This class is so bad!', 'ass', true)); 27 | $this->assertFalse(Str::containsCaseless('Theorem Analisys', 'anal', true)); 28 | } 29 | 30 | public function test_text_contains_match_in_strict_mode() 31 | { 32 | $this->assertTrue(Str::containsCaseless('This class is a crap!', 'crap', true)); 33 | $this->assertFalse(Str::containsCaseless('Theorem Analisys', 'anal', true)); 34 | $this->assertFalse(Str::containsCaseless('Sucker69', 'sucker', true)); 35 | } 36 | 37 | public function test_text_contains_match_in_not_strict_mode() 38 | { 39 | $this->assertTrue(Str::containsCaseless('This class is so bad!', 'ass', false)); 40 | $this->assertTrue(Str::containsCaseless('Theorem Analisys', 'anal', false)); 41 | } 42 | 43 | public function test_text_contains_the_same_insensitive_match_from_string() 44 | { 45 | $this->assertTrue(Str::containsCaseless('Fuck! This class is so bad!', 'Fuck')); 46 | } 47 | 48 | public function test_remove_accents_in_spanish_text() 49 | { 50 | $this->assertEquals('cojon', Str::removeAccent('cojón')); 51 | } 52 | 53 | public function test_enie_char_is_allowed() 54 | { 55 | $this->assertEquals('coño', Str::removeAccent('coño')); 56 | } 57 | 58 | public function test_remove_accents_in_greek() 59 | { 60 | $this->assertEquals('μαλακας', Str::removeAccent('μαλάκας')); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /tests/Support/ProfaneValidatorBuilder.php: -------------------------------------------------------------------------------- 1 | profaneValidator = new ProfaneValidator(new Dictionary($dictionary)); 25 | } 26 | 27 | /** 28 | * [validate description]. 29 | * 30 | * @param array $parameters [description] 31 | * 32 | * @return [type] [description] 33 | */ 34 | public function validate(array $parameters, $strict = false) 35 | { 36 | list($attribute, $text, $dictionaries) = $parameters; 37 | 38 | if ($strict) { 39 | return $this->build()->validateStrict($attribute, $text, $dictionaries); 40 | } 41 | 42 | return $this->build()->validate($attribute, $text, $dictionaries); 43 | } 44 | 45 | /** 46 | * [build description]. 47 | * 48 | * @return LaravelProfane\ProfaneValidator 49 | */ 50 | public function build() 51 | { 52 | return $this->profaneValidator; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /tests/TestCase.php: -------------------------------------------------------------------------------- 1 | mockConfigs(); 18 | } 19 | 20 | /** 21 | * [tearDown description]. 22 | * 23 | * @return [type] [description] 24 | */ 25 | public function tearDown(): void 26 | { 27 | parent::tearDown(); 28 | Mockery::close(); 29 | } 30 | 31 | /** 32 | * [mockConfigs description]. 33 | * 34 | * @return void 35 | */ 36 | protected function mockConfigs() 37 | { 38 | Config::shouldReceive('get') 39 | ->once() 40 | ->with('app.locale') 41 | ->andReturn('en'); 42 | 43 | Config::shouldReceive('has') 44 | ->once() 45 | ->with('app.locale') 46 | ->andReturn(true); 47 | } 48 | } 49 | --------------------------------------------------------------------------------