'Home', 'link' => '/'], //['title' => 'Blog', 'link' => '//blog.flash.moe'], ['title' => 'Blog', 'link' => '//flash.moe/2020/?blog=1'], ['title' => 'Projects', 'link' => '/projects'], ['title' => 'Contact', 'link' => '/contact'], //['title' => 'Related', 'link' => '/related'], ['title' => 'Etcetera', 'link' => '/etc'], ['title' => 'Forum', 'link' => '//forum.flash.moe'], ]); define('FM_BGS', [ '//mikoto.misaka.nl/i/Konachan.com%20-%20164484%20blush%20brown_eyes%20brown_hair%20drink%20misaka_mikoto%20seifuku%20short_hair%20skirt%20socks%20to_aru_kagaku_no_railgun%20to_aru_majutsu_no_index.png', '//mikoto.misaka.nl/i/misaka%202.png', '//mikoto.misaka.nl/i/misaka.jpg', '//mikoto.misaka.nl/i/Drl8DEPWwAAPniH.jpg', '//mikoto.misaka.nl/i/65776322_p2_master1200.jpg', '//mikoto.misaka.nl/i/52666925_p0.jpg', '//mikoto.misaka.nl/i/44161767_p0.jpg', '//mikoto.misaka.nl/i/32809110_p0.jpg', '//mikoto.misaka.nl/i/1551886307-ZEgXIk2.jpg', '//mikoto.misaka.nl/i/1551886971-MgnvSNG.jpg', '//mikoto.misaka.nl/i/1551881563-wR2Dcx8.jpg', '//mikoto.misaka.nl/i/1552084409-BsTLlKg.jpg', ]); define('FM_FEET', [ 'if it ain\'t broke, i\'ll break it', ]); define('FM_ERRS' , [ 403 => ['code' => 403, 'title' => 'Access Denied'], 404 => ['code' => 404, 'title' => 'Not Found'], 405 => ['code' => 405, 'title' => 'Method Not Supported'], ]); function fm_component(string $name, array $vars = []) { extract($vars); require __DIR__ . '/../components/' . $name . '.php'; } function first_paragraph(string $text, string $delimiter = "\n"): string { $index = mb_strpos($text, $delimiter); return $index === false ? $text : mb_substr($text, 0, $index); } function time_elapsed(int $since, bool $full = false): string { $now = new DateTime; $since = new DateTime(date('c', $since)); $diff = $now->diff($since); $diff->w = floor($diff->d / 7); $diff->d -= $diff->w * 7; $string = [ 'y' => 'year', 'm' => 'month', 'w' => 'week', 'd' => 'day', 'h' => 'hour', 'i' => 'minute', 's' => 'second', ]; foreach($string as $key => &$value) { if($diff->{$key}) $value = $diff->{$key} . ' ' . $value . ($diff->{$key} > 1 ? 's' : ''); else unset($string[$key]); } if(!$full) $string = array_slice($string, 0, 1); return $string ? implode(', ', $string) . ' ago' : 'just now'; } function cache_output(string $name, int $lifetime, callable $callable) { $path = sys_get_temp_dir() . '/fm-' . $name . '.cache'; if(!is_file($path) || (filemtime($path) + $lifetime) < time()) file_put_contents($path, serialize($callable())); return unserialize(file_get_contents($path)); } set_include_path(realpath(__DIR__ . '/../lib/') . PATH_SEPARATOR . get_include_path()); spl_autoload_extensions('.php'); spl_autoload_register(); ob_start(); $reqMethod = filter_input(INPUT_SERVER, 'REQUEST_METHOD', FILTER_SANITIZE_STRING); $reqPath = '/' . trim(parse_url(filter_input(INPUT_SERVER, 'REQUEST_URI', FILTER_SANITIZE_STRING), PHP_URL_PATH), '/'); if(substr($reqPath, 0, 7) === '/error/') { $statusCode = intval(substr($reqPath, 8, 3)); } else { foreach(glob(__DIR__ . '/../pages/*.php') as $page) { $result = include_once $page; $statusCode = $result & 0xFFF; if(($result & FM_HIT) === FM_HIT) { if($statusCode >= 100 && $statusCode <= 999) http_response_code($statusCode); return; } if(($result & FM_ERR) === FM_ERR) break; } } $errorInfo = FM_ERRS[$statusCode ?? 404] ?? FM_ERRS[404]; http_response_code($errorInfo['code']); fm_component('header', ['title' => $errorInfo['title']]); printf("

%s

\r\n", $errorInfo['title']); fm_component('footer');