From b5c939e9e48cc80ebbdeab13fd7e5943944bc52d Mon Sep 17 00:00:00 2001 From: Vladimir Bryzgalov Date: Tue, 21 Apr 2026 15:59:12 +0500 Subject: [PATCH] fix(classifier): iterate all email candidates per field; document method contract Co-Authored-By: Claude Sonnet 4.6 --- includes/class-classifier.php | 17 +++++++++++++++-- tests/ClassifierDropTest.php | 14 ++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/includes/class-classifier.php b/includes/class-classifier.php index bcbccc1..9686d32 100644 --- a/includes/class-classifier.php +++ b/includes/class-classifier.php @@ -216,6 +216,17 @@ final class Classifier return $hits; } + /** + * Checks whether any field value contains a syntactically valid email address. + * + * Used by drop-logic to spare submissions that include any plausible contact email + * (any TLD, including gmail.com and custom domains — not limited to RU domains). + * + * Handles flat string values and one level of array nesting (matches CF7 posted_data + * shape). Deeper nesting is intentionally NOT supported. + * + * @param array $fields CF7 posted_data + */ public static function has_valid_email_anywhere(array $fields): bool { foreach ($fields as $v) { @@ -223,8 +234,10 @@ final class Classifier foreach ($values as $val) { $val = trim((string)$val); if ($val === '') continue; - if (preg_match('/[A-Za-z0-9._%+\-]+@[A-Za-z0-9.\-]+\.[A-Za-z]{2,}/', $val, $m)) { - if (is_email($m[0])) return true; + if (preg_match_all('/[A-Za-z0-9._%+\-]+@[A-Za-z0-9.\-]+\.[A-Za-z]{2,}/', $val, $matches)) { + foreach ($matches[0] as $candidate) { + if (is_email($candidate)) return true; + } } } } diff --git a/tests/ClassifierDropTest.php b/tests/ClassifierDropTest.php index 7c283cf..067c510 100644 --- a/tests/ClassifierDropTest.php +++ b/tests/ClassifierDropTest.php @@ -29,4 +29,18 @@ final class ClassifierDropTest extends Cf7stgTestCase { self::assertFalse(Classifier::has_valid_email_anywhere([])); } + + public function test_has_valid_email_anywhere_finds_email_embedded_in_text(): void + { + $fields = ['your-message' => 'reach me at user@domain.com thanks']; + self::assertTrue(Classifier::has_valid_email_anywhere($fields)); + } + + public function test_has_valid_email_anywhere_finds_second_email_when_first_invalid(): void + { + // First candidate is "alice@in" which is not a valid email; second is valid. + // Without preg_match_all, the method would return false here. + $fields = ['msg' => 'try alice@in or bob@example.com']; + self::assertTrue(Classifier::has_valid_email_anywhere($fields)); + } }