Begin work on access control. Add variable and a setting, but they aren't used yet.

This commit is contained in:
Starbeamrainbowlabs 2015-11-05 10:00:04 +00:00
parent 173a72fa46
commit 22dad4cab3
1 changed files with 84 additions and 77 deletions

161
core.php
View File

@ -14,6 +14,13 @@ $env->user = "Anonymous";
$env->is_logged_in = false; $env->is_logged_in = false;
$env->is_admin = false; $env->is_admin = false;
$paths = new stdClass();
$paths->pageindex = "pageindex.json";
$paths->searchindex = "invindex.json";
$paths->idindex = "idindex.json";
$paths->upload_file_prefix = "Files/";
session_start(); session_start();
///////// Login System ///////// ///////// Login System /////////
// Clear expired sessions // Clear expired sessions
@ -78,7 +85,7 @@ if($env->is_logged_in)
* @summary Converts a filesize into a human-readable string. * @summary Converts a filesize into a human-readable string.
* @source http://php.net/manual/en/function.filesize.php#106569 * @source http://php.net/manual/en/function.filesize.php#106569
* @editor Starbeamrainbowlabs * @editor Starbeamrainbowlabs
* *
* @param $bytes - The number of bytes to convert. * @param $bytes - The number of bytes to convert.
* @param $decimals - The number of decimal places to preserve. * @param $decimals - The number of decimal places to preserve.
*/ */
@ -92,9 +99,9 @@ function human_filesize($bytes, $decimals = 2)
* @summary Calculates the time sincce a particular timestamp and returns a * @summary Calculates the time sincce a particular timestamp and returns a
* human-readable result. * human-readable result.
* @source http://snippets.pro/snippet/137-php-convert-the-timestamp-to-human-readable-format/ * @source http://snippets.pro/snippet/137-php-convert-the-timestamp-to-human-readable-format/
* *
* @param $time - The timestamp to convert. * @param $time - The timestamp to convert.
* *
* @returns {string} - The time since the given timestamp pas a human-readable string. * @returns {string} - The time since the given timestamp pas a human-readable string.
*/ */
function human_time_since($time) function human_time_since($time)
@ -118,10 +125,10 @@ function human_time_since($time)
/* /*
* @summary A recursive glob() function. * @summary A recursive glob() function.
* *
* @param $pattern - The glob pattern to use to find filenames. * @param $pattern - The glob pattern to use to find filenames.
* @param $flags - The glob flags to use when finding filenames. * @param $flags - The glob flags to use when finding filenames.
* *
* @returns {array} - An array of the filepaths that match the given glob. * @returns {array} - An array of the filepaths that match the given glob.
*/ */
// From http://in.php.net/manual/en/function.glob.php#106595 // From http://in.php.net/manual/en/function.glob.php#106595
@ -140,17 +147,17 @@ function glob_recursive($pattern, $flags = 0)
/* /*
* @summary Gets a list of all the sub pages of the current page. * @summary Gets a list of all the sub pages of the current page.
* *
* @param $pageindex - The pageindex to use to search. * @param $pageindex - The pageindex to use to search.
* @param $pagename - The name of the page to list the sub pages of. * @param $pagename - The name of the page to list the sub pages of.
* *
* @returns An objectt containing all the subpages, and their respective distances from the given page name in the pageindex tree. * @returns An objectt containing all the subpages, and their respective distances from the given page name in the pageindex tree.
*/ */
function get_subpages($pageindex, $pagename) function get_subpages($pageindex, $pagename)
{ {
$pagenames = get_object_vars($pageindex); $pagenames = get_object_vars($pageindex);
$result = new stdClass(); $result = new stdClass();
$stem = "$pagename/"; $stem = "$pagename/";
$stem_length = strlen($stem); $stem_length = strlen($stem);
foreach($pagenames as $entry => $value) foreach($pagenames as $entry => $value)
@ -158,7 +165,7 @@ function get_subpages($pageindex, $pagename)
if(substr($entry, 0, $stem_length) == $stem) if(substr($entry, 0, $stem_length) == $stem)
{ {
// We found a subpage // We found a subpage
// Extract the subpage's key relative to the page that we are searching for // Extract the subpage's key relative to the page that we are searching for
$subpage_relative_key = substr($entry, $stem_length, -3); $subpage_relative_key = substr($entry, $stem_length, -3);
// Calculate how many times removed the current subpage is from the current page. 0 = direct descendant. // Calculate how many times removed the current subpage is from the current page. 0 = direct descendant.
@ -167,16 +174,16 @@ function get_subpages($pageindex, $pagename)
$result->$entry = $times_removed; $result->$entry = $times_removed;
} }
} }
unset($pagenames); unset($pagenames);
return $result; return $result;
} }
/* /*
* @summary Makes sure that a subpage's parents exist. Note this doesn't check the pagename itself. * @summary Makes sure that a subpage's parents exist. Note this doesn't check the pagename itself.
* *
* @param The pagename to check. * @param The pagename to check.
* *
*/ */
function check_subpage_parents($pagename) function check_subpage_parents($pagename)
{ {
@ -187,14 +194,14 @@ function check_subpage_parents($pagename)
file_put_contents("./pageindex.json", json_encode($pageindex, JSON_PRETTY_PRINT)); file_put_contents("./pageindex.json", json_encode($pageindex, JSON_PRETTY_PRINT));
return; return;
} }
$parent_pagename = substr($pagename, 0, strrpos($pagename, "/")); $parent_pagename = substr($pagename, 0, strrpos($pagename, "/"));
$parent_page_filename = "$parent_pagename.md"; $parent_page_filename = "$parent_pagename.md";
if(!file_exists($parent_page_filename)) if(!file_exists($parent_page_filename))
{ {
// This parent page doesn't exist! Create it and add it to the page index. // This parent page doesn't exist! Create it and add it to the page index.
touch($parent_page_filename, 0); touch($parent_page_filename, 0);
$newentry = new stdClass(); $newentry = new stdClass();
$newentry->filename = $parent_page_filename; $newentry->filename = $parent_page_filename;
$newentry->size = 0; $newentry->size = 0;
@ -202,13 +209,13 @@ function check_subpage_parents($pagename)
$newentry->lasteditor = "none"; $newentry->lasteditor = "none";
$pageindex->$parent_pagename = $newentry; $pageindex->$parent_pagename = $newentry;
} }
check_subpage_parents($parent_pagename); check_subpage_parents($parent_pagename);
} }
/* /*
* @summary makes a path safe * @summary makes a path safe
* *
* @details paths may only contain alphanumeric characters, spaces, underscores, and dashes * @details paths may only contain alphanumeric characters, spaces, underscores, and dashes
*/ */
function makepathsafe($string) function makepathsafe($string)
@ -220,7 +227,7 @@ function makepathsafe($string)
/* /*
* @summary Hides an email address from bots by adding random html entities. * @summary Hides an email address from bots by adding random html entities.
* *
* @returns The mangled email address. * @returns The mangled email address.
*/ */
function hide_email($str) function hide_email($str)
@ -238,15 +245,15 @@ function hide_email($str)
else else
$hidden_email .= "&#" . ord($str[$i]) . ";"; $hidden_email .= "&#" . ord($str[$i]) . ";";
} }
return $hidden_email; return $hidden_email;
} }
/* /*
* @summary Checks to see if $haystack starts with $needle. * @summary Checks to see if $haystack starts with $needle.
* *
* @param $haystack {string} The string to search. * @param $haystack {string} The string to search.
* @param $needle {string} The string to search for at the beginning of $haystack. * @param $needle {string} The string to search for at the beginning of $haystack.
* *
* @returns {boolean} Whether $needle can be found at the beginning of $haystack. * @returns {boolean} Whether $needle can be found at the beginning of $haystack.
*/ */
function starts_with($haystack, $needle) function starts_with($haystack, $needle)
@ -305,7 +312,7 @@ if(!file_exists("./pageindex.json"))
for($i = 0; $i < count($existingpages); $i++) for($i = 0; $i < count($existingpages); $i++)
{ {
$pagefilename = $existingpages[$i]; $pagefilename = $existingpages[$i];
// Create a new entry // Create a new entry
$newentry = new stdClass(); $newentry = new stdClass();
$newentry->filename = utf8_encode($pagefilename); // Store the filename $newentry->filename = utf8_encode($pagefilename); // Store the filename
@ -315,7 +322,7 @@ if(!file_exists("./pageindex.json"))
$newentry->lasteditor = utf8_encode("unknown"); // Set the editor to "unknown" $newentry->lasteditor = utf8_encode("unknown"); // Set the editor to "unknown"
// Extract the name of the (sub)page without the ".md" // Extract the name of the (sub)page without the ".md"
$pagekey = utf8_encode(substr($pagefilename, 0, -3)); $pagekey = utf8_encode(substr($pagefilename, 0, -3));
// Subpage parent checker // Subpage parent checker
if(strpos($pagekey, "/") !== false) if(strpos($pagekey, "/") !== false)
{ {
@ -334,7 +341,7 @@ if(!file_exists("./pageindex.json"))
$existingpages[] = $subpage_parent_filename; $existingpages[] = $subpage_parent_filename;
} }
} }
// Store the new entry in the new page index // Store the new entry in the new page index
$pageindex->$pagekey = $newentry; $pageindex->$pagekey = $newentry;
} }
@ -362,30 +369,30 @@ class ids
public static function getid($pagename) public static function getid($pagename)
{ {
global $idindex; global $idindex;
foreach ($idindex as $id => $entry) foreach ($idindex as $id => $entry)
{ {
if($entry == $pagename) if($entry == $pagename)
return $id; return $id;
} }
// This pagename doesn't have an id - assign it one quick! // This pagename doesn't have an id - assign it one quick!
return self::assign($pagename); return self::assign($pagename);
} }
/* /*
* @summary Gets the page name associated with the given page id. * @summary Gets the page name associated with the given page id.
*/ */
public static function getpagename($id) public static function getpagename($id)
{ {
global $idindex; global $idindex;
if(!isset($idindex->$id)) if(!isset($idindex->$id))
return false; return false;
else else
return $idindex->$id; return $idindex->$id;
} }
/* /*
* @summary Assigns an id to a pagename. Doesn't check to make sure that * @summary Assigns an id to a pagename. Doesn't check to make sure that
* pagename doesn't exist in the pageindex. * pagename doesn't exist in the pageindex.
@ -393,18 +400,18 @@ class ids
protected static function assign($pagename) protected static function assign($pagename)
{ {
global $idindex; global $idindex;
$nextid = count(array_keys(get_object_vars($idindex))); $nextid = count(array_keys(get_object_vars($idindex)));
if(isset($idindex->$nextid)) if(isset($idindex->$nextid))
throw new Exception("The pageid is corrupt! Pepperminty Wiki generated the id $nextid, but that id is already in use."); throw new Exception("The pageid is corrupt! Pepperminty Wiki generated the id $nextid, but that id is already in use.");
// Update the id index // Update the id index
$idindex->$nextid = utf8_encode($pagename); $idindex->$nextid = utf8_encode($pagename);
// Save the id index // Save the id index
file_put_contents("idindex.json", json_encode($idindex)); file_put_contents("idindex.json", json_encode($idindex));
return $nextid; return $nextid;
} }
} }
@ -464,13 +471,13 @@ class page_renderer
</body> </body>
</html> </html>
"; ";
public static $main_content_template = "{navigation-bar} public static $main_content_template = "{navigation-bar}
<h1 class='sitename'>{sitename}</h1> <h1 class='sitename'>{sitename}</h1>
<main> <main>
{content} {content}
</main> </main>
<footer> <footer>
<p>{footer-message}</p> <p>{footer-message}</p>
<p>Powered by Pepperminty Wiki {version}, which was built by <a href='//starbeamrainbowlabs.com/'>Starbeamrainbowlabs</a>. Send bugs to 'bugs at starbeamrainbowlabs dot com' or <a href='//github.com/sbrl/Pepperminty-Wiki' title='Github Issue Tracker'>open an issue</a>.</p> <p>Powered by Pepperminty Wiki {version}, which was built by <a href='//starbeamrainbowlabs.com/'>Starbeamrainbowlabs</a>. Send bugs to 'bugs at starbeamrainbowlabs dot com' or <a href='//github.com/sbrl/Pepperminty-Wiki' title='Github Issue Tracker'>open an issue</a>.</p>
@ -487,17 +494,17 @@ class page_renderer
<p><em>Timed at {generation-date}</em></p> <p><em>Timed at {generation-date}</em></p>
<p><em>Powered by Pepperminty Wiki {version}.</em></p> <p><em>Powered by Pepperminty Wiki {version}.</em></p>
</footer>"; </footer>";
// An array of functions that have been registered to process the // An array of functions that have been registered to process the
// find / replace array before the page is rendered. Note that the function // find / replace array before the page is rendered. Note that the function
// should take a *reference* to an array as its only argument. // should take a *reference* to an array as its only argument.
protected static $part_processors = []; protected static $part_processors = [];
// Registers a function as a part post processor. // Registers a function as a part post processor.
public static function register_part_preprocessor($function) public static function register_part_preprocessor($function)
{ {
global $settings; global $settings;
// Make sure that the function we are about to register is valid // Make sure that the function we are about to register is valid
if(!is_callable($function)) if(!is_callable($function))
{ {
@ -506,19 +513,19 @@ class page_renderer
$admin_email = hide_email($settings->admindetails["email"]); $admin_email = hide_email($settings->admindetails["email"]);
exit(page_renderer::render("$settings->sitename - Module Error", "<p>$settings->sitename has got a misbehaving module installed that tried to register an invalid HTML handler with the page renderer. Please contact $settings->sitename's administrator $admin_name at <a href='mailto:$admin_email'>$admin_email</a>.")); exit(page_renderer::render("$settings->sitename - Module Error", "<p>$settings->sitename has got a misbehaving module installed that tried to register an invalid HTML handler with the page renderer. Please contact $settings->sitename's administrator $admin_name at <a href='mailto:$admin_email'>$admin_email</a>."));
} }
self::$part_processors[] = $function; self::$part_processors[] = $function;
return true; return true;
} }
public static function render($title, $content, $body_template = false) public static function render($title, $content, $body_template = false)
{ {
global $settings, $start_time, $version; global $settings, $start_time, $version;
if($body_template === false) if($body_template === false)
$body_template = self::$main_content_template; $body_template = self::$main_content_template;
if(strlen($settings->logo_url) > 0) if(strlen($settings->logo_url) > 0)
{ {
// A logo url has been specified // A logo url has been specified
@ -535,50 +542,50 @@ class page_renderer
throw new Exception("Invalid logo_position '$settings->logo_position'. Valid values are either \"left\" or \"right\" and are case sensitive."); throw new Exception("Invalid logo_position '$settings->logo_position'. Valid values are either \"left\" or \"right\" and are case sensitive.");
} }
} }
$parts = [ $parts = [
"{body}" => $body_template, "{body}" => $body_template,
"{sitename}" => $logo_html, "{sitename}" => $logo_html,
"{version}" => $version, "{version}" => $version,
"{favicon-url}" => $settings->favicon, "{favicon-url}" => $settings->favicon,
"{header-html}" => self::get_css_as_html(), "{header-html}" => self::get_css_as_html(),
"{navigation-bar}" => self::render_navigation_bar($settings->nav_links, $settings->nav_links_extra, "top"), "{navigation-bar}" => self::render_navigation_bar($settings->nav_links, $settings->nav_links_extra, "top"),
"{navigation-bar-bottom}" => self::render_navigation_bar($settings->nav_links_bottom, [], "bottom"), "{navigation-bar-bottom}" => self::render_navigation_bar($settings->nav_links_bottom, [], "bottom"),
"{admin-details-name}" => $settings->admindetails["name"], "{admin-details-name}" => $settings->admindetails["name"],
"{admin-details-email}" => $settings->admindetails["email"], "{admin-details-email}" => $settings->admindetails["email"],
"{admins-name-list}" => implode(", ", $settings->admins), "{admins-name-list}" => implode(", ", $settings->admins),
"{generation-date}" => date("l jS \of F Y \a\\t h:ia T"), "{generation-date}" => date("l jS \of F Y \a\\t h:ia T"),
"{all-pages-datalist}" => self::generate_all_pages_datalist(), "{all-pages-datalist}" => self::generate_all_pages_datalist(),
"{footer-message}" => $settings->footer_message, "{footer-message}" => $settings->footer_message,
/// Secondary Parts /// /// Secondary Parts ///
"{content}" => $content, "{content}" => $content,
"{title}" => $title, "{title}" => $title,
]; ];
// Pass the parts through the part processors // Pass the parts through the part processors
foreach(self::$part_processors as $function) foreach(self::$part_processors as $function)
{ {
$function($parts); $function($parts);
} }
$result = self::$html_template; $result = self::$html_template;
$result = str_replace(array_keys($parts), array_values($parts), $result); $result = str_replace(array_keys($parts), array_values($parts), $result);
$result = str_replace([ $result = str_replace([
], [ ], [
], $result); ], $result);
$result = str_replace("{generation-time-taken}", microtime(true) - $start_time, $result); $result = str_replace("{generation-time-taken}", microtime(true) - $start_time, $result);
return $result; return $result;
} }
@ -590,24 +597,24 @@ class page_renderer
{ {
return self::render($title, $content, self::$minimal_content_template); return self::render($title, $content, self::$minimal_content_template);
} }
public static function get_css_as_html() public static function get_css_as_html()
{ {
global $settings; global $settings;
if(preg_match("/^[^\/]*\/\/|^\//", $settings->css)) if(preg_match("/^[^\/]*\/\/|^\//", $settings->css))
return "<link rel='stylesheet' href='$settings->css' />"; return "<link rel='stylesheet' href='$settings->css' />";
else else
return "<style>$settings->css</style>"; return "<style>$settings->css</style>";
} }
public static $nav_divider = "<span class='nav-divider inflexible'> | </span>"; public static $nav_divider = "<span class='nav-divider inflexible'> | </span>";
/* /*
* @summary Function to render a navigation bar from an array of links. See * @summary Function to render a navigation bar from an array of links. See
* $settings->nav_links for format information. * $settings->nav_links for format information.
* *
* @param $nav_links - The links to add to the navigation bar. * @param $nav_links - The links to add to the navigation bar.
* @param $nav_links_extra - The extra nav links to add to the "More..." * @param $nav_links_extra - The extra nav links to add to the "More..."
* menu. * menu.
@ -616,7 +623,7 @@ class page_renderer
{ {
global $settings, $env; global $settings, $env;
$result = "<nav class='$class'>\n"; $result = "<nav class='$class'>\n";
// Loop over all the navigation links // Loop over all the navigation links
foreach($nav_links as $item) foreach($nav_links as $item)
{ {
@ -636,22 +643,22 @@ class page_renderer
else else
$result .= "<span class='inflexible'>Browsing as Anonymous.</span>" . /*page_renderer::$nav_divider . */"<span><a href='index.php?action=login'>Login</a></span>" . page_renderer::$nav_divider; $result .= "<span class='inflexible'>Browsing as Anonymous.</span>" . /*page_renderer::$nav_divider . */"<span><a href='index.php?action=login'>Login</a></span>" . page_renderer::$nav_divider;
break; break;
case "search": // Displays a search bar case "search": // Displays a search bar
$result .= "<span class='inflexible'><form method='get' action='index.php' style='display: inline;'><input type='search' name='page' list='allpages' placeholder='Type a page name here and hit enter' /><input type='hidden' name='search-redirect' value='true' /></form></span>"; $result .= "<span class='inflexible'><form method='get' action='index.php' style='display: inline;'><input type='search' name='page' list='allpages' placeholder='Type a page name here and hit enter' /><input type='hidden' name='search-redirect' value='true' /></form></span>";
break; break;
case "divider": // Displays a divider case "divider": // Displays a divider
$result .= page_renderer::$nav_divider; $result .= page_renderer::$nav_divider;
break; break;
case "menu": case "menu":
$result .= "<span class='inflexible nav-more'><label for='more-menu-toggler'>More...</label> $result .= "<span class='inflexible nav-more'><label for='more-menu-toggler'>More...</label>
<input type='checkbox' class='off-screen' id='more-menu-toggler' />"; <input type='checkbox' class='off-screen' id='more-menu-toggler' />";
$result .= page_renderer::render_navigation_bar($nav_links_extra, [], "nav-more-menu"); $result .= page_renderer::render_navigation_bar($nav_links_extra, [], "nav-more-menu");
$result .= "</span>"; $result .= "</span>";
break; break;
// It isn't a keyword, so just output it directly // It isn't a keyword, so just output it directly
default: default:
$result .= "<span>$item</span>"; $result .= "<span>$item</span>";
@ -663,7 +670,7 @@ class page_renderer
$result .= "<span><a href='" . str_replace("{page}", $env->page, $item[1]) . "'>$item[0]</a></span>"; $result .= "<span><a href='" . str_replace("{page}", $env->page, $item[1]) . "'>$item[0]</a></span>";
} }
} }
$result .= "</nav>"; $result .= "</nav>";
return $result; return $result;
} }
@ -674,21 +681,21 @@ class page_renderer
if(in_array($name, $settings->admins)) if(in_array($name, $settings->admins))
$result .= $settings->admindisplaychar; $result .= $settings->admindisplaychar;
$result .= $name; $result .= $name;
return $result; return $result;
} }
public static function generate_all_pages_datalist() public static function generate_all_pages_datalist()
{ {
global $pageindex; global $pageindex;
$result = "<datalist id='allpages'>\n"; $result = "<datalist id='allpages'>\n";
foreach($pageindex as $pagename => $pagedetails) foreach($pageindex as $pagename => $pagedetails)
{ {
$result .= "\t\t\t<option value='$pagename' />\n"; $result .= "\t\t\t<option value='$pagename' />\n";
} }
$result .= "\t\t</datalist>"; $result .= "\t\t</datalist>";
return $result; return $result;
} }
} }
@ -745,7 +752,7 @@ function add_parser($name, $parser_code)
global $parsers; global $parsers;
if(isset($parsers[$name])) if(isset($parsers[$name]))
throw new Exception("Can't register parser with name '$name' because a parser with that name already exists."); throw new Exception("Can't register parser with name '$name' because a parser with that name already exists.");
$parsers[$name] = $parser_code; $parsers[$name] = $parser_code;
} }
function parse_page_source($source) function parse_page_source($source)
@ -753,7 +760,7 @@ function parse_page_source($source)
global $settings, $parsers; global $settings, $parsers;
if(!isset($parsers[$settings->parser])) if(!isset($parsers[$settings->parser]))
exit(page_renderer::render_main("Parsing error - $settings->sitename", "<p>Parsing some page source data failed. This is most likely because $settings->sitename has the parser setting set incorrectly. Please contact <a href='mailto:" . hide_email($settings->admindetails["email"]) . "'>" . $settings->admindetails["name"] . "</a>, your $settings->sitename Administrator.")); exit(page_renderer::render_main("Parsing error - $settings->sitename", "<p>Parsing some page source data failed. This is most likely because $settings->sitename has the parser setting set incorrectly. Please contact <a href='mailto:" . hide_email($settings->admindetails["email"]) . "'>" . $settings->admindetails["name"] . "</a>, your $settings->sitename Administrator."));
/* Not needed atm because escaping happens when saving, not when rendering * /* Not needed atm because escaping happens when saving, not when rendering *
if($settings->clean_raw_html) if($settings->clean_raw_html)
$source = htmlentities($source, ENT_QUOTES | ENT_HTML5); $source = htmlentities($source, ENT_QUOTES | ENT_HTML5);