digitalstars/database

简化数据库操作库

v1.1 2024-02-04 19:38 UTC

This package is auto-updated.

Last update: 2024-09-29 01:04:47 UTC


README

DataBase logo

php version downloads repo size License

社区

为什么选择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

如果您的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)转换为
    • 表示为 stringdouble 的浮点数
    • bool(true) 转换为 int(1)
    • bool(false)null 转换为 int(0)
  • double 类型(填充器 ?d)转换为
    • 表示为 stringint 的整数
    • 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 "\% \_"

?nNULL 类型填充器

填充器简单地在请求中插入 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 или количество затронутых строк