将搜索限制为拉丁字符

时间:2017-03-22 作者:Michael Rogers

我想将搜索限制为英语+数字上使用的字符。原因是查看mysql日志上最慢的查询,我发现大多数来自阿拉伯、俄语和中文字符的搜索,所以我想跳过它们,显示一条错误消息。

4 个回复
最合适的回答,由SO网友:bosco 整理而成

此解决方案通过应用仅匹配常用和拉丁Unicode脚本中的字符的正则表达式来过滤搜索字符串。

用正则表达式匹配拉丁字符had my mind blown over at Stack Overflow. 事实证明,正则表达式a mechanism 匹配整个Unicode类别,包括指定整个Unicode "scripts", 每个对应于不同书写系统中使用的字符组。

这是通过使用\\p 在大括号中后跟Unicode类别标识符的元字符-so[\\p{Common}\\p{Latin}] 匹配Latin or Common scripts - 这包括标点符号、数字和其他符号。

@Paul \'Sparrow Hawk\' Biron points out, 这个u pattern modifier flag 应在正则表达式的末尾设置,以便PHP的PCRE函数将主题字符串视为UTF-8 Unicode编码。

那么,所有这些模式

/^[\\p{Latin}\\p{Common}]+$/u
将匹配由拉丁语和通用Unicode脚本中的一个或多个字符组成的整个字符串。

过滤搜索字符串的好地方是the pre_get_posts action 在WordPress执行查询之前立即触发。具有more care, 这也可以通过使用a request filter.

