Add PHP server version: leaderboard, identity, menu screens, lore
- php/: MySQL-backed (via config.php, gitignored) top-5 solutions per level, cookie identity with rename, server-side progress for "Продолжить" - Menu screens: Играть / Продолжить / Предыстория / Настройки, plus placeholder start/end screens for a future intro/outro - Lore screen: EXO:GRID backstory text (6 epochs, no gameplay changes yet) - levels.js/solver.js copied in as-is
This commit is contained in:
+51
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
// db.php — MySQL, БД уже создана на сервере (панель Тенетты), не SQLite.
|
||||
// Схема создаётся сама при первом обращении, руками ничего накатывать не
|
||||
// нужно — залил файлы и работает.
|
||||
|
||||
function get_db(): PDO {
|
||||
$cfg = require __DIR__ . '/config.php';
|
||||
$dsn = "mysql:host={$cfg['host']};dbname={$cfg['db']};charset=utf8mb4";
|
||||
$pdo = new PDO($dsn, $cfg['user'], $cfg['pass']);
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
$pdo->exec('CREATE TABLE IF NOT EXISTS users (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
token VARCHAR(64) UNIQUE NOT NULL,
|
||||
name VARCHAR(40) NOT NULL,
|
||||
last_level INT NOT NULL DEFAULT 0,
|
||||
created_at INT NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4');
|
||||
|
||||
// move_key хранится как md5-хеш последовательности ходов (фикс. длина
|
||||
// 32 символа) — а не сырой склеенной строкой, у которой длина растёт
|
||||
// с числом ходов и может упереться в лимит длины ключа InnoDB-индекса.
|
||||
$pdo->exec('CREATE TABLE IF NOT EXISTS solutions (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
level_name VARCHAR(64) NOT NULL,
|
||||
user_id INT NOT NULL,
|
||||
moves MEDIUMTEXT NOT NULL,
|
||||
move_count INT NOT NULL,
|
||||
move_key CHAR(32) NOT NULL,
|
||||
source VARCHAR(16) NOT NULL DEFAULT "player",
|
||||
created_at INT NOT NULL,
|
||||
UNIQUE KEY uniq_level_movekey (level_name, move_key)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4');
|
||||
|
||||
// MySQL/MariaDB не везде понимают "CREATE INDEX IF NOT EXISTS" — просто
|
||||
// глотаем "уже есть" при повторных запусках.
|
||||
try { $pdo->exec('CREATE INDEX idx_level_count ON solutions(level_name, move_count)'); }
|
||||
catch (PDOException $e) {}
|
||||
|
||||
return $pdo;
|
||||
}
|
||||
|
||||
// Идентичность — долгий cookie (год) с токеном, не PHP-сессия: имя должно
|
||||
// помниться неделями, а не до закрытия вкладки.
|
||||
function current_user(PDO $pdo): ?array {
|
||||
if (empty($_COOKIE['sokoban_token'])) return null;
|
||||
$stmt = $pdo->prepare('SELECT * FROM users WHERE token = ?');
|
||||
$stmt->execute([$_COOKIE['sokoban_token']]);
|
||||
$u = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
return $u ?: null;
|
||||
}
|
||||
Reference in New Issue
Block a user