Класс для работы с базой данных
Недавно я заметил, что в Интернете можно найти огромное количество PHP-классов для работы с базой данных. Как обычно, они всегда щеголяют своей функциональностью и количеством возможностей. Я решил тоже написать свой класс для работы с базой данных, но пошёл по другому пути. Я хотел сделать такой класс, чтобы в нём был тот необходимый минимум функционала, который только и требуется. Всё остальное - это уже непонятные навороты, которые использовать, как минимум, небезопасно.
Привожу свой прокомментированный класс для работы с базой данных:
<?php
class DataBase {
private static $db = null; // Единственный экземпляр класса, чтобы не создавать множество подключений
private $mysqli; // Идентификатор соединения
private $sym_query = "{?}"; // "Символ значения в запросе"
/* Получение экземпляра класса. Если он уже существует, то возвращается, если его не было, то создаётся и возвращается (паттерн Singleton) */
public static function getDB() {
if (self::$db == null) self::$db = new DataBase();
return self::$db;
}
/* private-конструктор, подключающийся к базе данных, устанавливающий локаль и кодировку соединения */
private function __construct() {
$this->mysqli = new mysqli("localhost", "root", "", "my_db");
$this->mysqli->query("SET lc_time_names = 'ru_RU'");
$this->mysqli->query("SET NAMES 'utf8'");
}
/* Вспомогательный метод, который заменяет "символ значения в запросе" на конкретное значение, которое проходит через "функции безопасности" */
private function getQuery($query, $params) {
if ($params) {
for ($i = 0; $i < count($params); $i++) {
$pos = strpos($query, $this->sym_query);
$arg = "'".$this->mysqli->real_escape_string($params[$i])."'";
$query = substr_replace($query, $arg, $pos, strlen($this->sym_query));
}
}
return $query;
}
/* SELECT-метод, возвращающий таблицу результатов */
public function select($query, $params = false) {
$result_set = $this->mysqli->query($this->getQuery($query, $params));
if (!$result_set) return false;
return $this->resultSetToArray($result_set);
}
/* SELECT-метод, возвращающий одну строку с результатом */
public function selectRow($query, $params = false) {
$result_set = $this->mysqli->query($this->getQuery($query, $params));
if ($result_set->num_rows != 1) return false;
else return $result_set->fetch_assoc();
}
/* SELECT-метод, возвращающий значение из конкретной ячейки */
public function selectCell($query, $params = false) {
$result_set = $this->mysqli->query($this->getQuery($query, $params));
if ((!$result_set) || ($result_set->num_rows != 1)) return false;
else {
$arr = array_values($result_set->fetch_assoc());
return $arr[0];
}
}
/* НЕ-SELECT методы (INSERT, UPDATE, DELETE). Если запрос INSERT, то возвращается id последней вставленной записи */
public function query($query, $params = false) {
$success = $this->mysqli->query($this->getQuery($query, $params));
if ($success) {
if ($this->mysqli->insert_id === 0) return true;
else return $this->mysqli->insert_id;
}
else return false;
}
/* Преобразование result_set в двумерный массив */
private function resultSetToArray($result_set) {
$array = array();
while (($row = $result_set->fetch_assoc()) != false) {
$array[] = $row;
}
return $array;
}
/* При уничтожении объекта закрывается соединение с базой данных */
public function __destruct() {
if ($this->mysqli) $this->mysqli->close();
}
}
?>
Как видите, нет ничего лишнего, только всё самое необходимое. Теперь разберём PHP-код, который использует данный класс:
<?php
$db = DataBase::getDB(); // Создаём объект базы данных
$query = "SELECT * FROM `users` WHERE `id` > {?} AND `online` = {?}";
$table = $db->select($query, array(10, 1)); // Запрос явно должен вывести таблицу, поэтому вызываем метод select()
$query = "SELECT `login` FROM `users` WHERE `email` = {?}";
$login = $db->selectCell($query, array("[email protected]"));// Запрос должен вывести конкретную ячейку, поэтому вызываем метод selectCell()
?>
Теперь Вы понимаете, что для удобной и безопасной работой с базой данных вовсе не требуется библиотека из 100 классов. Всё необходимое имеется, и данный класс без проблем обработает любой запрос. Единственное, что я рекомендую - это настройки вынести в отдельный класс. То есть адрес хоста, имя пользователя, пароль, название базы данных, кодировку, локаль и "символ значения" вынести в отдельный класс, откуда их считывать.
Вот такой незамысловатый класс для работы с базой данных я использую в своих проектах.
-
- Михаил Русаков
Комментарии (21):
Интересный метод getQuery(), напоминает параметризованные запросы prepare(), bind_param()... Как по вашему, стоит ли заморачиваться с ними или для безопасности вполне хватит вашего подхода для подстановки значений в запрос?
Ответить
Лично я их не использую и особого смысла не вижу.
Ответить
Михаил, а можете написать пример изменёной функции getQuery так, чтобы ставить не {?} а что-то типа :i, :s, :? тоесть i это число, s это строка, ? это любое значение, как сделать такое распределение, напишите пожалуйста, если вдруг тут не захотите писать, то напишите мне в ответ "Пишите на форум и я отвечу и помогу с примером", хорошо?
Ответить
Михаил, возникла проблема... Все методы работают кроме select и selectRow. Не знаю в чем проблема, никаких ошибок не выводит но и то, что нужно тоже :( Я в отчаянии...
Ответить
Скорее всего, ошибка в Вашем запросе. Используйте этот метод для поиска ошибок: http://myrusakov.ru/php-finderror.html и для поиска ошибки в SQL: http://myrusakov.ru/sql-finderror.html
Ответить
Ок, задам вопрос по другому. Как правильно вывести все данные из таблицы в БД используя метод select в вашем классе? $query = "SELECT * FROM `users`"; $db->select($query) - не прокатывает, возвращает Array если вывести print-ом.
Ответить
Он Array и должен возвращать. Это же массив данных.
Ответить
Михаил, спасибо БОЛЬШОЕ Вам за это курс, подскажите, пожалуста, нет ли в отправке формы в БД каких-либо особенностей при отправке значений радиокнопок? У меня есть форма отзыва о компании, в которой есть 2 текстовых поля и 2 поля с радиокнопками. Значения полей с текстом в БД попадает, а выбранное значение радиокнопок-нет. просто пустая ячейка. Хотя через echo на странице оно выводиться?
Ответить
Никаких особенностей нет, надо просто искать ошибку: http://myrusakov.ru/php-finderror.html
Ответить
Спасибо за класс, удобно. Прошу показать пример работы с insert и update
Ответить
Мне больше вот этот нравится, не знаю, дает он 100% защиту от sql инъекция, но хотя бы какая то. http://habrahabr.ru/post/165069/
Ответить
Дякую за посилання.. дуже зручно і безпечно.
Ответить
Не получается подключиться к базе данных. Куда класть этот файл класса БД?
Ответить
В папку положите корневую.
Ответить
Так и сделал. Все пхп туда положил. Даже пароль от базы данных пишу нарочно неправильный - ошибки не выдает.
Ответить
Сделал! Сделал! Оказывается в файле класса БД не надо было прописывать данные БД (логин пароль и пр.)!
Ответить
А я его чуть-чуть под себя переделал. Убрал конструктор, вместо него добавил метод set_parameters(). Это позволило задавать параметры объекта при создании нового экземпляра. Т.е. реализовано это так public $server; public $host; public $port; public $user; public $pass; public $base; public function set_parameters() { $this->mysqli = new mysqli($this->host.':'.$this->port,$this->user,$this->pass,$this->base); $this->mysqli->query("SET lc_time_names = 'ru_RU'"); $this->mysqli->query("SET NAMES 'utf8'"); } Теперь когда мне нужно создать новый экземпляр класса с другими параметрами, я делаю так $db = new dBase; $db -> server = SQL_SERVER; $db -> host = SQL_HOST; $db -> port = SQL_PORT; $db -> user = SQL_USER; $db -> pass = SQL_PASS; $db -> base = SQL_BASE; $db -> set_parameters(); Таким образом класс стал более гибким, ну т.е. мне не нужно каждый раз править файл класса чтобы подключиться к новому серверу, и появилась возможность переключаться между серверами "на лету"
Ответить
Добрый день. Не могу понять, а по чему в методах массиву $params присваевается значиние false?
Ответить
Здравствуйте! В запрос msqli->query(объект) отправляется как параметр объект класса. Вопрос: как этот запрос вытаскивает из объекта сформированный запрос для баз данных msql? Пример Вашего кода: $result_set = $this->mysqli->query(AbstractSelect $select);
Ответить
Добавить этот весь код надо в один файл? У меня database_class.php
Ответить
Подскажите я делаю запрос $query_made_pay_advertise = $db->select("SELECT * FROM `made_pay_advertise` WHERE `advertise_id` = ".$advertise_id." AND `status` = 2 ORDER BY `id` DESC"); while($row_made_pay_advertise = $db->selectRow($query_made_pay_advertise)){ echo "id = ".$row_made_pay_advertise['id']."<br>"; } но ничего не выводит
Ответить
Для добавления комментариев надо войти в систему.
Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.