Skip to content

Latest commit

History

57 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

DataBase logo

php versiondownloadsrepo sizeLicense

Комьюнити:

Беседа ВК (Помощь)Беседа ВК (Лог обновлений)

Почему DataBase?

  • Универсальность — Благодаря тому, что DataBase наследуется от PHP-PDO, её можно использовать с различными БД.
  • Простота — DataBase включает в себя удобные заполнители, которы серьёзно упрощают работу с SQL запросами. Также частые SQL запросы уже составлены и вынесены в виде методов.
  • При использовании Заполнителей, вы полностью защищены от SQL инъекций.

Функционал

В библиотеке поддерживается:

  • Все методы PHP-PDO
  • Свои заполнители
  • ORM конструкции

Оглавление

Подключение

Используя composer

composer require digitalstars/database
require_once"vendor/autoload.php"; //Подключаем библиотеку

Вручную

  1. Скачать последний релиз
  2. Подключить autoload.php

Вот так будет происходить подключение, если ваш бот находится в той же папке, что и папка DataBase-master

require_once"DataBase-master/autoload.php"; //Подключаем библиотеку

Подключение к СуБД

Синтаксис конструктора базового класса такой же, как и у PHP-PDO

useDigitalStars\DataBase\DB;
$dsn = ''; // Имя источника данных или DSN, содержащее информацию, необходимую для подключения к базе данных. $login = ''; // Логин$pass = ''; // Пароль$options = []; // Массив ключ=>значение специфичных для драйвера настроек подключения. $db = newDB($dsn, $login, $pass, $options);

Пример подключения к MySQL

useDigitalStars\DataBase\DB;
$db_type = 'mysql'; // Это может быть mysql, sybase или любой другой, в зависимости от вашей СуБД$db_name = 'test'; // Имя БД$login = 'root'; // Логин$pass = 'pass'; // Пароль$ip = 'localhost'; // Адрес// С портом по умолчанию$db = newDB("$db_type:host=$ip;dbname=$db_name", $login, $pass);
// С нестандартным портом$port = 1234;
$db = newDB("$db_type:host=$ip;port=$port;dbname=$db_name", $login, $pass);
// Подключение с выбором кодировки UTF8$db = newDB("$db_type:host=$ip;dbname=$db_name;charset=UTF8", $login, $pass);
// Или вот так (советуем использовать этот вариант)$db = newDB("$db_type:host=$ip;dbname=$db_name;", $login, $pass, [
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'",
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
]);
// В этом примере, сразу после подключения выполнится SQL запрос "SET NAMES 'utf8'"

Пример подключение к SQLite

useDigitalStars\DataBase\DB;
$db_type = 'sqlite';
$db_path = 'path/to/file/test.sqlite'; // Путь к файлу с базой данных// Подключение$db = newDB("$db_type:$db_path");

Что такое заполнители?

Заполнители — специальные типизированные маркеры, которые пишутся в строке SQL запроса вместо явных значений (параметров запроса), чем упрощают читаемость кода и защищают от SQL инъекций.
Заполнители поддерживаются в следующих методах:

  • exec()
  • execCommit()
  • query()
  • prepare()

О том как работают эти методы можно посмотреть в PHP-PDO.

<?phprequire'vendor/autoload.php';
useDigitalStars\DataBase\DB;
// Соединение с СУБД SQLite и получение объекта, который включает в себя все методы PHP-PDO и библиотеки$db = newDB("sqlite:./test.sqlite");
// Получение объекта результата PDOStatement$result = $db->query("SELECT * FROM users WHERE name = ?s AND age = ?i", ["Василий", 30]);
// Получаем данные (в виде ассоциативного массива)$data = $result->fetch();
// Не работает запрос? Не проблема - выведите его на печать:echo$db->getQueryString();

Параметры SQL-запроса, прошедшие через заполнители, обрабатываются специальными функциями экранирования, в зависимости от типа заполнителей. Т.е. вам теперь нет необходимости заключать переменные в функции экранирования типа quote() или приводить их к числовому типу, как это было раньше

Типы заполнителей и типы параметров SQL-запроса

Типы заполнителей и их предназначение описываются ниже. Прежде чем знакомиться с типами заполнителей, необходимо понять как работает механизм библиотеки DataBase.

