Big cleanup of bootstrapping, app, new routing style

This commit is contained in:
Sky Johnson 2024-07-17 22:11:45 -05:00
parent a20c443178
commit 2de9b823ee
10 changed files with 139 additions and 99 deletions

View File

@ -1,24 +1,21 @@
<?php // index.php :: Primary program script, evil alien overlord, you decide.
<?php
// index.php :: Primary program script, evil alien overlord, you decide.
// define our server path and bootstrap the request
const SERVER = '../server';
require_once SERVER.'/bootstrap.php';
// spin up our app container and the initial route
$app = new App(DB);
$app = new App(new Database(DB), new Request(), new Auth());
$route = App::$req->uri(0);
// redirect depending on installation status
installRedirect($route);
// route to the relevant module
if ($route == '/') return HomeModule::home();
if ($route == 'install') return InstallModule::handle();
if ($route == 'gate') return GateModule::handle();
// 404
http_response_code(404);
echo '404: ' . $route;
// cleanup
$app->cleanup();
$app->route('/', 'HomeModule')
->route('/install', 'InstallModule')
->route('/gate', 'GateModule')
->handle($route)
->cleanup();

View File

@ -6,19 +6,18 @@
class App
{
private array $routes = [];
public static Database $db;
private static string $dbPath;
public static Request $req;
public static Auth $auth;
public static array $s = []; // game settings
public static array $flashes = []; // flash messages
public function __construct(string $dbPath)
public function __construct(Database $db, Request $req, Auth $auth)
{
self::$req = new Request(); // the current request
self::$db = new Database($dbPath); // the database
self::$dbPath = $dbPath; // the database path
self::$auth = new Auth();
self::$req = $req; // the current request
self::$db = $db; // the database
self::$auth = $auth; // the auth system
// load game settings
$s = self::$db->q('SELECT * FROM settings WHERE id = 1;');
@ -33,19 +32,24 @@ class App
self::$flashes = $_SESSION['flash'] ?? [];
}
public static function performDatabaseReset(): void
{
if (file_exists(self::$dbPath)) {
unlink(self::$dbPath);
self::$db = new Database(self::$dbPath);
}
}
public static function auth(): bool
{
return self::$auth->good();
}
public function route(string $uri, string $module): App
{
$this->routes[$uri] = $module;
return $this;
}
public function handle(string $uri): App
{
if (!isset($this->routes[$uri])) return self::fourOhFour($uri);
$this->routes[$uri]::handle();
return $this;
}
public static function flash(string $key, mixed $value = null): mixed
{
// get a flash message
@ -54,12 +58,20 @@ class App
// set a flash message
$_SESSION['flash'][$key] = $value;
self::$flashes[$key] = $value;
return null;
}
public function cleanup()
{
// clean up flash messages
$_SESSION['flash'] = [];
unset($_SESSION['flash']);
self::$flashes = [];
}
public static function fourOhFour(string $uri): void
{
http_response_code(404);
echo "404: $uri";
}
}

View File

@ -13,11 +13,6 @@ class Auth
// id of the player
public static int $id = 0;
public function __construct()
{
}
public function login(string $identifier, string $password, bool $remember = false): bool
{
// delete the old session
@ -82,4 +77,25 @@ class Auth
return false;
}
public static function boot(): void
{
// adjust session settings
ini_set('session.gc_maxlifetime', 604800); // 1 week in seconds
ini_set('session.cookie_lifetime', 604800); // 1 week in seconds
// ensure secure session handling
ini_set('session.use_strict_mode', 1);
ini_set('session.cookie_httponly', 1);
ini_set('session.cookie_secure', 1); // only if using HTTPS
// start the session
session_start();
// regenerate session ID to prevent session fixation
if (!isset($_SESSION['initiated'])) {
session_regenerate_id(true);
$_SESSION['initiated'] = true;
}
}
}

View File

