diff --git a/public/index.php b/public/index.php
index 4bc5c77..d3432c7 100644
--- a/public/index.php
+++ b/public/index.php
@@ -7,15 +7,13 @@ require_once '../src/bootstrap.php';
$r = new Router;
$r->get('/', function() {
- global $userrow;
-
- if ($userrow["currentaction"] == "In Town") {
+ if (user()->currentaction === "In Town") {
$page = dotown();
$title = "In Town";
- } elseif ($userrow["currentaction"] == "Exploring") {
+ } elseif (user()->currentaction === "Exploring") {
$page = doexplore();
$title = "Exploring";
- } elseif ($userrow["currentaction"] == "Fighting") {
+ } elseif (user()->currentaction === "Fighting") {
redirect('/fight');
}
@@ -51,15 +49,13 @@ $l['handler'](...$l['params'] ?? []);
function donothing()
{
- global $userrow;
-
- if ($userrow["currentaction"] == "In Town") {
+ if (user()->currentaction == "In Town") {
$page = dotown();
$title = "In Town";
- } elseif ($userrow["currentaction"] == "Exploring") {
+ } elseif (user()->currentaction == "Exploring") {
$page = doexplore();
$title = "Exploring";
- } elseif ($userrow["currentaction"] == "Fighting") {
+ } elseif (user()->currentaction == "Fighting") {
redirect('/fight');
}
@@ -71,9 +67,9 @@ function donothing()
*/
function dotown()
{
- global $userrow, $controlrow;
+ global $controlrow;
- $townrow = get_town_by_xy($userrow['longitude'], $userrow['latitude']);
+ $townrow = get_town_by_xy(user()->longitude, user()->latitude);
if ($townrow === false) display("There is an error with your user account, or with the town data. Please try again.","Error");
$townrow["news"] = "";
@@ -119,6 +115,11 @@ function dotown()
HTML;
}
+ $u = User::find(1);
+ $u->gold += 100;
+ $u->save();
+ var_dump($u->gold);
+
return render('towns', ['town' => $townrow]);
}
@@ -145,7 +146,7 @@ function show_character_info(int $id = 0): void
{
global $controlrow, $userrow;
- $userrow = ($id === 0) ? $userrow : get_user_by_id($id);
+ $userrow = ($id === 0) ? $userrow : get_user($id);
if ($userrow === false) exit('Failed to show info for user ID '.$id);
$levelrow = db()->query("SELECT `{$userrow["charclass"]}_exp` FROM levels WHERE id=? LIMIT 1;", [$userrow['level'] + 1])->fetchArray(SQLITE3_ASSOC);
@@ -171,12 +172,10 @@ function show_character_info(int $id = 0): void
function showmap()
{
- global $userrow;
-
$pos = sprintf(
'
',
- round(258 + $userrow['longitude'] * (500 / 500) - 3),
- round(258 - $userrow['latitude'] * (500 / 500) - 3)
+ round(258 + user()->longitude * (500 / 500) - 3),
+ round(258 - user()->latitude * (500 / 500) - 3)
);
echo render('minimal', [
@@ -191,13 +190,11 @@ function showmap()
*/
function babblebox()
{
- global $userrow;
-
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$safecontent = make_safe($_POST["babble"]);
if (!empty($safecontent)) {
db()->query('INSERT INTO babble (posttime, author, babble) VALUES (CURRENT_TIMESTAMP, ?, ?);',
- [$userrow['username'], $safecontent]);
+ [user()->username, $safecontent]);
}
redirect('/babblebox');
}
diff --git a/src/actions/admin.php b/src/actions/admin.php
index 938884c..a7eb045 100644
--- a/src/actions/admin.php
+++ b/src/actions/admin.php
@@ -8,8 +8,7 @@ use Router;
function register_routes(Router $r): Router
{
- global $userrow;
- if (isset($userrow) && $userrow !== false && $userrow['authlevel'] === 1) {
+ if (user('authlevel') === 1) {
$r->get('/admin', 'Admin\donothing');
$r->form('/admin/main', 'Admin\primary');
diff --git a/src/actions/explore.php b/src/actions/explore.php
index bd01e75..37251c5 100644
--- a/src/actions/explore.php
+++ b/src/actions/explore.php
@@ -2,35 +2,55 @@
// explore.php :: Handles all map exploring, chances to fight, etc.
-function move()
-{
- global $userrow, $controlrow;
+function move() {
+ global $controlrow;
- if ($userrow["currentaction"] == "Fighting") { redirect('/fight'); }
+ // Early exit if fighting
+ if (user()->currentaction == 'Fighting') redirect('/fight');
- $latitude = $userrow["latitude"];
- $longitude = $userrow["longitude"];
+ // Validate direction
+ $form = validate($_POST, ['direction' => ['in:north,west,east,south']]);
+ if (!$form['valid']) display(ul_from_validate_errors($form['errors']), 'Move Error');
- $form = validate($_POST, [
- 'direction' => ['in:north,west,east,south']
- ]);
- if (!$form['valid']) display(ul_from_validate_errors($form['errors']), 'Move Error');
- $d = $form['data']['direction'];
+ // Current game state
+ $game_size = $controlrow['gamesize'];
+ $latitude = user('latitude');
+ $longitude = user('longitude');
+ $direction = $form['data']['direction'];
- if ($d === 'north') { $latitude++; if ($latitude > $controlrow["gamesize"]) { $latitude = $controlrow["gamesize"]; } }
- if ($d === 'south') { $latitude--; if ($latitude < ($controlrow["gamesize"]*-1)) { $latitude = ($controlrow["gamesize"]*-1); } }
- if ($d === 'east') { $longitude++; if ($longitude > $controlrow["gamesize"]) { $longitude = $controlrow["gamesize"]; } }
- if ($d === 'west') { $longitude--; if ($longitude < ($controlrow["gamesize"]*-1)) { $longitude = ($controlrow["gamesize"]*-1); } }
+ // Calculate new coordinates with boundary checks
+ switch ($direction) {
+ case 'north':
+ $latitude = min($latitude + 1, $game_size);
+ break;
+ case 'south':
+ $latitude = max($latitude - 1, -$game_size);
+ break;
+ case 'east':
+ $longitude = min($longitude + 1, $game_size);
+ break;
+ case 'west':
+ $longitude = max($longitude - 1, -$game_size);
+ break;
+ }
- $town = get_town_by_xy($longitude, $latitude);
+ // Check for town
+ $town = get_town_by_xy($longitude, $latitude);
if ($town !== false) {
Towns\travelto($town['id'], false);
return;
}
- $chancetofight = rand(1, 5);
- $action = $chancetofight === 1 ? "currentaction='Fighting', currentfight='1'," : "currentaction='Exploring',";
+ // Determine action (1 in 5 chance of fighting)
+ $action = (rand(1, 5) === 1)
+ ? "currentaction='Fighting', currentfight='1',"
+ : "currentaction='Exploring',";
+
+ // Update user's position
+ db()->query(
+ "UPDATE users SET $action latitude = ?, longitude = ?, dropcode = 0 WHERE id = ?;",
+ [$latitude, $longitude, user()->id]
+ );
- db()->query("UPDATE users SET $action latitude = ?, longitude = ?, dropcode = 0 WHERE id = ?;", [$latitude, $longitude, $userrow['id']]);
redirect('/');
}
diff --git a/src/actions/towns.php b/src/actions/towns.php
index 0eb1dbf..a1c3f02 100644
--- a/src/actions/towns.php
+++ b/src/actions/towns.php
@@ -25,20 +25,18 @@ function register_routes(Router $r): Router
*/
function inn()
{
- global $userrow;
-
- $townrow = get_town_by_xy($userrow["longitude"], $userrow["latitude"]);
+ $townrow = get_town_by_xy(user()->longitude, user()->latitude);
if ($townrow === false) { display("Cheat attempt detected.
Get a life, loser.", "Error"); }
- if ($userrow["gold"] < $townrow["innprice"]) {
+ if (user()->gold < $townrow["innprice"]) {
display("You do not have enough gold to stay at this Inn tonight.
You may return to town, or use the direction buttons on the left to start exploring.", "Inn");
}
if (isset($_POST["submit"])) {
- $newgold = $userrow["gold"] - $townrow["innprice"];
+ $newgold = user()->gold - $townrow["innprice"];
db()->query(
'UPDATE users SET gold=?, currenthp=?, currentmp=?, currenttp=? WHERE id=?',
- [$newgold, $userrow['maxhp'], $userrow['maxmp'], $userrow['maxtp'], $userrow['id']
+ [$newgold, user()->maxhp, user()->maxmp, user()->maxtp, user()->id
]);
$title = "Inn";
$page = "You wake up feeling refreshed and ready for action.
You may return to town, or use the direction buttons on the left to start exploring.";
@@ -63,9 +61,7 @@ function inn()
*/
function buy()
{
- global $userrow;
-
- $townrow = get_town_by_xy($userrow['longitude'], $userrow['latitude']);
+ $townrow = get_town_by_xy(user()->longitude, user()->latitude);
if ($townrow === false) display("Cheat attempt detected.
Get a life, loser.", "Error");
$items = db()->query("SELECT * FROM items WHERE id IN ({$townrow["itemslist"]});");
@@ -79,7 +75,7 @@ function buy()
2 => '',
3 => ''
};
- if ($userrow["weaponid"] == $itemsrow["id"] || $userrow["armorid"] == $itemsrow["id"] || $userrow["shieldid"] == $itemsrow["id"]) {
+ if (user()->weaponid == $itemsrow["id"] || user()->armorid == $itemsrow["id"] || user()->shieldid == $itemsrow["id"]) {
$page .= "".$itemsrow["name"]." | $attrib ".$itemsrow["attribute"]." | Already purchased | \n";
} else {
if ($itemsrow["special"] != "X") { $specialdot = "*"; } else { $specialdot = ""; }
@@ -98,21 +94,19 @@ function buy()
*/
function buy2($id)
{
- global $userrow;
-
- $townrow = get_town_by_xy($userrow['longitude'], $userrow['latitude']);
+ $townrow = get_town_by_xy(user()->longitude, user()->latitude);
if ($townrow === false) display("Cheat attempt detected.
Get a life, loser.", "Error");
$townitems = explode(",", $townrow["itemslist"]);
if (!in_array($id, $townitems)) display("Cheat attempt detected.
Get a life, loser.", "Error");
$item = get_item($id);
- if ($userrow["gold"] < $item["buycost"]) {
+ if (user()->gold < $item["buycost"]) {
display("You do not have enough gold to buy this item.
You may return to town, store, or use the direction buttons on the left to start exploring.", "Buy Items");
}
$type_to_row_mapping = [1 => 'weaponid', 2 => 'armorid', 3 => 'shieldid'];
- $current_equipped_id = $userrow[$type_to_row_mapping[$item['type']] ?? 0];
+ $current_equipped_id = user()[$type_to_row_mapping[$item['type']] ?? 0];
if ($current_equipped_id != 0) {
$item2 = get_item($current_equipped_id);
@@ -132,16 +126,14 @@ function buy3($id)
if (isset($_POST["cancel"])) redirect('/');
- global $userrow;
-
- $townrow = get_town_by_xy($userrow['longitude'], $userrow['latitude']);
+ $townrow = get_town_by_xy(user()->longitude, user()->latitude);
if ($townrow === false) display("Cheat attempt detected.
Get a life, loser.", "Error");
$townitems = explode(",", $townrow["itemslist"]);
if (!in_array($id, $townitems)) display("Cheat attempt detected.
Get a life, loser.", "Error");
$item = get_item($id);
- if ($userrow["gold"] < $item["buycost"]) {
+ if (user()->gold < $item["buycost"]) {
display("You do not have enough gold to buy this item.
You may return to town, store, or use the direction buttons on the left to start exploring.", "Buy Items");
}
@@ -157,7 +149,7 @@ function buy3($id)
}
// Retrieve current equipped item or create a default
- $current_equip_id = $userrow[$type_mapping[$item["type"]]['id']];
+ $current_equip_id = user()[$type_mapping[$item["type"]]['id']];
if ($current_equip_id != 0) {
$item2 = get_item($current_equip_id);
} else {
@@ -175,9 +167,9 @@ function buy3($id)
$toChange = $special[0];
$changeAmount = $index === 0 ? $special[1] : -$special[1];
- $userrow[$toChange] += $changeAmount;
+ user()[$toChange] += $changeAmount;
$specialFields[] = "$toChange = ?";
- $specialValues[] = $userrow[$toChange];
+ $specialValues[] = user()[$toChange];
// Adjust attack or defense power
if ($toChange == "strength" || $toChange == "dexterity") {
@@ -190,15 +182,15 @@ function buy3($id)
// Determine power and type-specific updates
$currentType = $type_mapping[$item["type"]];
$powerField = $currentType['power'];
- $newPower = $userrow[$powerField] + $item["attribute"] - $item2["attribute"];
+ $newPower = user()[$powerField] + $item["attribute"] - $item2["attribute"];
// Calculate new gold with trade-in value
- $newGold = $userrow["gold"] + ceil($item2["buycost"]/2) - $item["buycost"];
+ $newGold = user()->gold + ceil($item2["buycost"]/2) - $item["buycost"];
// Ensure current HP/MP/TP don't exceed max values
- $newhp = min($userrow["currenthp"], $userrow["maxhp"]);
- $newmp = min($userrow["currentmp"], $userrow["maxmp"]);
- $newtp = min($userrow["currenttp"], $userrow["maxtp"]);
+ $newhp = min(user()->currenthp, user()->maxhp);
+ $newmp = min(user()->currentmp, user()->maxmp);
+ $newtp = min(user()->currenttp, user()->maxtp);
$updateFields = array_merge(
$specialFields,
@@ -223,7 +215,7 @@ function buy3($id)
$newhp,
$newmp,
$newtp,
- $userrow["id"]
+ user()->id
]
);
@@ -238,9 +230,7 @@ function buy3($id)
*/
function maps()
{
- global $userrow;
-
- $mappedtowns = explode(",", $userrow["towns"]);
+ $mappedtowns = explode(",", user()->towns);
$page = "Buying maps will put the town in your Travel To box, and it won't cost you as many TP to get there.
\n";
$page .= "Click a town name to purchase its map.
\n";
@@ -272,11 +262,9 @@ function maps()
*/
function maps2($id)
{
- global $userrow;
-
$townrow = get_town_by_id($id);
- if ($userrow["gold"] < $townrow["mapprice"]) {
+ if (user()->gold < $townrow["mapprice"]) {
display("You do not have enough gold to buy this map.
You may return to town, store, or use the direction buttons on the left to start exploring.", "Buy Maps");
}
@@ -292,18 +280,16 @@ function maps3($id)
{
if (isset($_POST["cancel"])) redirect('/');
- global $userrow;
-
$townrow = get_town_by_id($id);
- if ($userrow["gold"] < $townrow["mapprice"]) {
+ if (user()->gold < $townrow["mapprice"]) {
display("You do not have enough gold to buy this map.
You may return to town, store, or use the direction buttons on the left to start exploring.", "Buy Maps");
}
- $mappedtowns = $userrow["towns"].",$id";
- $newgold = $userrow["gold"] - $townrow["mapprice"];
+ $mappedtowns = user()->towns.",$id";
+ $newgold = user()->gold - $townrow["mapprice"];
- db()->query('UPDATE users SET towns=?, gold=? WHERE id=?;', [$mappedtowns, $newgold, $userrow['id']]);
+ db()->query('UPDATE users SET towns=?, gold=? WHERE id=?;', [$mappedtowns, $newgold, user()->id]);
display("Thank you for purchasing this map.
You may return to town, store, or use the direction buttons on the left to start exploring.", "Buy Maps");
}
@@ -313,32 +299,30 @@ function maps3($id)
*/
function travelto($id, bool $usepoints = true)
{
- global $userrow;
-
- if ($userrow["currentaction"] == "Fighting") redirect('/fight');
+ if (user()->currentaction == "Fighting") redirect('/fight');
$townrow = get_town_by_id($id);
if ($usepoints) {
- if ($userrow["currenttp"] < $townrow["travelpoints"]) {
+ if (user()->currenttp < $townrow["travelpoints"]) {
display("You do not have enough TP to travel here. Please go back and try again when you get more TP.", "Travel To");
}
- $mapped = explode(",",$userrow["towns"]);
+ $mapped = explode(",",user()->towns);
if (!in_array($id, $mapped)) { display("Cheat attempt detected.
Get a life, loser.", "Error"); }
}
- if (($userrow["latitude"] == $townrow["latitude"]) && ($userrow["longitude"] == $townrow["longitude"])) {
+ if ((user()->latitude == $townrow["latitude"]) && (user()->longitude == $townrow["longitude"])) {
display("You are already in this town. Click here to return to the main town screen.", "Travel To");
}
- $newtp = ($usepoints) ? $userrow["currenttp"] - $townrow["travelpoints"] : $userrow["currenttp"];
+ $newtp = ($usepoints) ? user()->currenttp - $townrow["travelpoints"] : user()->currenttp;
$newlat = $townrow["latitude"];
$newlon = $townrow["longitude"];
- $newid = $userrow["id"];
+ $newid = user()->id;
// If they got here by exploring, add this town to their map.
- $mapped = explode(",",$userrow["towns"]);
+ $mapped = explode(",",user()->towns);
$town = false;
foreach($mapped as $b) if ($b == $id) $town = true;
$mapped = implode(",", $mapped);
diff --git a/src/actions/users.php b/src/actions/users.php
index 07c267b..c26c2bb 100644
--- a/src/actions/users.php
+++ b/src/actions/users.php
@@ -21,6 +21,8 @@ function register_routes(Router $r): Router
*/
function login()
{
+ global $auth;
+
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$form = validate($_POST, [
'username' => ['length:3-18', 'alpha-spaces'],
@@ -33,11 +35,8 @@ function login()
}
$form = $form['data'];
-
- $query = db()->query('SELECT id, username, password FROM users WHERE username = ? COLLATE NOCASE LIMIT 1;', [$form['username']]);
- $row = $query ? $query->fetchArray(SQLITE3_ASSOC) : false;
-
- if ($row === false || !password_verify($_POST['password'] ?? '', $row['password']))
+ $row = get_user($form['username']);
+ if ($row === false || !$auth->login($form['username'], $form['password']))
die("Invalid username or password. Please go back and try again.");
$expiretime = $form['remember'] ? time() + 31536000 : 0;
@@ -56,6 +55,8 @@ function login()
*/
function logout()
{
+ global $auth;
+ $auth->logout();
set_cookie("dkgame", "", -3600);
redirect('/login');
}
@@ -186,8 +187,6 @@ function changepassword()
function settings()
{
- global $userrow;
-
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$form = validate($_POST, [
'game_skin' => ['in:0,1']
@@ -195,7 +194,8 @@ function settings()
if (!$form['valid']) exit(ul_from_validate_errors($form['errors']));
$form = $form['data'];
- db()->query('UPDATE users SET game_skin=? WHERE id=?;', [$form['game_skin'], $userrow['id']]);
+ user()->game_skin = $form['game_skin'];
+ user()->save();
$alert = 'Settings updated
';
display($alert . render('settings'), "Account Settings");
diff --git a/src/auth.php b/src/auth.php
new file mode 100644
index 0000000..fcba9be
--- /dev/null
+++ b/src/auth.php
@@ -0,0 +1,104 @@
+ 2592000, // 30 days
+ 'path' => '/',
+ 'secure' => true,
+ 'httponly' => true,
+ 'samesite' => 'Strict'
+ ]);
+
+ session_start();
+
+ $this->validate();
+ }
+
+ private function validate(): void
+ {
+ // Check for IP address change
+ if (!isset($_SESSION['ip_address'])) {
+ $_SESSION['ip_address'] = $_SERVER['REMOTE_ADDR'];
+ } elseif ($_SESSION['ip_address'] !== $_SERVER['REMOTE_ADDR']) {
+ $this->destroy(); // Possible hijacking
+ exit;
+ }
+
+ // Check for User-Agent change
+ if (!isset($_SESSION['user_agent'])) {
+ $_SESSION['user_agent'] = $_SERVER['HTTP_USER_AGENT'];
+ } elseif ($_SESSION['user_agent'] !== $_SERVER['HTTP_USER_AGENT']) {
+ $this->destroy(); // Possible hijacking
+ exit;
+ }
+
+ // Regenerate session ID periodically for security
+ if (!isset($_SESSION['last_regeneration'])) {
+ $_SESSION['last_regeneration'] = time();
+ } elseif (time() - $_SESSION['last_regeneration'] > 300) { // Every 5 minutes
+ $this->regenerate();
+ }
+ }
+
+ public function login(string $username, string $password): bool
+ {
+ $user = get_user($username);
+ if ($user === false) return false;
+
+ if (password_verify($password, $user['password'])) {
+ $_SESSION['authenticated'] = true;
+ $_SESSION['user_id'] = $user['id'];
+ $_SESSION['login_time'] = time();
+
+ $this->regenerate();
+
+ return true;
+ }
+
+ return false;
+ }
+
+ public function good(): bool
+ {
+ return isset($_SESSION['authenticated']) && $_SESSION['authenticated'] === true;
+ }
+
+ public function logout(): void
+ {
+ $this->destroy();
+ }
+
+ private function regenerate(): void
+ {
+ session_regenerate_id(true);
+ $_SESSION['last_regeneration'] = time();
+ }
+
+ public function destroy(): void
+ {
+ $_SESSION = [];
+
+ if (ini_get("session.use_cookies")) {
+ $params = session_get_cookie_params();
+ setcookie(session_name(), '', time() - 42000, $params['path'], $params['domain'], $params['secure'], $params['httponly']);
+ }
+
+ session_destroy();
+ }
+}
diff --git a/src/bootstrap.php b/src/bootstrap.php
index 1536b08..c0ecd34 100644
--- a/src/bootstrap.php
+++ b/src/bootstrap.php
@@ -2,6 +2,7 @@
require_once 'lib.php';
require_once 'router.php';
+require_once 'auth.php';
require_once 'mail.php';
require_once 'actions/explore.php';
require_once 'actions/heal.php';
@@ -12,11 +13,14 @@ require_once 'actions/fight.php';
require_once 'actions/forum.php';
require_once 'actions/install.php';
require_once 'actions/admin.php';
+require_once 'models/model.php';
+require_once 'models/user.php';
env_load('../.env');
$uri = uri();
$GLOBALS['cache'] = [];
+$GLOBALS['state'] = [];
if (!file_exists('../.installed') && $uri[0] !== 'install') {
redirect('/install');
@@ -29,24 +33,26 @@ if (!file_exists('../.installed') && $uri[0] !== 'install') {
display("The game is currently closed for maintanence. Please check back later.", "Game Closed");
}
+ $auth = new Auth;
+
// Login (or verify) if not logged in.
- if (($userrow = checkcookies()) === false) {
+ if (user() === false) {
if (!in_array($uri[0], ['login', 'register', 'verify', 'lostpassword', 'help'])) {
redirect('/login');
}
} else {
// Block user if he/she has been banned.
- if ($userrow["authlevel"] === 2) {
+ if (user()->authlevel === 2) {
exit("Your account has been banned.");
}
// Force verify if the user isn't verified yet.
- if ($controlrow['verifyemail'] && $userrow['verify'] !== 'g2g' && !in_array($uri[0], ['verify', 'logout'])) {
+ if ($controlrow['verifyemail'] && user()->verify !== 'g2g' && !in_array($uri[0], ['verify', 'logout'])) {
redirect('/verify');
}
// Ensure the user can't use the admin panel.
- if ($userrow['authlevel'] !== 1 && $uri[0] === 'admin') {
+ if (user()->authlevel !== 1 && $uri[0] === 'admin') {
redirect('/');
}
}
diff --git a/src/lib.php b/src/lib.php
index 466d99a..ff787ac 100644
--- a/src/lib.php
+++ b/src/lib.php
@@ -99,10 +99,10 @@ function display_admin($content, $title)
*/
function display($content, $title, bool $topnav = true, bool $leftnav = true, bool $rightnav = true): void
{
- global $userrow, $controlrow;
+ global $controlrow;
if ($topnav == true) {
- if ($userrow !== false) { // user should be logged in
+ if (user() !== false) { // user should be logged in
$topnav = <<
@@ -118,75 +118,60 @@ function display($content, $title, bool $topnav = true, bool $leftnav = true, bo
$topnav = '';
}
- if (isset($userrow) && $userrow !== false) {
-
- // Get userrow again, in case something has been updated.
- $userquery = db()->query('SELECT * FROM users WHERE id = ? LIMIT 1;', [$userrow['id']]);
- unset($userrow);
- $userrow = $userquery->fetchArray(SQLITE3_ASSOC);
-
- // Current town name.
- if ($userrow['currentaction'] == 'In Town') {
- $townrow = get_town_by_xy($userrow['latitude'], $userrow['longitude']);
- $userrow['currenttown'] = "Welcome to {$townrow['name']}.
";
+ if (user() !== false) {
+ if (user()->currentaction == 'In Town') {
+ $town = get_town_by_xy(user()->latitude, user()->longitude);
+ $current_town = "Welcome to {$town['name']}.
";
} else {
- $userrow['currenttown'] = '';
+ $current_town = '';
}
- $userrow['forumslink'] = 'Forum
';
-
// Format various userrow stuffs...
- if ($userrow["latitude"] < 0) { $userrow["latitude"] = $userrow["latitude"] * -1 . "S"; } else { $userrow["latitude"] .= "N"; }
- if ($userrow["longitude"] < 0) { $userrow["longitude"] = $userrow["longitude"] * -1 . "W"; } else { $userrow["longitude"] .= "E"; }
- $userrow["experience"] = number_format($userrow["experience"]);
- $userrow["gold"] = number_format($userrow["gold"]);
- if ($userrow["authlevel"] == 1) { $userrow["adminlink"] = "Admin
"; } else { $userrow["adminlink"] = ""; }
-
- // HP/MP/TP bars.
- $userrow['statbars'] = create_stat_table($userrow);
+ if (user()->latitude < 0) { user()->latitude = user()->latitude * -1 . "S"; } else { user()->latitude .= "N"; }
+ if (user()->longitude < 0) { user()->longitude = user()->longitude * -1 . "W"; } else { user()->longitude .= "E"; }
+ user()->experience = number_format(user()->experience);
+ user()->gold = number_format(user()->gold);
// Now make numbers stand out if they're low.
- if ($userrow["currenthp"] <= ($userrow["maxhp"]/5)) { $userrow["currenthp"] = ""; }
- if ($userrow["currentmp"] <= ($userrow["maxmp"]/5)) { $userrow["currentmp"] = ""; }
+ if (user()->currenthp <= (user()->maxhp/5)) { user()->currenthp = ""; }
+ if (user()->currentmp <= (user()->maxmp/5)) { user()->currentmp = ""; }
- $user_spells = explode(',', $userrow['spells']);
+ $user_spells = explode(',', user()->spells);
$spellquery = get_spells_from_list($user_spells);
- $userrow['magiclist'] = '';
+ user()->magiclist = '';
while ($spell = $spellquery->fetchArray(SQLITE3_ASSOC)) {
$spell = false;
foreach($user_spells as $id) {
if ($id === $spell['id'] && $spell['type'] == 1) $spell = true;
}
if ($spell == true) {
- $userrow['magiclist'] .= "".$spell['name']."
";
+ user()->magiclist .= "".$spell['name']."
";
}
}
- if ($userrow["magiclist"] == "") { $userrow["magiclist"] = "None"; }
+ if (user()->magiclist == "") { user()->magiclist = "None"; }
// Travel To list.
- $townslist = explode(",",$userrow["towns"]);
+ $townslist = explode(",",user()->towns);
$townquery2 = db()->query('SELECT * FROM towns ORDER BY id;');
- $userrow["townslist"] = "";
+ $town_list_html = '';
while ($townrow2 = $townquery2->fetchArray(SQLITE3_ASSOC)) {
$town = false;
- foreach($townslist as $a => $b) {
- if ($b == $townrow2["id"]) { $town = true; }
+ foreach($townslist as $id) {
+ if ($id == $townrow2["id"]) { $town = true; }
}
if ($town == true) {
- $userrow["townslist"] .= "".$townrow2["name"]."
\n";
+ $town_list_html .= "".$townrow2["name"]."
\n";
}
}
- } else {
- $userrow = [];
}
echo render('primary', [
"dkgamename" => $controlrow["gamename"],
"title" => $title,
"content" => $content,
- "game_skin" => $userrow['game_skin'] ??= '0',
- 'rightnav' => $rightnav ? render('rightnav', ['user' => $userrow]) : '',
- "leftnav" => $leftnav ? render('leftnav', ['user' => $userrow]) : '',
+ "game_skin" => user()->game_skin ??= '0',
+ 'rightnav' => $rightnav ? render('rightnav', ['statbars' => create_stat_table(user())]) : '',
+ "leftnav" => $leftnav ? render('leftnav', ['town_list' => $town_list_html, 'current_town' => $current_town]) : '',
"topnav" => $topnav,
"totaltime" => round(microtime(true) - START, 4),
"numqueries" => db()->count,
@@ -271,11 +256,14 @@ function get_town_by_id(int $id): array|false
}
/**
- * Get a user's data by their ID.
+ * Get a user's data by their ID, username or email.
*/
-function get_user_by_id(int $id): array|false
+function get_user(int|string $id, string $data = '*'): array|false
{
- $query = db()->query('SELECT * FROM users WHERE id = ? LIMIT 1;', [$id]);
+ $query = db()->query(
+ "SELECT $data FROM users WHERE id=? OR username=? COLLATE NOCASE OR email=? COLLATE NOCASE LIMIT 1;",
+ [$id, $id, $id]
+ );
if ($query === false) return false;
return $query->fetchArray(SQLITE3_ASSOC);
}
@@ -610,11 +598,20 @@ function create_stat_table($userrow)
{
$stat_table = '' .
'
' .
- '
' . generate_stat_bar($userrow['currenthp'], $userrow['maxhp']) . '
HP
' .
- '
' . generate_stat_bar($userrow['currentmp'], $userrow['maxmp']) . '
MP
' .
- '
' . generate_stat_bar($userrow['currenttp'], $userrow['maxtp']) . '
TP
' .
+ '
' . generate_stat_bar(user()->currenthp, user()->maxhp) . '
HP
' .
+ '
' . generate_stat_bar(user()->currentmp, user()->maxmp) . '
MP
' .
+ '
' . generate_stat_bar(user()->currenttp, user()->maxtp) . '
TP
' .
'
' .
'
';
return $stat_table;
}
+
+/**
+ * Returns the user in the GLOBALS state, if there is one. If not, populates it if there is a SESSION user_id.
+ */
+function user(): User|false
+{
+ $GLOBALS['state']['user'] ??= ($_SESSION['user_id'] ? User::find($_SESSION['user_id']) : false);
+ return $GLOBALS['state']['user'];
+}
diff --git a/src/models/model.php b/src/models/model.php
new file mode 100644
index 0000000..76178d2
--- /dev/null
+++ b/src/models/model.php
@@ -0,0 +1,42 @@
+original_data = $data;
+ $this->changes = [];
+ }
+
+ public function __get(string $key): mixed
+ {
+ return array_key_exists($key, $this->changes) ? $this->changes[$key] : $this->original_data[$key] ?? false;
+ }
+
+ public function __set(string $key, mixed $value): void
+ {
+ if (array_key_exists($key, $this->original_data)) $this->changes[$key] = $value;
+ }
+
+ public function save(): bool
+ {
+ if (empty($this->changes)) return true;
+
+ $placeholders = [];
+ $values = [];
+ foreach ($this->changes as $key => $value) {
+ $placeholders[] = "$key=?";
+ $values[] = $value;
+ }
+
+ $values[] = $this->id;
+ $query = 'UPDATE ' . $this->table_name . ' SET ' . implode(', ', $placeholders) . ' WHERE id = ?;';
+
+ $result = db()->query($query, $values);
+ return $result === false ? false : true;
+ }
+}
diff --git a/src/models/user.php b/src/models/user.php
new file mode 100644
index 0000000..76da334
--- /dev/null
+++ b/src/models/user.php
@@ -0,0 +1,21 @@
+query(
+ "SELECT * FROM users WHERE id=? OR username=? COLLATE NOCASE OR email=? COLLATE NOCASE LIMIT 1;",
+ [$id, $id, $id]
+ );
+ if ($query === false) return false;
+ $data = $query->fetchArray(SQLITE3_ASSOC);
+ if ($data === false) return false;
+ return new User($data);
+ }
+}
diff --git a/templates/leftnav.php b/templates/leftnav.php
index cba34f6..f405321 100644
--- a/templates/leftnav.php
+++ b/templates/leftnav.php
@@ -1,8 +1,8 @@
- Currently: = $user['currentaction'] ?>
- Latitude: = $user['latitude'] ?>
- Longitude: = $user['longitude'] ?>
+ Currently: = user()->currentaction ?>
+ Latitude: = user()->latitude ?>
+ Longitude: = user()->longitude ?>
View Map