Передача массива в запрос с использованием предложения WHERE

Учитывая массив идентификаторов $galleries = array(1,2,5) Я хочу иметь SQL-запрос, который использует значения массива в своем предложении WHERE, например:

 SELECT * FROM galleries WHERE id = /* values of array $galleries... eg. (1 || 2 || 5) */ 

Как я могу сгенерировать эту строку запроса для использования с MySQL?

Solutions Collecting From Web of "Передача массива в запрос с использованием предложения WHERE"

BEWARE! Этот ответ содержит серьезную уязвимость SQL-инъекции . НЕ используйте примеры кода, представленные здесь, без необходимости очистки любого внешнего входа.

 $ids = join("','",$galleries); $sql = "SELECT * FROM galleries WHERE id IN ('$ids')"; 

Использование PDO: [1]

 $in = join(',', array_fill(0, count($ids), '?')); $select = <<<SQL SELECT * FROM galleries WHERE id IN ($in); SQL; $statement = $pdo->prepare($select); $statement->execute($ids); 

Использование MySQLi [2]

 $in = join(',', array_fill(0, count($ids), '?')); $select = <<<SQL SELECT * FROM galleries WHERE id IN ($in); SQL; $statement = $mysqli->prepare($select); $statement->bind_param(str_repeat('i', count($ids)), ...$ids); $statement->execute(); $result = $statement->get_result(); 

Объяснение:

Используйте оператор SQL IN() чтобы проверить, существует ли значение в данном списке.

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

 expr IN (value,...) 

Мы можем построить выражение для размещения внутри () из нашего массива. Обратите внимание, что в скобках должно быть хотя бы одно значение, или MySQL вернет ошибку; это соответствует тому, что наш входной массив имеет хотя бы одно значение. Чтобы помочь предотвратить атаки SQL-инъекций, сначала создайте ? для каждого элемента ввода для создания параметризованного запроса. Здесь я предполагаю, что массив, содержащий ваши идентификаторы, называется $ids :

 $in = join(',', array_fill(0, count($ids), '?')); $select = <<<SQL SELECT * FROM galleries WHERE id IN ($in); SQL; 

Учитывая входной массив из трех элементов, $select будет выглядеть так:

 SELECT * FROM galleries WHERE id IN (?, ?, ?) 

Снова обратите внимание, что есть ? для каждого элемента во входном массиве. Затем мы будем использовать PDO или MySQLi для подготовки и выполнения запроса, как указано выше.

Использование оператора IN() со строками