@ -13,6 +13,7 @@ class Database
private int $queries = 0;
private array $log = [];
private float $time = 0;
private string $path = '';
public function __construct(string $path, array $opts = [])
{
@ -25,6 +26,7 @@ class Database
$this->c = new PDO("sqlite:$path", null, null, $opts);
$this->c->exec('PRAGMA foreign_keys = ON;'); // Enable foreign keys
$this->c->exec('PRAGMA journal_mode = WAL;'); // Enable WAL
$this->path = $path;
} catch (PDOException $e) {
throw $e;
}
@ -82,6 +84,11 @@ class Database
return $this->time;
}
public function path(): string
{
return $this->path;
}
public function lastInsertID(): int
{
return $this->c->lastInsertId();

View File

@ -0,0 +1,34 @@
<?php
class Autoloader
{
// autoloader map
public const MAP = [
// 'Class' => 'path/to/class.php',
// server-level classes
'App' => SERVER.'/app/App.php',
'Database' => SERVER.'/app/Database.php',
'Request' => SERVER.'/app/Request.php',
'Auth' => SERVER.'/app/Auth.php',
// modules
'HomeModule' => SERVER.'/modules/HomeModule.php',
'InstallModule' => SERVER.'/modules/InstallModule.php',
'GateModule' => SERVER.'/modules/GateModule.php',
// models
'Classes' => SERVER.'/models/Classes.php',
'Player' => SERVER.'/models/Player.php',
'Spell' => SERVER.'/models/Spell.php',
'Session' => SERVER.'/models/Session.php',
];
// autoloader
public static function boot(): void
{
spl_autoload_register(function($class) {
if (isset(self::MAP[$class])) require_once self::MAP[$class];
});
}
}

31
server/boot/Boot.php Normal file
View File

@ -0,0 +1,31 @@
<?php
/*
This script loads all the ugly stuff we need to get the app working.
The script that uses this boot script will need to supply a SERVER
constant to define where the server root folder is.
*/
define('START', microtime(true)); // start the timer for this execution
// @todo move these to a settings config somewhere
const VERSION = '1.1.11';
const BUILD = '';
const DB = SERVER.'/database/dragon.db';
// @todo use a flag for this
ini_set('display_errors', 'on');
error_reporting(E_ALL | E_STRICT);
require_once SERVER.'/boot/Autoloader.php'; // include our autoloader
require_once SERVER.'/boot/Library.php'; // include our miscellaneous functions
// define whether we are installed or not
define('INSTALLED', file_exists(SERVER.'/.installed'));
// register our autoloader
Autoloader::boot();
// boot the settings for authentication
Auth::boot();

View File

@ -112,6 +112,7 @@ function makesafe($d) {
}
/*
function admindisplay($content, $title) { // Finalize page and output to browser.
global $numqueries, $userrow, $controlrow, $starttime, $version, $build;
@ -272,5 +273,4 @@ function display($content, $title, $topnav=true, $leftnav=true, $rightnav=true,
die();
}
?>
*/

View File

@ -1,62 +0,0 @@
<?php
// @todo use a flag for this
ini_set('display_errors', 'on');
error_reporting(E_ALL | E_STRICT);
define('START', microtime(true)); // start the timer for this execution
// adjust session settings
ini_set('session.gc_maxlifetime', 604800); // 1 week in seconds
ini_set('session.cookie_lifetime', 604800); // 1 week in seconds
// ensure secure session handling
ini_set('session.use_strict_mode', 1);
ini_set('session.cookie_httponly', 1);
ini_set('session.cookie_secure', 1); // only if using HTTPS
// start the session
session_start();
// regenerate session ID to prevent session fixation
if (!isset($_SESSION['initiated'])) {
session_regenerate_id(true);
$_SESSION['initiated'] = true;
}
// @todo move these to a settings config somewhere
const VERSION = '1.1.11';
const BUILD = '';
const DB = SERVER.'/database/dragon.db';
require_once SERVER.'/library.php'; // include our miscellaneous functions
// define whether we are installed or not
define('INSTALLED', file_exists(SERVER.'/.installed'));
// autoloader map
const MAP = [
// 'Class' => 'path/to/class.php',
// server-level classes
'App' => SERVER.'/app/App.php',
'Database' => SERVER.'/app/Database.php',
'Request' => SERVER.'/app/Request.php',
'Auth' => SERVER.'/app/Auth.php',
// modules
'HomeModule' => SERVER.'/modules/HomeModule.php',
'InstallModule' => SERVER.'/modules/InstallModule.php',
'GateModule' => SERVER.'/modules/GateModule.php',
// models
'Classes' => SERVER.'/models/Classes.php',
'Player' => SERVER.'/models/Player.php',
'Spell' => SERVER.'/models/Spell.php',
'Session' => SERVER.'/models/Session.php',
];
// autoloader
spl_autoload_register(function($class) {
if (isset(MAP[$class])) require_once MAP[$class];
});

View File

@ -2,9 +2,14 @@
class HomeModule
{
public static function handle()
{
return self::home();
}
public static function home()
{
foreach ($_SESSION['flash'] as $key => $value) {
foreach (($_SESSION['flash'] ?? []) as $key => $value) {
echo '<div class="alert ' . $key . '">- ' . $value . '</div>';
}

View File

@ -29,8 +29,8 @@ class InstallModule
$complete = $_POST['mode'] == 'complete'; // complete or partial setup
$defaults = SERVER.'/database/packs/Default/';
// if the database already exists, have the app remake it
App::performDatabaseReset();
// if the database already exists, delete and remake it
if (file_exists(DB) && unlink(DB)) App::$db = new Database(DB);
// @Settings
App::$db->q("CREATE TABLE IF NOT EXISTS 'settings' (