#php #mysql #mysqli
#php #mysql #mysqli
Вопрос:
Я знаком с основами работы mysqli_stmt_bind_param, но я все еще новичок в PHP и столкнулся с проблемой, которую я не уверен, как решить. Как мне реализовать метод mysqli_stmt_bind_param всякий раз, когда я не уверен, сколько? будет в SQL-запросе? Я прикрепил пример кода ниже, который иллюстрирует, о чем я говорю. Я также включил скриншот структуры базы данных, если это поможет.
В этом примере оператор SQL строится в зависимости от наличия аргументов в URL, других условий и т. Д. Потенциально может быть где угодно от 1? до 10 ?, с которыми я не уверен, как ориентироваться.
Я хочу добиться этого, потому что, насколько я понимаю, stmt_bind_param безопаснее, чем делать это так, как я сейчас это делаю .. верно?
if (isset($_GET['type'])) {
if ($_GET['type'] == "forgiven") {$supplemental = "discipline.forgiven = 1 AND ";}
else if ($_GET['type'] == "active") {$supplemental = "discipline.forgiven = 0 AND ";}
else if ($_GET['type'] == "all") {$supplemental = "discipline.forgiven IS NOT NULL AND ";}
else {$supplemental = "discipline.type = '" .$_GET['type']. "' AND ";}
}
if (isset($_GET['uuid'])) {$SQL = "SELECT users.firstName, users.lastName, users.homeroom, discipline.* FROM `discipline` INNER JOIN users ON users.uuid = discipline.recipient WHERE " .$supplemental. "discipline.recipient LIKE '" .$_GET['uuid']. "' ORDER BY discipline.timestamp DESC";}
else {$SQL = "SELECT users.firstName, users.lastName, users.homeroom, discipline.* FROM `discipline` INNER JOIN users ON users.uuid = discipline.recipient WHERE " .$supplemental. "users.homeroom LIKE '" .$_GET['search']. "' OR discipline.recipient LIKE '" .$_GET['search']. "' OR discipline.reason LIKE '%" .$_GET['search']. "%' OR discipline.action LIKE '%" .$_GET['search']. "%' ORDER BY discipline.timestamp DESC";}
$stmt = mysqli_stmt_init($connection);
if (!mysqli_stmt_prepare($stmt, $SQL)) {echo "SQL database connection error!";exit();}
else {
mysqli_stmt_execute($stmt);
$results = mysqli_stmt_get_result($stmt);
Структура таблицы:
Комментарии:
1. Я голосую за то, чтобы закрыть этот вопрос как дубликат, потому что ответ заключается в передаче массива в mysqli_stmt_bind_param() с использованием
...
синтаксиса, чтобы массив стал списком отдельных аргументов для этой функции. Это объясняется более подробно в ответе, на который я ссылался. Вы должны добавлять?
заполнители в SQL одновременно с добавлением элементов в массив значений, которые вы будете использовать при вызове bind_param .2. @BillKarwin это похоже на совершенно другой вопрос, я не понимаю, почему это дубликат..
3. Я написал ответ, чтобы проиллюстрировать, как это применимо к вашему случаю.
Ответ №1:
Вот пример того, как вы можете сделать связанные параметры «динамическими», или, другими словами, выполнить SQL-запрос с переменным количеством заполнителей параметров на основе условий. По мере написания условий добавляйте значения к массиву параметров.
$andTerms = [];
$types = "";
$params = [];
if (isset($_GET['type'])) {
if ($_GET['type'] == "forgiven") {
$andTerms[] = "discipline.forgiven = 1";
} else if ($_GET['type'] == "active") {
$andTerms[] = "discipline.forgiven = 0";
} else if ($_GET['type'] == "all") {
$andTerms[] = "discipline.forgiven IS NOT NULL";
} else {
$andTerms[] = "discipline.type = ?";
$types .= "s";
$params[] = $_GET['type'];
}
}
if (isset($_GET['uuid'])) {
$andTerms[] = "discipline.recipient LIKE ?"
$types .= "s";
$params[] = $_GET['uuid'];
} else {
$andTerms[] = "users.homeroom LIKE ? OR discipline.recipient LIKE ? OR discipline.reason LIKE ? OR discipline.action LIKE ?";
$types .= "ssss";
$params[] = $_GET['search']; // homeroom
$params[] = $_GET['search']; // recipient
$params[] = "%{$_GET['search']}%"; // reason
$params[] = "%{$_GET['search']}%"; // action
}
$andTermsImploded = implode(" AND ", $andTerms);
$SQL = "
SELECT users.firstName, users.lastName, users.homeroom, discipline.*
FROM `discipline` INNER JOIN users ON users.uuid = discipline.recipient
WHERE {$andTermsImploded}
ORDER BY discipline.timestamp DESC";
К тому времени, когда вы закончите это, вы добавили переменное количество терминов в предложение WHERE запроса. Между тем, значения для привязки $params
также имеют переменную длину, но если вы правильно написали каждый условный блок кода, он имеет то же количество элементов, что и количество заполнителей в SQL-запросе. Также $types
имеет правильное количество управляющих символов.
Затем пришло время выполнить вызов bind_param . Используйте ...
синтаксис для передачи вашего массива значений, как если бы это был список аргументов этой функции. Смотрите Пример # 10 в https://www.php.net/manual/en/functions.arguments.php это описывает списки аргументов переменной длины. Эта функция была введена в PHP 5.6 в 2014 году, поэтому она должна быть доступна любому сайту, на котором запущена версия PHP, срок службы которой не истек.
$stmt = mysqli_stmt_init($connection);
if (!mysqli_stmt_prepare($stmt, $SQL)) {
echo "SQL error!";
trigger_error($stmt->error);
exit();
}
mysqli_stmt_bind_param($stmt, $types, ...$params); // passing variable arguments
$ok = mysqli_stmt_execute($stmt);
if (!$ok) {
echo "SQL error!";
trigger_error($stmt->error);
exit();
}
$results = mysqli_stmt_get_result($stmt);
Не забывайте сообщать об ошибке в свой журнал ошибок каждый раз, когда вы вызываете prepare или execute .
PS: Я немного переформатировал код, чтобы соответствовать руководству по стилю PSR-2. Пожалуйста, следуйте этому руководству в будущем. Это облегчает другим разработчикам чтение вашего кода.