Поиск…


Вступление

Интерфейс mysqli является улучшением (это означает расширение MySQL Improvement) интерфейса mysql , которое устарело в версии 5.5 и удалено в версии 7.0. Расширение mysqli, или, как его иногда называют, улучшенное расширение MySQL, было разработано для использования новых функций, обнаруженных в версиях MySQL версии 4.1.3 и новее. Расширение mysqli включено в версии PHP 5 и более поздних версий.

замечания

Характеристики

Интерфейс mysqli имеет ряд преимуществ: ключевые улучшения над расширением mysql:

  • Объектно-ориентированный интерфейс
  • Поддержка подготовленных заявлений
  • Поддержка нескольких заявлений
  • Поддержка транзакций
  • Расширенные возможности отладки
  • Поддержка встроенного сервера

Он имеет двойной интерфейс : более старый, процедурный стиль и новый, объектно-ориентированный стиль программирования (ООП) . Устаревший mysql имел только процедурный интерфейс, поэтому объектно-ориентированный стиль часто предпочтителен. Тем не менее, новый стиль также благоприятен из-за мощности ООП.

альтернативы

Альтернативой интерфейсу mysqli для доступа к базам данных является новый интерфейс PHP Data Objects (PDO) . Это имеет только программирование в стиле ООП и может иметь доступ только к базам данных MySQL.

MySQLi connect

Объектно-ориентированный стиль

Подключение к серверу

$conn = new mysqli("localhost","my_user","my_password");

Установите базу данных по умолчанию: $conn->select_db("my_db");

Подключение к базе данных

$conn = new mysqli("localhost","my_user","my_password","my_db");

Процедурный стиль

Подключение к серверу

$conn = mysqli_connect("localhost","my_user","my_password");

Задайте базу данных по умолчанию: mysqli_select_db($conn, "my_db");

Подключение к базе данных

$conn = mysqli_connect("localhost","my_user","my_password","my_db");

Проверить подключение к базе данных

Объектно-ориентированный стиль

if ($conn->connect_errno > 0) {
    trigger_error($db->connect_error);
} // else: successfully connected

Процедурный стиль

if (!$conn) {
   trigger_error(mysqli_connect_error());
} // else: successfully connected

Запрос MySQLi

Функция query принимает действительную строку SQL и выполняет ее непосредственно против соединения с базой данных $conn

Объектно-ориентированный стиль

$result = $conn->query("SELECT * FROM `people`");

Процедурный стиль

$result = mysqli_query($conn, "SELECT * FROM `people`");

ВНИМАНИЕ

Общей проблемой здесь является то, что люди просто выполняют запрос и ожидают его работы (т. Е. Возвращают объект mysqli_stmt ). Поскольку эта функция принимает только строку, вы сначала создаете запрос. Если в SQL вообще имеются ошибки, компилятор MySQL завершится неудачно, и в этот момент эта функция вернет false .

$result = $conn->query('SELECT * FROM non_existent_table'); // This query will fail
$row = $result->fetch_assoc();

Вышеприведенный код генерирует ошибку E_FATAL потому что $result является false , а не объектом.

PHP Неустранимая ошибка: вызов функции-члена fetch_assoc () для не-объекта

Процедурная ошибка похожа, но не фатальная, потому что мы просто нарушаем ожидания функции.

$row = mysqli_fetch_assoc($result); // same query as previous

Вы получите следующее сообщение от PHP

mysqli_fetch_array () ожидает, что параметр 1 будет mysqli_result, boolean given

Вы можете избежать этого, выполнив сначала тест

if($result) $row = mysqli_fetch_assoc($result);

Цикл через результаты MySQLi

PHP позволяет легко получать данные из ваших результатов и перебирать их с помощью инструкции while . Когда он не может получить следующую строку, он возвращает false , и ваш цикл завершается. Эти примеры работают с

  • mysqli_fetch_assoc - Ассоциативный массив с именами столбцов в виде ключей
  • mysqli_fetch_object - объект stdClass с именами столбцов в качестве переменных
  • mysqli_fetch_array - ассоциативный и числовой массив (могут использовать аргументы для получения того или другого)
  • mysqli_fetch_row - числовой массив

Объектно-ориентированный стиль

while($row = $result->fetch_assoc()) {
    var_dump($row);
}

Процедурный стиль

while($row = mysqli_fetch_assoc($result)) {
    var_dump($row);
}

Чтобы получить точную информацию из результатов, мы можем использовать:

while ($row = $result->fetch_assoc()) {
    echo 'Name and surname: '.$row['name'].' '.$row['surname'].'<br>';
    echo 'Age: '.$row['age'].'<br>'; // Prints info from 'age' column
}

Закрыть соединение

Когда мы закончим запрос к базе данных, рекомендуется закрыть соединение, чтобы освободить ресурсы.

Объектно-ориентированный стиль

$conn->close();

Процедурный стиль

mysqli_close($conn);

Примечание . Соединение с сервером будет закрыто, как только выполнение скрипта закончится, если оно не будет закрыто ранее, явно вызвав функцию закрытия соединения.

