Как использовать подготовленные инструкции mysqli?

#php #mysqli #prepared-statement

#php #mysql #mysqli #подготовленный оператор

Вопрос:

Я пробую подготовленные инструкции, но приведенный ниже код не работает. Я получаю сообщение об ошибке:

Неустранимая ошибка: вызов функции-члена execute() для не-объекта в /var/www/prepared.php в строке 12

 <?php

    $mysqli = new mysqli("localhost", "root", "root", "test");
    if ($mysqli->connect_errno) {
        echo "Failed to connect to MySQL: " . $mysqli->connect_error;
    }

    $stmt = $mysqli->prepare("INSERT INTO users (name, age) VALUES (?,?)");

    // insert one row
    $stmt->execute(array('one',1));

    // insert another row with different values
    $stmt->execute(array('two',1));
?>
 

Кроме того, нужно ли мне использовать mysqli для подготовленных инструкций? Может кто-нибудь указать мне на полный пример подготовленных инструкций от подключения до вставки до выбора с обработкой ошибок?

Комментарии:

1. «Может ли кто-нибудь указать мне на полный пример подготовленного оператора от подключения до вставки до выбора с обработкой ошибок» Да. php.net/manual/en/mysqli.prepare.php . Обратите внимание на строку » mysqli_prepare() возвращает объект инструкции или FALSE если произошла ошибка.» .

Ответ №1:

Из mysqli::prepare документации:

Маркеры параметров должны быть привязаны к переменным приложения с помощью mysqli_stmt_bind_param() и / или mysqli_stmt_bind_result() перед выполнением инструкции или извлечением строк.

bind_param Документы.

т.е.:

 $name = 'one';
$age  = 1;

$stmt = $mysqli->prepare("INSERT INTO users (name, age) VALUES (?,?)");

// bind parameters. I'm guessing 'string' amp; 'integer', but read documentation.
$stmt->bind_param('si', $name, $age);

// *now* we can execute
$stmt->execute();
 

Ответ №2:

Также мне нужно использовать mysqli для подготовленного оператора. Может кто-нибудь указать мне на полный пример подготовленного оператора от подключения до вставки до выбора с обработкой ошибок

Вы также можете использовать PDO, который я предпочитаю. На самом деле, похоже, что вы путаете PDO и Mysqli в своем примере кода.

 $db = new PDO($dsn, $user, $pass);
$stmt = $db->prepare("INSERT INTO users (name, age) VALUES (?,?)");
$stmt->execute(array($name1, $age1));
$stmt->execute(array($name2, $age2));
 

В отличие от mysqli вам не нужно вызывать отдельную функцию привязки, хотя эта функция доступна, если вы предпочитаете / хотите / должны ее использовать.

Еще одна интересная особенность PDO — это именованные заполнители, которые могут быть гораздо менее запутанными в сложных запросах:

 $db = new PDO($dsn, $user, $pass);
$stmt = $db->prepare("INSERT INTO users (name, age) VALUES (:name,:age)");
$stmt->execute(array(':name' => $name1, ':age' => $age1));
$stmt->execute(array(':name' => $name2, ':age' => $age2));
 

Ответ №3:

Подключение

Важность соединения mysqli часто упускается из виду, сводясь к одной строке. В то время как правильный код подключения может решить множество проблем, от безопасности до удобства использования.

Учитывая, что ваш код является обычным процедурным PHP, вот простой код подключения mysqli, который будет включен в ваши скрипты:

 $host = '127.0.0.1';
$db   = 'test';
$user = 'root';
$pass = '';
$charset = 'utf8mb4';

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
try {
    $mysqli = new mysqli($host, $user, $pass, $db);
    $mysqli->set_charset($charset);
} catch (mysqli_sql_exception $e) {
     throw new mysqli_sql_exception($e->getMessage(), $e->getCode());
}
unset($host, $db, $user, $pass, $charset); // we don't need them anymore
 

