digitalstars / database
简化数据库操作库
Requires
- php: >=8.0
- ext-pdo: *
README
社区
为什么选择DataBase?
- 通用性 — 由于DataBase继承自
PHP-PDO
,它可以与各种数据库一起使用。 - 简单性 — DataBase包含方便的填充器,这极大地简化了SQL查询的工作。此外,常见的SQL查询已预先构建并作为方法提供。
- 使用填充器时,您可以完全防止
SQL注入
。
功能
库中支持
- 所有 PHP-PDO 方法
- 自定义填充器
- ORM结构
目录
- 连接
- 填充器
- 配置PhpStorm
- SQL查询处理器
- 填充器类型
- 附加方法
- getQueryString
- execCommit
- rows($sql, $args = [], $fetchMode = PDO::FETCH_ASSOC)
- row($sql, $args = [], $fetchMode = PDO::FETCH_ASSOC)
- getById($table, $id, $fetchMode = PDO::FETCH_ASSOC)
- count($sql, $args = [])
- insert($table, $data)
- update($table, $data, $where = [])
- delete($table, $where, $limit = -1)
- deleteAll($table)
- deleteById($table, $id)
- deleteByIds($table, $column, $ids)
- truncate($table)
连接
使用composer
composer require digitalstars/database
require_once "vendor/autoload.php"; //Подключаем библиотеку
手动
- 下载最新版本
- 连接
autoload.php
如果您的bot位于与
DataBase-master
同一目录下,连接方式如下
require_once "DataBase-master/autoload.php"; //Подключаем библиотеку
连接到子数据库
基本类的构造函数语法与PHP-PDO相同
use DigitalStars\DataBase\DB; $dsn = ''; // Имя источника данных или DSN, содержащее информацию, необходимую для подключения к базе данных. $login = ''; // Логин $pass = ''; // Пароль $options = []; // Массив ключ=>значение специфичных для драйвера настроек подключения. $db = new DB($dsn, $login, $pass, $options);
连接到MySQL的示例
use DigitalStars\DataBase\DB; $db_type = 'mysql'; // Это может быть mysql, sybase или любой другой, в зависимости от вашей СуБД $db_name = 'test'; // Имя БД $login = 'root'; // Логин $pass = 'pass'; // Пароль $ip = 'localhost'; // Адрес // С портом по умолчанию $db = new DB("$db_type:host=$ip;dbname=$db_name", $login, $pass); // С нестандартным портом $port = 1234; $db = new DB("$db_type:host=$ip;port=$port;dbname=$db_name", $login, $pass); // Подключение с выбором кодировки UTF8 $db = new DB("$db_type:host=$ip;dbname=$db_name;charset=UTF8", $login, $pass); // Или вот так (советуем использовать этот вариант) $db = new DB("$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的示例
use DigitalStars\DataBase\DB; $db_type = 'sqlite'; $db_path = 'path/to/file/test.sqlite'; // Путь к файлу с базой данных // Подключение $db = new DB("$db_type:$db_path");
什么是填充器?
填充器 — 特殊的、类型化的标记,它们在SQL查询字符串中代替显式值(查询参数),从而简化代码的可读性并保护免受SQL注入攻击。
填充器支持以下方法
- exec()
- execCommit()
- query()
- prepare()
有关这些方法的更多信息,请参阅 PHP-PDO.
<?php require 'vendor/autoload.php'; use DigitalStars\DataBase\DB; // Соединение с СУБД SQLite и получение объекта, который включает в себя все методы PHP-PDO и библиотеки $db = new DB("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查询
SELECT 123
在执行此命令的过程中,库将检查参数
123
是否是整数。填充器?i
由?
(问号)和单词integer
的第一个字母组成。如果参数确实是整数类型,则在SQL查询模板中,填充器?i
将被替换为123
,然后SQL将被执行。
由于PHP是弱类型语言,所以上述表达式等同于以下表达式
$db->query("SELECT ?i", '123');
转换模板后的SQL查询
SELECT 123
即数字(整数和浮点数)以自己的类型或以
string
类型表示,对库来说都是等价的。
转换为填充器类型
$db->query("SELECT ?i", '123.7');
转换模板后的SQL查询
SELECT 123
在本例中,整数类型的数据填充器期望接收类型为 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"
此行为与 PHP 中将类型
bool
转换为int
的行为不同,因为在实践中,MySql 通常将bool
记录为数字。 - 类型
null
(填充器?n
)简单地将NULL
插入到填充器位置。
不需要输入参数
配置PhpStorm
为了使 IDE 能够正确处理填充器,并且不将填充器位置标记为错误,需要将填充器添加到用户参数列表中。
设置对话框的路径
文件 >> 设置... >> 工具 >> 数据库 >> 用户参数
然后在“参数模式”窗口中,需要添加以下 2 个模板,并勾选“在脚本中”和“在字面量中”两个复选框
\?[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); });
数据库填充器类型
?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查询
SELECT NULL
?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 的集合填充器,显式类型和参数数量,生成填充 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` = 30 AND amount = 1000 AND 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` = 30 AND `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 方法。填充器通过额外的第二个参数嵌入,其余方法参数向右移动。支持填充器的方法
- exec()
- execCommit()
- query()
- prepare()
示例
<?php require_once "vendor/autoload.php"; //Подключаем библиотеку use DigitalStars\DataBase\DB; $db = new DB('sqlite:./test.sqlite'); // Вернёт PDOStatement $stm = $db->prepare("SELECT * FROM ?f WHERE name = ?s AND count = ?", ['test', 'имя']); // Вернёт выборку где count = 100 if ($stm->execute([100])) print_r($stm->fetchAll()); // Вернёт выборку где count = 200 if ($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
根据填充器从 $args
收集 $sql
查询并返回所有行(调用 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
根据填充器从 $args
收集 $sql
查询并返回行(调用 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
返回使用选择模式 $fetchMode
从 $table
表中获取的行(调用 PDOStatement::fetch
)按照以下描述的规则。
有关选择模式的更多信息 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
根据填充器从 $args
收集 $sql
查询并返回受影响的行数(调用方法 PDOStatement::rowCount
)
$row = $db->count('SELECT * FROM users WHERE name = ?s', ['Василий']); // Вернёт false или количество строк таблицы users, в которых name = 'Василий'
insert($table, $data) : int | false
将 $data
数组中的值插入到 $table
表中,其中键是字段名称,值是字段值。返回添加的记录的 id
。
$last_id = $db->insert('users', ['name' => 'Иван', 'age' => 30]); // Выполнит запрос: INSERT INTO `users` (`name`, `age`) VALUES ('Иван', '30') // Вернёт false или ID добавленной записи
update($table, $data, $where = []) : int | false
将数组 $data
中的值(其中键为字段名,值为字段值)应用于表 $table
,其中根据 $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 или количество затронутых строк