• База знаний
  • /
  • Блог
  • /
  • Wiki
  • /
+380 (44) 364 05 71

Работать с базой данных 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
Спасибо, что выбираете FREEhost.UA