Полное объяснение можно найти в моей статье Как правильно подключиться с помощью mysqli (а также множество полезных советов), но только небольшая цитата, чтобы выделить наиболее важные части:

  • установка правильного набора символов для соединения устранит целый класс ошибок, таких как странные символы / вопросительные знаки вместо ваших данных, пустой вывод json_encode(), проблемы с сохранением смайликов и т. Д.
  • установка правильного режима сообщения об ошибках устранит загадочные сообщения об ошибках, такие как ожидаемый параметр mysqli_fetch_assoc()… / Вызов функции-члена bind_param() …, вместо этого выдает фактическое сообщение об ошибке от MySQL.
  • безопасность — это не повод для смеха, не должно быть возможности утечки данных вашей базы данных наружу

Вставка

Вставить запрос относительно прост, и он уже рассмотрен в другом ответе.

Все, что вам нужно, это заменить все переменные (вместе с окружающими кавычками!) в запросе вопросительными знаками, затем подготовить запрос, затем вставить все переменные с их типами bind_param() и, наконец, выполнить запрос.

Только небольшой совет: MySQL с радостью примет все переменные в виде строк, поэтому не сходите с ума, находя правильный тип для определенной переменной, просто используя «s» для любой.

Итак, в основном вставка будет выглядеть так

 $sql = "INSERT INTO users (name, email, password) VALUES (?,?,?)";
$stmt= $conn->prepare($sql);
$stmt->bind_param("sss", $name, $email, $password_hash);
$stmt->execute();
 

Тот же принцип следует использовать для всех других типов запросов, таких как ОБНОВЛЕНИЕ или УДАЛЕНИЕ.

Выбор

Выполнение запроса select почти то же самое, но с одной маленькой хитростью. По какой-то неизвестной причине вы не можете использовать знакомые функции выборки сразу из подготовленного оператора. Итак, сначала вам нужно получить mysqli_result, а затем вы сможете использовать fetch_assoc() и т. fetch_obj() Д:

 $sql = "SELECT * FROM users WHERE id=?"; // SQL with parameters
$stmt = $conn->prepare($sql);
$stmt->bind_param("s", $id);
$stmt->execute();
$result = $stmt->get_result(); // get the mysqli result
$user = $result->fetch_assoc(); // fetch data 
 

Совет: нет абсолютно никакой необходимости в знакомой mysqli_num_rows() функции. Если вы подумаете об этом, вы всегда можете использовать сами данные, чтобы узнать, вернул ли ваш запрос какие-либо строки:

 $user = $result->fetch_assoc();
if ($user) {
    // found!
}
 

то же самое касается нескольких строк, благодаря

еще один совет: есть удобная функция fetch_all() , которая может получить массив всех выбранных строк за один раз. Например, если запрос возвращает несколько строк, вы можете преобразовать их в массив, изменив последнюю строку на

 $users = $result->fetch_all(MYSQLI_ASSOC); // fetch data 
 

Обработка ошибок

Обработка ошибок — самая важная, но несколько неожиданная часть. Несмотря на то, что говорится в многочисленных статьях и примерах, как правило, вам вообще не следует писать код для обработки ошибок. Это звучит абсолютно безумно, но именно так все и должно быть сделано. Большую часть времени все, что вам нужно сделать, это просто сообщить об ошибке. И mysqli / PHP уже может сделать это за вас, помощь не требуется. Поэтому вам не следует писать какой-либо код, который проверяет результат выполнения запроса — в случае ошибки mysqli сообщит об этом автоматически, благодаря mysqli_report() вызову функции, упомянутому в части #Connection . Опять же, полное объяснение этого принципа можно найти в другой статье, посвященной общим отчетам об ошибках PHP.

В редких случаях, когда вам действительно нужно обработать ошибку, то есть выполнить какое-то действие в случае ошибки, а не просто сообщить об этом, затем оберните ваши запросы в a try..catch .