This commit is contained in:
Freya Murphy 2024-09-18 14:14:53 -04:00
parent 2a88aba7a5
commit 1f9024763d
Signed by: freya
GPG key ID: 744AB800E383AE52
43 changed files with 681 additions and 712 deletions

View file

@ -7,4 +7,4 @@ brainfucked is a brainfuck dialect that makes you manage your memory manually!
The original interpreter gives you a tape of 30,000 cells, while i only give you The original interpreter gives you a tape of 30,000 cells, while i only give you
as much as a pointer takes up on your system: 4 or 8 depending if your on a 32bit or 64bit system. as much as a pointer takes up on your system: 4 or 8 depending if your on a 32bit or 64bit system.
You can than allocate a new tape and then use that! Also brainfucked is tuing complete proven by You can than allocate a new tape and then use that! Also brainfucked is tuing complete proven by
this amzing [proof](/blog/writeup?name=proof.md) that my friend [trimill](https://trimill.xyz) made. this amzing [proof](/blog/writeup/brainfucked) that my friend [trimill](https://trimill.xyz) made.

View file

@ -6,12 +6,12 @@
behavior: url(boxsizing.htc); behavior: url(boxsizing.htc);
} }
#main.legacy .col { #main .col {
display: block !important; display: block !important;
width: 100% !important; width: 100% !important;
} }
#main.legacy .left { #main .left {
padding-right: 0 !important; padding-right: 0 !important;
padding-bottom: $outer-gap; padding-bottom: $outer-gap;
} }
@ -22,4 +22,8 @@
#new_comment { #new_comment {
width: 400px; width: 400px;
.input {
width: 400px;
}
} }

View file

