Работать с базой данных Mysql в PHP можно с помощью:
- mysql — оригинальное API MySQL
- mysqli — улучшенный модуль MySQL
- PDO_MYSQL
Оригинальное API MySQL (функции mysql_*), начиная с версии PHP 5.5.0, объявлено как устаревшее (deprecated). Разработчики PHP настоятельно рекомендуют использовать в новых проектах либо mysqli, либо PDO_MYSQL.
Данная статья подскажет, как делать основные запросы с помощью mysqli, с чего начать и от чего оттолкнуться.
В зависимости от предпочтения, запросы можно выполнять либо через процедурный, либо через объектно-ориентированный стиль. В данной статье будет рассмотрен объектно-ориентированный подход, но любители процедурного стиля не сильно должны расстраиваться, поскольку все методы из основных классов зеркалируются в обычные функции.
Начало работы
Создадим класс, через который будем выполнять запросы:
<?php
class ourMysqli extends mysqli
{
public function __construct($connectConfig = array())
{
@parent::__construct(
$connectConfig['host'],
$connectConfig['username'],
$connectConfig['password'],
$connectConfig['dbname']
);
if ($this->connect_error) {
throw new \Exception (
$this->connect_error,
$this->connect_errno
);
}
}
}
?>
Здесь ничего сложного — объявляем класс-обертку над основным классом mysqli, через который и будет выполняться все работа с базой данных. В конструктор мы передаем данные доступа и пробуем подключиться, если что-то не так — бросаем Exception.
Выполним инициализацию класса и проверим, все ли хорошо:
<?php
$ourMysqli = new ourMysqli(array(
'host' => 'p:localhost',
'username' => 'dbuser',
'passwords' => 'dbpassword',
'dbname' => 'dbname',
));
echo get_class($ourMysqli);
?>
Если в результате видим наше название класса — поздравляем, все прошло успешно и можно двигаться дальше!
Простой SELECT-запрос
Рассмотрим следующий пример SELECT-запроса:
<?php
$selectQuery = 'SELECT field1, field2, field3 FROM table';
$resultQuery = $ourMysqli->query($selectQuery);
if ($resultQuery === false) {
throw new \Exception('Ошибка в SQL-запросе!');
}
// обработка результатов выборки
В $selectQuery описываем нужный SQL-запрос. После этого — выполняем запрос к базе данных с помощью метода query объекта mysqli. Если ошибок нету — получим объект mysqli_result, который сохраняется в переменной $resultQuery.
Следует обратить внимание, что объект mysqli_result возвращается только для запросов вида SELECT, SHOW, DESCRIBE и EXPLAIN, для других типов запросов метод query вернет TRUE в случае успешного выполнения. Если же в SQL-запросе присутствуют ошибки — метод query вернет FALSE, который нужно обработать с помощью Exception.
Обработка результатов
Результаты выборки из объекта $resultQuery мы можем получить с помощью различных методов:
<?php
// получить данные одной строки в виде ассоциативного массива
$entry = $resultQuery->fetch_assoc();
// получить данные одной строки в виде объекта
$entry = $resultQuery->fetch_object();
// получить все строки, вариант № 1
$entries = array();
while ($entry = $resultQuery->fetch_object()) {
$entries[] = $entry;
}
// получить все строки в виде ассоциативного массива, вариант № 2
$entries = $resultQuery->fetch_all(MYSQLI_ASSOC);
// num_rows содержит количество результатов выборки
if (!$resultQuery->num_rows) {
// если нет результатов выборки - выполнить какое-то действие
}
?>
Выбрать для себя удобный способ обработки результатов выборки Вы всегда можете в официальном PHP-мануале.
Простой SELECT-запрос с экранированием данных
Ни в коем случае нельзя подставлять в запросы данные от пользователя в чистом виде, поскольку можно словить SQL-injection. Для экранирования данных используется функция real_escape_string. Запрос может выглядеть следующим образом:
<?php
$selectQuery = '
SELECT
field1, field2, field3
FROM table
WHERE title="' . $ourMysqli->real_escape_string($dataFromUser) . '"';
$resultQuery = $ourMysqli->query($selectQuery);
if ($resultQuery === false) {
throw new \Exception('Ошибка в SQL-запросе!');
}
// обработка результатов выборки
?>
Подготовленный SELECT-запрос
В чем удобство подготовленных SELECT-запросов — на базу данных можно возложить ответственность за экранирование данных. Механизм приблизительно следующий:
<?php
// В SELECT-запросе нужно указать знаки вопроса в тех местах, где
нужно подставить неэкранированные данные от пользователя.
$selectQuery = <<< SQL_QUERY
SELECT field1, field2, field3
FROM table
WHERE id=?
SQL_QUERY;
// создать объект класса mysqli_stmt, который представляет подготовленное выражение
$mysqliStmt = $ourMysqli->stmt_init();
// подготовить запрос с помощью метода prepare у объекта $mysqliStmt
$mysqliStmt->prepare($selectQuery);
if ($mysqliStmt->errno) {
throw new \Exception('Ошибка в SQL-запросе!');
}
// подвязать переменные (данные от пользователя) к подготовленному запросу
$mysqliStmt->bind_param('i', $fieldId);
$mysqliStmt->execute();
if ($mysqliStmt->errno) {
throw new \Exception('Ошибка в SQL-запросе!');
}
// получить результат.
$resultQuery = $mysqliStmt->get_result();
// закрыть подготовленный запрос
$mysqliStmt->close();
// обработка результатов выборки
?>
Пояснение к примеру. Если подготовка запроса проходит успешно (нет ошибок в SQL-запросе) — тогда с помощью метода bind_param подвязываются переменные. Первый параметр содержит строку с типами переменных, последующие параметры — сами переменные, которые нужно "подставить" в запрос.
В нашем примере использовалась одна переменная, тип переменной представлен буквой i, что означает целое число. Всего можно подвязать 4 типа переменных:
- i — целое число.
- d — дробное число.
- s — строковые данные.
- b — двоичный объект (blob).
Примечание: метод $mysqliStmt->get_result() не будет работать, если не подключен mysqlnd-драйвер. Не все хостинги сайтов на сегодняшний день конфигурируют mysqlnd в минимальные пакеты, поэтому нужно быть внимательным!
Подготовленный SELECT-запрос с произвольным набором переменных для экранирования
Рано или поздно возникает ситуация, когда количество данных для экранирования может быть динамическим, то есть изменяется под влиянием каких-то условий пользовательского интерфейса.
Пример такого SELECT-запроса:
<?php
// в переменную $bindParamTypes типа string собираем типы подставляемых переменных
$bindParamTypes = '';
// в массив $bindParamVariables собираем значения переменных для подстановки
$bindParamVariables = array();
// в массив $whereArray собираем условия для команды WHERE в SQL-запросе
$whereArray = array();
// описываем параметр № 1
$bindParamTypes .= 'i';
$bindParamVariables[] = 1;
$whereArray[] = 'id=?';
// описываем параметр № 2
$bindParamTypes .= 's';
$bindParamVariables[] = '%some_title%';
$whereArray[] = 'title LIKE ?';
// формируем SQL запрос
$selectQuery = 'SELECT * FROM table'
if (count($whereArray) > 0) {
// если условия заданы — добавляем команду WHERE в SQL-запрос
$selectQuery .= ' WHERE ' . implode(' AND ', $whereArray);
}
if (count($whereArray) == 0) {
// если условия не заданы — выполняется неподготовленный SQL-запрос, результат
записывается в $resultQuery
$resultQuery = $ourMysqli->query($selectQuery);
if ($resultQuery === false) {
throw new \Exception('Ошибка в SQL-запросе!');
}
} else {
// если условия заданы — выполняем подготовленый SQL-запрос.
// создаем объект класса mysqli_stmt
$mysqliStmt = $ourMysqli->stmt_init();
// подготавливаем SQL-запрос
$mysqliStmt->prepare($selectQuery);
if ($mysqliStmt->errno) {
throw new \Exception('Ошибка в SQL-запросе!');
}
// "хитро" вызываем функцию bind_param
$mysqliStmtParameters = array_merge(array($bindParamTypes), $bindParamVariables);
call_user_func_array(
array(
$mysqliStmt,
'bind_param'
),
refArrayValues($mysqliStmtParameters)
);
$mysqliStmt->execute();
if ($mysqliStmt->errno) {
throw new \Exception('Ошибка в SQL-запросе!');
}
// получаем результат (работает при включенном mysqlnd драйвере)
$resultQuery = $mysqliStmt->get_result();
// закрываем подготовленный запрос
$mysqliStmt->close();
}
// обработка результатов выборки
// вспомогательная функция, которая создает ссылки на переменные внутри массива
function refArrayValues($arr){
if (strnatcmp(phpversion(),'5.3') >= 0)
{
$refs = array();
foreach($arr as $key => $value)
$refs[$key] = &$arr[$key];
return $refs;
}
return $arr;
}
?>
Пояснения. Для функции bind_param второй и последующий параметр должны быть переменными, переданными по ссылке. В php 5.3 изменилось поведение для массивов, в call_user_func_array нельзя просто передать обычный массив. Нужно обойти все значения из массива и сделать так, чтобы на элементы массива можно было ссылаться по ссылке, что и делается с помощью функции refArrayValues.
Выполнение INSERT, UPDATE и DELETE запросов
Запросы на обновление данных (INSERT, UPDATE, REPLACE, DELETE) выполняются аналогично запросам SELECT. Например:
Обычный запрос:
<?php
$insertQuery = '
INSERT INTO table
SET
field1="' . $ourMysqli->real_escape_string($data1) . '",
field2="' . $ourMysqli->real_escape_string($data2) . '"';
$resultQuery = $ourMysqli->query($insertQuery);
if ($resultQuery === false) {
throw new \Exception('Ошибка в SQL-запросе!');
}
?>
<
Подготовленный запрос:
<?php
$insertQuery = <<< SQL_QUERY
INSERT INTO table
SET
field1=?,
field2=?,
field3=?,
field4=?
SQL_QUERY;
$mysqliStmt = $ourMysqli->stmt_init();
$mysqliStmt->prepare($insertQuery);
if ($mysqliStmt->errno) {
throw new \Exception('Ошибка в SQL-запросе!');
}
$mysqliStmt->bind_param('issi', $field1Int, $field2Str, $field3Str, $field4Int);
$mysqliStmt->execute();
if ($mysqliStmt->errno) {
throw new \Exception('Ошибка в SQL-запросе!');
}
$insertId = $mysqliStmt->insert_id;
$mysqliStmt->close();
?>
Ссылки по теме:
Улучшенный модуль MySQL в мануале PHP
Дата: 21.05.2014 Автор: Игорь
|
|
Авторам статті важлива Ваша думка. Будемо раді його обговорити з Вами:
comments powered by Disqus