$db->query("SELECT ?i", [123]); 

SQL-запрос после преобразования шаблона:

SELECT123

В процессе исполнения этой команды библиотека проверяет, является ли аргумент 123 целочисленным значением. Заполнитель ?i представляет собой символ ? (знак вопроса) и первую букву слова integer. Если аргумент действительно представляет собой целочисленный тип данных, то в шаблоне SQL-запроса заполнитель ?i заменяется на значение 123 и SQL передается на исполнение.

Поскольку PHP слаботипизированный язык, то вышеописанное выражение эквивалентно нижеописанному:

$db->query("SELECT ?i", '123'); 

SQL-запрос после преобразования шаблона:

SELECT123

Т.е. числа (целые и с плавающей точкой) представленные как в своем типе, так и в виде string — равнозначны с точки зрения библиотеки.

Приведение к типу заполнителя

$db->query("SELECT ?i", '123.7'); 

SQL-запрос после преобразования шаблона:

SELECT123

В данном примере заполнитель целочисленного типа данных ожидает значение типа integer, а передается double.

Допускаются следующие преобразования:

  • К типу int (заполнитель ?i) приводятся:
    • Числа с плавающей точкой, представленные как string или double
    • bool(true) преобразуется в int(1)
    • bool(false) и null преобразуется в int(0)
  • К типу double (заполнитель ?d) приводятся:
    • Целые числа, представленные как string или int
    • bool(true) преобразуется в float(1)
    • bool(false) и null преобразуется в float(0)
  • К типу string (заполнитель ?s) приводятся:
    • numeric преобразуется в string
    • null преобразуется в string(0) ""
    • bool(true) преобразуется в string(1) "1"
    • bool(false) преобразуется в string(1) "0"

    Это поведение отличается от приведения типа bool к int в PHP, т.к. зачастую на практике bool записывается в MySql именно как число.

  • Тип null (заполнитель ?n) просто вставляет NULL в место заполнителя.
    Входные параметры не требуются

Настройка PhpStorm

Для того, что-бы IDE нормально реагировала на заполнители, и не подсвечивала места с заполнителями ошибками, необходимо добавить заполнители в список пользовательских параметров.

Путь диалогового окна с настройками

File >> Settings... >> Tools >> Database >> User Parameters

Затем в окошке "Parameter patterns" нужно добавить следующие 2 шаблона и поставить обе галочки "In scripts" и "In literals":

  • \?[aAvw]\[.*?\]
  • \?[aAvw]?[sSidnf]

Окно настройки должно выглядеть следующим образом

Окно настройки

Хандлер sql запросов

Если вам необходимо обрабатывать все выполняемые в скрипте SQL запросы, например для дебага.

$db->setLoggerFunc(function ($query) {
$file = 'log.txt';
$query = "Время: ".date('d.m.y H:i:s')."\n".$query;
file_put_contents($file, $query, FILE_APPEND | LOCK_EX);
});

Типы заполнителей DataBase

?i — заполнитель целого числа

$_POST['id'] = '123456';
$db->query('SELECT * FROM `users` WHERE `id` = ?i', [$_POST['id']]); 

SQL-запрос после преобразования шаблона:

SELECT*FROM`users`WHERE`id`=123456

ВНИМАНИЕ! Если вы оперируете числами, выходящими за пределы PHP_INT_MAX, то:

  • Оперируйте ими исключительно как строками в своих программах.
  • Не используйте данный заполнитель, используйте заполнитель строки ?s (см. ниже). Дело в том, что числа, выходящие за пределы PHP_INT_MAX, PHP интерпретирует как числа с плавающей точкой. Парсер библиотеки постарается преобразовать параметр к типу int, в итоге:

«результат будет неопределенным, так как float не имеет достаточной точности, чтобы вернуть верный результат. В этом случае не будет выведено ни предупреждения, ни даже замечания!» — php.net.

?d — заполнитель числа с плавающей точкой

ВНИМАНИЕ! Если вы используете библиотеку для работы с типом данных double, установите соответствующую локаль, что бы разделитель целой и дробной части был одинаков как на уровне PHP, так и на уровне СУБД.

