refactor namespaces, start work on sql
This commit is contained in:
parent
50b78f8131
commit
8b03b209dc
|
@ -1,23 +1,27 @@
|
||||||
/*
|
/*
|
||||||
@BLOG
|
============================================================
|
||||||
|
Stats
|
||||||
|
============================================================
|
||||||
*/
|
*/
|
||||||
DROP TABLE IF EXISTS blog;
|
CREATE TABLE stats (
|
||||||
CREATE TABLE blog (
|
|
||||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
`author_id` INTEGER NOT NULL,
|
`luck` INTEGER NOT NULL DEFAULT 0,
|
||||||
`title` TEXT NOT NULL,
|
`armor` INTEGER NOT NULL DEFAULT 0,
|
||||||
`slug` TEXT NOT NULL UNIQUE,
|
`focus` INTEGER NOT NULL DEFAULT 0,
|
||||||
`content` TEXT NOT NULL,
|
`power` INTEGER NOT NULL DEFAULT 0,
|
||||||
`created` DATETIME DEFAULT CURRENT_TIMESTAMP,
|
`resist` INTEGER NOT NULL DEFAULT 0,
|
||||||
`updated` DATETIME DEFAULT CURRENT_TIMESTAMP
|
`accuracy` INTEGER NOT NULL DEFAULT 0,
|
||||||
);
|
`ferocity` INTEGER NOT NULL DEFAULT 0,
|
||||||
CREATE INDEX idx_blog_author_id ON blog (`author_id`);
|
`precision` INTEGER NOT NULL DEFAULT 0,
|
||||||
CREATE INDEX idx_blog_slug ON blog (`slug`);
|
`toughness` INTEGER NOT NULL DEFAULT 0,
|
||||||
|
`penetration` INTEGER NOT NULL DEFAULT 0,
|
||||||
|
) STRICT;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@CHARS
|
============================================================
|
||||||
|
Characters
|
||||||
|
============================================================
|
||||||
*/
|
*/
|
||||||
DROP TABLE IF EXISTS characters;
|
|
||||||
CREATE TABLE characters (
|
CREATE TABLE characters (
|
||||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
`user_id` INTEGER NOT NULL,
|
`user_id` INTEGER NOT NULL,
|
||||||
|
@ -32,27 +36,14 @@ CREATE TABLE characters (
|
||||||
`m_mp` INTEGER NOT NULL DEFAULT 10,
|
`m_mp` INTEGER NOT NULL DEFAULT 10,
|
||||||
`tp` INTEGER NOT NULL DEFAULT 1,
|
`tp` INTEGER NOT NULL DEFAULT 1,
|
||||||
`m_tp` INTEGER NOT NULL DEFAULT 1,
|
`m_tp` INTEGER NOT NULL DEFAULT 1,
|
||||||
`pow` INTEGER NOT NULL DEFAULT 0, -- Power
|
`stats_id` INTEGER NOT NULL,
|
||||||
`acc` INTEGER NOT NULL DEFAULT 0, -- Accuracy
|
|
||||||
`pen` INTEGER NOT NULL DEFAULT 0, -- Penetration
|
|
||||||
`foc` INTEGER NOT NULL DEFAULT 0, -- Focus
|
|
||||||
`tou` INTEGER NOT NULL DEFAULT 0, -- Toughness
|
|
||||||
`arm` INTEGER NOT NULL DEFAULT 0, -- Armor
|
|
||||||
`res` INTEGER NOT NULL DEFAULT 0, -- Resist
|
|
||||||
`pre` INTEGER NOT NULL DEFAULT 0, -- Precision
|
|
||||||
`fer` INTEGER NOT NULL DEFAULT 0, -- Ferocity
|
|
||||||
`luck` INTEGER NOT NULL DEFAULT 0, -- Luck
|
|
||||||
`inv_slots` INTEGER NOT NULL DEFAULT 10,
|
`inv_slots` INTEGER NOT NULL DEFAULT 10,
|
||||||
`att_points` INTEGER NOT NULL DEFAULT 0,
|
`att_points` INTEGER NOT NULL DEFAULT 0,
|
||||||
`bio` TEXT DEFAULT ''
|
`bio` TEXT DEFAULT ''
|
||||||
);
|
);
|
||||||
CREATE INDEX idx_characters_user_id ON characters (`user_id`);
|
CREATE INDEX idx_characters_user_id ON characters (`user_id`);
|
||||||
|
|
||||||
/*
|
CREATE TABLE equipped_items (
|
||||||
@CHARGEAR
|
|
||||||
*/
|
|
||||||
DROP TABLE IF EXISTS char_gear;
|
|
||||||
CREATE TABLE char_gear (
|
|
||||||
`char_id` INTEGER NOT NULL,
|
`char_id` INTEGER NOT NULL,
|
||||||
`head` INTEGER NOT NULL DEFAULT 0,
|
`head` INTEGER NOT NULL DEFAULT 0,
|
||||||
`chest` INTEGER NOT NULL DEFAULT 0,
|
`chest` INTEGER NOT NULL DEFAULT 0,
|
||||||
|
@ -63,31 +54,43 @@ CREATE TABLE char_gear (
|
||||||
`rune` INTEGER NOT NULL DEFAULT 0,
|
`rune` INTEGER NOT NULL DEFAULT 0,
|
||||||
`ring` INTEGER NOT NULL DEFAULT 0,
|
`ring` INTEGER NOT NULL DEFAULT 0,
|
||||||
`amulet` INTEGER NOT NULL DEFAULT 0,
|
`amulet` INTEGER NOT NULL DEFAULT 0,
|
||||||
`pow` INTEGER NOT NULL DEFAULT 0, -- Power
|
`stats_id` INTEGER NOT NULL,
|
||||||
`acc` INTEGER NOT NULL DEFAULT 0, -- Accuracy
|
|
||||||
`pen` INTEGER NOT NULL DEFAULT 0, -- Penetration
|
|
||||||
`foc` INTEGER NOT NULL DEFAULT 0, -- Focus
|
|
||||||
`tou` INTEGER NOT NULL DEFAULT 0, -- Toughness
|
|
||||||
`arm` INTEGER NOT NULL DEFAULT 0, -- Armor
|
|
||||||
`res` INTEGER NOT NULL DEFAULT 0, -- Resist
|
|
||||||
`pre` INTEGER NOT NULL DEFAULT 0, -- Precision
|
|
||||||
`fer` INTEGER NOT NULL DEFAULT 0, -- Ferocity
|
|
||||||
`luck` INTEGER NOT NULL DEFAULT 0, -- Luck
|
|
||||||
`max_hp` INTEGER NOT NULL DEFAULT 0,
|
`max_hp` INTEGER NOT NULL DEFAULT 0,
|
||||||
`max_mp` INTEGER NOT NULL DEFAULT 0
|
`max_mp` INTEGER NOT NULL DEFAULT 0
|
||||||
);
|
);
|
||||||
CREATE INDEX idx_char_gear_char_id ON char_gear (`char_id`);
|
CREATE INDEX idx_char_gear_char_id ON char_gear (`char_id`);
|
||||||
|
|
||||||
/*
|
CREATE TABLE inventory_items (
|
||||||
@CHARINV
|
|
||||||
*/
|
|
||||||
DROP TABLE IF EXISTS char_inventory;
|
|
||||||
CREATE TABLE char_inventory (
|
|
||||||
`char_id` INTEGER NOT NULL,
|
`char_id` INTEGER NOT NULL,
|
||||||
`item_id` INTEGER NOT NULL
|
`item_id` INTEGER NOT NULL
|
||||||
);
|
);
|
||||||
CREATE INDEX idx_inventory_char_id ON char_inventory (`char_id`);
|
CREATE INDEX idx_inventory_char_id ON char_inventory (`char_id`);
|
||||||
|
|
||||||
|
-- Wallets are account-bound rather than character-bound. Should I move this to auth?
|
||||||
|
CREATE TABLE wallets (
|
||||||
|
`user_id` INTEGER NOT NULL,
|
||||||
|
`silver` INTEGER NOT NULL DEFAULT 10,
|
||||||
|
`stargem` INTEGER NOT NULL DEFAULT 0
|
||||||
|
);
|
||||||
|
CREATE INDEX idx_wallets_user_id ON wallets (`user_id`);
|
||||||
|
|
||||||
|
/*
|
||||||
|
============================================================
|
||||||
|
Blog
|
||||||
|
============================================================
|
||||||
|
*/
|
||||||
|
create table blog (
|
||||||
|
`id` integer primary KEY AUTOINCREMENT,
|
||||||
|
`author_id` integer not null,
|
||||||
|
`title` TEXT not null,
|
||||||
|
`slug` TEXT not null unique,
|
||||||
|
`content` TEXT not null,
|
||||||
|
`created` DATETIME default current_timestamp,
|
||||||
|
`updated` DATETIME default current_timestamp
|
||||||
|
);
|
||||||
|
CREATE INDEX idx_blog_author_id ON blog (`author_id`);
|
||||||
|
CREATE INDEX idx_blog_slug ON blog (`slug`);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@WALLETS
|
@WALLETS
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use Models\Character;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Setup
|
============================================================
|
||||||
|
Bootstrapping
|
||||||
|
============================================================
|
||||||
*/
|
*/
|
||||||
define('SRC', __DIR__ . '/../src');
|
define('SRC', __DIR__ . '/../src');
|
||||||
define('DATABASE_PATH', __DIR__ . '/../database');
|
define('DATABASE_PATH', __DIR__ . '/../database');
|
||||||
|
@ -10,7 +14,9 @@ require_once SRC . '/bootstrap.php';
|
||||||
$r = new Router;
|
$r = new Router;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
============================================================
|
||||||
Home
|
Home
|
||||||
|
============================================================
|
||||||
*/
|
*/
|
||||||
$r->get('/', function() {
|
$r->get('/', function() {
|
||||||
if (user()) redirect('/world');
|
if (user()) redirect('/world');
|
||||||
|
@ -18,73 +24,23 @@ $r->get('/', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
============================================================
|
||||||
Auth
|
Auth
|
||||||
|
============================================================
|
||||||
*/
|
*/
|
||||||
$r->get('/register', 'Actions\Auth::register_get')->middleware('guest_only');
|
$r->get('/register', 'Actions\Auth::register_get')->middleware('guest_only');
|
||||||
$r->post('/register', 'Actions\Auth::register_post')->middleware('guest_only');
|
$r->post('/register', 'Actions\Auth::register_post')->middleware('guest_only');
|
||||||
|
|
||||||
$r->get('/login', function() {
|
$r->get('/login', 'Actions\Auth::login_get')->middleware('guest_only');
|
||||||
echo render('layouts/basic', ['view' => 'pages/auth/login']);
|
$r->post('/login', 'Actions\Auth::login_post')->middleware('guest_only');
|
||||||
})->middleware('guest_only');
|
|
||||||
|
|
||||||
$r->post('/login', function() {
|
$r->post('/logout', 'Actions\Auth::logout')->middleware('auth_only');
|
||||||
$errors = [];
|
if (env('debug', false)) $r->get('/debug/logout', 'Actions\Auth::logout');
|
||||||
|
|
||||||
$u = trim($_POST['u'] ?? '');
|
|
||||||
$p = $_POST['p'] ?? '';
|
|
||||||
|
|
||||||
if (empty($u)) $errors['u'][] = 'Username is required.';
|
|
||||||
if (empty($p)) $errors['p'][] = 'Password is required.';
|
|
||||||
|
|
||||||
// If there are errors at this point, send them to the page with errors flashed.
|
|
||||||
if (!empty($errors)) {
|
|
||||||
$GLOBALS['form-errors'] = $errors;
|
|
||||||
echo render('layouts/basic', ['view' => 'pages/auth/login']);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
$user = User::find($u);
|
|
||||||
if ($user === false || !$user->check_password($p)) {
|
|
||||||
$errors['x'][] = 'Invalid username or password.';
|
|
||||||
$GLOBALS['form-errors'] = $errors;
|
|
||||||
echo render('layouts/basic', ['view' => 'pages/auth/login']);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
$_SESSION['user'] = serialize($user);
|
|
||||||
|
|
||||||
if ($_POST['remember'] ?? false) {
|
|
||||||
$session = Session::create($user->id, strtotime('+30 days'));
|
|
||||||
if ($session === false) error_response(400);
|
|
||||||
set_cookie('remember_me', $session->token, $session->expires);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($user->char_count() === 0) {
|
|
||||||
redirect('/character/create-first');
|
|
||||||
} elseif (!change_user_character($user->char_id)) {
|
|
||||||
echo "failed to change user character (aclp)";
|
|
||||||
error_response(999);
|
|
||||||
}
|
|
||||||
|
|
||||||
redirect('/');
|
|
||||||
})->middleware('guest_only');
|
|
||||||
|
|
||||||
$r->post('/logout', function() {
|
|
||||||
Session::delete(user()->id);
|
|
||||||
unset($_SESSION['user']);
|
|
||||||
set_cookie('remember_me', '', 1);
|
|
||||||
redirect('/');
|
|
||||||
});
|
|
||||||
|
|
||||||
$r->get('/debug/logout', function() {
|
|
||||||
Session::delete(user()->id);
|
|
||||||
unset($_SESSION['user']);
|
|
||||||
set_cookie('remember_me', '', 1);
|
|
||||||
redirect('/');
|
|
||||||
});
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
============================================================
|
||||||
Characters
|
Characters
|
||||||
|
============================================================
|
||||||
*/
|
*/
|
||||||
$r->get('/characters', function() {
|
$r->get('/characters', function() {
|
||||||
//echo page('chars/list', ['chars' => user()->char_list()]);
|
//echo page('chars/list', ['chars' => user()->char_list()]);
|
||||||
|
@ -220,7 +176,9 @@ $r->post('/character/delete', function() {
|
||||||
})->middleware('must_have_character');
|
})->middleware('must_have_character');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
============================================================
|
||||||
World
|
World
|
||||||
|
============================================================
|
||||||
*/
|
*/
|
||||||
$r->get('/world', function() {
|
$r->get('/world', function() {
|
||||||
echo render('layouts/game');
|
echo render('layouts/game');
|
||||||
|
@ -270,14 +228,18 @@ $r->post('/move', function() {
|
||||||
})->middleware('ajax_only')->middleware('must_have_character');
|
})->middleware('ajax_only')->middleware('must_have_character');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
UI
|
============================================================
|
||||||
|
UI Components
|
||||||
|
============================================================
|
||||||
*/
|
*/
|
||||||
$r->get('/ui/stats', function() {
|
$r->get('/ui/stats', function() {
|
||||||
echo c_profile_stats(char());
|
echo c_profile_stats(char());
|
||||||
})->middleware('ajax_only')->middleware('must_have_character');
|
})->middleware('ajax_only')->middleware('must_have_character');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
============================================================
|
||||||
Router
|
Router
|
||||||
|
============================================================
|
||||||
*/
|
*/
|
||||||
// [code, handler, params, middleware]
|
// [code, handler, params, middleware]
|
||||||
$l = $r->lookup($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI']);
|
$l = $r->lookup($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI']);
|
||||||
|
@ -287,6 +249,8 @@ if (!empty($l['middleware'])) foreach ($l['middleware'] as $middleware) $middlew
|
||||||
$l['handler'](...$l['params'] ?? []);
|
$l['handler'](...$l['params'] ?? []);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
============================================================
|
||||||
Cleanup
|
Cleanup
|
||||||
|
============================================================
|
||||||
*/
|
*/
|
||||||
clear_flashes();
|
clear_flashes();
|
||||||
|
|
|
@ -2,10 +2,17 @@
|
||||||
|
|
||||||
namespace Actions;
|
namespace Actions;
|
||||||
|
|
||||||
use \User;
|
use Models\Session;
|
||||||
|
use Models\User;
|
||||||
|
use Models\Wallet;
|
||||||
|
|
||||||
class Auth
|
class Auth
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
============================================================
|
||||||
|
Registration
|
||||||
|
============================================================
|
||||||
|
*/
|
||||||
public static function register_get(): void
|
public static function register_get(): void
|
||||||
{
|
{
|
||||||
echo render('layouts/basic', ['view' => 'pages/auth/register']);
|
echo render('layouts/basic', ['view' => 'pages/auth/register']);
|
||||||
|
@ -67,10 +74,76 @@ class Auth
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (\User::create($u, $e, $p) === false) error_response(400);
|
if (User::create($u, $e, $p) === false) error_response(400);
|
||||||
|
|
||||||
$_SESSION['user'] = serialize(\User::find($u));
|
$_SESSION['user'] = serialize(User::find($u));
|
||||||
\Wallet::create(user()->id);
|
Wallet::create(user()->id);
|
||||||
redirect('/character/create-first');
|
redirect('/character/create-first');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
============================================================
|
||||||
|
Login
|
||||||
|
============================================================
|
||||||
|
*/
|
||||||
|
public static function login_get(): void
|
||||||
|
{
|
||||||
|
echo render('layouts/basic', ['view' => 'pages/auth/login']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function login_post(): void
|
||||||
|
{
|
||||||
|
$errors = [];
|
||||||
|
|
||||||
|
$u = trim($_POST['u'] ?? '');
|
||||||
|
$p = $_POST['p'] ?? '';
|
||||||
|
|
||||||
|
if (empty($u)) $errors['u'][] = 'Username is required.';
|
||||||
|
if (empty($p)) $errors['p'][] = 'Password is required.';
|
||||||
|
|
||||||
|
// If there are errors at this point, send them to the page with errors flashed.
|
||||||
|
if (!empty($errors)) {
|
||||||
|
$GLOBALS['form-errors'] = $errors;
|
||||||
|
echo render('layouts/basic', ['view' => 'pages/auth/login']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = User::find($u);
|
||||||
|
if ($user === false || !$user->check_password($p)) {
|
||||||
|
$errors['x'][] = 'Invalid username or password.';
|
||||||
|
$GLOBALS['form-errors'] = $errors;
|
||||||
|
echo render('layouts/basic', ['view' => 'pages/auth/login']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$_SESSION['user'] = serialize($user);
|
||||||
|
|
||||||
|
if ($_POST['remember'] ?? false) {
|
||||||
|
$session = Session::create($user->id, strtotime('+30 days'));
|
||||||
|
if ($session === false) error_response(400);
|
||||||
|
set_cookie('remember_me', $session->token, $session->expires);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($user->char_count() === 0) {
|
||||||
|
redirect('/character/create-first');
|
||||||
|
} elseif (!change_user_character($user->char_id)) {
|
||||||
|
echo "failed to change user character (aclp)";
|
||||||
|
error_response(999);
|
||||||
|
}
|
||||||
|
|
||||||
|
redirect('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
============================================================
|
||||||
|
Logout
|
||||||
|
============================================================
|
||||||
|
*/
|
||||||
|
public static function logout(): void
|
||||||
|
{
|
||||||
|
Session::delete(user()->id);
|
||||||
|
unset($_SESSION['user']);
|
||||||
|
set_cookie('remember_me', '', 1);
|
||||||
|
redirect('/');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,11 +26,11 @@ session_start();
|
||||||
define('CLASS_MAP', [
|
define('CLASS_MAP', [
|
||||||
'Database' => '/database.php',
|
'Database' => '/database.php',
|
||||||
'Router' => '/router.php',
|
'Router' => '/router.php',
|
||||||
'User' => '/models/user.php',
|
|
||||||
'Character' => '/models/character.php',
|
|
||||||
'Wallet' => '/models/wallet.php',
|
|
||||||
'Session' => '/models/session.php',
|
|
||||||
'Actions\Auth' => '/actions/auth.php',
|
'Actions\Auth' => '/actions/auth.php',
|
||||||
|
'Models\User' => '/models/user.php',
|
||||||
|
'Models\Character' => '/models/character.php',
|
||||||
|
'Models\Wallet' => '/models/wallet.php',
|
||||||
|
'Models\Session' => '/models/session.php',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
spl_autoload_register(function (string $class) {
|
spl_autoload_register(function (string $class) {
|
||||||
|
@ -58,12 +58,11 @@ if (env('debug', false)) {
|
||||||
CSRF
|
CSRF
|
||||||
============================================================
|
============================================================
|
||||||
*/
|
*/
|
||||||
csrf(); // generate a CSRF token, or retrieve the current token
|
csrf();
|
||||||
|
|
||||||
// error any request that fails CSRF on these methods
|
|
||||||
if (in_array($_SERVER['REQUEST_METHOD'], ['POST', 'PUT', 'PATCH', 'DELETE'])) {
|
if (in_array($_SERVER['REQUEST_METHOD'], ['POST', 'PUT', 'PATCH', 'DELETE'])) {
|
||||||
$csrf = $_POST['csrf'] ?? $_SERVER['HTTP_X_CSRF'] ?? '';
|
$csrf = $_POST['csrf'] ?? $_SERVER['HTTP_X_CSRF'] ?? ''; // look for CSRF in AJAX requests
|
||||||
if (!hash_equals($_SESSION['csrf'] ?? '', $csrf)) error_response(418);
|
if (!hash_equals($_SESSION['csrf'] ?? '', $csrf)) error_response(418); // I'm a Teapot
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -71,9 +70,10 @@ if (in_array($_SERVER['REQUEST_METHOD'], ['POST', 'PUT', 'PATCH', 'DELETE'])) {
|
||||||
Global State
|
Global State
|
||||||
============================================================
|
============================================================
|
||||||
*/
|
*/
|
||||||
$GLOBALS['databases'] = []; // database interfaces
|
$GLOBALS['databases'] = [];
|
||||||
|
|
||||||
// all relevant state to handling requests
|
|
||||||
$GLOBALS['state'] = [
|
$GLOBALS['state'] = [
|
||||||
'logged_in' => isset($_SESSION['user']) || validate_session()
|
'logged_in' => isset($_SESSION['user']) || validate_session(),
|
||||||
|
'user' => null, // populated by user()
|
||||||
|
'char' => null, // user's selected character, populated by char()
|
||||||
|
'wallet' => null, // populated by wallet()
|
||||||
];
|
];
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use Models\Character;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render the logout button's form.
|
* Render the logout button's form.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -23,11 +23,7 @@ class Database extends SQLite3
|
||||||
$p = strpos($query, '?') !== false;
|
$p = strpos($query, '?') !== false;
|
||||||
$stmt = $this->prepare($query);
|
$stmt = $this->prepare($query);
|
||||||
|
|
||||||
if (!empty($params)) {
|
foreach ($params ?? [] as $k => $v) $stmt->bindValue($p ? $k + 1 : $k, $v, $this->getSQLiteType($v));
|
||||||
foreach ($params as $k => $v) {
|
|
||||||
$stmt->bindValue($p ? $k + 1 : $k, $v, $this->getSQLiteType($v));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$start = microtime(true);
|
$start = microtime(true);
|
||||||
$r = $stmt->execute();
|
$r = $stmt->execute();
|
||||||
|
@ -61,9 +57,7 @@ class Database extends SQLite3
|
||||||
$this->count++;
|
$this->count++;
|
||||||
$this->query_time += $time_taken;
|
$this->query_time += $time_taken;
|
||||||
|
|
||||||
if (env('debug', false)) {
|
if (env('debug', false)) $this->log[] = [$query, $time_taken];
|
||||||
$this->log[] = [$query, $time_taken];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getSQLiteType(mixed $value): int
|
private function getSQLiteType(mixed $value): int
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use Models\Character;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load the environment variables from the .env file.
|
* Load the environment variables from the .env file.
|
||||||
*/
|
*/
|
||||||
|
@ -170,7 +172,7 @@ function set_cookie($name, $value, $expires)
|
||||||
/**
|
/**
|
||||||
* Get the current user's object from SESSION if it exists.
|
* Get the current user's object from SESSION if it exists.
|
||||||
*/
|
*/
|
||||||
function user(): User|false
|
function user(): Models\User|false
|
||||||
{
|
{
|
||||||
if (empty($_SESSION['user'])) return false;
|
if (empty($_SESSION['user'])) return false;
|
||||||
return $GLOBALS['state']['user'] ??= unserialize($_SESSION['user']);
|
return $GLOBALS['state']['user'] ??= unserialize($_SESSION['user']);
|
||||||
|
@ -195,8 +197,7 @@ function modify_user_session(string $field, mixed $value): bool
|
||||||
function char(): Character|false
|
function char(): Character|false
|
||||||
{
|
{
|
||||||
if (empty($_SESSION['user'])) return false;
|
if (empty($_SESSION['user'])) return false;
|
||||||
if (empty($GLOBALS['char'])) $GLOBALS['char'] = user()->current_char();
|
return $GLOBALS['state']['char'] ??= Character::find(user()->char_id);
|
||||||
return $GLOBALS['char'];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -233,12 +234,10 @@ function percent(float $num, float $denom, int $precision = 4): float
|
||||||
* the data is up to date with every request without having to query the database every use within, for example, a
|
* the data is up to date with every request without having to query the database every use within, for example, a
|
||||||
* template. Will return false if the user or wallet does not exist.
|
* template. Will return false if the user or wallet does not exist.
|
||||||
*/
|
*/
|
||||||
function wallet(): Wallet|false
|
function wallet(): Models\Wallet|false
|
||||||
{
|
{
|
||||||
if (user() === false) return false;
|
if (user() === false) return false;
|
||||||
if (empty($GLOBALS['wallet'])) $w = user()->wallet();
|
return $GLOBALS['state']['wallet'] = Models\Wallet::find(user()->id);
|
||||||
if ($w === false) return false;
|
|
||||||
return $GLOBALS['wallet'] = $w;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -396,7 +395,7 @@ function db_fetch_array(SQLite3Result $result, int $mode = SQLITE3_ASSOC): array
|
||||||
function validate_session(): bool
|
function validate_session(): bool
|
||||||
{
|
{
|
||||||
if (!isset($_COOKIE['remember_me'])) return false;
|
if (!isset($_COOKIE['remember_me'])) return false;
|
||||||
if (($session = Session::find($_COOKIE['remember_me'])) && $session->validate()) return true;
|
if (($session = Models\Session::find($_COOKIE['remember_me'])) && $session->validate()) return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
namespace Models;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Characters are the living, breathing entities that interact with the game world. They are inextricably linked to their
|
Characters are the living, breathing entities that interact with the game world. They are inextricably linked to their
|
||||||
accounts, and are the primary means by which the character interacts with the game world. Separating the character from
|
accounts, and are the primary means by which the character interacts with the game world. Separating the character from
|
||||||
|
@ -74,7 +76,7 @@ class Character
|
||||||
"SELECT * FROM characters WHERE id = :id OR name = :id COLLATE NOCASE",
|
"SELECT * FROM characters WHERE id = :id OR name = :id COLLATE NOCASE",
|
||||||
[':id' => $id]
|
[':id' => $id]
|
||||||
);
|
);
|
||||||
if ($q === false) throw new Exception('Failed to query character. (C::f)'); // badly formed query
|
if ($q === false) throw new \Exception('Failed to query character. (C::f)'); // badly formed query
|
||||||
return ($c = $q->fetchArray(SQLITE3_ASSOC)) === false ? false : new Character($c);
|
return ($c = $q->fetchArray(SQLITE3_ASSOC)) === false ? false : new Character($c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,7 +101,7 @@ class Character
|
||||||
// Create the character!
|
// Create the character!
|
||||||
if (live_db()->query("INSERT INTO characters ($f) VALUES ($v)", $data) === false) {
|
if (live_db()->query("INSERT INTO characters ($f) VALUES ($v)", $data) === false) {
|
||||||
// @TODO: Log this error
|
// @TODO: Log this error
|
||||||
throw new Exception('Failed to create character. (cc)');
|
throw new \Exception('Failed to create character. (cc)');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the character ID
|
// Get the character ID
|
||||||
|
@ -153,7 +155,7 @@ class Character
|
||||||
"SELECT 1 FROM characters WHERE id = :i AND user_id = :u LIMIT 1",
|
"SELECT 1 FROM characters WHERE id = :i AND user_id = :u LIMIT 1",
|
||||||
[':i' => $id, ':u' => $user_id]
|
[':i' => $id, ':u' => $user_id]
|
||||||
);
|
);
|
||||||
if ($q === false) throw new Exception('Failed to query char ownership. (C::bt)');
|
if ($q === false) throw new \Exception('Failed to query char ownership. (C::bt)');
|
||||||
return $q->fetchArray(SQLITE3_ASSOC) !== false;
|
return $q->fetchArray(SQLITE3_ASSOC) !== false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,7 +188,7 @@ class Character
|
||||||
{
|
{
|
||||||
// Delete the character
|
// Delete the character
|
||||||
if (live_db()->query("DELETE FROM characters WHERE id = :p", [':p' => $id]) === false) {
|
if (live_db()->query("DELETE FROM characters WHERE id = :p", [':p' => $id]) === false) {
|
||||||
throw new Exception('Failed to delete character. (C::d)');
|
throw new \Exception('Failed to delete character. (C::d)');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,7 +205,7 @@ class Character
|
||||||
'SELECT awarded FROM owned_titles WHERE char_id = ? AND title_id = ? LIMIT 1',
|
'SELECT awarded FROM owned_titles WHERE char_id = ? AND title_id = ? LIMIT 1',
|
||||||
[$this->id, $this->title_id]
|
[$this->id, $this->title_id]
|
||||||
);
|
);
|
||||||
if ($q === false) throw new Exception('Failed to query title. (C::t)');
|
if ($q === false) throw new \Exception('Failed to query title. (C::t)');
|
||||||
|
|
||||||
$a = $q->fetchArray(SQLITE3_ASSOC);
|
$a = $q->fetchArray(SQLITE3_ASSOC);
|
||||||
if ($a === false) return false;
|
if ($a === false) return false;
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
namespace Models;
|
||||||
|
|
||||||
class Session
|
class Session
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
|
@ -29,7 +31,7 @@ class Session
|
||||||
return new Session($session['user_id'], $session['token'], $session['expires']);
|
return new Session($session['user_id'], $session['token'], $session['expires']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function delete(int $user_id): SQLite3Result|false
|
public static function delete(int $user_id): \SQLite3Result|false
|
||||||
{
|
{
|
||||||
return auth_db()->query("DELETE FROM sessions WHERE user_id = :u", [':u' => $user_id]);
|
return auth_db()->query("DELETE FROM sessions WHERE user_id = :u", [':u' => $user_id]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
namespace Models;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Representation of a User from the auth database. Contains auth-related info and handles meta-level state.
|
* Representation of a User from the auth database. Contains auth-related info and handles meta-level state.
|
||||||
*/
|
*/
|
||||||
|
@ -43,12 +45,12 @@ class User
|
||||||
/**
|
/**
|
||||||
* When this account was created (registered date).
|
* When this account was created (registered date).
|
||||||
*/
|
*/
|
||||||
public DateTime $created;
|
public int $created;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When the account was last logged in to.
|
* When the account was last logged in to.
|
||||||
*/
|
*/
|
||||||
public DateTime $last_login;
|
public int $last_login;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Populate a User object with data; assumes you are passing the associatve array from SQLite directly.
|
* Populate a User object with data; assumes you are passing the associatve array from SQLite directly.
|
||||||
|
@ -57,7 +59,7 @@ class User
|
||||||
{
|
{
|
||||||
foreach ($data as $k => $v) {
|
foreach ($data as $k => $v) {
|
||||||
if (property_exists($this, $k)) {
|
if (property_exists($this, $k)) {
|
||||||
$this->$k = in_array($k, ['created', 'last_login']) ? new DateTime($v) : $v;
|
$this->$k = in_array($k, ['created', 'last_login']) ? strtotime($v) : $v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,7 +74,7 @@ class User
|
||||||
"SELECT * FROM users WHERE username = :i COLLATE NOCASE OR email = :i COLLATE NOCASE OR id = :i LIMIT 1",
|
"SELECT * FROM users WHERE username = :i COLLATE NOCASE OR email = :i COLLATE NOCASE OR id = :i LIMIT 1",
|
||||||
[':i' => $identifier]
|
[':i' => $identifier]
|
||||||
);
|
);
|
||||||
if ($r === false) throw new Exception("Failed to query user. (U::f)"); // badly formed query
|
if ($r === false) throw new \Exception("Failed to query user. (U::f)"); // badly formed query
|
||||||
$u = $r->fetchArray(SQLITE3_ASSOC);
|
$u = $r->fetchArray(SQLITE3_ASSOC);
|
||||||
if ($u === false) return false; // no user found
|
if ($u === false) return false; // no user found
|
||||||
return new User($u);
|
return new User($u);
|
||||||
|
@ -83,7 +85,7 @@ class User
|
||||||
* of the username or password passed to it; that is the responsibility of the caller. Returns false on
|
* of the username or password passed to it; that is the responsibility of the caller. Returns false on
|
||||||
* failure.
|
* failure.
|
||||||
*/
|
*/
|
||||||
public static function create(string $username, string $email, string $password, int $auth = 0): SQLite3Result|false
|
public static function create(string $username, string $email, string $password, int $auth = 0): \SQLite3Result|false
|
||||||
{
|
{
|
||||||
return auth_db()->query("INSERT INTO users (username, email, password, auth) VALUES (:u, :e, :p, :a)", [
|
return auth_db()->query("INSERT INTO users (username, email, password, auth) VALUES (:u, :e, :p, :a)", [
|
||||||
':u' => $username,
|
':u' => $username,
|
||||||
|
@ -120,7 +122,7 @@ class User
|
||||||
/**
|
/**
|
||||||
* Delete a user by their username, email, or id.
|
* Delete a user by their username, email, or id.
|
||||||
*/
|
*/
|
||||||
public static function delete(string|int $identifier): SQLite3Result|false
|
public static function delete(string|int $identifier): \SQLite3Result|false
|
||||||
{
|
{
|
||||||
return auth_db()->query(
|
return auth_db()->query(
|
||||||
"DELETE FROM users WHERE username = :i OR email = :i OR id = :i",
|
"DELETE FROM users WHERE username = :i OR email = :i OR id = :i",
|
||||||
|
@ -137,7 +139,7 @@ class User
|
||||||
"SELECT COUNT(*) FROM characters WHERE user_id = :u",
|
"SELECT COUNT(*) FROM characters WHERE user_id = :u",
|
||||||
[':u' => $this->id]
|
[':u' => $this->id]
|
||||||
)->fetchArray(SQLITE3_NUM);
|
)->fetchArray(SQLITE3_NUM);
|
||||||
if ($c === false) throw new Exception('Failed to count characters. (U::cc)');
|
if ($c === false) throw new \Exception('Failed to count characters. (U::cc)');
|
||||||
return (int) $c[0];
|
return (int) $c[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,7 +150,7 @@ class User
|
||||||
public function char_list(): array|false
|
public function char_list(): array|false
|
||||||
{
|
{
|
||||||
$q = live_db()->query("SELECT id, name, level FROM characters WHERE user_id = ?", [$this->id]);
|
$q = live_db()->query("SELECT id, name, level FROM characters WHERE user_id = ?", [$this->id]);
|
||||||
if ($q === false) throw new Exception('Failed to list characters. (U->cl)');
|
if ($q === false) throw new \Exception('Failed to list characters. (U->cl)');
|
||||||
|
|
||||||
$c = [];
|
$c = [];
|
||||||
while ($row = $q->fetchArray(SQLITE3_ASSOC)) {
|
while ($row = $q->fetchArray(SQLITE3_ASSOC)) {
|
||||||
|
@ -158,20 +160,4 @@ class User
|
||||||
// return false if no characters
|
// return false if no characters
|
||||||
return empty($c) ? false : $c;
|
return empty($c) ? false : $c;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the user's current Character.
|
|
||||||
*/
|
|
||||||
public function current_char(): Character|false
|
|
||||||
{
|
|
||||||
return Character::find($this->char_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the user's wallet.
|
|
||||||
*/
|
|
||||||
public function wallet(): Wallet|false
|
|
||||||
{
|
|
||||||
return Wallet::find($this->id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
namespace Models;
|
||||||
|
|
||||||
class Wallet
|
class Wallet
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
|
@ -11,13 +13,13 @@ class Wallet
|
||||||
public static function find(int $user_id): Wallet|false
|
public static function find(int $user_id): Wallet|false
|
||||||
{
|
{
|
||||||
$r = live_db()->query('SELECT * FROM wallets WHERE user_id = ?', [$user_id]);
|
$r = live_db()->query('SELECT * FROM wallets WHERE user_id = ?', [$user_id]);
|
||||||
if ($r === false) throw new Exception('Failed to query wallet. (W::f)'); // badly formed query
|
if ($r === false) throw new \Exception('Failed to query wallet. (W::f)'); // badly formed query
|
||||||
$w = $r->fetchArray(SQLITE3_ASSOC);
|
$w = $r->fetchArray(SQLITE3_ASSOC);
|
||||||
if ($w === false) return false; // no wallet found
|
if ($w === false) return false; // no wallet found
|
||||||
return new Wallet($user_id, $w['silver'], $w['stargem']);
|
return new Wallet($user_id, $w['silver'], $w['stargem']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function create(int $user_id, int $silver = -1, int $starGems = -1): SQLite3Result|false
|
public static function create(int $user_id, int $silver = -1, int $starGems = -1): \SQLite3Result|false
|
||||||
{
|
{
|
||||||
return live_db()->query(
|
return live_db()->query(
|
||||||
"INSERT INTO wallets (user_id, silver, stargem) VALUES (:u, :s, :sg)",
|
"INSERT INTO wallets (user_id, silver, stargem) VALUES (:u, :s, :sg)",
|
||||||
|
@ -32,7 +34,7 @@ class Wallet
|
||||||
/**
|
/**
|
||||||
* Add a certain amount of currency to the user's wallet.
|
* Add a certain amount of currency to the user's wallet.
|
||||||
*/
|
*/
|
||||||
public function give(Currency $c, int $amt): SQLite3Result|false
|
public function give(\Currency $c, int $amt): \SQLite3Result|false
|
||||||
{
|
{
|
||||||
$cs = $c->string(true);
|
$cs = $c->string(true);
|
||||||
$new = $this->{$cs} + $amt;
|
$new = $this->{$cs} + $amt;
|
||||||
|
@ -42,7 +44,7 @@ class Wallet
|
||||||
/**
|
/**
|
||||||
* Remove a certain amount of currency from the user's wallet.
|
* Remove a certain amount of currency from the user's wallet.
|
||||||
*/
|
*/
|
||||||
public function take(Currency $c, int $amt): SQLite3Result|false
|
public function take(\Currency $c, int $amt): \SQLite3Result|false
|
||||||
{
|
{
|
||||||
$cs = $c->string(true);
|
$cs = $c->string(true);
|
||||||
$new = $this->{$cs} - $amt;
|
$new = $this->{$cs} - $amt;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user