安全 MySQL 查询以防止 SQL 注入出现无效参数号错误

问题描述 投票:0回答:1

我正在尝试保护 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 . '%"))';

一切正常!!我花了几个小时努力寻找解决方案。

php mysql pdo
1个回答
1
投票

你把事情想得太复杂了。假设您有一个

$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);

确保将您的条件正确添加到查询中,添加您可能拥有的任何其他参数,并确保在执行查询时应用这些参数。

© www.soinside.com 2019 - 2024. All rights reserved.