?s — заполнитель строкового типа

Значения экранируются с помощью функции PDO::quote()

$db->query('SELECT ?s, ?s, ?s, ?s, ?s', [55.5, true, false, null, 'Д"Артаньян']); 

SQL-запрос после преобразования шаблона:

SELECT"55.5", "1", "0", "", "Д\"Артаньян"

?S — заполнитель строкового типа для подстановки в SQL-оператор LIKE

Значения экранируются с помощью функции PDO::quote() + экранирование спецсимволов, используемых в операторе LIKE (% и _):

$db->query('SELECT "?S"', '% _'); 

SQL-запрос после преобразования шаблона:

SELECT"\% \_"

?n — заполнитель NULL типа

Заполнитель просто вставляет NULL в запрос, входной параметр не нужен

$db->query('SELECT ?n'); 

SQL-запрос после преобразования шаблона:

SELECTNULL

?f — заполнитель имени таблицы или поля

Данный заполнитель предназначен для случаев, когда имя таблицы или поля передается в запросе через параметр. Значение обрамляется символом апостроф:

$db->query('SELECT * FROM ?f', 'table'); 

SQL-запрос после преобразования шаблона:

SELECT*FROM`table`

?A* — заполнитель ассоциативного множества из ассоциативного массива, генерирующий последовательность пар ключ = значение

Пример: "key_1" = "val_1", "key_2" = "val_2", ..., "key_N" = "val_N"
Ключи экранируются заполнителем ?f

где * после заполнителя — один из типов:

  • i (заполнитель целого числа)
  • d (заполнитель числа с плавающей точкой)
  • s (заполнитель строкового типа)
  • f (заполнитель имени таблицы или поля)

Правила преобразования и экранирования такие же, как и для одиночных скалярных типов, описанных выше.

$db->query('UPDATE test SET ?Ai', [
['count' => 30, 'amount' => 1000, 'status' => 66]
]);

SQL-запрос после преобразования шаблона:

UPDATE test SET`count`=30, `amount`=1000, `status`=66

?A[?n, ?s, ?i, ?d, ...] — заполнитель ассоциативного множества с явным указанием типа и количества аргументов, генерирующий последовательность пар ключ = значение

Пример: "key_1" = "val_1", "key_2" => "val_2", ..., "key_N" = "val_N"

$db->query('UPDATE test SET ?A[?i, ?s, ?d]', [
['count' => 30.25, 'title' => 'Какой-то заголовок', 'amount' => '66.55']
]);

SQL-запрос после преобразования шаблона:

UPDATE test SET`count`=30, `title`='Какой-то заголовок', `amount`=66.55

?a* — заполнитель множества из простого (или также ассоциативного) массива, генерирующий последовательность значений

Пример: "val_1", "val_2", ..., "val_N"

где * после заполнителя — один из типов:

  • i (заполнитель целого числа)
  • d (заполнитель числа с плавающей точкой)
  • s (заполнитель строкового типа)
  • f (заполнитель имени таблицы или поля)

правила преобразования и экранирования такие же, как и для одиночных скалярных типов, описанных выше.

$db->query('INSERT INTO test (count, amount, status) VALUES (?ai)', [
[30, 1000, 66]
]);

SQL-запрос после преобразования шаблона:

INSERT INTO test (count, amount, status) VALUES (30, 1000, 66)

?a[?n, ?s, ?i, ?d, ...] — заполнитель множества с явным указанием типа и количества аргументов, генерирующий последовательность значений

Пример: "val_1", "val_2", ..., "val_N"

$db->query('INSERT INTO test (count, title, amount) VALUES (?a[?i, ?s, ?d])', [
[30.25, 'Какой-то заголовок', '66.55']
]);

SQL-запрос после преобразования шаблона:

INSERT INTO test (count, title, amount) VALUES (30, 'Какой-то заголовок', 66.55)

?v* — заполнитель VALUES из простого (или также ассоциативного) двумерного массива, генерирующий последовательность значений для заполнения VALUES

Пример: ("val_1", "val_2", ..., "val_N"), ("val_1", "val_2", ..., "val_N"), ...

