Вход Регистрация
Файл: system/database.php
Строк: 182
<?php
/* Обновление игры под PHP 8.4 / PDO и усиление безопасности: by Метриум (Стэлп) */
declare(strict_types=1);

final class 
DBResult implements ArrayAccessCountableIteratorAggregate {
    public array 
$rows;
    public 
int $cursor 0;
    public function 
__construct(array $rows = []) { $this->rows $rows; }

    
/* Legacy PHP 5 compatibility: some old game files used db_query(...)['field']
       instead of fetching the first row. PDO returns an object, so expose the first
       result row read-only while the old code is being progressively refactored.
       Обновление: by Метриум (Стэлп). */
    
public function offsetExists(mixed $offset): bool {
        return isset(
$this->rows[0]) && array_key_exists((string)$offset$this->rows[0]);
    }
    public function 
offsetGet(mixed $offset): mixed {
        return 
$this->rows[0][(string)$offset] ?? null;
    }
    public function 
offsetSet(mixed $offsetmixed $value): void {
        throw new 
LogicException('DBResult is read-only');
    }
    public function 
offsetUnset(mixed $offset): void {
        throw new 
LogicException('DBResult is read-only');
    }
    public function 
count(): int { return count($this->rows); }
    public function 
getIterator(): Traversable { return new ArrayIterator($this->rows); }
}

$GLOBALS['__db_pdo'] = $GLOBALS['__db_pdo'] ?? null;
$GLOBALS['__db_last_error'] = '';
$GLOBALS['__db_last_insert_id'] = 0;
$GLOBALS['__db_query_count'] = 0;
$GLOBALS['__db_query_time'] = 0.0;

function 
db_config(): array {
    static 
$cfg;
    return 
$cfg ??= require __DIR__ '/config.php';
}
function 
db_pdo(): PDO {
    if (
$GLOBALS['__db_pdo'] instanceof PDO) return $GLOBALS['__db_pdo'];
    
$c db_config()['db'];
    
$dsn sprintf('mysql:host=%s;dbname=%s;charset=%s'$c['host'], $c['name'], $c['charset']);
    
$pdo = new PDO($dsn$c['user'], $c['pass'], [
        
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        
PDO::ATTR_EMULATE_PREPARES => false,
        
PDO::ATTR_STRINGIFY_FETCHES => false,
        
PDO::ATTR_PERSISTENT => false,
    ]);
    
$pdo->exec("SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci");
    
$GLOBALS['__db_pdo']=$pdo;
    return 
$pdo;
}
function 
db_connect(...$args): PDO|false { try { return db_pdo(); } catch (Throwable $e) { $GLOBALS['__db_last_error']=$e->getMessage(); return false; } }
function 
db_select_db(...$args): bool { return db_connect() !== false; }
function 
db_query(string $sql): DBResult|bool {
    
$started=microtime(true);
    
$GLOBALS['__db_query_count']=(int)($GLOBALS['__db_query_count'] ?? 0)+1;
    try {
        
$stmt=db_pdo()->query($sql);
        
$GLOBALS['__db_last_insert_id']=(int)db_pdo()->lastInsertId();
        if (
preg_match('/^s*(SELECT|SHOW|DESCRIBE|EXPLAIN|WITH)b/i',$sql)) return new DBResult($stmt->fetchAll(PDO::FETCH_ASSOC));
        return 
true;
    } catch (
Throwable $e) {
        
$GLOBALS['__db_last_error']=$e->getMessage();
        
$compactSql substr((string)preg_replace('/s+/',' '$sql), 01000);
        
// Не пишем значения строковых литералов и секреты пользователей в журнал. by Метриум (Стэлп)
        
$safeSql preg_replace("/'(?:''|[^'])*'/""'[redacted]'"$compactSql) ?? '[query redacted]';
        if (
function_exists('app_log_write')) app_log_write('DB''Database query failed', ['sql'=>$safeSql,'type'=>get_class($e)]);
        else 
error_log('[DB] Database query failed SQL='.$safeSql);
        return 
false;
    } finally {
        
$GLOBALS['__db_query_time']=(float)($GLOBALS['__db_query_time'] ?? 0)+(microtime(true)-$started);
    }
}
function 
db_db_query(string $database,string $query): DBResult|bool { return db_query($query); }
function 
db_fetch_assoc(mixed $r): array|false { if(is_array($r)) return $r; if(!$r instanceof DBResult) return false; return $r->rows[$r->cursor++] ?? false; }
function 
db_fetch_array(mixed $rint $mode=MYSQLI_BOTH): array|false {
    
$row=db_fetch_assoc($r); if($row===false) return false;
    if(
$mode===MYSQLI_ASSOC) return $row;
    if(
$mode===MYSQLI_NUM) return array_values($row);
    
$both=$row; foreach(array_values($row) as $i=>$v$both[$i]=$v; return $both;
}
function 
db_num_rows(mixed $r): int { if($r instanceof DBResult) return count($r->rows); if(is_array($r)) return count($r); return 0; }
function 
db_result(mixed $rint $row=0int|string $field=0): mixed {
    if(
is_array($r)){ $x=$r; if(is_int($field)) return array_values($x)[$field] ?? false; return $x[$field] ?? false; }
    if(!
$r instanceof DBResult || !isset($r->rows[$row])) return false;
    
$x=$r->rows[$row]; if(is_int($field)) return array_values($x)[$field] ?? false; return $x[$field] ?? false;
}
function 
db_insert_id(): int { return (int)($GLOBALS['__db_last_insert_id'] ?: (db_connect() ? db_pdo()->lastInsertId() : 0)); }
function 
db_real_escape_string(string $s): string $q=db_pdo()->quote($s); return substr($q,1,-1); }
function 
db_error(): string { return (string)($GLOBALS['__db_last_error'] ?? ''); }
function 
db_prepare(string $sql, array $params=[]): PDOStatement {
    
$started=microtime(true); $GLOBALS['__db_query_count']=(int)($GLOBALS['__db_query_count'] ?? 0)+1;
    try {
        
$stmt=db_pdo()->prepare($sql);
        
$stmt->execute($params);
        return 
$stmt;
    } catch (
Throwable $e) {
        
$GLOBALS['__db_last_error']=$e->getMessage();
        
$compactSql=substr((string)preg_replace('/s+/',' ',$sql),0,1000);
        
$safeSql=preg_replace("/'(?:''|[^'])*'/""'[redacted]'"$compactSql) ?? '[query redacted]';
        if(
function_exists('app_log_write')) app_log_write('DB','Prepared query failed',['sql'=>$safeSql,'type'=>get_class($e)]);
        throw 
$e;
    } finally {
        
$GLOBALS['__db_query_time']=(float)($GLOBALS['__db_query_time'] ?? 0)+(microtime(true)-$started);
    }
}

function 
db_fetch_one(string $sql,array $params=[]): ?array { $r=db_prepare($sql,$params)->fetch(PDO::FETCH_ASSOC); return $r===false?null:$r; }
function 
db_execute(string $sql,array $params=[]): bool { return db_prepare($sql,$params)->rowCount() >= 0; }
Онлайн: 2
Реклама