Передача массива в запрос с использованием предложения WHERE - PullRequest
292 голосов
/ 25 мая 2009

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

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

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

Ответы [ 18 ]

307 голосов
/ 25 мая 2009

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

$ids = join("','",$galleries);   
$sql = "SELECT * FROM galleries WHERE id IN ('$ids')";
291 голосов
/ 14 мая 2014

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

56 голосов
/ 11 августа 2011

Интс:

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

строка:

$query = "SELECT * FROM `$table` WHERE `$column` IN('".implode("','",$array)."')";
27 голосов
/ 25 мая 2009

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

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

Тогда просто настройте ваш запрос:

SELECT *
FROM galleries
WHERE id IN ( $matches ) 

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

10 голосов
/ 25 мая 2009

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

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

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

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

8 голосов
/ 15 апреля 2015

Для 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 голосов
/ 11 апреля 2015

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

$ids = join(',', array_map('intval', $galleries));  
$sql = "SELECT * FROM galleries WHERE id IN ($ids)";
6 голосов
/ 16 апреля 2015

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

5 голосов
/ 13 апреля 2015

Безопаснее.

$galleries = array(1,2,5);
array_walk($galleries , 'intval');
$ids = implode(',', $galleries);
$sql = "SELECT * FROM galleries WHERE id IN ($ids)";
5 голосов
/ 15 апреля 2015

Мы можем использовать это предложение "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})";

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...