где * после заполнителя — один из типов:

  • i (заполнитель целого числа)
  • d (заполнитель числа с плавающей точкой)
  • s (заполнитель строкового типа)
  • f (заполнитель имени таблицы или поля)

правила преобразования и экранирования такие же, как и для одиночных скалярных типов, описанных выше.

$db->query('INSERT INTO test (count, amount, status) VALUES ?vi', [
[
[30, 1000, 66],
[41, 2500, 77],
[25, 3211, 24]
]
]);

SQL-запрос после преобразования шаблона:

INSERT INTO test (count, amount, status) VALUES (30, 1000, 66), (41, 2500, 77), (25, 3211, 24)

?v[?n, ?s, ?i, ?d, ...] — заполнитель множества из двумерного массива с явным указанием типа и количества аргументов, генерирующий последовательность значений для заполнения VALUES

Пример: ("val_1", "val_2", ..., "val_N"), ("val_1", "val_2", ..., "val_N"), ...

$db->query('INSERT INTO test (count, title, amount) VALUES ?v[?i, ?s, ?d]', [
[
[30.25, 'Какой-то заголовок', '66.55'],
[40, 'Какой-то заголовок 2', '77'],
['21.55', 'Какой-то заголовок 3', 66.88]
]
]);

SQL-запрос после преобразования шаблона:

INSERT INTO test (count, title, amount) VALUES (30, 'Какой-то заголовок', 66.55), (40, 'Какой-то заголовок 2', 77), (21, 'Какой-то заголовок 3', 66.88)

?w* — заполнитель ассоциативного множества из ассоциативного массива, генерирующий последовательность пар ключ = значение с разделителем AND

Пример: "key_1" = "val_1" AND "key_2" = "val_2" AND ... AND "key_N" = "val_N"

Ключи экранируются заполнителем ?f

где * после заполнителя — один из типов:

  • i (заполнитель целого числа)
  • d (заполнитель числа с плавающей точкой)
  • s (заполнитель строкового типа)
  • f (заполнитель имени таблицы или поля)

Правила преобразования и экранирования такие же, как и для одиночных скалярных типов, описанных выше.

$db->query('SELECT * FROM test WHERE ?wi', [
['count' => 30, 'amount' => 1000, 'status' => 66]
]);

SQL-запрос после преобразования шаблона:

SELECT*FROM test WHERE`count`=30AND amount =1000AND status =66

?w[?n, ?s, ?i, ?d, ...] — заполнитель ассоциативного множества с явным указанием типа и количества аргументов, генерирующий последовательность пар ключ = значение с разделителем AND

Пример: "key_1" = "val_1" AND "key_2" => "val_2" AND ... AND "key_N" = "val_N"

$db->query('SELECT * FROM test WHERE ?w[?i, ?s, ?d]', [
['count' => 30.25, 'title' => 'Какой-то заголовок', 'amount' => '66.55']
]);

SQL-запрос после преобразования шаблона:

SELECT*FROM test WHERE`count`=30AND`title`='Какой-то заголовок'AND`amount`=66.55

Примеры для понимания сути заполнителей

Различные варианты INSERT:

Простая вставка данных через заполнители разных типов:
$db->query("INSERT INTO `users` VALUES (?n, ?s, ?i, ?s)", ['Иоанн Грозный', '54', 'в палатах']);

SQL-запрос после преобразования шаблона:

INSERT INTO`users`VALUES (NULL, 'Иоанн Грозный', 54, 'в палатах')
Вставка значений через заполнитель ассоциативного множества типа string:
$user = ['name' => 'Пётр', 'age' => '30', 'adress' => "ООО 'Рога и Копыта'"];
$db->query('INSERT INTO `users` SET ?As', [$user]);

SQL-запрос после преобразования шаблона:

INSERT INTO`users`SET`name`="Пётр", `age`="30", `adress`="ООО \'Рога и Копыта\'"
Вставка значений через заполнитель ассоциативного множества с явным указанием типа и количества аргументов:
$user = ['name' => "Д'Артаньян", 'age' => '19', 'adress' => 'замок Кастельмор'];
$db->query('INSERT INTO `users` SET ?A[?s, ?i, ?s]', [$user]);

SQL-запрос после преобразования шаблона:

