am试图创建一个搜索功能,以便能够搜索产品,并通过相关性过滤结果,但查询后出现语法错误。 以下是我也遇到的错误
sql error
SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'mens', 'winter', 'jacket'%',6,0) + if (title LIKE '%'mens'%',5,0) + if (title LI' at line 5
The SQL being executed was: SELECT p.product_id,p.title,p.price,p.unit_sold,
p.profile_img,p.store_name,p.item_number,
(
(-- Title score
if (title LIKE '%'mens', 'winter', 'jacket'%',6,0) + if (title LIKE '%'mens'%',5,0) + if (title LIKE '%'winter'%',5,0) + if (title LIKE '%'jacket'%',5,0)
)+
(-- description
if (description LIKE '%'mens', 'winter', 'jacket'%',5,0) + if (description LIKE '%'mens'%',4,0) + if (description LIKE '%'winter'%',4,0) + if (description LIKE '%'jacket'%',4,0)
)
) as relevance
FROM products p
WHERE p.is_active = '1'
HAVING relevance > 0
ORDER BY relevance DESC,p.unit_sold DESC
LIMIT 10
和搜索功能
function search($q){
if (mb_strlen(trim($q))===0){
// no need for empty search
return false;
}
$query = $this->limitChars(trim($q));
// Weighing scores
$scoreFullTitle = 6;
$scoreTitleKeyword = 5;
$scoreFullDescription = 5;
$scoreDescriptionKeyword = 4;
$keywords = $this->filterSearchKeys($query);
$escQuery = $this->escape($keywords);
$titleSQL = array();
$descSQL = array();
/** Matching full occurences **/
if (count($keywords) > 1){
$titleSQL[] = "if (title LIKE '%".$escQuery."%',{$scoreFullTitle},0)";
$descSQL[] = "if (description LIKE '%".$escQuery."%',{$scoreFullDescription},0)";
/** Matching Keywords **/
foreach($keywords as $key){
$titleSQL[] = "if (title LIKE '%".Yii::$app->db->quoteValue($key)."%',{$scoreTitleKeyword},0)";
$descSQL[] = "if (description LIKE '%".Yii::$app->db->quoteValue($key)."%',{$scoreDescriptionKeyword},0)";
}
//add 0 is query string is empty to avoid error
if (empty($titleSQL)){
$titleSQL[] = 0;
}
if (empty($descSQL)){
$descSQL[] = 0;
}
$sql = "SELECT p.product_id,p.title,p.price,p.unit_sold,
p.profile_img,p.store_name,p.item_number,
(
(-- Title score
".implode(" + ", $titleSQL)."
)+
(-- description
".implode(" + ", $descSQL)."
)
) as relevance
FROM products p
WHERE p.is_active = '1'
HAVING relevance > 0
ORDER BY relevance DESC,p.unit_sold DESC
LIMIT 10";
$results = Yii::$app->db->createCommand($sql)->queryAll();
if (!$results){
return false;
}
return $results;
}
我还使用其他的escape()方法来转义查询字符串以避免sql注入,但并不能说服这是最佳实践,因为escape方法所做的是在字符串周围添加单引号,这反过来会甚至没有返回表中的任何匹配项,我也尝试使用mysqli_escape_string()但也无法使它正常工作,所以我想知道Yii2中逃避查询字符串并避免sql注入攻击的最佳实践是什么。
function escape($values)
{
$values = (array)$values;
$escaped = array();
foreach($values as $value) {
if(!is_scalar($value)) {
throw new CException('One of the values passed to values() is not a scalar.');
}
$escaped[] = Yii::$app->db->quoteValue($value);
}
return implode(', ', $escaped);
}
答案 0 :(得分:0)
您应转义LIKE
的整个表达式,包括%
通配符:
$value = Yii::$app->db->quoteValue('%' . implode(', ', (array) $keywords) . '%');
$titleSQL[] = "if (title LIKE $value,$scoreFullTitle,0)";
这将产生类似的内容:
if (title LIKE '%mens, winter, jacket%',6,0)