summaryrefslogtreecommitdiff
path: root/src/web/core
diff options
context:
space:
mode:
authorFreya Murphy <freya@freyacat.org>2024-09-18 14:14:53 -0400
committerFreya Murphy <freya@freyacat.org>2024-09-18 14:48:54 -0400
commit1f9024763d9224c4cd9a181bac27e6b9f12ad672 (patch)
tree00f827470dad9aa2692483acbdef9502c1a464d3 /src/web/core
parentfix rss (diff)
downloadwebsite-1f9024763d9224c4cd9a181bac27e6b9f12ad672.tar.gz
website-1f9024763d9224c4cd9a181bac27e6b9f12ad672.tar.bz2
website-1f9024763d9224c4cd9a181bac27e6b9f12ad672.zip
refactor
Diffstat (limited to 'src/web/core')
-rw-r--r--src/web/core/_controller.php54
-rw-r--r--src/web/core/_model.php51
-rw-r--r--src/web/core/component.php119
-rw-r--r--src/web/core/controller.php43
-rw-r--r--src/web/core/core.php85
-rw-r--r--src/web/core/loader.php112
-rw-r--r--src/web/core/model.php29
-rw-r--r--src/web/core/router.php227
8 files changed, 380 insertions, 340 deletions
diff --git a/src/web/core/_controller.php b/src/web/core/_controller.php
deleted file mode 100644
index 1da5a96..0000000
--- a/src/web/core/_controller.php
+++ /dev/null
@@ -1,54 +0,0 @@
-<?php /* Copyright (c) 2024 Freya Murphy */
-abstract class Controller {
-
- // the main model
- public Main_model $main;
-
- // the loader
- public Loader $load;
-
- /**
- * Creates a constructor
- * @param Loader $load - the website loaded object
- */
- function __construct($load) {
- $this->load = $load;
- $this->main = $this->load->model('main');
-
- $this->load->lang();
- $info = $this->main->info;
- $app = $info['app'];
- if ($app) {
- $this->load->app_lang($app);
- }
- }
-
- public function index(): void {}
-
- public function redirect(string $link): void {
- header('Location: '. $link, true, 301);
- die();
- }
-
- /**
- * @param array<int,mixed> $data
- */
- protected function view(string $__name, array $data = array()): void {
- $__root = $GLOBALS['webroot'];
- $__path = $__root . '/_views/' . $__name . '.php';
- if (is_file($__path)) {
- extract($data);
- require($__path);
- return;
- }
- }
-
- protected function error(int $code): void {
- $_GET['code'] = $code;
- $this->main->info['app'] = 'error';
- $error_controller = $this->load->controller('error');
- $error_controller->index();
- die();
- }
-
-}
diff --git a/src/web/core/_model.php b/src/web/core/_model.php
deleted file mode 100644
index 57127de..0000000
--- a/src/web/core/_model.php
+++ /dev/null
@@ -1,51 +0,0 @@
-<?php /* Copyright (c) 2024 Freya Murphy */
-abstract class Model {
- // the main model
- // shared by all controllers and models
- public Main_model $main;
- public Loader $load;
-
- // the database
- public DatabaseHelper $db;
-
- private mixed $config;
-
- /**
- * Creates a model
- * @param Loader $load - the main loader object
- * @param ?Main_model $main
- */
- function __construct(Loader $load, bool $main = FALSE) {
- $this->load = $load;
- if ($main) {
- $this->main = $this;
- } else {
- $this->main = $this->load->model('main');
- }
- $this->db = $this->load->db();
- }
-
- /**
- * @returns the base model data
- */
- public function get_data(): ?array {
- $data = array();
-
- $info = $this->main->info;
- $app = $info['app'];
-
- $data['title'] = lang('first_name');
- $data['desc'] = lang('default_short_desc');
- $data['css'] = array();
-
- $style = $GLOBALS['style'];
- if (isset($style[$app])) {
- $css = $style[$app];
- if (!is_array($css))
- $css = array($css);
- $data['css'] = $css;
- }
-
- return $data;
- }
-}
diff --git a/src/web/core/component.php b/src/web/core/component.php
new file mode 100644
index 0000000..376e24d
--- /dev/null
+++ b/src/web/core/component.php
@@ -0,0 +1,119 @@
+<?php /* Copyright (c) 2024 Freya Murphy */
+
+/**
+ * Gives access to imporant
+ * needed utility functions for
+ * accessing everything else!
+ */
+abstract class Component extends Core {
+
+ // keep track of what has been loaded
+ private static array $loaded = array();
+
+// ============================= LOADABLE OBJECTS ==
+
+ /**
+ * Loads a $type of object from a $dir with a given $name
+ * @param string $name - the name of the object to load
+ * @param string $dir - the directory theese objects are stored in
+ * @param string $type - the type of the object
+ */
+ private function load_type($name, $dir, $type): object|NULL
+ {
+
+ $path = $dir . '/' . $name . '.php';
+
+ // dont reload an ohject
+ if (array_key_exists($path, Component::$loaded))
+ return Component::$loaded[$path];
+
+ // only load a object if it exists
+ if (!file_exists($path))
+ return NULL;
+
+
+ $parts = explode('/', $name);
+ $part = end($parts);
+ $class = ucfirst($part) . '_' . $type;
+ require($path);
+
+ $ref = NULL;
+ try {
+ $ref = new ReflectionClass($class);
+ } catch (Exception $_e) {}
+
+ if ($ref === NULL)
+ return NULL;
+
+ $obj = $ref->newInstance();
+ Component::$loaded[$path] = $obj;
+
+ return $obj;
+ }
+
+ /**
+ * Loads a model
+ * @param string $name - the name of the model to load
+ */
+ protected function load_model($name): Model|NULL
+ {
+ $dir = WEB_ROOT . '/_model';
+ return $this->load_type($name, $dir, 'model');
+ }
+
+ /**
+ * Loads a controller
+ * @param string $name - the name of the controller to load
+ */
+ public function load_controller($name): Controller|NULL
+ {
+ $dir = WEB_ROOT . '/_controller';
+ return $this->load_type($name, $dir, 'controller');
+ }
+
+// ========================================= LANG ==
+
+ /**
+ * Loads a php lang file into the lang array
+ */
+ private static function load_lang_file(string $file): void
+ {
+ $lang = $GLOBALS['__lang'];
+ require($file);
+ $GLOBALS['__lang'] = $lang;
+ }
+
+ /**
+ * Loads each php file lang strings in a directory
+ */
+ private static function load_lang_dir(string $dir): void
+ {
+ if ($handle = opendir($dir)) {
+ while (false !== ($entry = readdir($handle))) {
+ if ($entry === '.' || $entry === '..')
+ continue;
+ Component::load_lang_file($entry);
+ }
+ }
+ }
+
+ /**
+ * Loads the given common lang
+ */
+ protected static function load_lang(string ...$langs): void
+ {
+ $root = WEB_ROOT . '/lang';
+
+ foreach ($langs as $lang) {
+ $file = "{$root}/{$lang}.php";
+ $dir = "{$root}/{$lang}";
+
+ if (file_exists($file))
+ Component::load_lang_file($file);
+ else if (is_dir($dir))
+ Component::load_lang_dir($dir);
+
+ }
+ }
+
+}
diff --git a/src/web/core/controller.php b/src/web/core/controller.php
new file mode 100644
index 0000000..340bbb1
--- /dev/null
+++ b/src/web/core/controller.php
@@ -0,0 +1,43 @@
+<?php /* Copyright (c) 2024 Freya Murphy */
+
+abstract class Controller extends Component {
+
+ /**
+ * Default index for a app, empty
+ */
+ public function index(): void {}
+
+ /**
+ * Redirectes to a link
+ */
+ public function redirect(string $link): void
+ {
+ header('Location: '. $link, true, 301);
+ die();
+ }
+
+ /**
+ * Lodas a view
+ */
+ protected function view(string $__name, array $data = array()): void
+ {
+ $__path = WEB_ROOT . '/_views/' . $__name . '.php';
+ if (is_file($__path)) {
+ extract($data);
+ require($__path);
+ return;
+ }
+ }
+
+ /**
+ * Loads a erorr page with a given
+ * error code
+ */
+ protected function error(int $code): void
+ {
+ $error_controller = $this->load_controller('error');
+ $error_controller->code($code);
+ die();
+ }
+
+}
diff --git a/src/web/core/core.php b/src/web/core/core.php
new file mode 100644
index 0000000..d71870e
--- /dev/null
+++ b/src/web/core/core.php
@@ -0,0 +1,85 @@
+<?php /* Copyright (c) 2024 Freya Murphy */
+
+/**
+ * Core functions needed everywhere
+ */
+abstract class Core {
+
+ private static ?DatabaseHelper $db = NULL;
+
+ /**
+ * Loads the database
+ */
+ public static function db(): DatabaseHelper
+ {
+ if (!Component::$db)
+ Component::$db = new DatabaseHelper();
+ return Component::$db;
+ }
+
+ /**
+ * Gets the stamp for a asset path
+ * @param string $path
+ */
+ public static function asset_stamp(string $path): int
+ {
+ $path = PUBLIC_ROOT . '/' . $path;
+ return @filemtime($path);
+ }
+
+ /**
+ * Gets a full path url from a relative path
+ * @param string $path
+ * @param bool $timestamp
+ */
+ public static function get_url(string $path, bool $timestamp = FALSE): string
+ {
+ $host = $_SERVER['HTTP_HOST'];
+
+ if (ENVIRONMENT == 'production')
+ $host = lang('domain');
+
+ $base = lang('base_path');
+ $url = "http://{$host}{$base}{$path}";
+ if ($timestamp) {
+ $time = @filemtime(PHP_ROOT . '/' . $path);
+ $url .= "?timestamp={$time}";
+ }
+ return $url;
+ }
+
+ /**
+ * Loads a css html link
+ * @param string $path - the path to the css file
+ */
+ public static function link_css(string $path): string
+ {
+ $stamp = Core::asset_stamp($path);
+ $href = Core::get_url("public/{$path}?stamp={$stamp}");
+ return '<link rel="stylesheet" href="'. $href .'">';
+ }
+
+ /**
+ * Loads a css html link
+ * @param string $path - the path to the css file
+ */
+ public static function embed_css(string $path): string
+ {
+ $file = PUBLIC_ROOT . '/' . $path;
+ if (file_exists($file)) {
+ $text = file_get_contents($file);
+ return "<style>{$text}</style>";
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * Formats a ISO date
+ * @param $iso_date the ISO date
+ */
+ public static function format_date(string $iso_date): string
+ {
+ return date("Y-m-d D H:m", strtotime($iso_date));
+ }
+}
diff --git a/src/web/core/loader.php b/src/web/core/loader.php
deleted file mode 100644
index 101abef..0000000
--- a/src/web/core/loader.php
+++ /dev/null
@@ -1,112 +0,0 @@
-<?php /* Copyright (c) 2024 Freya Murphy */
-class Loader {
-
- // keep track of what has been loaded
- private array $loaded;
-
- // the database
- private ?DatabaseHelper $db;
-
- function __construct() {
- $this->loaded = array();
- $this->db = NULL;
- }
-
- /**
- * Loads a $type of object from a $dir with a given $name
- * @param string $name - the name of the object to load
- * @param string $dir - the directory theese objects are stored in
- * @param string $type - the type of the object
- */
- private function load_type($name, $dir, $type): object|NULL {
- $path = $dir . '/' . $name . '.php';
- if (array_key_exists($path, $this->loaded)) {
- return $this->loaded[$path];
- }
-
- if (!file_exists($path)) {
- return NULL;
- }
-
- $parts = explode('/', $name);
- $part = end($parts);
- $class = ucfirst($part) . '_' . $type;
- require($path);
-
- $ref = NULL;
- try {
- $ref = new ReflectionClass($class);
- } catch (Exception $_e) {}
-
- if ($ref === NULL) {
- return NULL;
- }
-
- $obj = $ref->newInstance($this);
- $this->loaded[$path] = $obj;
-
- return $obj;
- }
-
- /**
- * Loads a model
- * @param string $name - the name of the model to load
- */
- public function model($name): object|NULL {
- $root = $GLOBALS['webroot'];
- $dir = $root . '/_model';
- return $this->load_type($name, $dir, 'model');
- }
-
- /**
- * Loads a controller
- * @param string $name - the name of the controller to load
- */
- public function controller($name): Controller|NULL {
- $root = $GLOBALS['webroot'];
- $dir = $root . '/_controller';
- return $this->load_type($name, $dir, 'controller');
- }
-
- /**
- * Loads the given common lang
- */
- public function lang(): void {
- $dir = $GLOBALS['webroot'] . '/lang/';
- $lang = $GLOBALS['lang'];
- if ($handle = opendir($dir)) {
- while (false !== ($entry = readdir($handle))) {
- if ($entry === '.' || $entry === '..' || $entry === 'apps') {
- continue;
- }
- $path = $dir . $entry;
- require($path);
- }
- }
- $GLOBALS['lang'] = $lang;
- }
-
- /**
- * Loads a given app specific lang
- * @param string $name - the name of the app
- */
- public function app_lang($name): void {
- $dir = $GLOBALS['webroot'] . '/lang/apps/';
- $file = $dir . $name . '.php';
- if (file_exists($file)) {
- $lang = $GLOBALS['lang'];
- require($dir . $name . '.php');
- $GLOBALS['lang'] = $lang;
- }
- }
-
- public function db(): DatabaseHelper {
- if ($this->db) {
- return $this->db;
- } else {
- $this->db = new DatabaseHelper();
- return $this->db;
- }
- }
-
-}
diff --git a/src/web/core/model.php b/src/web/core/model.php
new file mode 100644
index 0000000..8e105da
--- /dev/null
+++ b/src/web/core/model.php
@@ -0,0 +1,29 @@
+<?php /* Copyright (c) 2024 Freya Murphy */
+
+abstract class Model extends Component {
+
+ public static function get_base_data(?string $app = NULL): array
+ {
+ $data = array();
+ $data['title'] = lang('first_name');
+ $data['desc'] = lang('default_short_desc');
+ $data['css'] = array();
+
+ $style = $GLOBALS['style'];
+
+ if (!$app)
+ $app = CONTEXT['app'];
+
+ if (isset($style[$app])) {
+ $css = $style[$app];
+ if (!is_array($css))
+ $css = array($css);
+ else
+ $css = $style['app'];
+ $data['css'] = $css;
+ }
+
+ return $data;
+ }
+
+}
diff --git a/src/web/core/router.php b/src/web/core/router.php
index 1ad6cb5..2cda384 100644
--- a/src/web/core/router.php
+++ b/src/web/core/router.php
@@ -1,68 +1,91 @@
<?php /* Copyright (c) 2024 Freya Murphy */
-class Router {
- // the loader
- private Loader $load;
-
- // the main model
- private Main_model $main;
-
- // the database
- private DatabaseHelper $db;
+class Router extends Component {
private bool $db_ready;
+ private bool $recursed;
+ private array $req;
/**
* Creates a router
* @param Loader $load - the main laoder object
*/
- function __construct($load) {
- $this->load = $load;
- $this->db = $load->db();
- $this->main = $this->load->model('main');
+ function __construct()
+ {
$this->db_ready = file_exists('/status/ready');
+ $this->recursed = FALSE;
+ $this->req = $this->get_req();
}
/**
- * @param string $path - the current request path
+ * @param string $path - the current request path
* Gets the current route
* @return array<string,mixed>
*/
- private function get_req_route($path): array {
+ private function get_req_route($path): array
+ {
// trim the path
$path = trim($path);
// remove first '/'
$path = substr($path, 1);
+
+ // get modified route
+ foreach ($GLOBALS['routes'] as $key => $value) {
+ $key = "/^{$key}$/";
+ if (!preg_match($key, $path, $matches))
+ continue;
+
+ $path = $value;
+
+ for ($i = 1; $i < count($matches); $i++) {
+ $path = str_replace(
+ "\\{$i}",
+ $matches[$i],
+ $path);
+ }
+
+ break;
+ }
+
// get path parts
$parts = explode('/', $path);
-
+ // get the length
$len = count($parts);
// get route info
$route = array();
// e.g. /
- if ($path === '') {
+ if ($path === '')
$route = array(
- 'app' => '',
+ 'app' => 'index',
'slug' => 'index',
+ 'args' => array(),
);
// e.g. /home /login
- } else if ($len === 1) {
+ else if ($len === 1)
$route = array(
'app' => $parts[0],
'slug' => 'index',
+ 'args' => array(),
);
// e.g. /home/posts
- } else {
+ else if ($len === 2)
$route = array (
- 'app' => implode('/', array_slice($parts, 0, -1)),
- 'slug' => end($parts)
+ 'app' => $parts[0],
+ 'slug' => $parts[1],
+ 'args' => array(),
+ );
+ // e.g. /home/posts/joe
+ else
+ $route = array (
+ 'app' => $parts[0],
+ 'slug' => $parts[1],
+ 'args' => array_slice($parts, 2),
);
- };
$routes = $GLOBALS['routes'];
- if (array_key_exists($route['app'], $routes)) {
- $parts = explode('/', $routes[$route['app']]);
+ if (isset($routes[$path])) {
+ $parts = explode('/', $routes[$path]);
if (count($parts) == 1) {
$route['app'] = $parts[0];
} else {
@@ -77,7 +100,8 @@ class Router {
/**
* Gets the users ip
*/
- private function get_ip(): string {
+ private function get_ip(): string
+ {
$ip = '';
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
@@ -93,13 +117,14 @@ class Router {
* Gets the curret request info
* @return array<string,mixed>
*/
- private function get_req(): array|bool {
+ private function get_req(): array
+ {
$method = $_SERVER['REQUEST_METHOD'];
-
$uri_str = $_SERVER['REQUEST_URI'];
$uri = parse_url($uri_str);
+
if (!$uri) {
- return FALSE;
+ $uri = array('path' => '/error');
}
$path = '';
@@ -121,138 +146,94 @@ class Router {
/**
* Handles a router error code
* @param int $code - the http error code
- * @param bool $recursed
*/
- private function handle_error(int $code, bool $recursed): void {
- if ($recursed) {
+ private function handle_error(int $code): void
+ {
+ if ($this->recursed)
die($code . ' (recursed)');
- }
- $uri_str = $_SERVER['REQUEST_URI'];
- $req = array();
- $req['slug'] = 'index';
- $req['app'] = 'error';
- $req['uri_str'] = $uri_str;
- $this->main->info = $req;
- $_GET['code'] = $code;
- $this->handle_req($req, TRUE);
+
+ $this->recursed = TRUE;
+ $this->req['app'] = 'error';
+ $this->req['slug'] = 'code';
+ $this->req['args'] = array($code);
+ $this->handle_req();
}
- /**
- * @param array<int,mixed> $req
- */
- private function load_htc(array $req, bool $recursed): void {
+ /**
+ * @param array<int,mixed> $req
+ */
+ private function load_htc(array $req): void
+ {
$parts = explode('/', $req['uri_str']);
$file = end($parts);
- $path = $GLOBALS['publicroot'] . '/polyfills/' . $file;
+ $path = PUBLIC_ROOT . '/polyfills/' . $file;
if (file_exists($path)) {
header('Content-type: text/x-component');
include($path);
} else {
- $this->handle_error(400, $recursed);
+ $this->handle_error(400);
}
}
/**
* @param array $req
- * @param array<int,mixed> $req
- * @param bool $recursed
+ * @param array<int,mixed> $req
*/
- private function handle_req(array $req, bool $recursed = FALSE): void {
-
- if ($recursed === false) {
- if (
- $this->db_ready === false &&
- in_array($req['app'], $GLOBALS['serviceable']) === false
- ) {
- $this->handle_error(503, $recursed);
- return;
- }
-
- if ($this->check_banned($req)) {
- $this->handle_error(401, $recursed);
+ public function handle_req(): void
+ {
+ if ($this->recursed === FALSE) {
+ // if we are in a recursing error handler
+ // we dont want to trigger a db 503 forever
+ // since its already active
+ if ($this->db_ready === FALSE) {
+ $this->handle_error(503);
return;
}
}
- if (!$req) {
- $this->handle_error(500, $recursed);
+ // server error if we cannot parse url
+ if (!$this->req) {
+ $this->handle_error(500);
return;
}
- if (str_ends_with($req['uri_str'], '.htc')) {
- $this->load_htc($req, $recursed);
+ // load htc if someone is requesting it (hi IE6 :3)
+ if (str_ends_with($this->req['uri_str'], '.htc')) {
+ $this->load_htc($this->req);
return;
}
- $controller = $this->load->controller($req['app']);
-
+ // load the controller
+ $controller = $this->load_controller($this->req['app']);
if ($controller === NULL) {
- $this->handle_error(404, $recursed);
+ $this->handle_error(404);
return;
}
$ref = NULL;
try {
- $ref = new ReflectionMethod($controller, $req['slug']);
+ $cls = new ReflectionClass($controller);
+ $mds = $cls->getMethods(ReflectionMethod::IS_PUBLIC);
+ foreach ($mds as $md) {
+ if ($md->name !== $this->req['slug'])
+ continue;
+ if (count($md->getParameters()) !=
+ count($this->req['args']))
+ continue;
+ $ref = $md;
+ break;
+ }
} catch (Exception $_e) {}
- if ($ref === NULL || !$ref->isPublic()) {
- $this->handle_error(404, $recursed);
+ if ($ref === NULL) {
+ $this->handle_error(404);
return;
-
}
- $ref->invoke($controller);
- }
-
- /**
- * @param array<int,mixed> $req
- */
- private function log_request(array $req): void {
- if (
- $req === FALSE ||
- $this->db_ready === FALSE ||
- in_array($req['app'], $GLOBALS['serviceable'])
- ) {
- return;
- }
-
- $query = $this->db
- ->insert_into('admin.request_log',
- 'ip', 'method', 'uri')
- ->values(
- $req['ip'], $req['method'], $req['uri_str']);
-
- $query->execute();
- }
-
- /**
- * @param array<int,mixed> $req
- */
- private function check_banned(array $req): bool {
- $ip = FALSE;
- if ($req) {
- $ip = $req['ip'];
- } else {
- $ip = $this->get_ip();
- }
- $query = $this->db
- ->select('TRUE')
- ->from('admin.banned')
- ->where('ip')->eq($ip);
-
- return !!($query->row());
- }
-
- /**
- * Handels the incomming reuqest
- */
- public function handle_request(): void {
- $req = $this->get_req();
- $this->log_request($req);
- $this->main->info = $req;
- $this->handle_req($req);
+ define('CONTEXT', $this->req);
+ Component::load_lang('common', $this->req['app']);
+ $ref->invokeArgs($controller, $this->req['args']);
}
}