INSERT INTO`users`SET`name`="Д\'Артаньян",`age`=19,`adress`="замок Кастельмор"

Различные варианты SELECT

Укажем некорректный числовой параметр - значение типа double:
$db->query('SELECT * FROM `users` WHERE `id` = ?i', ['1.00']);

SQL-запрос после преобразования шаблона:

SELECT*FROM`users`WHERE`id`=1

$db->query(
'SELECT id, adress FROM `users` WHERE `name` IN (?a["?s", "?s", "?s"])',
[['Василий', 'Иван', "Д'Артаньян"]]
); 

SQL-запрос после преобразования шаблона:

SELECT id, adress FROM`users`WHERE`name`IN ("Василий", "Иван", "Д\'Артаньян")
Имя базы данных, таблицы и поля передаются также, как и аргументы запроса
$db->query(
'SELECT * FROM ?f WHERE ?f IN (?as) OR `id` IN (?ai)',
'users', 'users.name', ['Василий'], ['2', 3.000]
);

SQL-запрос после преобразования шаблона:

SELECT*FROM`users`WHERE`users`.`name`IN ("Василий") OR`id`IN (2, 3)

Методы ORM

В библиотеке есть несколько методов ORM. Заполнители встроены дополнительным 2-ым параметром, остальные параметры методов сдвинуты. Методы с поддержкой заполнителей:

  • exec()
  • execCommit()
  • query()
  • prepare()

Пример:

<?phprequire_once"vendor/autoload.php"; //Подключаем библиотекуuseDigitalStars\DataBase\DB;
$db = newDB('sqlite:./test.sqlite');
// Вернёт PDOStatement$stm = $db->prepare("SELECT * FROM ?f WHERE name = ?s AND count = ?", ['test', 'имя']);
// Вернёт выборку где count = 100if ($stm->execute([100]))
print_r($stm->fetchAll());
// Вернёт выборку где count = 200if ($stm->execute([200]))
print_r($stm->fetchAll());

Дополнительные методы

getQueryString() : sql (string)

Метод возвращает последний собранный запрос, в котором были заполнители

$stm = $db->prepare("SELECT * FROM ?f WHERE name = ?s AND count = ?", ['test', 'имя']);
echo$db->getQueryString();

Вернёт

SELECT*FROM`test`WHERE name ='имя'AND count = ?

execCommit() : int | false

Аналогичен exec(), но запрос проходит с использованием beginTransaction(), commit() и rollBack() в случае неудачи.

$db->execCommit("DELETE FROM users WHERE id = ?i", [5]);;

rows($sql, $args = [], $fetchMode = PDO::FETCH_ASSOC) : array | false

Соберёт $sql запрос по заполнителям из $args и вернёт все строки (вызов PDOStatement::fetchAll) с режимом выборки $fetchMode.

Подробнее о режимах выборки PHP-PDO

$rows = $db->rows("SELECT * FROM users WHERE age = ?i", [30]);
// Вернёт false или все строки таблицы, где age = 30

row($sql, $args = [], $fetchMode = PDO::FETCH_ASSOC) : array | false

Соберёт $sql запрос по заполнителям из $args и вернёт строку (вызов PDOStatement::fetch) с режимом выборки $fetchMode.

Подробнее о режимах выборки PHP-PDO

$row = $db->row("SELECT * FROM users WHERE age = ?i", [30]);
// Вернёт false или строку таблицы, где age = 30

getById($table, $id, $fetchMode = PDO::FETCH_ASSOC) : array | false

Вернёт строку (вызов PDOStatement::fetch) с режимом выборки $fetchMode из таблицы $table ро правилу, описанному ниже.

Подробнее о режимах выборки PHP-PDO

  • Если $id - число, то вернёт запись, где id = $id

  • Если $id - массив, то вернёт запись по WHERE, где ключи массив - названия полей, значения массива - значения полей

$row = $db->getById('users', 6);
// Выполнит SELECT * FROM `users` WHERE id = 6// Вернёт false или строку таблицы, где id = 6$row = $db->getById('users', ['user_id' => 12, 'status' => 5]);
// Выполнит SELECT * FROM `users` WHERE user_id = '12' AND status = '5'// Вернёт false или строку таблицы, где user_id = 12 или status = 5

