PHP/MYSQL-布尔全文搜索-精确字符串运算符(“";”)在预处理语句和SQL查询中给出不同的结果集
我在我的网站上制作了一个高级搜索页面,使用PHP编写的语句使用布尔全文搜索查询MySQL数据库MyISAM表 它非常类似于谷歌提供的高级搜索的第一部分,包括以下标准:PHP/MYSQL-布尔全文搜索-精确字符串运算符(“";”)在预处理语句和SQL查询中给出不同的结果集,php,mysql,exact-match,boolean-search,Php,Mysql,Exact Match,Boolean Search,我在我的网站上制作了一个高级搜索页面,使用PHP编写的语句使用布尔全文搜索查询MySQL数据库MyISAM表 它非常类似于谷歌提供的高级搜索的第一部分,包括以下标准: 所有这些话 确切的词语或陈述(注意:这就是问题所在) 这些词中的任何一个 这些话都没有 我检索每个输入值,清理并处理字符串集合的每个部分,然后通过prepared语句附加适当的信息以形成mySQL查询 因此,本质上,对于以下搜索: 全部- 精确的- 任何-希捷东芝 没有- 将输出为以下字符串: seagate* toshi
- 所有这些话
- 确切的词语或陈述(注意:这就是问题所在)
- 这些词中的任何一个
- 这些话都没有
- 全部-
- 精确的-
- 任何-希捷东芝
- 没有-
seagate* toshiba*
查询将产生如下结果:
SELECT id, description
FROM `items`
WHERE MATCH (description)
AGAINST ('seagate* toshiba*' IN BOOLEAN MODE)
这将列出所有行,在描述字段中,单词“seagate”后跟任何内容,“toshiba”后跟任何内容
这可以很好地工作,以下输出也可以:
-(750gb*) -(320gb*) seagate* toshiba*
+(16mb*) +(7200rpm*) -(750gb*) -(320gb*) seagate* toshiba*
+(16mb*) +(7200rpm*) -(750gb*) -(320gb*) +("serial ata 600") seagate* toshiba*
+("serial ata 600")
它将如上所述列出所有行,但不包括描述字段中带有“750gb”和“320gb”的任何行
通过向“所有这些单词”字符串添加一个值,我们将得到以下输出:
-(750gb*) -(320gb*) seagate* toshiba*
+(16mb*) +(7200rpm*) -(750gb*) -(320gb*) seagate* toshiba*
+(16mb*) +(7200rpm*) -(750gb*) -(320gb*) +("serial ata 600") seagate* toshiba*
+("serial ata 600")
它将如上所述列出所有行,但仅显示在描述字段中同时包含“16mb”和“7200rpm”的下行
现在查看有问题的部分。如果我使用“语句的确切单词”字符串并添加值“serial ata 600”,我们将得到以下输出:
-(750gb*) -(320gb*) seagate* toshiba*
+(16mb*) +(7200rpm*) -(750gb*) -(320gb*) seagate* toshiba*
+(16mb*) +(7200rpm*) -(750gb*) -(320gb*) +("serial ata 600") seagate* toshiba*
+("serial ata 600")
使用phpmyadmin将此字符串和结果查询作为sql查询运行,我将得到一个由2行组成的结果集,这些行与搜索条件匹配
然而,当在我的网站上运行时,我得到了6行的结果,这表明+(“serial ata 600”)“被完全忽略了
如果我只为字符串“Exact word of statement”输入一个值,那么我们将得到以下输出:
-(750gb*) -(320gb*) seagate* toshiba*
+(16mb*) +(7200rpm*) -(750gb*) -(320gb*) seagate* toshiba*
+(16mb*) +(7200rpm*) -(750gb*) -(320gb*) +("serial ata 600") seagate* toshiba*
+("serial ata 600")
结果表明,该字符串将列出包含“serial”或“ata”或“600”的所有行
通过在mysql中直接运行相同的查询,该结果将列出所有包含单词“serial ata 600”的行
在报告中指出:
A phrase that is enclosed within double quote (“"”) characters matches
only rows that contain the phrase literally, as it was typed.
MySQL中就是这种情况,但是当使用PHP作为预处理语句运行相同的查询时,返回不同的结果集
以下是准备好的声明:
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在工作方式上有任何不同的原因
我可以提供关于如何根据请求生成字符串的任何附加代码,但输出与我的示例中的一样
任何建议/建议/输入/反馈或评论都将不胜感激。这是一个事先准备好的陈述平铺直叙的地方。在内部,准备引擎将执行相当于:
$quoted = mysql_real_escape_string('+("serial ata 600")');
这就等于
+(\"serial ata 600\")
现在,您不再使用三个单词的引号短语,而是发送以下单独的单词:
+("serial
ata
600")
这是因为“
引号是SQL元字符,您需要将它们视为元字符。但是,由于它们是元字符,prep引擎将引用它们,将它们减少为普通的简引号,现在它们不再包含搜索短语。它们已经成为搜索短语的一部分
不知道这是否真的有效,但您可能必须重写准备好的语句,使其更像
... MATCH AGAINST (CONCAT('("', ?, '")'))
嗨,马克,非常感谢你的投入!实际上,它似乎确实是这样工作的,但实现起来更为复杂。尽管如此,你让我走上了思想链条的正确轨道,我能够解决这个问题,尽管我不太确定如何解决。我将联盟更改为UTF-8 bin,并将所有值转换为大写,这在任何情况下都更加统一。但是现在,我的查询似乎不用concat就可以运行了!谢谢你的帮助<代码>等价于:$quoted=mysql\u real\u escape\u字符串(“+(\“串行ata 600\”))我实际上一直在使用
mysqli\u real\u escape\u string()
来“清理”输入文本,这产生了如您所述的结果,但是在$pattern
输出之前,再次清理了结果,产生了如我所述的结果。双引号必须按照您在示例中描述的那样进行转义:+(\“serial ata 600\”
。如果没有转义,结果将返回3个单独的值,正如您所建议的那样。非常感谢您的理解!