function wpse261038_validate_search_characters( $query ) {
  // Leave admin, non-main query, and non-search queries alone
  if( is_admin() || !$query->is_main_query() || !$query->is_seach() )
    return;

  // Check if the search string contains only Latin/Common Unicode characters
  $match_result = preg_match( \'/^[\\p{Latin}\\p{Common}]+$/u\', $query->get( \'s\' ) );

  // If the search string only contains Latin/Common characters, let it continue
  if( 1 === $match_result )
    return;

  // If execution reaches this point, the search string contains non-Latin characters
  //TODO: Handle non-Latin search strings
  //TODO: Set up logic to display error message
}

add_action( \'pre_get_posts\', \'wpse261038_validate_search_characters\' );
响应不允许的搜索一旦确定搜索字符串包含非拉丁字符,您可以使用WP_Query::set() 通过更改查询的名称来修改查询query vars - 因此会影响SQL查询WordPress随后的组合和执行。

最相关的查询变量可能如下所示:

  • s 是与搜索字符串相对应的查询变量。将其设置为null 或空字符串(\'\') 将导致WordPress不再将查询视为搜索-通常情况下,这会导致存档模板显示所有帖子或网站首页,具体取决于其他查询变量的值。将其设置为单个空间(\' \'), 但是,将导致WordPress将其识别为搜索,从而尝试显示search.php 模板
  • page_id 可用于将用户引导到您选择的特定页面
  • post__in 可以将查询限制为特定的帖子选择。通过将其设置为具有不可能的post ID的数组,it can serve as a measure to ensure that the query returns absolutely nothing.
考虑到上述情况,您可以通过加载search.php 没有结果的模板:

function wpse261038_validate_search_characters( $query ) {
  // Leave admin, non-main query, and non-search queries alone
  if( is_admin() || !$query->is_main_query() || !$query->is_seach() )
    return;

  // Check if the search string contains only Latin/Common Unicode characters
  $match_result = preg_match( \'/^[\\p{Latin}\\p{Common}]+$/u\', $query->get( \'s\' ) );

  // If the search string only contains Latin/Common characters, let it continue
  if( 1 === $match_result )
    return;

  $query->set( \'s\', \' \' ); // Replace the non-latin search with an empty one
  $query->set( \'post__in\', array(0) ); // Make sure no post is ever returned

  //TODO: Set up logic to display error message
}

add_action( \'pre_get_posts\', \'wpse261038_validate_search_characters\' );
显示错误的方式实际上显示错误消息的方式在很大程度上取决于您的应用程序和主题的能力,可以通过多种方式来实现。如果主题调用get_search_form() 在它的搜索模板中,最简单的解决方案可能是使用pre_get_search_form action 钩住以在搜索表单的正上方输出错误:

function wpse261038_validate_search_characters( $query ) {
  // Leave admin, non-main query, and non-search queries alone
  if( is_admin() || !$query->is_main_query() || !$query->is_seach() )
    return;

  // Check if the search string contains only Latin/Common Unicode characters
  $match_result = preg_match( \'/^[\\p{Latin}\\p{Common}]+$/u\', $query->get( \'s\' ) );

  // If the search string only contains Latin/Common characters, let it continue
  if( 1 === $match_result )
    return;

  $query->set( \'s\', \' \' ); // Replace the non-latin search with an empty one
  $query->set( \'post__in\', array(0) ); // Make sure no post is ever returned

  add_action( \'pre_get_search_form\', \'wpse261038_display_search_error\' );
}

add_action( \'pre_get_posts\', \'wpse261038_validate_search_characters\' );

function wpse261038_display_search_error() {
  echo \'<div class="notice notice-error"><p>Your search could not be completed as it contains characters from non-Latin alphabets.<p></div>\';
}
显示错误消息的其他一些可能性包括:

如果您的网站使用JavaScript,可以显示;闪光灯“;或“或”;“模态”;消息(或您自己添加此类功能),添加在设置特定变量时显示页面加载消息的逻辑,然后添加wp_enqueue_script 用钩子钩住$priority 大于将该JavaScript排队并使用wp_localize_script() 将该变量设置为包含错误消息使用wp_redirect() 将用户发送到您选择的URL(此方法需要额外的页面加载)s 查询变量至\'\' 而不是\' \' 和使用page_id 代替post__in 以便返回您选择的页面loop_start hook 注射假药WP_Post 对象将您的错误包含到查询结果中-这无疑是一个丑陋的黑客行为,可能与您的特定主题不符,但它具有潜在的令人满意的副作用,即抑制;“无结果”;消息template_include 过滤挂钩,将搜索模板与主题或插件中显示错误的自定义模板交换

SO网友:Cedon

您可以通过在PHP中加入一个验证函数来根据正则表达式测试输入,如^[a-zA-Z0-9,.!?\' ]*

所以看起来是这样的:

if ( preg_match( "^[a-zA-Z0-9,.!?\'" ]*", {search variable} ) ) {
   // Success
} else {
   // Fail
}
我用于所有角色的RexExA-Z, a-z, 0-9, 以及,, ., !, ?, \', ", 和 (空格)。

SO网友:bosco

编辑:不推荐使用此解决方案。我下面的解决方案是一种黑客行为,它滥用PHP的mbstring函数,试图通过查看组成字符串的字节排列来神奇地创造字母表<这真是个糟糕的主意highly prone to error

Please see my other answer for a far simpler and much more reliable solution.


防止使用非拉丁字母进行搜索的一种方法是PHP\'s mb_detect_encoding() function 查看搜索字符串是否符合自定义字符编码选择之一。这样做的好地方是the pre_get_posts action, 因为它在执行查询之前激发。

在确定搜索使用的是无效编码后,实际执行的操作实际上是特定于应用程序的。在这里,我将搜索查询设置为单个空格,以确保WordPress仍然将查询解释为搜索,从而仍然加载search.php 模板(并且不会将用户引导到首页,当搜索字符串为空字符串时会发生这种情况)。我还采取了额外的预防措施setting \'post__in\' to an array with an impossible post ID in order to make sure that absolutely nothing is returned.

或者,您可以考虑将搜索字符串设置为null 和设置page_id 以便将用户引导到包含自定义错误消息的页面。

function wpse261038_validate_search_query_encoding( $query ) {
  $valid_encodings = array( \'Windows-1252\' );

  // Ignore admin, non-main query, and non-search queries
  if( is_admin() || !$query->is_main_query() || !$query->is_seach() )
    return;

  // Retrieve the encoding of the search string (if it\'s one listed in $valid_encodings)
  $search_encoding = mb_detect_encoding( $query->get( \'s\' ), $valid_encodings, true );

  // If the search encoding is one in $valid_encodings, leave the query as-is
  if( in_array( $search_encoding, $valid_encodings ) )
    return;

  // If it wasn\'t, sabotage the search query
  $query->set( \'s\', \' \' );
  $query->set( \'post__in\', array(0) );

  // Set up your error message logic here somehow, perhaps one of the following:
  // - Add a template_include filter to load a custom error template
  // - Add a wp_enqueue_scripts hook with a greater priority than your theme/plugin\'s, and
  //     use wp_localize_script() in the hook to pass an error message for your JavaScript
  //     to display
  // - Perform a wp_redirect() to send the user to the URL of your choice
  // - Set a variable with an error message which your theme or plugin can display
}

add_action( \'pre_get_posts\', \'wpse261038_validate_search_query_encoding\' );
我编写了一个覆盖率测试,将不同字母中的一些伪字符串与所有default encodings supported by PHP. 无论如何,它都不是完美的(我不知道我的假字符串有多逼真,而且似乎被日本人检测到窒息了),但它对确定候选人有一定的帮助。你可以看到它在起作用here.

在研究了该测试标记的潜在字符编码后,似乎Windows-1252 是满足您需求的完美选择,涵盖拉丁字母表以及常见拉丁语言的口音。

选择ISO-8859 角色集应该是另一个可行的选择,然而,由于我无法理解的原因mb_ 功能似乎无法区分ISO-8859\'s不同的字符集,尽管它们作为单独的编码列出。

要允许使用其他常见字符,还可以考虑添加HTML-ENTITIES.

SO网友:Paul \'Sparrow Hawk\' Biron

几天前,当@MichaelRogers发布了一个类似的问题时,我试图向他解释,知道字符串中使用的字符集(或脚本)是NOT 足以检测该字符串的语言。

因此,虽然@bosco详述的方法将删除俄语等字符串(下面有2个更正),但它将NOT 将搜索限制为英语。

要查看此信息,请尝试:

$strings = array (
    \'I\\\'m sorry\',                   // English
    \'Je suis désolé\',               // French
    \'Es tut mir Leid\',              // German
    \'Lorem ipsum dolor sit amet\',   // Lorem ipsum
    \'أنا سعيد\',                     // Arabic
    \'я счастлив\',                   // Russian
    \'我很高兴\',                     // Chinese (Simplified)
    \'我很高興\',                     // Chinese (Traditional)
    ) ;
foreach ($strings as $s) {
    if (preg_match (\'/^[\\p{Latin}\\p{Common}]+$/u\', $s) === 1) {
        echo "$s: matches latin+common\\n" ;
        }
    else {
        echo "$s: does not match latin+common\\n" ;
        }
    }
[note: 上述对@bosco提供的2项更正如下:

模式包含一个字符串(需要语法正确的PHP)

  • 添加了/u 修饰符(需要将图案和主题视为UTF-8编码,请参阅PHP: Regex Pattern Modifiers]
  • 将产生:

    I\'m sorry: matches latin+common
    Je suis désolé: matches latin+common
    Es tut mir Leid: matches latin+common
    Lorem ipsum dolor sit amet: matches latin+common
    أنا سعيد: does not match latin+common
    я счастлив: does not match latin+common
    我很高兴: does not match latin+common
    我很高興: does not match latin+common
    
    [note: 我会说英语、法语和法语;一些德国人(还有一些Lorem ipsum :-), 但阿拉伯语、俄语和汉语都依赖谷歌翻译]

    正如您所看到的,依靠检查拉丁文脚本NOT 确保你有英语。

    StackOverflow上有许多线程(例如。,Detect language from string in PHP) 提供有关该主题的更多信息。

    相关推荐

    Media searching ignored

    我们的网站使用WordPress,有很多媒体文件。我们网站的媒体名称格式如下[Car brand\'s name]-[number].jpg, 例如Tesla-1.jpg 或Aston Martin-3.jpg. 因此,我们可以通过搜索文章的名称轻松找到文章的特定媒体。但突然间,我们找不到媒体。我们正在尝试搜索名称为的媒体,但搜索结果不变。(不搜索任何内容时的媒体屏幕)(搜索Aston Martin时的媒体屏幕)当然,在填充搜索文本框后,它会显示一个加载图标,但结果总是一样的。为什么会发生这种情况?更新+