/', '', $content); } /** * Parses custom `` tags from the given input string and extracts parameters. * Returns the input string with `` tags removed and a list of parameters. * * @param string $input The input HTML or text containing `` tags. * @return array Returns an associative array with 'parameters' (parsed from the tag) * and 'output' (the modified input string with `` tags removed). */ function parsePageTag(string $input): array { // Define the pattern for the tag $pattern = '/]+)><\/page>/i'; // Check if the pattern matches the input if (preg_match($pattern, $input, $matches)) { // Extract parameters $parameters = []; if (preg_match_all('/(\w+)="([^"]+)"/', $matches[1], $paramMatches, PREG_SET_ORDER)) { foreach ($paramMatches as $paramMatch) { $parameters[$paramMatch[1]] = $paramMatch[2]; } } // Remove the tag from the input $output = preg_replace($pattern, '', $input, 1); return ['parameters' => $parameters, 'output' => $output]; } // If no match is found, return the original input return ['parameters' => [], 'output' => $input]; } /** * Renders a page based on specified page and site names, handling dynamic and static content, * permissions, and error pages. * * @param string|null $page_name The name of the page to render. If null, uses default from request. * @param string|null $site_name The name of the site to render. If null, uses default from request. * @return array Returns an associative array containing the rendered page content, page name, site name, and page title. */ function renderPage(string $page_name = null, string $site_name = null): array { global $routerConfig; global $routerRequest; if(!$site_name) { $site_name = $routerRequest["site_name"]; } $site_title = str_replace("_", " ", $site_name); $site_title = ucfirst($site_title); if(!$page_name){ $page_name = $routerRequest["page_name"]; } $dynamic_page_file = $routerConfig["page_dir"] . $site_name . "/" . $page_name . ".php"; $page_file = $routerConfig["page_dir"] . $site_name . "/" . $page_name . ".html"; if (file_exists($dynamic_page_file)){ $pageMetadata = renderDynamicPage($dynamic_page_file); $page = $pageMetadata["output"]; } elseif (file_exists($page_file)){ $page_tmp = file_get_contents($page_file); $pageMetadata = parsePageTag($page_tmp); $page = $pageMetadata["output"]; } else{ $page_tmp = file_get_contents($routerConfig["template_dir"] . "404.html"); $pageMetadata = parsePageTag($page_tmp); $page = $pageMetadata["output"]; http_response_code(404); } if(!empty($pageMetadata["parameters"]["minimal_permission_level"])){ $page_required_permission = intval($pageMetadata["parameters"]["minimal_permission_level"]); } else{ $page_required_permission = $routerConfig["page"]["default_permissions"]; } if(!empty($pageMetadata["parameters"]["secret"])){ $origSecret = $pageMetadata["parameters"]["secret"]; if ($origSecret == "yes"){ $is_secret_page = 1; } elseif ($origSecret == "no"){ $is_secret_page = 0; } else{ $is_secret_page = $routerConfig["page"]["default_secret"]; } } else{ $is_secret_page = $routerConfig["page"]["default_secret"]; } if($page_required_permission > $_SESSION["privilege_level"]){ if($is_secret_page == 1) { $page_tmp = file_get_contents($routerConfig["template_dir"] . "404.html"); $pageMetadata = parsePageTag($page_tmp); $page = $pageMetadata["output"]; http_response_code(404); } else{ $page_tmp = file_get_contents($routerConfig["template_dir"] . "403.html"); $pageMetadata = parsePageTag($page_tmp); $page = $pageMetadata["output"]; http_response_code(403); } } $page = str_replace("__DEFAULT_LINK__", "/" . $routerConfig["default_site"] . "/" . $routerConfig["default_page"], $page); if(!is_string($page)){ $page = ""; } if(!empty($pageMetadata["parameters"]["page_title"])){ $page_title = $pageMetadata["parameters"]["page_title"]; } else{ $page_title = $page_name; } $page_title = $routerConfig['site_prefix'] . " " . $site_title . " " . $page_title; $page = str_replace("__TEMPLATE_PAGE_TITLE__", $page_title, $page); $page = removeHtmlComments($page); return [ "PageContent" => $page, "PageName" => $page_name, "SiteName" => $site_name, "PageTitle" => $page_title, ]; } /** * Compiles a complete web page by injecting dynamic elements into a template skeleton, * including headers, footers, and SEO tags. * It is used when not going to a page by AJAX to initialize everything. * * @param string|null $site_name_in The site name to be used; defaults from global configuration if null. * @param string|null $page_name_in The page name to be used; defaults from global configuration if null. * @return string The complete HTML content of the web page ready for display. */ function getPage(string $site_name_in = null, string $page_name_in = null): string { $page_tmp = renderPage($page_name_in, $site_name_in); $page = $page_tmp["PageContent"]; $page_name = $page_tmp["PageName"]; $site_name = $page_tmp["SiteName"]; global $routerConfig; $skeleton = file_get_contents($routerConfig["template_dir"] . "skeleton.html"); $footer = file_get_contents($routerConfig["template_dir"] . "footer.html"); $page_title = $page_tmp["PageTitle"]; $dynamic_style = doDynamicStyling(); $dynamic_script_data = [ "currentPage" => $page_name, "currentSite" => $site_name, "currentTitle" => $page_title, "defaultPage" => $routerConfig["default_page"], "defaultSite" => $routerConfig["default_site"], "UserInfo_Privileges" => $_SESSION["privilege_level"], ]; if(isLoggedIn()){ $dynamic_script_data += [ "UserInfo_FirstName" => $_SESSION["first_name"], "UserInfo_LastName" => $_SESSION["last_name"], "UserInfo_Nickname" => $_SESSION["nickname"], "UserInfo_Email" => $_SESSION["email"], "UserInfo_MinecraftNick" => $_SESSION["minecraft_nickname"], ]; } $dynamic_script = generateScriptData($dynamic_script_data); $navigation = generateNavigation(); $seo = array(); if(!empty($pageMetadata["parameters"]["author"])){ $seo["author"] = htmlspecialchars($pageMetadata["parameters"]["author"]); } else{ $seo["author"] = $routerConfig["seo"]["author"]; } if(!empty($pageMetadata["parameters"]["description"])){ $seo["description"] = htmlspecialchars($pageMetadata["parameters"]["description"]); } else{ $seo["description"] = $routerConfig["seo"]["description"]; } if(!empty($pageMetadata["parameters"]["keywords"])){ $seo["keywords"] = $routerConfig["seo"]["keywords"] . ", " . htmlspecialchars($pageMetadata["parameters"]["keywords"]); } else{ $seo["keywords"] = $routerConfig["seo"]["keywords"]; } $seo["generator"] = $routerConfig["seo"]["generator"]; $seo["robots"] = $routerConfig["seo"]["robots"]; $seo_stuff = ""; foreach ($seo as $key => $value){ $seo_stuff .= "\n"; } $out = $skeleton; $out = str_replace("__TEMPLATE__NAV__", $navigation, $out); $out = str_replace("__TEMPLATE__PAGE__", $page, $out); $out = str_replace("__TEMPLATE__FOOTER__", $footer, $out); $out = str_replace("__TEMPLATE__DYNAMIC__SCRIPT__", $dynamic_script, $out); $out = str_replace("__TEMPLATE__DYNAMIC__STYLE__", $dynamic_style, $out); $out = str_replace("__TEMPLATE_SEO_STUFF__", $seo_stuff, $out); if($routerConfig["inlining"]) { require_once "lib/inliner.php"; $out = inlineLocalStylesFromHref($out); $out = inlineScriptFromSrc($out); } return str_replace("__TEMPLATE_PAGE_TITLE__", $page_title, $out); } /** * Provides an API interface to get page details including content and meta-information for routing purposes. * This is what enables the page to never refresh. * * @param string $page_name The name of the page. * @param string $site_name The name of the site. * @return array Returns an array with status, page content, location URL, and title for the requested page. */ function getPageEndpoint(string $page_name, string $site_name) :array { $page_location = "/" . $site_name . "/" . $page_name; $page_tmp = renderPage($page_name, $site_name); return [ "Status" => "Success", "Page" => $page_tmp["PageContent"], "PageLocation" => $page_location, "PageTitle" => $page_tmp["PageTitle"], ]; }