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

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

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

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

Ответы

Ответ 1

ОСТОРОЖНО! Этот ответ содержит серьезную уязвимость SQL injection. НЕ используйте примеры кода, представленные здесь, без необходимости очистки любого внешнего входа.

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

Ответ 2

Использование 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 или выше. Снова я пропустил некоторую проверку ошибок для краткости.

Ответ 3

Интс:

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

строки:

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

Ответ 4

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

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

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

SELECT *
FROM galleries
WHERE id IN ( $matches ) 

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

Ответ 5

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

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

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

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

Ответ 6

Как ответ Flavius ​​Stef, вы можете использовать intval(), чтобы все id были значениями int:

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

Ответ 7

Для 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);

Ответ 8

Мы должны позаботиться об уязвимости 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 в тройной ложной части.

Ответ 9

Безопаснее.

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

Ответ 10

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

$galleries = array();

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

Как показано ниже: enter image description here

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

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

Ответ 11

У вас может быть таблица 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 или другого языка программирования.

Ответ 12

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

Например:

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

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

Ответ 13

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

Я обнаружил, что каждая строка должна быть инкапсулирована в одинарные кавычки для работы с функцией 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.

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

Ответ 14

Помимо использования запроса IN, у вас есть две возможности сделать это, так как в запросе IN существует риск уязвимости SQL-инъекции. Вы можете использовать цикл, чтобы получить точные данные, которые вы хотите, или вы можете использовать запрос с 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;
   }

Ответ 15

Еще пример:

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

Ответ 16

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

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

Ответ 17

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

$owner_id = 123;
$galleries = array(1,2,5,'abc');

$good_galleries = array_filter($chapter_arr, 'is_numeric');

$sql = "SELECT * FROM galleries WHERE owner=:OWNER_ID AND id IN ($good_galleries)";
$stmt = $dbh->prepare($sql);
$stmt->execute(array(
    "OWNER_ID" => $owner_id,
));

$data = $stmt->fetchAll(PDO::FETCH_ASSOC);

Ответ 18

Безопасный путь без PDO:

$ids = array_filter(array_unique(array_map('intval', (array)$ids)));

if ($ids) {
    $query = 'SELECT * FROM 'galleries' WHERE 'id' IN ('.implode(',', $ids).');';
}
  • (array)$ids $ids переменную $ids в массив
  • array_map Преобразование всех значений массива в целые числа
  • array_unique Удалить повторяющиеся значения
  • array_filter Удалить нулевые значения
  • implode Присоединить все значения к выбору IN

Ответ 19

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

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

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

Вы можете сгенерировать запросы с помощью 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:: цитата()

Ответ 20

$ids = "(".implode(',',$galleries).")";  // you can remplace "implode" with "join"  
$sql = "SELECT * FROM galleries WHERE id IN $ids";