$override_value) { if (!array_key_exists($override_key, $config)) { trigger_error('Undefined key in config file', E_USER_ERROR); } if (gettype($override_value) !== gettype($config[$override_key])) { trigger_error('Type mismatch in config file', E_USER_ERROR); } $config[$override_key] = $override_value; } return $config[$key]; } /** * Helper for evaluating/including views */ function view(string $_view, array $_data = []) { $_path = __DIR__ . '/../views/' . $_view . '.php'; extract($_data); require $_path; } /** * Helper for converting and outputting JSON */ function json_response(mixed $data, int $status_code = 200) { http_response_code($status_code); header('Content-type: application/json'); echo json_encode($data); } /** * Helper for reading and decoding JSON from request body */ function json_decode_input(): array|bool|null { return json_decode(file_get_contents('php://input'), true); } /** * Helper for generating URLs */ function url(string $url, bool $full = false): string { $dir = dirname($_SERVER['SCRIPT_NAME']); if ($dir === '/') { $dir = ''; } if (!$full) { return $dir . $url; } return isset($_SERVER['HTTPS']) ? 'https' : 'http' . '://' . $_SERVER['HTTP_HOST'] . $dir . $url; } //----------------------------------------------------- // Let's get routing! //----------------------------------------------------- use WillySoft\ErrorHandler; use WillySoft\Route; Route::get('/', function() { view('pages/home'); }); ErrorHandler::register(function($error_messages) { if (config('debug')) { view('errors/500', ['error_messages' => $error_messages]); } else { view('errors/500', ['error_messages' => []]); } }); Route::group(function() { Route::get('/', fn() => view('pages/home')); Route::get('/echo/$text?', fn($text= 'You sent nothing...') => json_response($text)); Route::get('/error', fn() => 1 / 0); }); Route::group(function() { if (!config('debug')) { return; } Route::get('/blog/', fn() => view('pages/blog/home')); Route::get('/blog/test', fn() => view('pages/blog/test')); }); Route::group(function() { $data_path = '/dev/shm/database.json'; $messages = []; Route::middleware(function() use (&$data_path, &$messages) { if (!file_exists($data_path)) { file_put_contents( $data_path, json_encode([]) ); } $messages = json_decode( file_get_contents($data_path), true ); }); Route::form('/willychat/', function() use (&$data_path, &$messages) { if (empty($_POST)) { return view('pages/willychat/index', [ 'nick' => 'Willy', 'just_sent_message' => false, 'errmsg' => false ]); } $nick = filter_input(INPUT_POST, 'nick'); $text = filter_input(INPUT_POST, 'text'); $errmsg = (function() use (&$text, &$nick): string|false { if (empty(trim($nick, ' '))) { return 'You must choose a nickname.'; } $nick_max_chars = 128; if (strlen($nick) > $nick_max_chars) { return 'Your nickname is TOO LONG! ' . strlen($nick) . ' out of ' . $nick_max_chars. ' characters.'; } $text_max_chars = 4096; if (strlen($text) > $text_max_chars) { return 'Your message is TOO LONG!!!! ' . strlen($text) . ' out of ' . $text_max_chars . ' characters.'; } if (empty(trim($text, ' '))) { return 'Message body cannot be empty.'; } return false; })(); if (!$errmsg) { if (count($messages) > 100) { array_pop($messages); } array_unshift($messages, [ 'nick' => $nick, 'date' => time(), 'text' => $text ]); file_put_contents($data_path, json_encode( $messages ) ); } view('pages/willychat/index', [ 'nick' => $nick, 'just_sent_message' => true, 'errmsg' => $errmsg ]); }); Route::get('/willychat/messages', function() use (&$messages) { view('pages/willychat/messages', ['messages' => $messages]); }); Route::get('/willychat/sync', function() use (&$messages) { json_response(hash('crc32', serialize($messages))); }); }); http_response_code(404); view('errors/404');