Выполнить запрос с условием или без

$query = !empty($_GET['box']) ?
"SELECT*FROM products WHERE categoryID IN (" . implode(',', $_GET['box']) . ")"
:
"SELECT*FROM products";

$result = $pdo->query($query);
$products = $result->fetchAll();

Всем привет! Есть три чекбокса, name которых передается в $_GET['box']. Хотела сделать параметризацию categoryID (categoryID=:categoryID) и передать методу execute() индексы для дальнейшего вывода запрашиваемых данных экран. У меня получилось это сделать в нижеприведенном скрипте, но с огромными костылями.

$arr = [];
$arr_products = [];
$products = [];

if(!empty($_GET['box'])) {
$arr = $_GET['box'];
}
else {
$products = [];
$result = $pdo->query("SELECT * FROM products");
$products = $result->fetchAll();
}

foreach ($arr as $key) {
$query= "SELECT * FROM products WHERE categoryID =:categoryID";
$result = $pdo->prepare($query);
$result -> execute(['categoryID' => $key]);
$arr_products = $products;
$products = array_merge($arr_products, $result->fetchAll());
}

Ответы (2 шт):

Автор решения: teran

не именуйте параметры. В целом всегда надо следовать двум вариантам: либо вы передаете значения как параметры, либо вы проверяете их значения по списку или еще как-то их валидируете. Если у вас тут числовые идентификаторы, то потенциально вы можете удостовериться, что там именно числовые значения и подставить их в запрос. Либо же передать их не именованными, условно говоря:

 $box = $_GET['box'] ?? [];
 $sql = "SELECT id, title FROM products";

 if($box) {
    $cats = implode(',', array_map('intval', $box));
    $sql .= " WHERE category_id IN ($cats)";
 }
 $st = $pdo->query($sql);
 if($st){
      $result = $st->fetchAll(PDO::FETCH_ASSOC);
 }

либо

if($box){
    $cats = array_map('intval', $box);
    $q = implode(',', array_fill(0, count($box)-1, '?');
    $sql .= "WHERE category_id IN ($q)";        
}
$st = $pdo->prepare($sql)

и т.д.

→ Ссылка
Автор решения: Ипатьев

Параметризовать запрос IN действительно получается грязновато, но в целом несложно:

  • надо создать строку с плейсходерами вида ?,?,? по числу элементов в массиве
  • а сам массив передать в execute

В общем виде код выглядит так

$in  = str_repeat('?,', count($in_array) - 1) . '?';
$sql = "SELECT * FROM my_table WHERE my_value IN ($in)";
$stm = $db->prepare($sql);
$stm->execute($in_array);
$data = $stm->fetchAll();

Для это конкретной задачи можно также оптимизировать алгоритм

$arr = [];
$sql = "SELECT * FROM products";

if(!empty($_GET['box'])) {
    $arr = $_GET['box'];
    $in  = str_repeat('?,', count($arr) - 1) . '?';
    $sql .= " WHERE categoryID in ($in)"
}
$stmt = $pdo->prepare($query);
$stmt -> execute($arr);
$products = $stmt->fetchAll();
→ Ссылка