使用 MATCH () AGAINST () 和 PDO 的奇怪行为(语法错误)
Weird behavior using MATCH () AGAINST () with PDO (syntax error)
我正在处理一个在 FULLTEXT 索引上使用 MATCH () AGAINST () 的查询。
奇怪的是,查询在 PHP 的 PDO 中不起作用,但 与 HeidiSQL 甚至 MySQL 控制台(mysql -u [...]).
这是我正在处理的查询:
SELECT *
FROM `announcements`
WHERE MATCH (`name`, `email`, `trademark`, `model`, `phone`, `city`) AGAINST ('+Ravenna*' IN BOOLEAN MODE)
这是 PDO 的错误:
SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near
'?) against ('?' in boolean mode))'
第 1 行
SELECT count(*) AS AGGREGATE
FROM `announcements`
WHERE `archived_at` IS NULL
AND (MATCH (`name`, `email`, `trademark`, `model`, `phone`, `city`) against ('+Ravenna*' IN boolean MODE))
编辑:
这是导致错误的函数:
[...]
$this->customQueries[] = function ($query) use ($words) {
$columnsToSearch = array_map(function ($key) {
return "`{$key}`";
}, [
'name', 'email', 'trademark', 'model', 'phone', 'city'
]);
$matchColumns = implode(', ', $columnsToSearch);
$againstWords = value(function () use ($words) {
$string = "";
foreach ($words as $word) {
$string .= "+{$word}* ";
}
$string = trim($string);
return $string;
});
// This is specifically the function that causes the error.
$query->whereNested(function ($q) use ($matchColumns, $againstWords) {
$q->whereRaw("match (?) against ('?' in boolean mode)", [$matchColumns, $againstWords]);
});
};
我不明白为什么它不能只在 PDO 上工作。
我已经在 Whosebug 上搜索过了,所有单引号都已经检查过了。
您不能将以逗号分隔的列名字符串作为预准备语句的参数插入。相反,您应该将它们注入 SQL 语句中,而不是将它们作为参数传递。
其次,永远不要用引号将占位符 (?
) 括起来。
所以尝试修改您的代码:
$query->whereNested(function ($q) use ($matchColumns, $againstWords) {
$q->whereRaw("match ($matchColumns) against (? in boolean mode)", [$againstWords]);
});
你可能认为像这样在 SQL 字符串中注入 $matchColumns
是不好的,但由于你可以完全控制该值,因此不存在 SQL 注入的风险).
我正在处理一个在 FULLTEXT 索引上使用 MATCH () AGAINST () 的查询。
奇怪的是,查询在 PHP 的 PDO 中不起作用,但 与 HeidiSQL 甚至 MySQL 控制台(mysql -u [...]).
这是我正在处理的查询:
SELECT *
FROM `announcements`
WHERE MATCH (`name`, `email`, `trademark`, `model`, `phone`, `city`) AGAINST ('+Ravenna*' IN BOOLEAN MODE)
这是 PDO 的错误:
SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near
'?) against ('?' in boolean mode))'
第 1 行
SELECT count(*) AS AGGREGATE
FROM `announcements`
WHERE `archived_at` IS NULL
AND (MATCH (`name`, `email`, `trademark`, `model`, `phone`, `city`) against ('+Ravenna*' IN boolean MODE))
编辑:
这是导致错误的函数:
[...]
$this->customQueries[] = function ($query) use ($words) {
$columnsToSearch = array_map(function ($key) {
return "`{$key}`";
}, [
'name', 'email', 'trademark', 'model', 'phone', 'city'
]);
$matchColumns = implode(', ', $columnsToSearch);
$againstWords = value(function () use ($words) {
$string = "";
foreach ($words as $word) {
$string .= "+{$word}* ";
}
$string = trim($string);
return $string;
});
// This is specifically the function that causes the error.
$query->whereNested(function ($q) use ($matchColumns, $againstWords) {
$q->whereRaw("match (?) against ('?' in boolean mode)", [$matchColumns, $againstWords]);
});
};
我不明白为什么它不能只在 PDO 上工作。
我已经在 Whosebug 上搜索过了,所有单引号都已经检查过了。
您不能将以逗号分隔的列名字符串作为预准备语句的参数插入。相反,您应该将它们注入 SQL 语句中,而不是将它们作为参数传递。
其次,永远不要用引号将占位符 (?
) 括起来。
所以尝试修改您的代码:
$query->whereNested(function ($q) use ($matchColumns, $againstWords) {
$q->whereRaw("match ($matchColumns) against (? in boolean mode)", [$againstWords]);
});
你可能认为像这样在 SQL 字符串中注入 $matchColumns
是不好的,但由于你可以完全控制该值,因此不存在 SQL 注入的风险).