代码之家  ›  专栏  ›  技术社区  ›  mister martin

仅在PHP表单提交时强制使用英语

  •  0
  • mister martin  · 技术社区  · 2 年前

    我希望我网站上的联系表格只接受英文提交的文本。我最近一直在处理很多以多种语言出现的垃圾邮件,这些垃圾邮件正从CAPTCHA中消失。任何人都没有理由用英语以外的语言提交这份表格,因为这不是一项业务,更多的是个人使用的爱好。

    我一直在看 this documentation 并希望 preg_match( '/[\p{Latin}]/u', $input) 也许可以,但我不会说两种语言,也不理解字符编码的所有细微差别,所以虽然这将有助于过滤掉俄语等语言,但它仍然允许越南语等语言通过。

    理想情况下,我希望它接受:

    • 任何Unicode 象征 可能会用到的。例如,我经常遇到不同风格的破折号、撇号或与数学有关的东西。
    • 常见的变音标记/重音字符出现在像“rsum”这样的单词中

    我希望它拒绝:

    • 任何看起来不是英语的东西,或者不常见的东西。我不太在意诸如“nave”之类的口音或从其他语言借来的单词。

    我想简单地剥离所有可能有效的字符,如下所示:

    $input = 'testing for English only!';
    
    // reference: https://en.wikipedia.org/wiki/List_of_Unicode_characters
    // allowed punctuation
    $basic_latin = '`~!@#$%^&*()-_=+[{]}\\|;:\'",<.>/?';
    $input = str_replace(str_split($basic_latin), '', $input);
    
    // allowed symbols and accents
    $latin1_supplement = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿É×é÷';
    $input = str_replace(str_split($latin1_supplement), '', $input);
    $unicode_symbols = '–—―‗‘’‚‛“”„†‡•…‰′″‹›‼‾⁄⁊';
    $input = str_replace(str_split($unicode_symbols), '', $input);
    
    // remove all spaces including tabs and end lines
    $input = preg_replace('/\s+/', '', $input);
    
    // check that remaining characters are alpha-numeric
    if (strlen($input) > 0 && ctype_alnum($input)) {
        echo 'this is English';
    } else {
        echo 'no bueno señor';
    }
    

    然而,恐怕我无意中遗漏了一些非常常见和有效的例外情况。我希望有人能够提供一个更优雅的解决方案或方法?

    0 回复  |  直到 2 年前
        1
  •  2
  •   Markus AO    2 年前

    没有任何原生PHP功能可以提供语言识别。有一个废弃的梨包和一些课程在网络空间里流传(我还没有测试)。如果外部API可以,谷歌的Translation API Basic可以 detect language ,每月50万个免费字符。

    然而,这一切有一个非常简单的解决方案。我们真的不需要知道 什么语言 是的。我们需要知道的是 合理有效的英语 。而不是斯瓦希里语、克林贡语、俄语或吉博里语。现在,有一个方便的PHP扩展: PSpell

    以下是您可能使用的示例函数:

    /**
     *  Spell Check Stats.
     *  Returns an array with OK, FAIL spell check counts and their ratio.
     *  Use the ratio to filter out undesirable (non-English/garbled) content.
     *  
     *  @updated 2022-12-29 00:00:29 +07:00
     *  @author @cmswares
     *  @ref https://stackoverflow.com/q/74910421/4630325
     *
     *  @param string   $text
     *  
     *  @return array
     */
    
    function spell_check_stats(string $text): array
    {
        $stats = [
            'ratio' => null,
            'ok' => 0,
            'fail' => 0
        ];
        
        // Split into words
        $words = preg_split('~[^\w\']+~', $text, -1, PREG_SPLIT_NO_EMPTY);
        
        // Nw PSpell:
        $pspeller = pspell_new("en");
        
        // Check spelling and build stats
        foreach($words as $word) {
            if(pspell_check($pspeller, $word)) {
                $stats['ok']++;
            } else {
                $stats['fail']++;
            }
        }
        
        // Calculate ratio of OK to FAIL
        $stats['ratio'] = match(true) {
            $stats['fail'] === 0 => 0, // avoiding division by zero here!
            $stats['ok'] === 0 => count($words), 
            default => $stats['ok'] / $stats['fail'],
        };
    
        return $stats;
    }
    

    Source at BitBucket .功能用法:

    $stats = spell_check_stats('This starts in English, esto no se quiere, tätä ei haluta.');
    // ratio: 0.7142857142857143, ok: 5, fail: 7
    

    然后简单地决定拒绝提交的阈值。例如,如果100个单词中有20个失败;即80:20比例,或“比例=4”。这个比例越高,英语就越(拼写正确)。

    如果您需要为非常短的字符串单独校准,也会返回“ok”和“fail”计数。对现有的有效内容和垃圾邮件内容进行一些测试,看看你得到了什么样的数字,然后相应地调整你的拒绝阈值。


    默认情况下,您的服务器上可能不会安装用于PHP的PSpell包。在Cents/RedHat上, yum install php-pspell aspell-en ,以安装PHP模块(包括ASpell依赖项)以及英语词典。对于其他平台,请按照软件包管理器进行安装。

    对于Windows和现代PHP,我找不到扩展dll或维护的Aspell端口。如果你找到了解决方案,请分享。我也想在我的开发机器上也有这个。