Случай использования. Если наш скрипт имеет достаточную сумму обработки для выполнения после получения результата и получил полный набор результатов, мы обязательно должны закрыть соединение. Если бы мы этого не сделали, существует вероятность того, что сервер MySQL достигнет предела соединения, когда веб-сервер находится в тяжелом режиме.

Подготовленные утверждения в MySQLi

Пожалуйста, прочитайте раздел «Предотвращение SQL-инъекции с параметризованными запросами» для полного обсуждения того, почему подготовленные операторы помогают защитить ваши SQL- запросы от атак SQL Injection

Здесь переменная $conn - это объект MySQLi. См. Пример подключения MySQLi для получения более подробной информации.

Для обоих примеров предположим, что $sql

$sql = "SELECT column_1 
    FROM table 
    WHERE column_2 = ? 
        AND column_3 > ?";

? представляет значения, которые мы предоставим позже. Обратите внимание, что нам не нужны котировки для заполнителей, независимо от типа. Мы также можем предоставить только заполнители в частях данных запроса, то есть SET , VALUES и WHERE . Вы не можете использовать заполнители в частях SELECT или FROM .

Объектно-ориентированный стиль

if ($stmt = $conn->prepare($sql)) {
  $stmt->bind_param("si", $column_2_value, $column_3_value);
  $stmt->execute();

  $stmt->bind_result($column_1);
  $stmt->fetch();
  //Now use variable $column_1 one as if it were any other PHP variable
  $stmt->close();
}

Процедурный стиль

if ($stmt = mysqli_prepare($conn, $sql)) {
  mysqli_stmt_bind_param($stmt, "si", $column_2_value, $column_3_value);
  mysqli_stmt_execute($stmt);
  // Fetch data here
  mysqli_stmt_close($stmt);
}

Первый параметр $stmt->bind_param или второй параметр mysqli_stmt_bind_param определяется типом данных соответствующего параметра в SQL-запросе:

параметр Тип данных связанного параметра
i целое число
d двойной
s строка
b капля

Ваш список параметров должен быть в порядке, указанном в вашем запросе. В этом примере si означает, что первый параметр ( column_2 = ? ) Является строкой, а второй параметр ( column_3 > ? ) Является целым числом.

Сведения о получении данных см. В разделе Как получить данные из подготовленного оператора

Исключение строк

Экранирование строк - это более старый ( и менее безопасный ) способ обеспечения безопасности данных для вставки в запрос. Он работает с использованием функции MySQL mysql_real_escape_string () для обработки и дезинфекции данных (другими словами, PHP не выполняет экранирование). API MySQLi обеспечивает прямой доступ к этой функции

$escaped = $conn->real_escape_string($_GET['var']);
// OR
$escaped = mysqli_real_escape_string($conn, $_GET['var']);

На данный момент у вас есть строка, которую MySQL считает безопасной для использования в прямом запросе

$sql = 'SELECT * FROM users WHERE username = "' . $escaped . '"';
$result = $conn->query($sql);

Так почему же это не так безопасно, как подготовленные заявления ? Есть способы обмануть MySQL для создания строки, которую он считает безопасным. Рассмотрим следующий пример

$id = mysqli_real_escape_string("1 OR 1=1");    
$sql = 'SELECT * FROM table WHERE id = ' . $id;

1 OR 1=1 не представляет данные, которые MySQL выйдет, но это все еще представляет SQL-инъекцию. Существуют и другие примеры, которые представляют собой места, где они возвращают небезопасные данные. Проблема заключается в том, что функция ускорения MySQL предназначена для обеспечения соответствия данных синтаксису SQL . Он НЕ предназначен для обеспечения того, чтобы MySQL не мог путать пользовательские данные для инструкций SQL .

Идентификатор ввода MySQLi

Получите последний идентификатор, сгенерированный запросом INSERT в таблице с столбцом AUTO_INCREMENT .

Объектно-ориентированный стиль

$id = $conn->insert_id;

Процедурный стиль

$id = mysqli_insert_id($conn);

Возвращает ноль, если ранее не было запроса на соединение, или если запрос не обновил значение AUTO_INCREMENT.

Вставить идентификатор при обновлении строк

Обычно оператор UPDATE не возвращает идентификатор вставки, поскольку идентификатор AUTO_INCREMENT возвращается только в том случае, когда новая строка была сохранена (или вставлена). Один из способов сделать обновления для нового идентификатора - использовать INSERT ... ON DUPLICATE KEY UPDATE для обновления.

Настройка для следующих примеров:

CREATE TABLE iodku (
    id INT AUTO_INCREMENT NOT NULL,
    name VARCHAR(99) NOT NULL,
    misc INT NOT NULL,
    PRIMARY KEY(id),
    UNIQUE(name)
) ENGINE=InnoDB;

INSERT INTO iodku (name, misc)
    VALUES
    ('Leslie', 123),
    ('Sally', 456);
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0
+----+--------+------+
| id | name   | misc |
+----+--------+------+
|  1 | Leslie |  123 |
|  2 | Sally  |  456 |
+----+--------+------+