@ -3,12 +3,10 @@ class _comments_controller extends Controller {
private $comments_model; private $comments_model;
function __construct($load) { function __construct() {
parent::__construct($load); $this->comments_model = $this->load_model('_comments');
$this->comments_model = $this->load->model('_comments');
} }
public function comments(string $page, string $ref): void { public function comments(string $page, string $ref): void {
$data = $this->comments_model->get_comments($page); $data = $this->comments_model->get_comments($page);
$this->view('comments', array( $this->view('comments', array(
@ -79,7 +77,7 @@ class _comments_controller extends Controller {
->post_comment($author, $content, $page, $vulgar); ->post_comment($author, $content, $page, $vulgar);
if ($result) { if ($result) {
header('Location: ' . $this->main->get_url($ref) . '#comments'); header('Location: ' . $this->get_url($ref) . '#comments');
} else { } else {
$this->error(500); $this->error(500);
} }

View file

@ -1,13 +1,10 @@
<?php /* Copyright (c) 2024 Freya Murphy */ <?php /* Copyright (c) 2024 Freya Murphy */
class _meta_controller extends Controller { class _meta_controller extends Controller {
function __construct($load) { public function robots(): void
parent::__construct($load); {
}
public function robots(): void {
header("Content-Type: text/plain"); header("Content-Type: text/plain");
$sitemap = $this->main->get_url_full('sitemap.xml'); $sitemap = $this->get_url('sitemap.xml');
echo "User-agent: *\n"; echo "User-agent: *\n";
echo "Disallow:\n"; echo "Disallow:\n";
@ -18,14 +15,16 @@ class _meta_controller extends Controller {
echo "Sitemap: {$sitemap}\n"; echo "Sitemap: {$sitemap}\n";
} }
private function sitemap_page(string $url, string $priority): void { private function sitemap_page(string $url, string $priority): void
{
echo "<url>\n"; echo "<url>\n";
echo "<loc>{$this->main->get_url_full($url)}</loc>\n"; echo "<loc>{$this->get_url($url)}</loc>\n";
echo "<priority>{$priority}</priority>\n"; echo "<priority>{$priority}</priority>\n";
echo "</url>"; echo "</url>";
} }
public function sitemap(): void { public function sitemap(): void
{
header("Content-Type: application/xml"); header("Content-Type: application/xml");
echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
@ -35,8 +34,8 @@ class _meta_controller extends Controller {
$this->sitemap_page('projects', 0.8); $this->sitemap_page('projects', 0.8);
$this->sitemap_page('blog', 0.8); $this->sitemap_page('blog', 0.8);
$this->load->app_lang('blog'); $this->load_lang('blog');
$blog_modal = $this->load->model('blog'); $blog_modal = $this->load_model('blog');
$blog = $blog_modal->get_data()['blog']; $blog = $blog_modal->get_data()['blog'];
foreach ($blog as $name => $_) { foreach ($blog as $name => $_) {
@ -46,20 +45,21 @@ class _meta_controller extends Controller {
echo "</urlset>\n"; echo "</urlset>\n";
} }
public function manifest(): void { public function manifest(): void
{
$json = array( $json = array(
'short_name' => lang('domain'), 'short_name' => lang('domain'),
'name' => lang('domain'), 'name' => lang('domain'),
'icons' => [ 'icons' => [
array( array(
'src' => $this->main->get_url('public/icons/logo512.png'), 'src' => $this->get_url('public/icons/logo512.png'),
'type' => 'image/png', 'type' => 'image/png',
'sizes' => '512x512', 'sizes' => '512x512',
'purpose' => 'any maskable' 'purpose' => 'any maskable'
) )
], ],
'id' => $this->main->get_url('home'), 'id' => $this->get_url('home'),
'start_url' => $this->main->get_url('home'), 'start_url' => $this->get_url('home'),
'background_color' => lang('theme_color'), 'background_color' => lang('theme_color'),
'display' => 'standalone', 'display' => 'standalone',
'scope' => lang('base_path'), 'scope' => lang('base_path'),

View file

@ -4,29 +4,28 @@ class Blog_controller extends Controller {
public $comments_controller; public $comments_controller;
private $blog_model; private $blog_model;
function __construct($load) { function __construct()
parent::__construct($load); {
$this->blog_model = $this->load->model('blog'); $this->blog_model = $this->load_model('blog');
$this->comments_controller = $this->load->controller('_comments'); $this->comments_controller = $this->load_controller('_comments');
} }
public function index(): void { public function index(): void
{
parent::index(); parent::index();
$data = $this->blog_model->get_data(); $data = $this->blog_model->get_data();
$this->view('header', $data); $this->view('header', $data);
$this->view('apps/blog', $data); $this->view('apps/blog', $data);
$this->view('footer', $data); $this->view('footer', $data);
} }
private function protect(string $folder): void { private function protect(string $folder, string $name): void
if (!array_key_exists('name', $_GET)) { {
$this->error(400); $basepath = ASSET_ROOT . '/' . $folder . '/';
}
$basepath = $GLOBALS['assetroot'] . '/' . $folder . '/';
$realBase = realpath($basepath); $realBase = realpath($basepath);
$userpath = $basepath . $_GET['name']; $userpath = $basepath . $name . '.md';
$realUserPath = realpath($userpath); $realUserPath = realpath($userpath);
if ($realUserPath === false || strpos($realUserPath, $realBase) !== 0) { if ($realUserPath === false || strpos($realUserPath, $realBase) !== 0) {
@ -34,35 +33,42 @@ class Blog_controller extends Controller {
} }
} }
public function post(): void { public function post($name): void
$this->protect('blog'); {
$this->protect('blog', $name);
parent::index(); parent::index();
$data = $this->blog_model->get_post($_GET['name']);
$data = $this->blog_model->get_post($name);
if ($data === FALSE) { if ($data === FALSE) {
$this->error(404); $this->error(404);
} }
$this->view('header', $data); $this->view('header', $data);
$this->view('apps/blog_post', $data); $this->view('apps/blog_post', $data);
$ref = 'blog/post?name=' . $_GET['name']; $ref = "blog/post{$name}";
$this->comments_controller->comments($data['post']['meta']['name'], $ref); $this->comments_controller->comments($data['post']['meta']['name'], $ref);
$this->view('footer', $data); $this->view('footer', $data);
} }
public function writeup(): void { public function writeup($name): void
$this->protect('writeup'); {
$this->protect('writeup', $name);
parent::index(); parent::index();
$data = $this->blog_model->get_writeup($_GET['name']);
$data = $this->blog_model->get_writeup($name);
if ($data === FALSE) { if ($data === FALSE) {
$this->error(404); $this->error(404);
} }
$this->view('header', $data); $this->view('header', $data);
$this->view('apps/blog_writeup', $data); $this->view('apps/blog_writeup', $data);
$ref = 'blog/writeup?name=' . $_GET['name']; $ref = "blog/writeup/{$name}";
$this->comments_controller->comments($data['post']['meta']['name'], $ref); $this->comments_controller->comments($data['post']['meta']['name'], $ref);
$this->view('footer', $data); $this->view('footer', $data);
} }
public function rss(): void { public function rss(): void
{
$data = $this->blog_model->get_data(); $data = $this->blog_model->get_data();
header('Content-Type: application/xml'); header('Content-Type: application/xml');
$this->view('apps/blog_rss', $data); $this->view('apps/blog_rss', $data);

View file

@ -3,12 +3,13 @@ class Bucket_controller extends Controller {
private $bucket_model; private $bucket_model;
function __construct($load) { function __construct()
parent::__construct($load); {
$this->bucket_model = $this->load->model('bucket'); $this->bucket_model = $this->load_model('bucket');
} }
public function index(): void { public function index(): void
{
parent::index(); parent::index();
$data = $this->bucket_model->get_data(); $data = $this->bucket_model->get_data();
if ($data === NULL) { if ($data === NULL) {

View file

@ -3,19 +3,26 @@ class Error_controller extends Controller {
private $error_model; private $error_model;
function __construct($load) { function __construct()
parent::__construct($load); {
$this->error_model = $this->load->model('error'); $this->error_model = $this->load_model('error');
} }
public function index(): void { public function code(int $code): void
{
parent::index(); parent::index();
$data = $this->error_model->get_data(); $this->load_lang('error');
$data = $this->error_model->get_data($code);
$this->view('header', $data); $this->view('header', $data);
$this->view('apps/error', $data); $this->view('apps/error', $data);
$this->view('footer', $data); $this->view('footer', $data);
} }
public function index(): void
{
$this->code(500);
}
} }
?> ?>

View file

@ -1,12 +1,11 @@
<?php /* Copyright (c) 2024 Freya Murphy */ <?php /* Copyright (c) 2024 Freya Murphy */
class Home_controller extends Controller { class Home_controller extends Controller {
function __construct($load) {
parent::__construct($load);
}
public function index(): void { public function index(): void
{
parent::index(); parent::index();
$data = $this->main->get_data();
$data = Model::get_base_data();
$this->view('header', $data); $this->view('header', $data);
$this->view('apps/home', $data); $this->view('apps/home', $data);
$this->view('footer', $data); $this->view('footer', $data);

View file

@ -3,13 +3,15 @@ class Projects_controller extends Controller {
private $projects_model; private $projects_model;
function __construct($load) { function __construct()
parent::__construct($load); {
$this->projects_model = $this->load->model('projects'); $this->projects_model = $this->load_model('projects');
} }
public function index(): void { public function index(): void
{
parent::index(); parent::index();
$data = $this->projects_model->get_data(); $data = $this->projects_model->get_data();
$this->view('header', $data); $this->view('header', $data);
$this->view('apps/projects', $data); $this->view('apps/projects', $data);

View file

@ -1,12 +1,9 @@
<?php /* Copyright (c) 2024 Freya Murphy */ <?php /* Copyright (c) 2024 Freya Murphy */
class _comments_model extends Model { class _comments_model extends Model {
function __construct($load) { private function load_profanity()
parent::__construct($load); {
} $path = ASSET_ROOT . '/profanity.txt';
private function load_profanity() {
$path = $GLOBALS['assetroot'] . '/profanity.txt';
$str = file_get_contents($path); $str = file_get_contents($path);
$lines = explode("\n", $str); $lines = explode("\n", $str);
@ -25,14 +22,16 @@ class _comments_model extends Model {
return $regex; return $regex;
} }
public function is_vulgar($text) { public function is_vulgar($text)
{
$profanity = $this->load_profanity(); $profanity = $this->load_profanity();
return preg_match($profanity, $text); return preg_match($profanity, $text);
} }
public function get_comments($page) { public function get_comments($page)
$ip = $this->main->info['ip']; {
$query = $this->db $ip = CONTEXT['ip'];
$query = $this->db()
->select('*') ->select('*')
->from('admin.comment c') ->from('admin.comment c')
->where('c.page') ->where('c.page')
@ -46,17 +45,19 @@ class _comments_model extends Model {
return $result; return $result;
} }
public function ban_user() { public function ban_user()
$ip = $this->main->info['ip']; {
$this->db $ip = CONTEXT['ip'];
$this->db()
->insert_into('admin.banned', 'ip', 'reason') ->insert_into('admin.banned', 'ip', 'reason')
->values($ip, 'vulgar language') ->values($ip, 'vulgar language')
->execute(); ->execute();
} }
public function post_comment($author, $content, $page, $vulgar) { public function post_comment($author, $content, $page, $vulgar)
$ip = $this->main->info['ip']; {
return $this->db $ip = CONTEXT['ip'];
return $this->db()
->insert_into('admin.comment', ->insert_into('admin.comment',
'author', 'content', 'page', 'ip', 'vulgar') 'author', 'content', 'page', 'ip', 'vulgar')
->values($author, $content, $page, $ip, $vulgar) ->values($author, $content, $page, $ip, $vulgar)

View file

@ -3,17 +3,18 @@ class Blog_model extends Model {
private $markdown; private $markdown;
function __construct($load) { function __construct()
parent::__construct($load); {
$this->markdown = new MarkdownParser(); $this->markdown = new MarkdownParser();
} }
/** /**
* @param mixed $data * @param mixed $data
* @return void * @return void
*/ */
private function load_blog(&$data): void { private function load_blog(&$data): void
{
$blog = array(); $blog = array();
$dir = $GLOBALS['assetroot'] . '/blog'; $dir = ASSET_ROOT . '/blog';
if ($handle = opendir($dir)) { if ($handle = opendir($dir)) {
while (false !== ($entry = readdir($handle))) { while (false !== ($entry = readdir($handle))) {
if (str_starts_with($entry, ".")) { if (str_starts_with($entry, ".")) {
@ -29,31 +30,31 @@ class Blog_model extends Model {
} }
public function get_data(): ?array { public function get_data(): ?array {
$data = parent::get_data(); $data = parent::get_base_data('blog');
$this->load_blog($data); $this->load_blog($data);
$data['title'] = lang('title'); $data['title'] = lang('title');
$data['desc'] = lang('blog_short_desc'); $data['desc'] = lang('blog_short_desc');
return $data; return $data;
} }
/** /**
* @param mixed $name * @param mixed $name
* @return bool|<missing> * @return bool|<missing>
*/ */
private function load_post($name): ?array { private function load_post($name): ?array {
$dir = $GLOBALS['assetroot'] . '/blog'; $dir = ASSET_ROOT . '/blog';
$path = $dir . '/' . $name; $path = $dir . '/' . $name . '.md';
if(!file_exists($path)) { if(!file_exists($path)) {
return NULL; return NULL;
} }
$md = $this->markdown->parse($path); $md = $this->markdown->parse($path);
return $md; return $md;
} }
/** /**
* @param mixed $name * @param mixed $name
* @return bool|null|array * @return bool|null|array
*/ */
public function get_post($name): ?array { public function get_post($name): ?array {
$data = parent::get_data(); $data = parent::get_base_data();
$post = $this->load_post($name); $post = $this->load_post($name);
if (!$post) { if (!$post) {
return NULL; return NULL;
@ -63,24 +64,24 @@ class Blog_model extends Model {
$data['post'] = $post; $data['post'] = $post;
return $data; return $data;
} }
/** /**
* @param mixed $name * @param mixed $name
*/ */
private function load_writeup($name): ?array { private function load_writeup($name): ?array {
$dir = $GLOBALS['assetroot'] . '/writeup'; $dir = ASSET_ROOT . '/writeup';
$path = $dir . '/' . $name; $path = $dir . '/' . $name . '.md';
if(!file_exists($path)) { if(!file_exists($path)) {
return NULL; return NULL;
} }
$md = $this->markdown->parse($path); $md = $this->markdown->parse($path);
return $md; return $md;
} }
/** /**
* @param mixed $name * @param mixed $name
* @return bool|null|array * @return bool|null|array
*/ */
public function get_writeup($name): ?array { public function get_writeup($name): ?array {
$data = parent::get_data(); $data = parent::get_base_data();
$writeup = $this->load_writeup($name); $writeup = $this->load_writeup($name);
if (!$writeup) { if (!$writeup) {
return NULL; return NULL;

View file

@ -1,24 +1,19 @@
<?php /* Copyright (c) 2024 Freya Murphy */ <?php /* Copyright (c) 2024 Freya Murphy */
class Bucket_model extends Model { class Bucket_model extends Model {
function __construct($load) { public function get_data(): ?array
parent::__construct($load); {
} $data = parent::get_base_data();
public function get_data(): ?array { if (array_key_exists('name', $_GET))
$data = parent::get_data();
if (array_key_exists('name', $_GET)) {
$data['name'] = $_GET['name']; $data['name'] = $_GET['name'];
} else { else
return NULL; return NULL;
}
if (array_key_exists('lightmode', $_GET)) { if (array_key_exists('lightmode', $_GET))
$data['lightmode'] = $_GET['lightmode']; $data['lightmode'] = $_GET['lightmode'];
} else { else
$data['lightmode'] = 'false'; $data['lightmode'] = 'false';
}
return $data; return $data;
} }

View file

@ -1,30 +1,22 @@
<?php /* Copyright (c) 2024 Freya Murphy */ <?php /* Copyright (c) 2024 Freya Murphy */
class Error_model extends Model { class Error_model extends Model {
function __construct($load) { private function get_msg(&$data, int $code)
parent::__construct($load); {
} http_response_code($code);
$data['title'] = $code;
private function get_msg(&$data) { $msg = ucfirst(lang('error_' . $code, FALSE));
if (!array_key_exists('code', $_GET)) { if (!$msg) {
http_response_code(500); $msg = ucfirst(lang('error'));
$data['msg'] = ucfirst(lang('error'));
$data['title'] = '500';
} else {
$code = $_GET['code'];
http_response_code($code);
$data['title'] = $code;
$msg = ucfirst(lang('error_' . $code, FALSE));
if (!$msg) {
$msg = ucfirst(lang('error'));
}
$data['msg'] = $msg;
} }
$data['msg'] = $msg;
} }
public function get_data(): ?array { public function get_data(int $code): array
$data = parent::get_data(); {
$this->get_msg($data); $data = parent::get_base_data('error');
$this->get_msg($data, $code);
return $data; return $data;
} }
} }

View file

@ -1,110 +0,0 @@
<?php /* Copyright (c) 2024 Freya Murphy */
class Main_model extends Model {
// stores the current request info
public mixed $info;
// the main loader
public Loader $load;
/**
* Loads the main model
* @param Loader $load - the main loader object
*/
function __construct(Loader $load) {
parent::__construct($load, TRUE);
$GLOBALS['main_model'] = $this;
}
/**
* Gets the stamp for a asset path
* @param string $path
*/
private function asset_stamp(string $path): int {
$root = $GLOBALS['webroot'];
$path = $root . '/../public/' . $path;
return @filemtime($path);
}
/**
* Get the current IE version
* @returns the IE version if valid IE user agent, INT_MAX if not
*/
public function get_ie_version(): int {
if (preg_match('/MSIE\s(?P<v>\d+)/i', @$_SERVER['HTTP_USER_AGENT'], $B)) {
return $B['v'];
} else {
return PHP_INT_MAX;
}
}
/**
* Gets the full url including the http scheme and host part
* Needed for IE 6 & 7 need.
* @param string $path
* @param bool $timestamp
*/
public function get_url_full(string $path, bool $timestamp = FALSE): string {
$host = $_SERVER['HTTP_HOST'];
$base = lang('base_path');
$url = "http://{$host}{$base}{$path}";
if ($timestamp) {
$time = @filemtime($GLOBALS['rootroot'] . '/' . $path);
$url .= "?timestamp={$time}";
}
return $url;
}
/**
* Gets a full path url from a relative path
* @param string $path
* @param bool $timestamp
*/
public function get_url(string $path, bool $timestamp = FALSE): string {
if ($this->get_ie_version() <= 7) {
return $this->get_url_full($path, $timestamp);
}
$base = lang('base_path');
$url = "{$base}{$path}";
if ($timestamp) {
$time = @filemtime($GLOBALS['rootroot'] . '/' . $path);
$url .= "?timestamp={$time}";
}
return $url;
}
/**
* Loads a css html link
* @param string $path - the path to the css file
*/
public function link_css(string $path): string {
$stamp = $this->asset_stamp($path);
$href = $this->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 function embed_css(string $path): string {
$file = $GLOBALS['publicroot'] . '/' . $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 function format_date(string $iso_date): string {
return date("Y-m-d D H:m", strtotime($iso_date));
}
}
?>

View file

@ -3,17 +3,18 @@ class Projects_model extends Model {
private $markdown; private $markdown;
function __construct($load) { function __construct()
parent::__construct($load); {
$this->markdown = new MarkdownParser(); $this->markdown = new MarkdownParser();
} }
/** /**
* @param array<string,mixed> $data * @param array<string,mixed> $data
*/ */
private function load_projects(&$data): void { private function load_projects(&$data): void
{
$projects = array(); $projects = array();
$dir = $GLOBALS['assetroot'] . '/projects'; $dir = ASSET_ROOT . '/projects';
if ($handle = opendir($dir)) { if ($handle = opendir($dir)) {
while (false !== ($entry = readdir($handle))) { while (false !== ($entry = readdir($handle))) {
if (str_starts_with($entry, ".")) { if (str_starts_with($entry, ".")) {
@ -28,8 +29,9 @@ class Projects_model extends Model {
$data['projects'] = $projects; $data['projects'] = $projects;
} }
public function get_data(): ?array { public function get_data(): ?array
$data = parent::get_data(); {
$data = parent::get_base_data();
$this->load_projects($data); $this->load_projects($data);
$data['title'] = lang('title'); $data['title'] = lang('title');
$data['desc'] = lang('short_desc'); $data['desc'] = lang('short_desc');

View file

@ -1,13 +1,13 @@
<?php /* Copyright (c) 2024 Freya Murphy */ ?> <?php /* Copyright (c) 2024 Freya Murphy */ ?>
<?=aria_section('blog', lang('title'))?> <?=aria_section('blog', lang('title'))?>
<p><?=lang('blog_desc', sub: [$this->main->get_url('rss.xml')])?></p> <p><?=lang('blog_desc', sub: [$this->get_url('rss.xml')])?></p>
<?php <?php
foreach($blog as $name => $post) { foreach($blog as $name => $post) {
$meta = $post['meta']; $meta = $post['meta'];
$link = $this->main->get_url('blog/post?name=' . $name); $link = $this->get_url('blog/post/' . substr($name, 0, -3));
echo '<a href="' . $link . '"><h3>' . $meta['name'] . '</h3></a>'; echo '<a href="' . $link . '"><h3>' . $meta['name'] . '</h3></a>';
echo '<span>' . $meta['desc'] . '</span><br>'; echo '<span>' . $meta['desc'] . '</span><br>';
echo '<span><time>' . $this->main->format_date($meta['date']) . '</time></span>'; echo '<span><time>' . $this->format_date($meta['date']) . '</time></span>';
} }
?> ?>
</div> </div>

View file

@ -1,6 +1,6 @@
<?php /* Copyright (c) 2024 Freya Murphy */ ?> <?php /* Copyright (c) 2024 Freya Murphy */ ?>
<?=aria_section('post', $post['meta']['name'])?> <?=aria_section('post', $post['meta']['name'])?>
<span><?=ucfirst(lang('posted'))?>: <time><?=$this->main->format_date($post['meta']['date'])?></time></span> <span><?=ucfirst(lang('posted'))?>: <time><?=$this->format_date($post['meta']['date'])?></time></span>
<br> <br>
<?=$post['content']?> <?=$post['content']?>
</div> </div>

View file

@ -7,12 +7,13 @@
<language><?=lang('lang_short')?></language> <language><?=lang('lang_short')?></language>
<?php <?php
foreach ($blog as $name => $post) { foreach ($blog as $name => $post) {
$name = substr($name, 0, -3);
echo '<item>'; echo '<item>';
echo '<title>' . $post['meta']['name'] . '</title>'; echo '<title>' . $post['meta']['name'] . '</title>';
echo '<description>' . $post['meta']['desc'] . '</description>'; echo '<description>' . $post['meta']['desc'] . '</description>';
echo '<pubDate>' . $post['meta']['date'] . '</pubDate>'; echo '<pubDate>' . $post['meta']['date'] . '</pubDate>';
echo '<link>' . lang('root_url') . 'blog/post?name=' . $name . '</link>'; echo '<link>' . lang('root_url') . 'blog/post/' . $name . '</link>';
echo '<guid>' . lang('root_url') . 'blog/post?name=' . $name . '</guid>'; echo '<guid>' . lang('root_url') . 'blog/post/' . $name . '</guid>';
echo '</item>'; echo '</item>';
} }
?> ?>

View file

@ -3,9 +3,9 @@
$root='https://webring.bucketfish.me/redirect.html?to=%s&name=' . $name; $root='https://webring.bucketfish.me/redirect.html?to=%s&name=' . $name;
$this->view('head', $data); $this->view('head', $data);
if ($lightmode === 'true') { if ($lightmode === 'true') {
echo $this->main->link_css('css/bucket_light.css'); echo $this->link_css('css/bucket_light.css');
} else { } else {
echo $this->main->link_css('css/bucket.css'); echo $this->link_css('css/bucket.css');
} }
?> ?>
<base target="_parent" /> <base target="_parent" />

View file

@ -3,7 +3,7 @@
<?php <?php
if ($comments) if ($comments)
foreach($comments as $comment) { foreach($comments as $comment) {
$date = $this->main->format_date($comment['created']); $date = $this->format_date($comment['created']);
echo '<div class="comment">'; echo '<div class="comment">';
echo '<h3 class="header">' . esc($comment['author']) . '</h3>'; echo '<h3 class="header">' . esc($comment['author']) . '</h3>';

View file

@ -6,8 +6,6 @@
} else { } else {
$footer_text = ''; $footer_text = '';
} }
$legacy = $this->main->get_ie_version() <= 7;
?> ?>
</div> </div>
</div> </div>
@ -39,13 +37,12 @@
height="40" height="40"
class="bucket" class="bucket"
title="<?=lang('bucket_title')?>" title="<?=lang('bucket_title')?>"
src="<?=$this->main->get_url('bucket?name=freya')?>" src="<?=$this->get_url('bucket?name=freya')?>"
></iframe> ></iframe>
</div> </div>
<?php if($legacy): ?>
</center>
<?php else: ?>
</div> </div>
<?php endif; ?> <!--[if lt IE 8 ]>
</center>
<![endif]-->
</body> </body>
</html> </html>

View file

@ -12,18 +12,18 @@
<meta property="og:description" content="<?=$desc?>"> <meta property="og:description" content="<?=$desc?>">
<meta property="og:title" content="<?=$title?>"> <meta property="og:title" content="<?=$title?>">
<meta property="og:site_name" content="<?=lang('domain')?>"> <meta property="og:site_name" content="<?=lang('domain')?>">
<meta property="og:image" content="<?=$this->main->get_url_full('public/icons/logo640.png', TRUE)?>"> <meta property="og:image" content="<?=$this->get_url('public/icons/logo640.png', TRUE)?>">
<title><?=$title?></title> <title><?=$title?></title>
<link rel="icon" type="image/png" sizes="16x16" href="<?=$this->main->get_url("public/icons/logo16.png", TRUE)?>"> <link rel="icon" type="image/png" sizes="16x16" href="<?=$this->get_url("public/icons/logo16.png", TRUE)?>">
<link rel="icon" type="image/png" sizes="32x32" href="<?=$this->main->get_url("public/icons/logo32.png", TRUE)?>"> <link rel="icon" type="image/png" sizes="32x32" href="<?=$this->get_url("public/icons/logo32.png", TRUE)?>">
<link rel="icon" type="image/png" sizes="64x64" href="<?=$this->main->get_url("public/icons/logo64.png", TRUE)?>"> <link rel="icon" type="image/png" sizes="64x64" href="<?=$this->get_url("public/icons/logo64.png", TRUE)?>">
<link rel="icon" type="image/png" sizes="320x320" href="<?=$this->main->get_url("public/icons/logo320.png", TRUE)?>"> <link rel="icon" type="image/png" sizes="320x320" href="<?=$this->get_url("public/icons/logo320.png", TRUE)?>">
<link rel="icon" type="image/png" sizes="512x512" href="<?=$this->main->get_url("public/icons/logo512.png", TRUE)?>"> <link rel="icon" type="image/png" sizes="512x512" href="<?=$this->get_url("public/icons/logo512.png", TRUE)?>">
<link rel="icon" type="image/png" sizes="640x640" href="<?=$this->main->get_url("public/icons/logo640.png", TRUE)?>"> <link rel="icon" type="image/png" sizes="640x640" href="<?=$this->get_url("public/icons/logo640.png", TRUE)?>">
<link rel="manifest" href="/manifest.json"> <link rel="manifest" href="/manifest.json">
<?php if($this->main->get_ie_version() <= 7) <!--[if lt IE 8 ]>
echo $this->main->link_css('css/legacy.css'); <?=$this->link_css('css/legacy.css')?>
?> <![endif]-->
<?php foreach($css as $file) <?php foreach($css as $file)
echo $this->main->embed_css($file); echo $this->embed_css($file);
?> ?>

View file

@ -1,16 +1,14 @@
<?php /* Copyright (c) 2024 Freya Murphy */ ?> <?php /* Copyright (c) 2024 Freya Murphy */ ?>
<?php <?php
$this->view('head', $data); $this->view('head', $data);
echo $this->main->link_css('css/main.css'); echo $this->link_css('css/main.css');
$legacy = $this->main->get_ie_version() <= 7;
?> ?>
</head> </head>
<body> <body>
<?php if($legacy): ?> <!--[if lt IE 8 ]>
<center> <center>
<?php else: ?> <![endif]-->
<div class="center"> <div class="center">
<?php endif; ?>
<div id="header" role="banner" aria-label="banner"> <div id="header" role="banner" aria-label="banner">
<?=image('img/headerLogo', 'alt_website_logo', size: '200')?> <?=image('img/headerLogo', 'alt_website_logo', size: '200')?>
<div class="content"> <div class="content">
@ -20,24 +18,20 @@
<div role="navigation"> <div role="navigation">
<ul id="nav"> <ul id="nav">
<li><?=ilang('action_home', <li><?=ilang('action_home',
href: $this->main->get_url('home'), href: $this->get_url('home'),
container: 'h2' container: 'h2'
)?></li> )?></li>
<li><?=ilang('action_projects', <li><?=ilang('action_projects',
href: $this->main->get_url('projects'), href: $this->get_url('projects'),
container: 'h2' container: 'h2'
)?></li> )?></li>
<li><?=ilang('action_blog', <li><?=ilang('action_blog',
href: $this->main->get_url('blog'), href: $this->get_url('blog'),
container: 'h2' container: 'h2'
)?></li> )?></li>
</ul> </ul>
</div> </div>
</div> </div>
</div> </div>
<?php if($legacy): ?>
<div id="main" class="legacy" role="main">
<?php else: ?>
<div id="main" role="main" aria-label="main"> <div id="main" role="main" aria-label="main">
<?php endif; ?>
<div id="container"> <div id="container">

View file

@ -1,11 +1,7 @@
<?php /* Copyright (c) 2024 Freya Murphy */ <?php /* Copyright (c) 2024 Freya Murphy */
$routes = array(); $routes = array();
$routes[''] = 'home'; $routes[''] = 'home';
$routes['robots.txt'] = '_meta/robots'; $routes['robots.txt'] = '_meta/robots';
$routes['sitemap.xml'] = '_meta/sitemap'; $routes['sitemap.xml'] = '_meta/sitemap';
$routes['manifest.json'] = '_meta/manifest'; $routes['manifest.json'] = '_meta/manifest';
$routes['rss.xml'] = 'blog/rss'; $routes['rss.xml'] = 'blog/rss';
$serviceable = array('bucket');

View file

@ -1,7 +1,5 @@
<?php /* Copyright (c) 2024 Freya Murphy */ <?php /* Copyright (c) 2024 Freya Murphy */
$style = array(); $style = array();
$style['home'] = 'css/home.css'; $style['home'] = 'css/home.css';
$style['blog'] = 'css/blog.css'; $style['blog'] = 'css/blog.css';
$style['error'] = 'css/error.css'; $style['error'] = 'css/error.css';

View file

@ -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();
}
}

View file

@ -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;
}
}

119
src/web/core/component.php Normal file
View file

@ -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);
}
}
}

View file

@ -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();
}
}

85
src/web/core/core.php Normal file
View file

@ -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));
}
}

View file

@ -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;
}
}
}

29
src/web/core/model.php Normal file
View file

@ -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;
}
}

View file

@ -1,68 +1,91 @@
<?php /* Copyright (c) 2024 Freya Murphy */ <?php /* Copyright (c) 2024 Freya Murphy */
class Router {
// the loader class Router extends Component {
private Loader $load;
// the main model
private Main_model $main;
// the database
private DatabaseHelper $db;
private bool $db_ready; private bool $db_ready;
private bool $recursed;
private array $req;
/** /**
* Creates a router * Creates a router
* @param Loader $load - the main laoder object * @param Loader $load - the main laoder object
*/ */
function __construct($load) { function __construct()
$this->load = $load; {
$this->db = $load->db();
$this->main = $this->load->model('main');
$this->db_ready = file_exists('/status/ready'); $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 * Gets the current route
* @return array<string,mixed> * @return array<string,mixed>
*/ */
private function get_req_route($path): array { private function get_req_route($path): array
{
// trim the path // trim the path
$path = trim($path); $path = trim($path);
// remove first '/' // remove first '/'
$path = substr($path, 1); $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 // get path parts
$parts = explode('/', $path); $parts = explode('/', $path);
// get the length
$len = count($parts); $len = count($parts);
// get route info // get route info
$route = array(); $route = array();
// e.g. / // e.g. /
if ($path === '') { if ($path === '')
$route = array( $route = array(
'app' => '', 'app' => 'index',
'slug' => 'index', 'slug' => 'index',
'args' => array(),
); );
// e.g. /home /login // e.g. /home /login
} else if ($len === 1) { else if ($len === 1)
$route = array( $route = array(
'app' => $parts[0], 'app' => $parts[0],
'slug' => 'index', 'slug' => 'index',
'args' => array(),
); );
// e.g. /home/posts // e.g. /home/posts
} else { else if ($len === 2)
$route = array ( $route = array (
'app' => implode('/', array_slice($parts, 0, -1)), 'app' => $parts[0],
'slug' => end($parts) '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']; $routes = $GLOBALS['routes'];
if (array_key_exists($route['app'], $routes)) { if (isset($routes[$path])) {
$parts = explode('/', $routes[$route['app']]); $parts = explode('/', $routes[$path]);
if (count($parts) == 1) { if (count($parts) == 1) {
$route['app'] = $parts[0]; $route['app'] = $parts[0];
} else { } else {
@ -77,7 +100,8 @@ class Router {
/** /**
* Gets the users ip * Gets the users ip
*/ */
private function get_ip(): string { private function get_ip(): string
{
$ip = ''; $ip = '';
if (!empty($_SERVER['HTTP_CLIENT_IP'])) { if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
$ip = $_SERVER['HTTP_CLIENT_IP']; $ip = $_SERVER['HTTP_CLIENT_IP'];
@ -93,13 +117,14 @@ class Router {
* Gets the curret request info * Gets the curret request info
* @return array<string,mixed> * @return array<string,mixed>
*/ */
private function get_req(): array|bool { private function get_req(): array
{
$method = $_SERVER['REQUEST_METHOD']; $method = $_SERVER['REQUEST_METHOD'];
$uri_str = $_SERVER['REQUEST_URI']; $uri_str = $_SERVER['REQUEST_URI'];
$uri = parse_url($uri_str); $uri = parse_url($uri_str);
if (!$uri) { if (!$uri) {
return FALSE; $uri = array('path' => '/error');
} }
$path = ''; $path = '';
@ -121,138 +146,94 @@ class Router {
/** /**
* Handles a router error code * Handles a router error code
* @param int $code - the http error code * @param int $code - the http error code
* @param bool $recursed
*/ */
private function handle_error(int $code, bool $recursed): void { private function handle_error(int $code): void
if ($recursed) { {
if ($this->recursed)
die($code . ' (recursed)'); die($code . ' (recursed)');
}
$uri_str = $_SERVER['REQUEST_URI']; $this->recursed = TRUE;
$req = array(); $this->req['app'] = 'error';
$req['slug'] = 'index'; $this->req['slug'] = 'code';
$req['app'] = 'error'; $this->req['args'] = array($code);
$req['uri_str'] = $uri_str; $this->handle_req();
$this->main->info = $req;
$_GET['code'] = $code;
$this->handle_req($req, TRUE);
} }
/** /**
* @param array<int,mixed> $req * @param array<int,mixed> $req
*/ */
private function load_htc(array $req, bool $recursed): void { private function load_htc(array $req): void
{
$parts = explode('/', $req['uri_str']); $parts = explode('/', $req['uri_str']);
$file = end($parts); $file = end($parts);
$path = $GLOBALS['publicroot'] . '/polyfills/' . $file; $path = PUBLIC_ROOT . '/polyfills/' . $file;
if (file_exists($path)) { if (file_exists($path)) {
header('Content-type: text/x-component'); header('Content-type: text/x-component');
include($path); include($path);
} else { } else {
$this->handle_error(400, $recursed); $this->handle_error(400);
} }
} }
/** /**
* @param array $req * @param array $req
* @param array<int,mixed> $req * @param array<int,mixed> $req
* @param bool $recursed
*/ */
private function handle_req(array $req, bool $recursed = FALSE): void { public function handle_req(): void
{
if ($recursed === false) { if ($this->recursed === FALSE) {
if ( // if we are in a recursing error handler
$this->db_ready === false && // we dont want to trigger a db 503 forever
in_array($req['app'], $GLOBALS['serviceable']) === false // since its already active
) { if ($this->db_ready === FALSE) {
$this->handle_error(503, $recursed); $this->handle_error(503);
return;
}
if ($this->check_banned($req)) {
$this->handle_error(401, $recursed);
return; return;
} }
} }
if (!$req) { // server error if we cannot parse url
$this->handle_error(500, $recursed); if (!$this->req) {
$this->handle_error(500);
return; return;
} }
if (str_ends_with($req['uri_str'], '.htc')) { // load htc if someone is requesting it (hi IE6 :3)
$this->load_htc($req, $recursed); if (str_ends_with($this->req['uri_str'], '.htc')) {
$this->load_htc($this->req);
return; return;
} }
$controller = $this->load->controller($req['app']); // load the controller
$controller = $this->load_controller($this->req['app']);
if ($controller === NULL) { if ($controller === NULL) {
$this->handle_error(404, $recursed); $this->handle_error(404);
return; return;
} }
$ref = NULL; $ref = NULL;
try { 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) {} } catch (Exception $_e) {}
if ($ref === NULL || !$ref->isPublic()) { if ($ref === NULL) {
$this->handle_error(404, $recursed); $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; return;
} }
$query = $this->db define('CONTEXT', $this->req);
->insert_into('admin.request_log', Component::load_lang('common', $this->req['app']);
'ip', 'method', 'uri') $ref->invokeArgs($controller, $this->req['args']);
->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);
} }
} }

View file

@ -1,6 +1,7 @@
<?php /* Copyright (c) 2024 Freya Murphy */ <?php /* Copyright (c) 2024 Freya Murphy */
function aria_section(string $id, ?string $title = NULL): string { function aria_section(string $id, ?string $title = NULL): string
{
$out = ''; $out = '';
if ($title) { if ($title) {
$idh = $id . '_heading'; $idh = $id . '_heading';

View file

@ -1,6 +1,7 @@
<?php /* Copyright (c) 2024 Freya Murphy */ <?php /* Copyright (c) 2024 Freya Murphy */
function __nullify(mixed $val): mixed { function __nullify(mixed $val): mixed
{
if (!$val) { if (!$val) {
return NULL; return NULL;
} else { } else {
@ -18,7 +19,8 @@ class DatabaseQuery {
private array $param; private array $param;
function __construct(\PDO $conn) { function __construct(\PDO $conn)
{
$this->conn = $conn; $this->conn = $conn;
$this->query = ''; $this->query = '';
@ -31,7 +33,8 @@ class DatabaseQuery {
/// ARBITRARY QUERY /// ARBITRARY QUERY
/// ///
public function query(string $query): DatabaseQuery { public function query(string $query): DatabaseQuery
{
$this->query .= $query; $this->query .= $query;
return $this; return $this;
} }
@ -40,12 +43,14 @@ class DatabaseQuery {
/// SELECT /// SELECT
/// ///
public function select(string $select): DatabaseQuery { public function select(string $select): DatabaseQuery
{
$this->query .= "SELECT $select\n"; $this->query .= "SELECT $select\n";
return $this; return $this;
} }
public function from(string $from): DatabaseQuery { public function from(string $from): DatabaseQuery
{
$this->query .= "FROM $from\n"; $this->query .= "FROM $from\n";
return $this; return $this;
} }
@ -54,7 +59,8 @@ class DatabaseQuery {
/// INSERT /// INSERT
/// ///
public function insert_into(string $insert, string ...$columns): DatabaseQuery { public function insert_into(string $insert, string ...$columns): DatabaseQuery
{
$this->query .= "INSERT INTO $insert\n ("; $this->query .= "INSERT INTO $insert\n (";
foreach ($columns as $idx => $column) { foreach ($columns as $idx => $column) {
if ($idx !== 0) { if ($idx !== 0) {
@ -66,7 +72,8 @@ class DatabaseQuery {
return $this; return $this;
} }
public function values(mixed ...$values): DatabaseQuery { public function values(mixed ...$values): DatabaseQuery
{
$this->query .= "VALUES ("; $this->query .= "VALUES (";
foreach ($values as $idx => $value) { foreach ($values as $idx => $value) {
if ($idx !== 0) { if ($idx !== 0) {
@ -83,7 +90,8 @@ class DatabaseQuery {
/// WHERE /// WHERE
/// ///
public function where(string $cond): DatabaseQuery { public function where(string $cond): DatabaseQuery
{
if (!$this->where) { if (!$this->where) {
$this->where = TRUE; $this->where = TRUE;
$this->query .= "WHERE "; $this->query .= "WHERE ";
@ -97,7 +105,8 @@ class DatabaseQuery {
/** /**
* @param array<mixed> $array * @param array<mixed> $array
*/ */
public function where_in(string $column, array $array): DatabaseQuery { public function where_in(string $column, array $array): DatabaseQuery
{
if (!$this->where) { if (!$this->where) {
$this->where = TRUE; $this->where = TRUE;
$this->query .= "WHERE "; $this->query .= "WHERE ";
@ -116,7 +125,8 @@ class DatabaseQuery {
/** /**
* @param array<mixed> $array * @param array<mixed> $array
*/ */
private function in(array $array): DatabaseQuery { private function in(array $array): DatabaseQuery
{
$in = 'IN ('; $in = 'IN (';
foreach ($array as $idx => $item) { foreach ($array as $idx => $item) {
if ($idx != 0) { if ($idx != 0) {
@ -133,31 +143,36 @@ class DatabaseQuery {
/// OPERATORS /// OPERATORS
/// ///
public function like(mixed $item): DatabaseQuery { public function like(mixed $item): DatabaseQuery
{
$this->query .= "LIKE ?\n"; $this->query .= "LIKE ?\n";
array_push($this->param, $item); array_push($this->param, $item);
return $this; return $this;
} }
public function eq(mixed $item): DatabaseQuery { public function eq(mixed $item): DatabaseQuery
{
$this->query .= "= ?\n"; $this->query .= "= ?\n";
array_push($this->param, $item); array_push($this->param, $item);
return $this; return $this;
} }
public function ne(mixed $item): DatabaseQuery { public function ne(mixed $item): DatabaseQuery
{
$this->query .= "<> ?\n"; $this->query .= "<> ?\n";
array_push($this->param, $item); array_push($this->param, $item);
return $this; return $this;
} }
public function lt(mixed $item): DatabaseQuery { public function lt(mixed $item): DatabaseQuery
{
$this->query .= "< ?\n"; $this->query .= "< ?\n";
array_push($this->param, $item); array_push($this->param, $item);
return $this; return $this;
} }
public function le(mixed $item): DatabaseQuery { public function le(mixed $item): DatabaseQuery
{
$this->query .= "<= ?\n"; $this->query .= "<= ?\n";
array_push($this->param, $item); array_push($this->param, $item);
return $this; return $this;
@ -167,7 +182,8 @@ class DatabaseQuery {
/// JOINS /// JOINS
/// ///
public function join(string $table, string $on, string $type = 'LEFT'): DatabaseQuery { public function join(string $table, string $on, string $type = 'LEFT'): DatabaseQuery
{
$this->query .= "$type JOIN $table ON $on\n"; $this->query .= "$type JOIN $table ON $on\n";
return $this; return $this;
} }
@ -176,19 +192,22 @@ class DatabaseQuery {
/// LIMIT, OFFSET, ORDER /// LIMIT, OFFSET, ORDER
/// ///
public function limit(int $limit): DatabaseQuery { public function limit(int $limit): DatabaseQuery
{
$this->query .= "LIMIT ?\n"; $this->query .= "LIMIT ?\n";
array_push($this->param, $limit); array_push($this->param, $limit);
return $this; return $this;
} }
public function offset(int $offset): DatabaseQuery { public function offset(int $offset): DatabaseQuery
{
$this->query .= "OFFSET ?\n"; $this->query .= "OFFSET ?\n";
array_push($this->param, $offset); array_push($this->param, $offset);
return $this; return $this;
} }
public function order_by(string $column, string $order = 'ASC'): DatabaseQuery { public function order_by(string $column, string $order = 'ASC'): DatabaseQuery
{
$this->query .= "ORDER BY " . $column . ' ' . $order . ' '; $this->query .= "ORDER BY " . $column . ' ' . $order . ' ';
return $this; return $this;
} }
@ -197,7 +216,8 @@ class DatabaseQuery {
/// COLLECT /// COLLECT
/// ///
public function rows(mixed ...$params): ?array { public function rows(mixed ...$params): ?array
{
$args = $this->param; $args = $this->param;
foreach ($params as $param) { foreach ($params as $param) {
array_push($args, $param); array_push($args, $param);
@ -213,7 +233,8 @@ class DatabaseQuery {
return __nullify($stmt->fetchAll(PDO::FETCH_ASSOC)); return __nullify($stmt->fetchAll(PDO::FETCH_ASSOC));
} }
public function row(mixed ...$params): ?array { public function row(mixed ...$params): ?array
{
$args = $this->param; $args = $this->param;
foreach ($params as $param) { foreach ($params as $param) {
array_push($args, $param); array_push($args, $param);
@ -223,7 +244,8 @@ class DatabaseQuery {
return __nullify($stmt->fetch(PDO::FETCH_ASSOC)); return __nullify($stmt->fetch(PDO::FETCH_ASSOC));
} }
public function execute(mixed ...$params): bool { public function execute(mixed ...$params): bool
{
$args = $this->param; $args = $this->param;
foreach ($params as $param) { foreach ($params as $param) {
array_push($args, $param); array_push($args, $param);
@ -250,11 +272,13 @@ class DatabaseHelper {
private ?\PDO $conn; private ?\PDO $conn;
function __construct() { function __construct()
{
$this->conn = NULL; $this->conn = NULL;
} }
private function connect(): \PDO { private function connect(): \PDO
{
if ($this->conn === NULL) { if ($this->conn === NULL) {
$user = getenv("POSTGRES_USER"); $user = getenv("POSTGRES_USER");
$pass = getenv("POSTGRES_PASSWORD"); $pass = getenv("POSTGRES_PASSWORD");
@ -275,19 +299,22 @@ class DatabaseHelper {
return $this->conn; return $this->conn;
} }
public function select(string $select): DatabaseQuery { public function select(string $select): DatabaseQuery
{
$conn = $this->connect(); $conn = $this->connect();
$query = new DatabaseQuery($conn); $query = new DatabaseQuery($conn);
return $query->select($select); return $query->select($select);
} }
public function insert_into(string $insert, string ...$columns): DatabaseQuery { public function insert_into(string $insert, string ...$columns): DatabaseQuery
{
$conn = $this->connect(); $conn = $this->connect();
$query = new DatabaseQuery($conn); $query = new DatabaseQuery($conn);
return $query->insert_into($insert, ...$columns); return $query->insert_into($insert, ...$columns);
} }
public function query(string $query_str): DatabaseQuery { public function query(string $query_str): DatabaseQuery
{
$conn = $this->connect(); $conn = $this->connect();
$query = new DatabaseQuery($conn); $query = new DatabaseQuery($conn);
return $query->query($query_str); return $query->query($query_str);

View file

@ -1,6 +1,7 @@
<?php /* Copyright (c) 2024 Freya Murphy */ <?php /* Copyright (c) 2024 Freya Murphy */
function __get_mime($type) { function __get_mime($type)
{
switch ($type) { switch ($type) {
case 'mp4': case 'mp4':
return 'video/mp4'; return 'video/mp4';
@ -22,15 +23,14 @@ function __get_mime($type) {
function __make_source( function __make_source(
$name, $name,
$format, $format,
$media $media)
) { {
if ($media) { if ($media) {
$media = "media=\"$media\""; $media = "media=\"$media\"";
} else { } else {
$media = ''; $media = '';
} }
$main = $GLOBALS['main_model']; $path = Core::get_url('public/' . $name . '.' . $format, TRUE);
$path = $main->get_url('public/' . $name . '.' . $format, TRUE);
$mime = __get_mime($format); $mime = __get_mime($format);
return sprintf('<source type="%s" srcset="%s" %s>', return sprintf('<source type="%s" srcset="%s" %s>',
$mime, $path, $media); $mime, $path, $media);
@ -45,8 +45,8 @@ function image(
$height = NULL, $height = NULL,
$width = NULL, $width = NULL,
$size = NULL, $size = NULL) :string
) :string { {
if ($animated === TRUE) { if ($animated === TRUE) {
$animated = array('gif'); $animated = array('gif');
@ -68,8 +68,7 @@ function image(
} }
$format = end($formats); $format = end($formats);
$main = $GLOBALS['main_model']; $path = Core::get_url('public/' . $name . '.' . $format, TRUE);
$path = $main->get_url('public/' . $name . '.' . $format, TRUE);
$out .= "<img src=\"$path\""; $out .= "<img src=\"$path\"";
if ($alt) { if ($alt) {
$alt = lang($alt); $alt = lang($alt);

View file

@ -1,5 +1,5 @@
<?php /* Copyright (c) 2024 Freya Murphy */ <?php /* Copyright (c) 2024 Freya Murphy */
$lang = array(); $__lang = array();
/** /**
* @param ?array<string,mixed> $sub * @param ?array<string,mixed> $sub
@ -8,7 +8,7 @@ function lang(
string $key, string $key,
?string $default = NULL, ?string $default = NULL,
?array $sub = NULL) { ?array $sub = NULL) {
$lang = $GLOBALS['lang']; $lang = $GLOBALS['__lang'];
if(array_key_exists($key, $lang)) { if(array_key_exists($key, $lang)) {
if ($sub) { if ($sub) {
return sprintf($lang[$key], ...$sub); return sprintf($lang[$key], ...$sub);

View file

@ -1,39 +1,57 @@
<?php /* Copyright (c) 2024 Freya Murphy */ <?php /* Copyright (c) 2024 Freya Murphy */
// ========================= ENVIRONMENT ==
ini_set('html_errors', '1'); ini_set('html_errors', '1');
$webroot = dirname(__FILE__); // ENVIRONMENT
$assetroot = realpath(dirname(__FILE__) . '/../assets'); //
$publicroot = realpath(dirname(__FILE__) . '/../public'); // devlopment - do not cache any assets
$rootroot = realpath(dirname(__FILE__) . '/..'); // - allways reload
$main_model = NULL; //
// production - use generated timestamps
// - for eachfile
//
define('ENVIRONMENT', 'devlopment');
// loadd all third party // FOLDER_ROOT
require($webroot . '/third_party/parsedown.php'); //
require($webroot . '/third_party/parsedown_extra.php'); // define folder directiroy paths based on this file
define('PHP_ROOT', dirname(__FILE__) . '/..');
define('WEB_ROOT', PHP_ROOT . '/web');
define('ASSET_ROOT', PHP_ROOT . '/assets');
define('PUBLIC_ROOT', PHP_ROOT . '/public');
// ========================== BOOTSTRAP ==
// load all third party
require(WEB_ROOT . '/third_party/parsedown.php');
require(WEB_ROOT . '/third_party/parsedown_extra.php');
// load all the config files // load all the config files
require($webroot . '/config/routes.php'); require(WEB_ROOT . '/config/routes.php');
require($webroot . '/config/style.php'); require(WEB_ROOT . '/config/style.php');
// load all the helpers // load all the helpers
require($webroot . '/helpers/lang.php'); require(WEB_ROOT . '/helpers/lang.php');
require($webroot . '/helpers/aria.php'); require(WEB_ROOT . '/helpers/aria.php');
require($webroot . '/helpers/image.php'); require(WEB_ROOT . '/helpers/image.php');
require($webroot . '/helpers/markdown.php'); require(WEB_ROOT . '/helpers/markdown.php');
require($webroot . '/helpers/database.php'); require(WEB_ROOT . '/helpers/database.php');
require($webroot . '/helpers/sanitize.php'); require(WEB_ROOT . '/helpers/sanitize.php');
// load all core files // load all core files
require($webroot . '/core/_controller.php'); require(WEB_ROOT . '/core/core.php');
require($webroot . '/core/_model.php'); require(WEB_ROOT . '/core/component.php');
require($webroot . '/core/loader.php'); require(WEB_ROOT . '/core/controller.php');
require($webroot . '/core/router.php'); require(WEB_ROOT . '/core/model.php');
require(WEB_ROOT . '/core/router.php');
// ============================== START ==
function __init() { function __init() {
$load = new Loader(); $router = new Router();
$router = new Router($load); $router->handle_req();
$router->handle_request();
}; };
__init(); __init();