0

我正在使用 PHP 准备语句在我的网站上制作高级搜索页面,以使用布尔全文搜索查询 MySQL 数据库 MyISAM 表。

它与 Google 提供的高级搜索的第一部分非常相似,涵盖以下条件:

  • 所有这些话
  • 确切的词或陈述(注意:这就是问题所在)
  • 这些词中的任何一个
  • 这些话都没有

我检索每个输入值,清理和处理字符串集合的每个部分,然后通过准备好的语句附加适当的信息以形成 mySQL 查询。

因此,本质上是以下搜索:

  • 全部 -
  • 精确的 -
  • 任意——希捷东芝
  • 没有任何 -

将输出为以下字符串:

seagate* toshiba*

查询将导致如下内容:

SELECT id, description
FROM `items` 
WHERE MATCH (description)
AGAINST ('seagate* toshiba*' IN BOOLEAN MODE)

这将列出所有行,其中包含单词“seagate”后跟任何内容和“toshiba”后跟描述字段中的任何内容。

这很好用,输出如下:

-(750gb*) -(320gb*) seagate* toshiba*

这将列出上述所有行,但排除描述字段中包含“750gb”和“320gb”的任何行。

通过向“所有这些单词”字符串添加一个值,我们将获得以下输出:

+(16mb*) +(7200rpm*) -(750gb*) -(320gb*) seagate* toshiba*

这将列出上述所有行,但仅显示描述字段中同时包含“16mb”和“7200rpm”的下降。

现在是有问题的部分。如果我要使用“Exact word of statement”字符串并添加值“serial ata 600”,我们将得到以下输出:

+(16mb*) +(7200rpm*) -(750gb*) -(320gb*) +("serial ata 600") seagate* toshiba*

使用 phpmyadmin 将这个字符串和结果查询作为 sql 查询运行,我得到一个与搜索条件匹配的 2 行结果集。

但是,在我的网站上运行它时,我得到了 6 行的结果,这表明 +("serial ata 600")" 被完全忽略了。

如果我只为字符串“Exact word of statement”输入一个值,那么我们将得到以下输出:

+("serial ata 600")

结果表明该字符串将列出所有包含“serial”或“ata”或“600”的行。

通过直接在 mysql 中运行相同的查询,这个结果将列出所有包含“serial ata 600”字样的行。

此运算符的 MySQL 定义中,它指出:

A phrase that is enclosed within double quote (“"”) characters matches 
only rows that contain the phrase literally, as it was typed.

在 MySQL 中就是这种情况,但是当使用 PHP 作为 Prepared Statement 运行相同的查询时,会返回不同的结果集。

这是准备好的声明:

if ($result = $link->prepare("
    SELECT id, description
    FROM `items` 
    WHERE MATCH (description)
    AGAINST (? IN BOOLEAN MODE)
"))
{
    $result->bind_param("s", $pattern);
    ... ETC
}

这是$pattern在此之前的输出:

+("serial ata 600")

任何人都可以提出这种行为的原因,因为我认为 PHP 和 MySQL 之间的工作方式存在任何差异。

我可以提供与如何根据请求生成字符串有关的任何附加代码,但输出与我的示例中一样。

任何建议/建议/输入/反馈或评论将不胜感激。

4

1 回答 1

2

这是一个让准备好的陈述平淡无奇的地方。在内部,准备引擎将执行以下操作:

$quoted = mysql_real_escape_string('+("serial ata 600")');

这给了你相当于

+(\"serial ata 600\")

现在您不再使用 3 个单词的引用短语,而是发送以下单独的单词:

+("serial

ata

600")

这是因为"引号是 SQL 元字符,您需要将它们视为元字符。但是,因为它们是元字符,所以准备引擎会引用它们,将它们减少为普通的普通简引号,现在它们不再包含您的搜索短语。它们已成为搜索词组的一部分。

不知道这是否真的有效,但您可能需要重写准备好的语句以更像

... MATCH AGAINST (CONCAT('("', ?, '")'))
于 2013-05-21T16:23:07.243 回答