Случай IODKU, выполняющий «обновление» и LAST_INSERT_ID() извлекает соответствующий id :

$sql = "INSERT INTO iodku (name, misc)
    VALUES
    ('Sally', 3333)            -- should update
    ON DUPLICATE KEY UPDATE    -- `name` will trigger "duplicate key"
    id = LAST_INSERT_ID(id),
    misc = VALUES(misc)";
$conn->query($sql);
$id = $conn->insert_id;        -- picking up existing value (2)

Случай, когда IODKU выполняет «вставку», и LAST_INSERT_ID() извлекает новый id :

$sql = "INSERT INTO iodku (name, misc)
    VALUES
    ('Dana', 789)            -- Should insert
    ON DUPLICATE KEY UPDATE
    id = LAST_INSERT_ID(id),
    misc = VALUES(misc);
$conn->query($sql);
$id = $conn->insert_id;      -- picking up new value (3)

Результирующее содержимое таблицы:

SELECT * FROM iodku;
+----+--------+------+
| id | name   | misc |
+----+--------+------+
|  1 | Leslie |  123 |
|  2 | Sally  | 3333 |  -- IODKU changed this
|  3 | Dana   |  789 |  -- IODKU added this
+----+--------+------+

Отладка SQL в MySQLi

Таким образом, ваш запрос не удался (см. MySQLi connect для того, как мы создали $conn )

$result = $conn->query('SELECT * FROM non_existent_table'); // This query will fail

Как мы узнаем, что произошло? $result является false так что это не поможет. К счастью, connect $conn может рассказать нам, что MySQL рассказал нам об ошибке

trigger_error($conn->error);

или процедурный

trigger_error(mysqli_error($conn));

Вы должны получить ошибку, аналогичную

Таблица «my_db.non_existent_table» не существует

Как получить данные из подготовленного заявления

Подготовленные заявления

См. Подготовленные операторы в MySQLi для подготовки и выполнения запроса.

Связывание результатов

Объектно-ориентированный стиль

$stmt->bind_result($forename);

Процедурный стиль

mysqli_stmt_bind_result($stmt, $forename);

Проблема с использованием bind_result заключается в том, что он требует, чтобы оператор указывал столбцы, которые будут использоваться. Это означает, что для выполнения вышеперечисленного запрос должен выглядеть так, как этот SELECT forename FROM users . Чтобы включить больше столбцов, просто добавьте их в качестве параметров в функцию bind_result (и убедитесь, что вы добавили их в SQL-запрос).

В обоих случаях мы присваиваем forename столбец в $forename переменной. Эти функции принимают столько аргументов, сколько столбцы, которые вы хотите назначить. Назначение выполняется только один раз, поскольку функция связывается по ссылке.

Затем мы можем выполнить петлю следующим образом:

Объектно-ориентированный стиль

while ($stmt->fetch())
    echo "$forename<br />";

Процедурный стиль

while (mysqli_stmt_fetch($stmt))
    echo "$forename<br />";

Недостатком этого является то, что вы должны сразу назначить множество переменных. Это затрудняет отслеживание больших запросов. Если у вас установлен MySQL Native Driver ( mysqlnd ) , все, что вам нужно сделать, это использовать get_result .

Объектно-ориентированный стиль

$result = $stmt->get_result();

Процедурный стиль

$result = mysqli_stmt_get_result($stmt);

С этим гораздо легче работать, потому что теперь мы получаем объект mysqli_result . Это тот же объект, что и mysqli_query . Это означает, что вы можете использовать регулярный цикл результатов для получения ваших данных.


Что делать, если я не могу установить mysqlnd ?

Если это так, то @Sophivorus вы покрыли этот удивительный ответ .

Эта функция может выполнять задачу get_result без ее установки на сервере. Он просто перебирает результаты и строит ассоциативный массив

function get_result(\mysqli_stmt $statement)
{
    $result = array();
    $statement->store_result();
    for ($i = 0; $i < $statement->num_rows; $i++)
    {
        $metadata = $statement->result_metadata();
        $params = array();
        while ($field = $metadata->fetch_field())
        {
            $params[] = &$result[$i][$field->name];
        }
        call_user_func_array(array($statement, 'bind_result'), $params);
        $statement->fetch();
    }
    return $result;
}

Затем мы можем использовать эту функцию для получения таких результатов, как если бы мы использовали mysqli_fetch_assoc()

<?php
$query = $mysqli->prepare("SELECT * FROM users WHERE forename LIKE ?");
$condition = "J%";
$query->bind_param("s", $condition);
$query->execute();
$result = get_result($query);

while ($row = array_shift($result)) {
    echo $row["id"] . ' - ' . $row["forename"] . ' ' . $row["surname"] . '<br>';
}

Он будет иметь такой же результат, как если бы вы использовали драйвер mysqlnd , за исключением того, что его не нужно устанавливать. Это очень полезно, если вы не можете установить указанный драйвер в своей системе. Просто реализуйте это решение.



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow