Передача массива в запрос с помощью предложения WHERE
учитывая массив идентификаторов $galleries = array(1,2,5) Я хочу иметь SQL-запрос, который использует значения массива в его предложении WHERE, например:
SELECT *
FROM galleries
WHERE id = /* values of array $galleries... eg. (1 || 2 || 5) */
Как я могу создать эту строку запроса для использования с MySQL?
18 ответов:
остерегайтесь! этот ответ содержит строгое 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 change
str_repeat('i',доstr_repeat('s',если вам нужно проверить строки.[1]: я опустил некоторые ошибки проверки для краткости. Вам нужно проверить Обычные ошибки для каждого метода базы данных (или установите драйвер БД для создания исключений).
[2]: требуется PHP 5.6 или выше. Снова я опустил некоторые ошибки проверки для краткости.
ints:
$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цикл будет работать.путь Флавия / Аватаркавы лучше, но убедитесь, что ни одно из значений массива содержат запятые.
как ответ Флавия Стефа, вы можете использовать
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);
мы должны позаботиться о SQL injection уязвимостей и пустое условие. Я собираюсь обрабатывать оба, как показано ниже.
для чистого числового массива используйте соответствующее преобразование типа viz
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 в ложной части Троицы.
безопаснее.
$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})";
полковник шрапнель SafeMySQL библиотека для PHP предоставляет типовые заполнители в своих параметризованных запросах и включает в себя несколько удобных заполнителей для работы с массивами. Элемент
?aзаполнитель разворачивает массив в разделенный запятыми список экранированных строк*.например:
$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, у вас есть два варианта, чтобы сделать это, так как в запросе IN существует риск уязвимости SQL-инъекции. Вы можете использовать циклы чтобы получить точные данные, которые вы хотите, или вы можете использовать запрос с или случае
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();
Ниже приведен метод, который я использовал, используя 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);
безопасный способ без PDO:
$ids = array_filter(array_unique(array_map('intval', (array)$ids))); if ($ids) { $query = 'SELECT * FROM `galleries` WHERE `id` IN ('.implode(',', $ids).');'; }
(array)$idsCast$idsпеременной в массивеarray_mapпреобразовать все значения массива в целые числаarray_uniqueудалить повторяющиеся значенияarray_filterудалить нулевые значенияimplodeобъединить все значения в selection
основные методы предотвращения инъекции SQL являются:
- используйте подготовленные операторы и параметризованные запросы
- экранирование специальных символов в свой небезопасных переменная
использование подготовленных операторов и параметризованных запросов запрос считается лучшей практикой, но если вы выберете метод экранирования символов, вы можете попробовать мой пример ниже.
вы можете генерировать запросы с помощью
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:: quote ()

Comments