| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384 |
- <?php
- declare(strict_types=1);
- namespace Glacier\Core;
- use PDO;
- /**
- * PDO 数据访问封装(单库多表,架构约定见 docs/architecture.md §3.5)。
- * - 一律 prepared statement(防注入)
- * - utf8mb4 + 会话时区 UTC+8(三层统一约定)
- * - 异常模式(ERRMODE_EXCEPTION)
- */
- final class Database
- {
- private static ?PDO $pdo = null;
- public static function pdo(): PDO
- {
- if (self::$pdo === null) {
- $host = (string) Config::get('db.host', '127.0.0.1');
- $port = (int) Config::get('db.port', 3306);
- $name = (string) Config::get('db.name', 'glacier');
- $charset = (string) Config::get('db.charset', 'utf8mb4');
- $user = (string) Config::get('db.user', 'root');
- $pass = (string) Config::get('db.pass', '');
- $dsn = "mysql:host={$host};port={$port};dbname={$name};charset={$charset}";
- self::$pdo = new PDO($dsn, $user, $pass, [
- PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
- PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
- PDO::ATTR_EMULATE_PREPARES => false,
- PDO::ATTR_TIMEOUT => 5,
- ]);
- self::$pdo->exec("SET time_zone = '+08:00'");
- }
- return self::$pdo;
- }
- /** 执行 prepared statement(唯一写库/查询路径)。 */
- public static function run(string $sql, array $params = []): \PDOStatement
- {
- $stmt = self::pdo()->prepare($sql);
- $stmt->execute($params);
- return $stmt;
- }
- public static function fetchAll(string $sql, array $params = []): array
- {
- return self::run($sql, $params)->fetchAll();
- }
- public static function fetchOne(string $sql, array $params = []): ?array
- {
- $row = self::run($sql, $params)->fetch();
- return $row === false ? null : $row;
- }
- public static function fetchValue(string $sql, array $params = []): mixed
- {
- $value = self::run($sql, $params)->fetchColumn();
- return $value === false ? null : $value;
- }
- /** 插入一行(表名白名单校验),返回自增 ID。 */
- public static function insert(string $table, array $data): int
- {
- if (!preg_match('/^[a-z][a-z0-9_]*$/', $table)) {
- throw new \InvalidArgumentException("非法表名: {$table}");
- }
- $q = chr(96); // 反引号字符,MySQL 标识符引用
- $columns = array_keys($data);
- $quoted = array_map(static fn(string $c) => $q . $c . $q, $columns);
- $sql = sprintf(
- 'INSERT INTO %s (%s) VALUES (%s)',
- $table,
- implode(', ', $quoted),
- implode(', ', array_map(static fn(string $c) => ':' . $c, $columns))
- );
- self::run($sql, $data);
- return (int) self::pdo()->lastInsertId();
- }
- }
|