From 169e6179892143e71a91446e80edd6efa3e76bac Mon Sep 17 00:00:00 2001 From: Sky Johnson Date: Tue, 17 Dec 2024 22:10:49 -0600 Subject: [PATCH] big model changes --- public/index.php | 37 +++++++------- src/actions/admin.php | 3 +- src/actions/explore.php | 58 ++++++++++++++-------- src/actions/towns.php | 82 +++++++++++++------------------ src/actions/users.php | 16 +++---- src/auth.php | 104 ++++++++++++++++++++++++++++++++++++++++ src/bootstrap.php | 14 ++++-- src/lib.php | 89 +++++++++++++++++----------------- src/models/model.php | 42 ++++++++++++++++ src/models/user.php | 21 ++++++++ templates/leftnav.php | 21 +++++--- templates/rightnav.php | 16 +++---- 12 files changed, 340 insertions(+), 163 deletions(-) create mode 100644 src/auth.php create mode 100644 src/models/model.php create mode 100644 src/models/user.php 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 => 'armor', 3 => 'shield' }; - 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 = <<Log Out Help @@ -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"] = "*".$userrow["currenthp"]."*"; } - if ($userrow["currentmp"] <= ($userrow["maxmp"]/5)) { $userrow["currentmp"] = "*".$userrow["currentmp"]."*"; } + if (user()->currenthp <= (user()->maxhp/5)) { user()->currenthp = "*".user()->currenthp."*"; } + if (user()->currentmp <= (user()->maxmp/5)) { user()->currentmp = "*".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 @@
Location
- Currently:
- Latitude:
- Longitude:
+ Currently: currentaction ?>
+ Latitude: latitude ?>
+ Longitude: longitude ?>
View Map
@@ -16,18 +16,25 @@
Towns
- + currentaction == 'In Town') { + $town = get_town_by_xy((int) user()->latitude, (int) user()->longitude); + echo "Welcome to {$town['name']}.

"; + } + ?> Travel To:
- +
Functions
Home
- - + Forum
Settings
Change Password
Log Out
+ authlevel === 1): ?> + Admin
+ Help
diff --git a/templates/rightnav.php b/templates/rightnav.php index 159d86f..ffde49f 100644 --- a/templates/rightnav.php +++ b/templates/rightnav.php @@ -1,13 +1,13 @@
Character
-
- Level:
- Exp:
- Gold:
- HP:
- MP:
- TP:

-
+ username ?>
+ Level: level ?>
+ Exp: experience ?>
+ Gold: gold ?>
+ HP: currenthp ?>
+ MP: currentmp ?>
+ TP: currenttp ?>

+
Extended Stats