<?php if(!defined('PRIVATE_DIR'))exit;
class Database{
    public static bool $autoDecrypt=true;
    private static ?PDO $instance=null; private static array $stmtCache=[]; public static function connect():PDO{ if(self::$instance===null){ try{ $dsn=sprintf('mysql:host=%s;port=%d;dbname=%s;charset=utf8mb4',DB_HOST,defined('DB_PORT')?DB_PORT:3306,DB_NAME); self::$instance=new PDO($dsn,DB_USER,DB_PASS,[ PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE=>PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES=>false, PDO::MYSQL_ATTR_INIT_COMMAND=>"SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci", ]); }catch(\PDOException $e){ error_log('[FATAL DB ERROR] '.$e->getMessage()); http_response_code(500); exit('System database connection error.'); } } return self::$instance; } public static function get():PDO{return self::connect();} public static function c():PDO{return self::connect();} public static function query(string $sql,array $params=[]):\PDOStatement{ $key=md5($sql); if(!isset(self::$stmtCache[$key])){ self::$stmtCache[$key]=self::connect()->prepare($sql); if(count(self::$stmtCache)>200){array_shift(self::$stmtCache);} } $stmt=self::connect()->prepare($sql); $stmt->execute($params); return $stmt; } public static function fetchAll(string $sql,array $params=[]):array{ $stmt=self::connect()->prepare($sql); $stmt->execute($params); return self::autoDecrypt($stmt->fetchAll()); } public static function all(string $sql,array $params=[]):array{return self::fetchAll($sql,$params);} public static function fetchOne(string $sql,array $params=[]):?array{ $stmt=self::connect()->prepare($sql); $stmt->execute($params); $row=$stmt->fetch(); return $row?self::autoDecrypt($row):null; } public static function one(string $sql,array $params=[]):?array{return self::fetchOne($sql,$params);} public static function scalar(string $sql,array $params=[]):mixed{ $stmt=self::connect()->prepare($sql); $stmt->execute($params); $v=$stmt->fetchColumn(); return is_string($v)?self::autoDecryptVal($v):$v; } public static function value(string $sql,array $params=[]):mixed{return self::scalar($sql,$params);} public static function val(string $sql,array $params=[]):mixed{return self::scalar($sql,$params);} public static function execute(string $sql,array $params=[]):int{ $stmt=self::connect()->prepare($sql); $stmt->execute($params); return $stmt->rowCount(); } public static function run(string $sql,array $params=[]):int{return self::execute($sql,$params);} public static function insert(string $sql,array $params=[]):int{ $stmt=self::connect()->prepare($sql); $stmt->execute($params); return(int)self::connect()->lastInsertId(); } public static function ins(string $sql,array $params=[]):int{return self::insert($sql,$params);} public static function transaction(callable $callback):mixed{ $pdo=self::connect(); $pdo->beginTransaction(); try{$result=$callback($pdo);$pdo->commit();return $result;}catch(\Throwable $e){$pdo->rollBack();throw $e;} } public static function beginTransaction():bool{return self::connect()->beginTransaction();} public static function commit():bool{return self::connect()->commit();} public static function rollBack():bool{return self::connect()->rollBack();} private static function autoDecryptVal(string $v):string{
        if(!self::$autoDecrypt)return $v;
        if(class_exists('SecureVault')&&SecureVault::isEncrypted($v)){return SecureVault::decrypt($v);}
        return $v;
    } private static function autoDecrypt(mixed $val):mixed{ if(is_array($val)){foreach($val as $k=>$v){$val[$k]=self::autoDecrypt($v);}return $val;} if(is_string($val)){return self::autoDecryptVal($val);} return $val; } } class DB{ public static function connect(){return Database::connect();} public static function c(){return Database::connect();} public static function get(){return Database::connect();} public static function query($sql,$params=[]){return Database::query($sql,$params);} public static function all($sql,$params=[]){return Database::all($sql,$params);} public static function one($sql,$params=[]){return Database::one($sql,$params);} public static function value($sql,$params=[]){return Database::value($sql,$params);} public static function val($sql,$params=[]){return Database::val($sql,$params);} public static function insert($sql,$params=[]){return Database::insert($sql,$params);} public static function ins($sql,$params=[]){return Database::ins($sql,$params);} public static function execute($sql,$params=[]){return Database::execute($sql,$params);} public static function run($sql,$params=[]){return Database::run($sql,$params);} public static function fetchAll($sql,$params=[]){return Database::fetchAll($sql,$params);} public static function fetchOne($sql,$params=[]){return Database::fetchOne($sql,$params);} public static function scalar($sql,$params=[]){return Database::scalar($sql,$params);} public static function transaction(callable $cb):mixed{return Database::transaction($cb);} public static function beginTransaction():bool{return Database::beginTransaction();} public static function commit():bool{return Database::commit();} public static function rollBack():bool{return Database::rollBack();} } 