feat(classifier): has_short_latin_name() helper for drop-logic

This commit is contained in:
Vladimir Bryzgalov
2026-04-21 16:01:58 +05:00
parent b5c939e9e4
commit 660a0d2b7c
2 changed files with 57 additions and 0 deletions
+19
View File
@@ -243,4 +243,23 @@ final class Classifier
} }
return false; return false;
} }
/**
* Checks whether the form's name field contains 1-3 ASCII alphanumeric characters
* (typical bot pattern: "OB", "MU", "A1B"). Used by drop hard-rule.
*
* Looks first at canonical CF7 keys (your-name, name, имя, fio), then falls back to
* the value-based heuristic in FieldDetector::find_name(). Returns false if no name
* field is present (i.e. forms without a name field are immune to this rule).
*
* @param array<string,string|string[]> $fields CF7 posted_data
*/
public static function has_short_latin_name(array $fields): bool
{
$name = self::pick_field($fields, ['your-name', 'name', 'имя', 'fio']);
if ($name === '') $name = FieldDetector::find_name($fields);
$name = trim($name);
if ($name === '') return false;
return (bool)preg_match('/^[A-Za-z0-9]{1,3}$/', $name);
}
} }
+38
View File
@@ -43,4 +43,42 @@ final class ClassifierDropTest extends Cf7stgTestCase
$fields = ['msg' => 'try alice@in or bob@example.com']; $fields = ['msg' => 'try alice@in or bob@example.com'];
self::assertTrue(Classifier::has_valid_email_anywhere($fields)); self::assertTrue(Classifier::has_valid_email_anywhere($fields));
} }
public function test_has_short_latin_name_true_for_two_letters(): void
{
$fields = ['your-name' => 'OB'];
self::assertTrue(Classifier::has_short_latin_name($fields));
}
public function test_has_short_latin_name_true_for_three_alnum(): void
{
$fields = ['name' => 'A1B'];
self::assertTrue(Classifier::has_short_latin_name($fields));
}
public function test_has_short_latin_name_false_for_long_name(): void
{
$fields = ['your-name' => 'Melissa'];
self::assertFalse(Classifier::has_short_latin_name($fields));
}
public function test_has_short_latin_name_false_for_cyrillic(): void
{
$fields = ['your-name' => 'Иван'];
self::assertFalse(Classifier::has_short_latin_name($fields));
}
public function test_has_short_latin_name_false_when_no_name_field(): void
{
// Только телефон, нет name-полей. FieldDetector::find_name пропустит +79991234567 (digits)
$fields = ['tel-1' => '+79991234567'];
self::assertFalse(Classifier::has_short_latin_name($fields));
}
public function test_has_short_latin_name_picks_via_field_detector(): void
{
// text-211 не в списке известных name-ключей, FieldDetector найдёт 'XY' (no digits, len=2)
$fields = ['text-211' => 'XY', 'text-212' => '+79991234567'];
self::assertTrue(Classifier::has_short_latin_name($fields));
}
} }