我正在尝试保护 MySQL 代码以防止 SQL 注入,因此在下面的代码中我使用准备好的语句和占位符。为此我更换了代码:
return '(r.recipe_name LIKE "%' . $term . '%" OR (ri.ingredient_name IS NOT NULL AND ri.ingredient_name LIKE "%' . $term . '%"))';
与:
return '(r.recipe_name LIKE :term OR (ri.ingredient_name IS NOT NULL AND ri.ingredient_name LIKE :term))';
这是我编辑的 PHP 片段:
$all_text_filter = '';
$ttAll = '';
if (isset($_REQUEST['q']) && $_REQUEST['q'] != '') {
$search_terms = array_map('trim', explode(' ', $_REQUEST['q']));
$text_conditions = array_filter($search_terms, function ($term) {
return !empty($term);
});
$text_conditions = array_map(function ($term) {
return '(r.recipe_name LIKE :term OR (ri.ingredient_name IS NOT NULL AND ri.ingredient_name LIKE :term))';
}, $text_conditions);
if (!empty($text_conditions)) {
$all_text_filter = ' AND (' . implode(' OR ', $text_conditions) . ')';
$ttAll = $all_text_filter;
}
}
echo "Debug: ttAll = $ttAll";
$searchText = isset($_REQUEST['q']) ? htmlspecialchars($_REQUEST['q']) : '';
$searchTerms = explode(' ', $searchText);
$searchConditions = array_map(function($index, $term) {
$paramName = ":searchTerm" . $index;
return "r.recipe_name LIKE $paramName";
}, array_keys($searchTerms), $searchTerms);
try {
$q = $pdo->prepare("SELECT r.*,
rc.recipe_category_name,
rc.recipe_category_slug,
rc1.recipe_cuisine_name,
u.name,
u.username,
u.photo
FROM recipes as r
JOIN recipe_categories as rc ON r.recipe_category_id = rc.id
JOIN recipe_cuisines rc1 ON r.recipe_cuisine_id = rc1.id
JOIN users u ON r.user_id = u.id
LEFT JOIN recipe_ingredients ri ON r.id = ri.recipe_id
WHERE r.recipe_status='Active' " . $tt1 . $tt2 . $tt3 . $tt4 . $tt5 . $tt6 . $ttAll . "
GROUP BY r.id
ORDER BY
CASE
WHEN " . implode(' OR ', $searchConditions) . " THEN 1
ELSE 2
END,
r.id DESC
LIMIT :offset, :resultsPerPage");
$q->bindParam(':offset', $offset, PDO::PARAM_INT);
$q->bindParam(':resultsPerPage', $resultsPerPage, PDO::PARAM_INT);
// Here I bind the parameters for text conditions
foreach ($text_conditions as $index => $termCondition) {
$paramName = ":term" . $index;
$q->bindValue($paramName, '%' . $termCondition . '%', PDO::PARAM_STR);
}
// Bind parameters for search terms
foreach ($searchTerms as $index => $term) {
$paramName = ":searchTerm" . $index;
$q->bindValue($paramName, '%' . $term . '%', PDO::PARAM_STR);
}
//echo $q->queryString; // Display the SQL query for debugging
$q->execute();
$res_data = $q->fetchAll();
} catch (PDOException $e) {
// Handle the exception, log the error, or show an error message
echo "Error executing the query: " . $e->getMessage();
}
问题是,现在当我搜索某些术语时,例如:苹果+柠檬,我收到错误:
Error executing the query: SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens
当我执行查询时:
SELECT r.*, rc.recipe_category_name, rc.recipe_category_slug, rc1.recipe_cuisine_name, u.name, u.username, u.photo FROM recipes as r JOIN recipe_categories as rc ON r.recipe_category_id = rc.id JOIN recipe_cuisines rc1 ON r.recipe_cuisine_id = rc1.id JOIN users u ON r.user_id = u.id LEFT JOIN recipe_ingredients ri ON r.id = ri.recipe_id WHERE r.recipe_status='Active' AND ((r.recipe_name LIKE :term OR (ri.ingredient_name IS NOT NULL AND ri.ingredient_name LIKE :term)) OR (r.recipe_name LIKE :term OR (ri.ingredient_name IS NOT NULL AND ri.ingredient_name LIKE :term))) GROUP BY r.id ORDER BY CASE WHEN r.recipe_name LIKE :searchTerm0 OR r.recipe_name LIKE :searchTerm1 THEN 1 ELSE 2 END, r.id DESC LIMIT :offset, :resultsPerPage
使用代码:
return '(r.recipe_name LIKE "%' . $term . '%" OR (ri.ingredient_name IS NOT NULL AND ri.ingredient_name LIKE "%' . $term . '%"))';
一切正常!!我花了几个小时努力寻找解决方案。
你把事情想得太复杂了。假设您有一个
$terms
数组。然后你可以这样做:
//'(r.recipe_name LIKE :term OR (ri.ingredient_name IS NOT NULL AND ri.ingredient_name LIKE :term))'
$params = [];
$criterias = [];
for ($i = 0; $i < $terms; $i++) {
$params[":term_" . $i] = "%" . $terms[$i] . "%";
$criterias[]="(r.recipe_name LIKE :term_{$i} OR (ri.ingredient_name IS NOT NULL AND ri.ingredient_name LIKE :term_{$i}))";
}
$criteria = implode(" OR ", $criterias);
确保将您的条件正确添加到查询中,添加您可能拥有的任何其他参数,并确保在执行查询时应用这些参数。