count($sql, $args = []) : int | false

Соберёт $sql запрос по заполнителям из $args и вернёт количество затронутых строк (вызов метода PDOStatement::rowCount)

$row = $db->count('SELECT * FROM users WHERE name = ?s', ['Василий']);
// Вернёт false или количество строк таблицы users, в которых name = 'Василий'

insert($table, $data) : int | false

Вставит в таблицу $table значения из массива $data, в котором ключи - названия полей, значения - значения полей. Вернёт id добавленной записи

$last_id = $db->insert('users', ['name' => 'Иван', 'age' => 30]);
// Выполнит запрос: INSERT INTO `users` (`name`, `age`) VALUES ('Иван', '30')// Вернёт false или ID добавленной записи

update($table, $data, $where = []) : int | false

Изменить таблицу $table значениями из массива $data, в котором ключи - названия полей, значения - значения полей, где по $where, в котором ключи - названия полей, значения - значения полей. Вернёт количество затронутых строк или false в случае ошибки.

Внимание! Если функция отработала без ошибок, но затронула 0 строк - она вернёт 0. Что при нестрогой проверке приведётся к false

Если не передан $where, то будут затронуты все строки

$count = $db->update('users', [
'name' => 'Иван',
'age' => 30
],
[
'id' => 6,
'status' => 9
]);
// Выполнит запрос: UPDATE `users` SET `name` = 'Иван', `age` = '30' WHERE `id` = '6' AND `status` = '9'// Вернёт false или количество затронутых строк

delete($table, $where, $limit = -1) : int | false

Удалить из таблицы $table$limit записей, где по $where, в котором ключи - названия полей, значения - значения полей. Вернёт количество затронутых строк или false в случае ошибки.

Внимание! Если функция отработала без ошибок, но затронула 0 строк - она вернёт 0. Что при нестрогой проверке приведётся к false

Если не передан $limit или равен -1, то будут удален все выбранные записи

$count = $db->delete('users', ['id' => 6, 'status' => 9], 5);
// Выполнит запрос: DELETE FROM `users` WHERE `id` = '6' AND `status` = '9' LIMIT 5// Вернёт false или количество затронутых строк

deleteAll($table) : int | false

Удалить из таблицы $table все записи. Вернёт количество затронутых строк или false в случае ошибки.

Внимание! Если функция отработала без ошибок, но затронула 0 строк - она вернёт 0. Что при нестрогой проверке приведётся к false

$count = $db->deleteAll('users');
// Выполнит запрос: DELETE FROM `users`// Вернёт false или количество затронутых строк

deleteById($table, $id) : int | false

Удалить из таблицы $table записи с id = $id. Вернёт количество затронутых строк или false в случае ошибки.

Внимание! Если функция отработала без ошибок, но затронула 0 строк - она вернёт 0. Что при нестрогой проверке приведётся к false

$count = $db->deleteById('users', 6);
// Выполнит запрос: DELETE FROM `users` WHERE `id` = 6// Вернёт false или количество затронутых строк

deleteByIds($table, $column, $ids) : int | false

Удалить из таблицы $table записи, где $column равен одному из $ids. Вернёт количество затронутых строк или false в случае ошибки.

$ids должен быть обычным или ассоциативным массивом.

Внимание! Если функция отработала без ошибок, но затронула 0 строк - она вернёт 0. Что при нестрогой проверке приведётся к false

$count = $db->deleteByIds('users', 'status', [6, 8, 10]);
// Выполнит запрос: DELETE FROM `users` WHERE `status` IN ('6', '8', '10')// Вернёт false или количество затронутых строк

truncate($table) : int | false

Очищает таблицу $table. Вернёт количество затронутых строк или false в случае ошибки.

Сбрасываются также внутренние счётчики таблицы

Внимание! Если функция отработала без ошибок, но затронула 0 строк - она вернёт 0. Что при нестрогой проверке приведётся к false

$count = $db->truncate('users');
// Выполнит запрос: TRUNCATE TABLE `users`// Вернёт false или количество затронутых строк

About

Библиотека-обертка над стандартным PDO PHP для простой, удобной работы с различными базами данных и с защитой от SQL инъекций

Topics

Resources

Stars

13 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages