query
В этой статье рассматривается функция mysqli_query() в PHP, которая используется для выполнения SQL-запросов к базе данных MySQL.
$mysqli->query() выполняет один SQL-оператор в базе данных MySQL через открытое соединение MySQLi. Это простейший способ взаимодействия с MySQL из PHP, поэтому он является правильной отправной точкой — однако, как вы увидите ниже, в тот момент, когда запрос содержит пользовательский ввод, следует использовать подготовленные выражения.
На этой странице рассматривается, что возвращает query(), как читать набор результатов, как функция ведёт себя при запросах на запись, а также ловушка SQL-инъекций, которую необходимо избегать.
Синтаксис
// Object-oriented style
$result = $mysqli->query($sql);
// Procedural style
$result = mysqli_query($mysqli, $sql);Обе формы делают одно и то же; в этой статье используется объектно-ориентированный стиль.
Что возвращает query()
Возвращаемое значение зависит от типа выполняемого оператора:
| Тип запроса | При успехе | При ошибке |
|---|---|---|
SELECT, SHOW, DESCRIBE, EXPLAIN | объект mysqli_result | false |
INSERT, UPDATE, DELETE, CREATE, ... | true | false |
Поскольку при ошибке всегда возвращается false, можно ветвить логику по возвращаемому значению с помощью обычного if. Никогда не считайте, что запрос выполнился успешно — опечатка в имени столбца или отсутствующая таблица возвращают false.
Выполнение запроса SELECT
При выполнении SELECT итерируйте по возвращённому результату и извлекайте каждую строку с помощью fetch_assoc() (или fetch_array()), а затем освобождайте результат по завершении:
<?php
$mysqli = new mysqli("localhost", "username", "password", "database");
// Stop early if the connection failed.
if ($mysqli->connect_errno) {
echo "Failed to connect to MySQL: " . $mysqli->connect_error;
exit();
}
$result = $mysqli->query("SELECT id, name FROM users");
if ($result) {
while ($row = $result->fetch_assoc()) {
echo $row["id"] . ": " . $row["name"] . "\n";
}
$result->free(); // release the result set's memory
} else {
echo "Query failed: " . $mysqli->error;
}
$mysqli->close();
?>Цикл while завершается, когда fetch_assoc() возвращает null (строк больше нет). $result->free() освобождает набор результатов, что важно в долго работающих скриптах, выполняющих множество запросов.
Выполнение INSERT, UPDATE и DELETE
Запросы на запись не возвращают набор результатов — при успехе они возвращают true. Чтобы узнать, сколько строк было затронуто, прочитайте $mysqli->affected_rows; чтобы получить auto-increment id только что вставленной строки, прочитайте $mysqli->insert_id:
<?php
$mysqli = new mysqli("localhost", "username", "password", "database");
if ($mysqli->query("UPDATE users SET active = 1 WHERE active = 0")) {
echo $mysqli->affected_rows . " rows updated";
} else {
echo "Query failed: " . $mysqli->error;
}
$mysqli->close();
?>Никогда не вставляйте пользовательский ввод напрямую в запрос
query() принимает строку необработанного SQL, поэтому конкатенация пользовательского ввода открывает дверь для SQL-инъекции — наиболее распространённой уязвимости безопасности баз данных в сети:
// DANGEROUS — do NOT do this
$id = $_GET['id'];
$result = $mysqli->query("SELECT * FROM users WHERE id = $id");Если посетитель отправит id=0 OR 1=1, этот запрос вернёт всех пользователей. Решение — подготовленное выражение, которое отправляет SQL и значения раздельно, чтобы значения никогда не могли интерпретироваться как SQL:
$stmt = $mysqli->prepare("SELECT * FROM users WHERE id = ?");
$stmt->bind_param("i", $_GET['id']); // "i" = integer
$stmt->execute();
$result = $stmt->get_result();Используйте query() только для фиксированного SQL без пользовательского ввода; для всего, что содержит значения, поступающие извне вашего кода, используйте подготовленные выражения. Полное руководство см. в разделе MySQL prepared statements.
Итоги
$mysqli->query()выполняет один SQL-оператор на открытом соединении MySQLi.SELECTвозвращаетmysqli_result, по которому итерируют с помощьюfetch_assoc(); другие операторы возвращаютtrue; любая ошибка возвращаетfalse.- После запроса на запись читайте
affected_rows, а послеINSERT—insert_id. - Переходите на подготовленные выражения, как только в запросе появляется пользовательский ввод.