php按短语搜索mysql索引

时间:2017-10-12 15:29:54

标签: php mysql

已经看过几个例子,当单词用双引号括起来时,按短语搜索全文的位置。但是,在我的情况下,我有一个来自我要搜索的post数组的变量。

function find_images($term,$dbh) {
$results = $dbh->prepare("
SELECT * FROM images 
WHERE 
MATCH(imgTitle,imgDescr,copyright,keywords) 
AGAINST( "$term" IN BOOLEAN MODE)
ORDER BY copyright, images.imgName, images.sortOrder ASC");
$results->execute();

这不起作用:

  

解析错误:语法错误,意外的'$ term'(T_VARIABLE)...

我正在使用

AGAINST('+$term*' IN BOOLEAN MODE) ...

但返回包含短语中任何单词的结果。如果我在代码中输入确切的短语,我会得到正确的结果。所以我的问题是如何将我的变量放入我的代码中的双引号中而不抛出错误?

8 个答案:

答案 0 :(得分:5)

你的报价都错了。 PHP将在一个查询中用单引号插入变量,如下所示:

function find_images($term,$dbh) {
$results = $dbh->prepare("
SELECT * FROM images 
WHERE 
MATCH(imgTitle,imgDescr,copyright,keywords) 
AGAINST( '$term' IN BOOLEAN MODE)
ORDER BY copyright, images.imgName, images.sortOrder ASC");
$results->execute();

警告!

Little Bobby your script is at risk for SQL Injection Attacks. 了解preparedMySQLi语句。即使escaping the string也不安全!

由于您已经在使用支持它们的数据库API,您正在准备查询,因此将准备好的语句与占位符一起用于变量将会对您有所帮助。

答案 1 :(得分:4)

这不是SQL问题,它是一个PHP问题。因此,让我们简化问题,使其成为一个带有变量的PHP字符串。

SELECT * FROM mytable WHERE REGEXP_LIKE(mycolumn, 'regexp', 'i');

在字符串中使用PHP变量无法以这种方式完成,因为要在变量周围使用的双引号会在字符串的开头处终止双引号。

您可以通过转义它们将双引号变为文字双引号字符而不是PHP字符串分隔符:

$string = "blah blah ("$term") yadda yadda";

但我发现这很难看。

您还可以在PHP字符串中使用不同的单引号而不转义它们:

$string = "blah blah (\"$term\") yadda yadda";

因为双引号内的单引号被视为文字字符。对于SQL,它更受欢迎,因为单引号在SQL语法中是更标准的字符串分隔符。

您可以将变量与字符串串联组合使用:

$string = "blah blah ('$term') yadda yadda";

这使用字符串连接运算符$string = "blah blah (" . $term . ") yadda yadda"; 来组合三个字符串。第一个和第三个字符串使用双引号。中间一个是你的变量。但是这个解决方案并没有给你你想要的东西,因为结果字符串看起来像:

.

当你想要的是:

blah blah (term) yadda yadda

所以你必须把单引号放在里面,所以它们最终会出现在结果中:

blah blah ('term') yadda yadda

最后,在任何现代版本的PHP中都不需要字符串连接。我总是觉得令人费解的是为什么人们继续使用这种方法,可能是因为它出现在一些关于PHP的旧书中。您现在可以更简单地执行此操作:

$string = "blah blah ('" . $term . "') yadda yadda";

如果你的变量像数组元素那样更复杂,你可能需要像这样把它包围起来:

$string = "blah blah ('$term') yadda yadda";

以上所有内容都解决了将PHP变量与PHP字符串结合起来的问题。你应该明白该怎么做。

但是你也应该明白,对于SQL查询作为字符串,使用查询参数会更好。参数使得将变量与查询组合的整个问题更加简单。你不必担心引用或逃避。

$string = "blah blah ('{$term[0]}') yadda yadda";

使用占位符$results = $dbh->prepare(" SELECT * FROM images WHERE MATCH(imgTitle,imgDescr,copyright,keywords) AGAINST( ? IN BOOLEAN MODE) ORDER BY copyright, images.imgName, images.sortOrder ASC"); 替换您的变量。不要在SQL字符串中的占位符周围加上引号。

然后在执行时单独将变量传递给准备好的查询:

?

该PDO用法。我无法判断您是否正在使用代码中的PDO或Mysqli。 Mysqli有点不同:

$results->execute([$term]);

答案 2 :(得分:1)

PHP有两种形式的字符串。变量插值的内容(双引号),其中一个不是(单引号)。根据您的使用方式,您需要:

转义要使用的双引号(注意引号前的斜杠):

"SELECT * FROM ... \"$term\" ... "

对字符串使用单个字符串,然后连接变量(注意字符串是如何结束的,变量连接的,另一个字符串(查询的结尾)是连接到的):

'SELECT * FROM ... "' . $term . '" ... "

无论如何,reading the manual会解决这个问题。

编辑:正如其他人所说,您的代码存在SQL注入的严重风险。 从不只取一个值并将其填充到数据库查询中,特别是如果该值来自表单字段或其他外部源。您需要parameterize您的查询,以确保您的查询不能用作SQL注入的方法。

在使用之前,您还应该检查价值的有效性。他们是空的吗?它们是否包含您期望的数据类型?

答案 3 :(得分:1)

您的代码存在SQL注入风险。您需要使用Prepared Statement,如下所示。

如果您使用的是PDO:

$results = $dbh->prepare("
SELECT * FROM images 
WHERE 
MATCH(imgTitle,imgDescr,copyright,keywords) 
AGAINST( :term IN BOOLEAN MODE)
ORDER BY copyright, images.imgName, images.sortOrder ASC");
$stmt->bindParam(':term', $term);

如果您使用的是MySQLi:

$results = $dbh->prepare("
SELECT * FROM images 
WHERE 
MATCH(imgTitle,imgDescr,copyright,keywords) 
AGAINST( ? IN BOOLEAN MODE)
ORDER BY copyright, images.imgName, images.sortOrder ASC");
$stmt->bind_param('s', $term);

使用Parameter binding尝试阻止SQL Injections进行更多信息检查Prepared Statements

How can I prevent SQL injection in PHP?

答案 4 :(得分:0)

两件事。 补充:$ term ='+'。$ term。'*'; 更改为:反对(?在布尔模式下)和 改为:执行([$ term]); 我为所有的PDO查询执行此操作,而不是这个查询,所以非常感谢。

与此同时,我正在使用htmlentities来清理$ _POST变量,最终将双引号更改为&符号“分号”版本,我认为MySql在查看字符串时无法识别。相反,我改变了 $ term = strtolower(strip_tags($ _ POST ['term']));

因此,这两个更改似乎解决了问题并使查询更安全。谢谢你的帮助。

答案 5 :(得分:-2)

您必须以不同的方式在字符串中使用变量。使用点将字符串与变量连接起来 如果你需要在doublequote字符串中使用doublequote,只需使用反斜杠转义doublequote:

\"

说,你的代码变成了:

$results = $dbh->prepare("
SELECT * FROM images 
WHERE 
MATCH(imgTitle,imgDescr,copyright,keywords) 
AGAINST( \"" . $term . "\" IN BOOLEAN MODE)
ORDER BY copyright, images.imgName, images.sortOrder ASC");

答案 6 :(得分:-2)

问题是你在双引号字符串中有双引号。

$term周围的引号更改为单引号。

$results = $dbh->prepare("
SELECT * FROM images 
WHERE 
MATCH(imgTitle,imgDescr,copyright,keywords) 
AGAINST( '$term' IN BOOLEAN MODE)
ORDER BY copyright, images.imgName, images.sortOrder ASC");

答案 7 :(得分:-2)

试试这个可能有帮助

$results = $dbh->prepare("
SELECT * FROM images 

WHERE 

MATCH(imgTitle,imgDescr,copyright,keywords) 
AGAINST( '".$term."' IN BOOLEAN MODE)

ORDER BY copyright, images.imgName, images.sortOrder ASC");