106 lines
2.5 KiB
PHP
106 lines
2.5 KiB
PHP
<?php
|
|
|
|
namespace App\Services\PressRelease;
|
|
|
|
use App\Models\PressRelease;
|
|
|
|
/**
|
|
* Wortbasierte Blacklist-Prüfung für Pressemitteilungen.
|
|
*
|
|
* Die Liste kommt aktuell aus config/blacklist.php; ein Wechsel auf
|
|
* eine Datenbank-Tabelle (Admin-UI) ist später ohne API-Bruch möglich.
|
|
*/
|
|
class BlacklistService
|
|
{
|
|
/**
|
|
* @var list<string>|null
|
|
*/
|
|
private ?array $words = null;
|
|
|
|
/**
|
|
* @param array{words?: list<string>}|null $config
|
|
*/
|
|
public function __construct(?array $config = null)
|
|
{
|
|
if ($config !== null) {
|
|
$this->words = $this->normalizeList($config['words'] ?? []);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Findet das erste Blacklist-Wort, das in Titel oder Text vorkommt.
|
|
*/
|
|
public function findInPressRelease(PressRelease $pressRelease): ?string
|
|
{
|
|
$haystack = $pressRelease->title.' '.$pressRelease->text;
|
|
|
|
return $this->find($haystack);
|
|
}
|
|
|
|
/**
|
|
* Findet das erste Blacklist-Wort in einem beliebigen String.
|
|
* Vergleich ist case-insensitiv und ganzwörtlich.
|
|
*/
|
|
public function find(string $text): ?string
|
|
{
|
|
$words = $this->words();
|
|
|
|
if ($words === []) {
|
|
return null;
|
|
}
|
|
|
|
$needle = $this->normalizeText($text);
|
|
|
|
foreach ($words as $word) {
|
|
$padded = ' '.trim($word).' ';
|
|
|
|
if (trim($padded) === '') {
|
|
continue;
|
|
}
|
|
|
|
if (str_contains($needle, $padded)) {
|
|
return trim($padded);
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public function matches(string $text): bool
|
|
{
|
|
return $this->find($text) !== null;
|
|
}
|
|
|
|
/**
|
|
* @return list<string>
|
|
*/
|
|
private function words(): array
|
|
{
|
|
if ($this->words === null) {
|
|
$this->words = $this->normalizeList((array) config('blacklist.words', []));
|
|
}
|
|
|
|
return $this->words;
|
|
}
|
|
|
|
/**
|
|
* @param array<int, mixed> $words
|
|
* @return list<string>
|
|
*/
|
|
private function normalizeList(array $words): array
|
|
{
|
|
return array_values(array_filter(array_map(
|
|
fn ($word): string => $this->normalizeText((string) $word),
|
|
$words,
|
|
), fn (string $word): bool => $word !== ''));
|
|
}
|
|
|
|
private function normalizeText(string $text): string
|
|
{
|
|
$text = mb_strtolower($text, 'UTF-8');
|
|
$text = preg_replace('/[^\p{L}\p{N}\s]+/u', ' ', $text) ?? '';
|
|
$text = preg_replace('/\s+/u', ' ', $text) ?? '';
|
|
|
|
return ' '.trim($text).' ';
|
|
}
|
|
}
|