Из-за связанных параметров легко менять строки и целые числа. Для PDO изменений не требуется; для MySQLi измените str_repeat('i', на str_repeat('s', если вам нужно проверить строки.

[1]: Я пропустил некоторую проверку ошибок для краткости. Вам нужно проверить обычные ошибки для каждого метода базы данных (или установить драйвер БД для исключения исключений).

[2]: Требуется PHP 5.6 или выше. Снова я пропустил некоторую проверку ошибок для краткости.

Интс:

 $query = "SELECT * FROM `$table` WHERE `$column` IN(".implode(',',$array).")"; 

строки:

 $query = "SELECT * FROM `$table` WHERE `$column` IN('".implode("','",$array)."')"; 

Предполагая, что вы должным образом дезинфицируете свои входы заранее …

 $matches = implode(',', $galleries); 

Затем просто настройте свой запрос:

 SELECT * FROM galleries WHERE id IN ( $matches ) 

Введите значения в зависимости от вашего набора данных.

Использование:

 select id from galleries where id in (1, 2, 5); 

Простой for each цикла будет работать.

Способ Flavius ​​/ AvatarKava лучше, но убедитесь, что ни одно из значений массива не содержит запятых.

Как ответ Флавиуса Стефа , вы можете использовать intval() чтобы убедиться, что все id являются значениями int:

 $ids = join(',', array_map('intval', $galleries)); $sql = "SELECT * FROM galleries WHERE id IN ($ids)"; 

Для MySQLi с функцией escape:

 $ids = array_map(function($a) use($mysqli) { return is_string($a) ? "'".$mysqli->real_escape_string($a)."'" : $a; }, $ids); $ids = join(',', $ids); $result = $mysqli->query("SELECT * FROM galleries WHERE id IN ($ids)"); 

Для PDO с подготовленным заявлением:

 $qmarks = implode(',', array_fill(0, count($ids), '?')); $sth = $dbh->prepare("SELECT * FROM galleries WHERE id IN ($qmarks)"); $sth->execute($ids); 

Безопаснее.

 $galleries = array(1,2,5); array_walk($galleries , 'intval'); $ids = implode(',', $galleries); $sql = "SELECT * FROM galleries WHERE id IN ($ids)"; 

Мы можем использовать это предложение WHERE id IN, если мы правильно фильтруем входной массив. Что-то вроде этого:

 $galleries = array(); foreach ($_REQUEST['gallery_id'] as $key => $val) { $galleries[$key] = filter_var($val, FILTER_SANITIZE_NUMBER_INT); } 

Как пример ниже: введите описание изображения здесь

 $galleryIds = implode(',', $galleries); 

Т.е. теперь вы должны безопасно использовать $query = "SELECT * FROM galleries WHERE id IN ({$galleryIds})";

Мы должны позаботиться об уязвимости SQL-инъекций и о пустом состоянии . Я собираюсь обрабатывать оба, как показано ниже.

Для чистого числового массива используйте соответствующее преобразование типов: intval или floatval или doubleval над каждым элементом. Для типов строк mysqli_real_escape_string() которые могут также применяться к числовым значениям, если хотите. MySQL позволяет использовать числа, а также варианты даты в виде строки .

Чтобы соответствующим образом избежать значений перед переходом к запросу, создайте функцию, аналогичную:

 function escape($string) { // Assuming $db is a link identifier returned by mysqli_connect() or mysqli_init() return mysqli_real_escape_string($db, $string); } 

Такая функция, скорее всего, уже будет доступна вам в вашем приложении, или, возможно, вы уже создали ее.

Очистите массив строк следующим образом:

 $values = array_map('escape', $gallaries); 

Цифровой массив можно дезинфицировать с использованием intval или floatval или doubleval вместо подходящего:

 $values = array_map('intval', $gallaries); 

Затем, наконец, построим условие запроса

 $where = count($values) ? "`id` = '" . implode("' OR `id` = '", $values) . "'" : 0; 

или

 $where = count($values) ? "`id` IN ('" . implode("', '", $values) . "')" : 0; 

Так как массив иногда также может быть пустым, например $galleries = array(); поэтому следует отметить, что IN () не допускает пустой список. Вместо этого можно использовать OR , но проблема остается. Таким образом, вышеуказанная проверка, count($values) , должна гарантировать то же самое.

И добавьте его в окончательный запрос:

 $query = 'SELECT * FROM `galleries` WHERE ' . $where; 

СОВЕТ . Если вы хотите показать все записи (без фильтрации) в случае пустого массива вместо того, чтобы скрывать все строки, просто замените 0 на 1 в ложной части тернария.

Библиотека SafeMySQL от Col. Shrapnel для PHP предоставляет типовые заполнители в параметризованных запросах и включает в себя несколько удобных заполнителей для работы с массивами. «Заполнитель» расширяет массив в список экранированных строк *.

Например:

 $someArray = [1, 2, 5]; $galleries = $db->getAll("SELECT * FROM galleries WHERE id IN (?a)", $someArray); 

* Обратите внимание, что поскольку MySQL выполняет автоматическое принуждение типа, не имеет значения, что SafeMySQL преобразует идентификаторы выше в строки – вы все равно получите правильный результат.

У вас могут быть табличные texts (T_ID (int), T_TEXT (text)) и табличный test (id (int), var (varchar(255)))

insert into test values (1, '1,2,3') ; следующее выводит строки из табличных текстов, где T_ID IN (1,2,3) :

 SELECT * FROM `texts` WHERE (SELECT FIND_IN_SET( T_ID, ( SELECT var FROM test WHERE id =1 ) ) AS tm) >0 

Таким образом, вы можете управлять простым отношением базы данных n2m без дополнительной таблицы и использовать только SQL без необходимости использования PHP или другого языка программирования.

Просто использование функции IN будет работать.

SELECT * FROM galleries WHERE id IN(1,2,3,4);

Поскольку исходный вопрос относится к массиву чисел, и я использую массив строк, я не мог заставить данные примеры работать.

Я обнаружил, что каждая строка должна быть инкапсулирована в одинарные кавычки для работы с функцией IN() .

Вот мое решение

 foreach($status as $status_a) { $status_sql[] = '\''.$status_a.'\''; } $status = implode(',',$status_sql); $sql = mysql_query("SELECT * FROM table WHERE id IN ($status)"); 

Как вы можете видеть, первая функция обертывает каждую переменную массива в single quotes (\') а затем взрывает массив.

ПРИМЕЧАНИЕ: $status не имеет одинарных кавычек в инструкции SQL.

Вероятно, есть лучший способ добавить цитаты, но это работает.

Помимо использования запроса IN, у вас есть две возможности сделать это, так как в запросе IN существует риск уязвимости SQL-инъекции. Вы можете использовать looping для получения точных данных, которые вы хотите, или вы можете использовать запрос с OR case

 1. SELECT * FROM galleries WHERE id=1 or id=2 or id=5; 2. $ids = array(1, 2, 5); foreach ($ids as $id) { $data[] = SELECT * FROM galleries WHERE id= $id; } 

Еще один пример:

 $galleryIds = [1, '2', 'Vitruvian Man']; $ids = array_filter($galleryIds, function($n){return (is_numeric($n));}); $ids = implode(', ', $ids); $sql = "SELECT * FROM galleries WHERE id IN ({$ids})"; // output: 'SELECT * FROM galleries WHERE id IN (1, 2)' $statement = $pdo->prepare($sql); $statement->execute(); 

Основными методами предотвращения внедрения SQL являются:

  • Использовать подготовленные операторы и параметризованные запросы
  • Экранирование специальных символов в вашей небезопасной переменной

Использование подготовленных операторов и запрос параметризованных запросов считается лучшей практикой, но если вы выберете метод экранирующих символов, вы можете попробовать мой пример ниже.

Вы можете сгенерировать запросы с помощью array_map чтобы добавить одну кавычку к каждому array_map в $galleries :

 $galleries = array(1,2,5); $galleries_str = implode(', ', array_map(function(&$item){ return "'" .mysql_real_escape_string($item) . "'"; }, $galleries)); $sql = "SELECT * FROM gallery WHERE id IN (" . $galleries_str . ");"; 

Сгенерированный $ sql var будет:

 SELECT * FROM gallery WHERE id IN ('1', '2', '5'); 

Примечание: mysql_real_escape_string , как описано в его документации здесь , устарела в PHP 5.5.0, и она была удалена в PHP 7.0.0. Вместо этого следует использовать расширение MySQLi или PDO_MySQL. См. Также MySQL: выбирая руководство по API и связанные с ним FAQ для получения дополнительной информации. Альтернативы этой функции включают:

  • mysqli_real_escape_string ()

  • PDO :: цитата ()