У меня есть массив идентификаторов, $galleries = array(1,2,5), и я хочу создать SQL-запрос, который использует значения массива в своем предложении WHERE, например:
SELECT *
FROM galleries
WHERE id = /* значения из массива $galleries... eg. (1 || 2 || 5) */
Как я могу сгенерировать эту строку запроса для использования с MySQL?
Ответ 1
Использование PDO:
$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:
$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();
Объяснение:
Используйте IN() оператор SQL, чтобы проверить, существует ли значение в данном списке.
В целом это выглядит так:
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', если вам нужно проверять строки.
Ответ 2
Для 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);
Ответ 3
Мы должны позаботиться об уязвимостях SQL-инъекций и null состоянии. Для числового массива используйте соответствующее преобразование типа, а именно intval, floatval или doubleval для каждого элемента. Для строковых типов, mysqli_real_escape_string(), которые при желании также могут применяться к числовым значениям. MySQL допускает числа, а также варианты даты в виде строки .
Чтобы соответствующим образом избежать значений перед переходом к запросу, создайте функцию, подобную этой:
function escape($string) {
// Предполагается, что $db — это идентификатор ссылки, возвращенный mysqli_connect() или mysqli_init()
return mysqli_real_escape_string($db, $string);
}
Такая функция, скорее всего, уже будет доступна вам в вашем приложении или, может быть, вы уже ее создали.
Очистите массив строк, например:
$values = array_map('escape', $gallaries);
Числовой массив можно обезопасить, используя intval, floatval или doubleval:
$values = array_map('intval', $gallaries);
Затем, наконец, создайте where запроса:
$where = count($values) ? "`id` = '" . implode("' OR `id` = '", $values) . "'" : 0;
или же
$where = count($values) ? "`id` IN ('" . implode("', '", $values) . "')" : 0;
Поскольку массив также иногда может быть пустым, $galleries = array(); поэтому необходимо быть уверенным в наличие значений, так как IN() не допускает пустой список. Можно также использовать OR вместо этого, но проблема остается.
И добавляем в финальный запрос:
$query = 'SELECT * FROM `galleries` WHERE ' . $where;
Web