From e465a05083ecc02757f1e64a5f755d256acb53b8 Mon Sep 17 00:00:00 2001 From: Starbeamrainbowlabs Date: Sat, 19 Sep 2015 10:19:56 +0100 Subject: [PATCH] Erm what's happening here...? --- .gitignore | 14 +- README.md | 178 +- build.bat | 10 +- build.php | 158 +- build/index.php | 3162 ++++++++++++++++++------------------ core.php | 1226 +++++++------- download.php | 178 +- modules/action-hash.php | 48 +- modules/extra-sidebar.php | 218 +-- modules/page-credits.php | 122 +- modules/page-delete.php | 76 +- modules/page-edit.php | 278 ++-- modules/page-export.php | 102 +- modules/page-help.php | 122 +- modules/page-list.php | 80 +- modules/page-login.php | 166 +- modules/page-logout.php | 48 +- modules/page-move.php | 128 +- modules/page-update.php | 132 +- modules/page-view.php | 134 +- modules/parser-default.php | 254 +-- rebuild_module_index.php | 64 +- start-server.bat | 2 +- 23 files changed, 3450 insertions(+), 3450 deletions(-) diff --git a/.gitignore b/.gitignore index c24ef1f..a207002 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ -# all wiki pages -*.md -# include the README -!README.md - -# the page index -pageindex.json +# all wiki pages +*.md +# include the README +!README.md + +# the page index +pageindex.json diff --git a/README.md b/README.md index 59d2ab0..f9ec471 100644 --- a/README.md +++ b/README.md @@ -1,90 +1,90 @@ -# Pepperminty Wiki -A Wiki in a box - -Pepperminty Wiki is a complete wiki contained in a single file, inspired by @am2064's [Minty Wiki](https://github.com/am2064/Minty-Wiki). - -## Screenshots -![Main Page Example](https://cloud.githubusercontent.com/assets/9929737/9069904/12acfad6-3ae4-11e5-8ec4-6ec0e3de7249.png) - -Above: A Main Page with the sidebar enabled. - -## Features -- Configurable settings -- User login system -- Page creation -- Sub pages -- Markdown-powered syntax -- Internal links -- Printable page view -- Customisable theme -- Basic 'search' bar -- (Optional) Sidebar with a tree of all the current pages -- List of all pages & details -- Inbuilt help page - -## Demo -A Live demo of the latest stable version can be found over at [my website](//starbeamrainbowlabs.com/labs/peppermint) - -## Getting Started -### Requirements -- PHP-enabled webserver -- PHP session support (for logging in, see [here](https://php.net/manual/en/session.installation.php) for more information) -- Write access to own folder (only for editing) - -### Getting your own copy -Setting up your own copy of Pepperminty Wiki is easy. Since Pepperminty Wiki works on a module based system, all you need to do is choose the modules you want installed, and then configure your new installation so that it fits your needs. There are several ways to do this: - -#### Method 1: Using the latest pre-built stable release -If you want a pre-built stable version, then you can [use the latest release](https://github.com/sbrl/Pepperminty-Wiki/releases/latest). It has a changelog that tells you what has changed since the last release, along with a pre-built version with all the latest modules. - -#### Method 2: Grabbing the pre-built verion from the repository -If you're feeling lazy, you can grab the bleeding-edge version from this respository, which comes with all the latest modules. You can get it [here](https://raw.githubusercontent.com/sbrl/Pepperminty-Wiki/master/build/index.php). - -#### Method 3: Using the online downloader -Pepperminty Wiki has a downloader that you can use to select the modules you want to include in your install. The online downloader will give you the latest stable release. You can find it [here](//starbeamrainbowlabs.com/labs/peppermint/download.php). - -#### Method 3.5: Using the downloader offline -You can also you the downloader offline. Simply clone this repository to your web server and then point your web browser at `your.server/path/to/perppminty/wiki/download.php`. - -#### Method 4: Building your own from source -Pepperminty Wiki can also be built from source (and I do this all the time when testing). Start by cloning the repository. Then go into the `modules` folder and append `.disabled` to the names of any modules you don't want to be included (e.g. `modules/page-edit.php` would become `modules/page-edit.php.disabled`). Then follow the instructions for your platform: - -##### Windows -Simply run the `build.bat` script in the root of the repository. It will handle everything for you. - -##### Linux and Everyone Else -Run the following commands from the root of the repository in order, adjusting them for your specific platform (these are for a standard Ubuntu Server install): - -```bash -rm build/index.php -php rebuild_module_index.php -php build.php -``` - -Here's an explanation of what each command does: - -1. Deletes the old `index.php` in the build folder that comes with the repository -2. Rebuilds the module index that the build scripts uses to determine what modules it should include when building -3. Actually builds Pepperminty Wiki. Outputs to `index.php`. - -### Configuring -To configure your new install, open `index.php` in your favourite text editor and take a look at the comments. They should be self explanatory, but if you need any help, just contact me or [open an issue](//github.com/sbrl/Pepperminty-Wiki/issues/new). - -## Reference -At some point (soon I hope!), I am going to write a reference here for those who would like to build their own modules. - -## Real World Usage -None yet! Contact me or [open an issue](//github.com/sbrl/Pepperminty-Wiki/issues/new) and tell me about where you are using Pepperminty Wiki and I will add you to this section! - -## Todo -Here's a list of things that I want to add at some point (please feel free to [send a pull request](//github.com/sbrl/Pepperminty-Wiki/pulls) and help out!). - -- Page history -- Password changing -- Intelligent auto-updating system that doesn't wipe your settings / module choices -- Make links to non-existent pages red -- Optional module support -- Redirect pages -- ...? - +# Pepperminty Wiki +A Wiki in a box + +Pepperminty Wiki is a complete wiki contained in a single file, inspired by @am2064's [Minty Wiki](https://github.com/am2064/Minty-Wiki). + +## Screenshots +![Main Page Example](https://cloud.githubusercontent.com/assets/9929737/9069904/12acfad6-3ae4-11e5-8ec4-6ec0e3de7249.png) + +Above: A Main Page with the sidebar enabled. + +## Features +- Configurable settings +- User login system +- Page creation +- Sub pages +- Markdown-powered syntax +- Internal links +- Printable page view +- Customisable theme +- Basic 'search' bar +- (Optional) Sidebar with a tree of all the current pages +- List of all pages & details +- Inbuilt help page + +## Demo +A Live demo of the latest stable version can be found over at [my website](//starbeamrainbowlabs.com/labs/peppermint) + +## Getting Started +### Requirements +- PHP-enabled webserver +- PHP session support (for logging in, see [here](https://php.net/manual/en/session.installation.php) for more information) +- Write access to own folder (only for editing) + +### Getting your own copy +Setting up your own copy of Pepperminty Wiki is easy. Since Pepperminty Wiki works on a module based system, all you need to do is choose the modules you want installed, and then configure your new installation so that it fits your needs. There are several ways to do this: + +#### Method 1: Using the latest pre-built stable release +If you want a pre-built stable version, then you can [use the latest release](https://github.com/sbrl/Pepperminty-Wiki/releases/latest). It has a changelog that tells you what has changed since the last release, along with a pre-built version with all the latest modules. + +#### Method 2: Grabbing the pre-built verion from the repository +If you're feeling lazy, you can grab the bleeding-edge version from this respository, which comes with all the latest modules. You can get it [here](https://raw.githubusercontent.com/sbrl/Pepperminty-Wiki/master/build/index.php). + +#### Method 3: Using the online downloader +Pepperminty Wiki has a downloader that you can use to select the modules you want to include in your install. The online downloader will give you the latest stable release. You can find it [here](//starbeamrainbowlabs.com/labs/peppermint/download.php). + +#### Method 3.5: Using the downloader offline +You can also you the downloader offline. Simply clone this repository to your web server and then point your web browser at `your.server/path/to/perppminty/wiki/download.php`. + +#### Method 4: Building your own from source +Pepperminty Wiki can also be built from source (and I do this all the time when testing). Start by cloning the repository. Then go into the `modules` folder and append `.disabled` to the names of any modules you don't want to be included (e.g. `modules/page-edit.php` would become `modules/page-edit.php.disabled`). Then follow the instructions for your platform: + +##### Windows +Simply run the `build.bat` script in the root of the repository. It will handle everything for you. + +##### Linux and Everyone Else +Run the following commands from the root of the repository in order, adjusting them for your specific platform (these are for a standard Ubuntu Server install): + +```bash +rm build/index.php +php rebuild_module_index.php +php build.php +``` + +Here's an explanation of what each command does: + +1. Deletes the old `index.php` in the build folder that comes with the repository +2. Rebuilds the module index that the build scripts uses to determine what modules it should include when building +3. Actually builds Pepperminty Wiki. Outputs to `index.php`. + +### Configuring +To configure your new install, open `index.php` in your favourite text editor and take a look at the comments. They should be self explanatory, but if you need any help, just contact me or [open an issue](//github.com/sbrl/Pepperminty-Wiki/issues/new). + +## Reference +At some point (soon I hope!), I am going to write a reference here for those who would like to build their own modules. + +## Real World Usage +None yet! Contact me or [open an issue](//github.com/sbrl/Pepperminty-Wiki/issues/new) and tell me about where you are using Pepperminty Wiki and I will add you to this section! + +## Todo +Here's a list of things that I want to add at some point (please feel free to [send a pull request](//github.com/sbrl/Pepperminty-Wiki/pulls) and help out!). + +- Page history +- Password changing +- Intelligent auto-updating system that doesn't wipe your settings / module choices +- Make links to non-existent pages red +- Optional module support +- Redirect pages +- ...? + Is the feature you want to see not on this list? [Open an issue](//github.com/sbrl/Pepperminty-Wiki/issues/new) or [send a pull request](//github.com/sbrl/Pepperminty-Wiki/pulls)! \ No newline at end of file diff --git a/build.bat b/build.bat index 7c363b1..9c3b059 100644 --- a/build.bat +++ b/build.bat @@ -1,5 +1,5 @@ -@echo off -echo Deleting old index.php -del build\index.php -php rebuild_module_index.php -php build.php +@echo off +echo Deleting old index.php +del build\index.php +php rebuild_module_index.php +php build.php diff --git a/build.php b/build.php index f699ff9..798cf9f 100644 --- a/build.php +++ b/build.php @@ -1,79 +1,79 @@ -id; -} - -if(isset($_GET["modules"])) -{ - $module_list = explode(",", $_GET["modules"]); -} - -if(php_sapi_name() != "cli") -{ - header("content-type: text/php"); -} - -if(php_sapi_name() == "cli") echo("Reading in core files..."); - -$core = file_get_contents("core.php"); -$settings = file_get_contents("settings.fragment.php"); -$settings = str_replace([ "" ], "", $settings); -$core = str_replace("{settings}", $settings, $core); - -$result = $core; - -foreach($module_list as $module_id) -{ - if($module_id == "") continue; - - if(php_sapi_name() == "cli") echo("Adding $module_id\n"); - - $module_filepath = "modules/" . preg_replace("[^a-zA-Z0-9\-]", "", $module_id) . ".php"; - - //echo("id: $module_id | filepath: $module_filepath\n"); - - if(!file_exists($module_filepath)) - { - http_response_code(400); - exit("Failed to load module with name: $module_filepath"); - } - - $modulecode = file_get_contents($module_filepath); - $modulecode = str_replace([ "" ], "", $modulecode); - $result = str_replace( - "// %next_module% //", - "$modulecode\n// %next_module% //", - $result); -} - -if(php_sapi_name() == "cli") -{ - if(file_exists("build/index.php")) - { - echo("index.php already exists in the build folder, exiting\n"); - exit(1); - } - else - { - echo("Done. Saving to disk..."); - file_put_contents("build/index.php", $result); - echo("complete!\n"); - echo("*** Build Completed ***\n"); - } -} -else -{ - exit($result); -} - -?> +id; +} + +if(isset($_GET["modules"])) +{ + $module_list = explode(",", $_GET["modules"]); +} + +if(php_sapi_name() != "cli") +{ + header("content-type: text/php"); +} + +if(php_sapi_name() == "cli") echo("Reading in core files..."); + +$core = file_get_contents("core.php"); +$settings = file_get_contents("settings.fragment.php"); +$settings = str_replace([ "" ], "", $settings); +$core = str_replace("{settings}", $settings, $core); + +$result = $core; + +foreach($module_list as $module_id) +{ + if($module_id == "") continue; + + if(php_sapi_name() == "cli") echo("Adding $module_id\n"); + + $module_filepath = "modules/" . preg_replace("[^a-zA-Z0-9\-]", "", $module_id) . ".php"; + + //echo("id: $module_id | filepath: $module_filepath\n"); + + if(!file_exists($module_filepath)) + { + http_response_code(400); + exit("Failed to load module with name: $module_filepath"); + } + + $modulecode = file_get_contents($module_filepath); + $modulecode = str_replace([ "" ], "", $modulecode); + $result = str_replace( + "// %next_module% //", + "$modulecode\n// %next_module% //", + $result); +} + +if(php_sapi_name() == "cli") +{ + if(file_exists("build/index.php")) + { + echo("index.php already exists in the build folder, exiting\n"); + exit(1); + } + else + { + echo("Done. Saving to disk..."); + file_put_contents("build/index.php", $result); + echo("complete!\n"); + echo("*** Build Completed ***\n"); + } +} +else +{ + exit($result); +} + +?> diff --git a/build/index.php b/build/index.php index a499a44..d9dd80a 100644 --- a/build/index.php +++ b/build/index.php @@ -1,6 +1,6 @@ -sessionprefix-expiretime"]) and - $_SESSION["$settings->sessionprefix-expiretime"] < time()) -{ - //clear the session variables - $_SESSION = []; - session_destroy(); -} - -if(!isset($_SESSION[$settings->sessionprefix . "-user"]) and - !isset($_SESSION[$settings->sessionprefix . "-pass"])) -{ - //the user is not logged in - $isloggedin = false; -} -else -{ - $user = $_SESSION[$settings->sessionprefix . "-user"]; - $pass = $_SESSION[$settings->sessionprefix . "-pass"]; - if($settings->users[$user] == $pass) - { - //the user is logged in - $isloggedin = true; - } - else - { - //the user's login details are invalid (what is going on here?) - //unset the session variables, treat them as an anonymous user, and get out of here - $isloggedin = false; - unset($user); - unset($pass); - //clear the session data - $_SESSION = []; //delete al lthe variables - session_destroy(); //destroy the session - } -} -//check to see if the currently logged in user is an admin -$isadmin = false; -if($isloggedin) -{ - foreach($settings->admins as $admin_username) - { - if($admin_username == $user) - { - $isadmin = true; - break; - } - } -} -/////// Login System End /////// - -/////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////// Functions //////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////// - -/* - * @summary Converts a filesize into a human-readable string. - * @source http://php.net/manual/en/function.filesize.php#106569 - * @editor Starbeamrainbowlabs - * - * @param $bytes - The number of bytes to convert. - * @param $decimals - The number of decimal places to preserve. - */ -function human_filesize($bytes, $decimals = 2) -{ - $sz = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "YB", "ZB"]; - $factor = floor((strlen($bytes) - 1) / 3); - return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . @$sz[$factor]; -} -/* - * @summary Calculates the time sincce a particular timestamp and returns a - * human-readable result. - * @source http://snippets.pro/snippet/137-php-convert-the-timestamp-to-human-readable-format/ - * - * @param $time - The timestamp to convert. - * - * @returns {string} - The time since the given timestamp pas a human-readable string. - */ -function human_time_since($time) -{ - $timediff = time() - $time; - $tokens = array ( - 31536000 => 'year', - 2592000 => 'month', - 604800 => 'week', - 86400 => 'day', - 3600 => 'hour', - 60 => 'minute', - 1 => 'second' - ); - foreach ($tokens as $unit => $text) { - if ($timediff < $unit) continue; - $numberOfUnits = floor($timediff / $unit); - return $numberOfUnits.' '.$text.(($numberOfUnits>1)?'s':'').' ago'; - } -} - -/* - * @summary A recursive glob() function. - * - * @param $pattern - The glob pattern to use to find filenames. - * @param $flags - The glob flags to use when finding filenames. - * - * @returns {array} - An array of the filepaths that match the given glob. - */ -// From http://in.php.net/manual/en/function.glob.php#106595 -function glob_recursive($pattern, $flags = 0) -{ - $files = glob($pattern, $flags); - foreach (glob(dirname($pattern).'/*', GLOB_ONLYDIR|GLOB_NOSORT) as $dir) - { - $prefix = "$dir/"; - // Remove the "./" from the beginning if it exists - if(substr($prefix, 0, 2) == "./") $prefix = substr($prefix, 2); - $files = array_merge($files, glob_recursive($prefix . basename($pattern), $flags)); - } - return $files; -} - -/* - * @summary Gets a list of all the sub pagess of the current page. - * - * @param $pageindex - The pageindex to use to search. - * @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. - */ -function get_subpages($pageindex, $pagename) -{ - $pagenames = get_object_vars($pageindex); - $result = new stdClass(); - - $stem = "$pagename/"; - $stem_length = strlen($stem); - foreach($pagenames as $entry => $value) - { - if(substr($entry, 0, $stem_length) == $stem) - { - // We found a subpage - - // Extract the subpage's key relative to the page that we are searching for - $subpage_relative_key = substr($entry, $stem_length, -3); - // Calculate how many times removed the current subpage is from the current page. 0 = direct descendant. - $times_removed = substr_count($subpage_relative_key, "/"); - // Store the name of the subpage we found - $result->$entry = $times_removed; - } - } - - unset($pagenames); - return $result; -} - -/* - * @summary Makes sure that a subpage's parents exist. Note this doesn't check the pagename itself. - * - * @param The pagename to check. - * - */ -function check_subpage_parents($pagename) -{ - global $pageindex; - // Save the new pageindex and return if there aren't any more parent pages to check - if(strpos($pagename, "/") === false) - { - file_put_contents("./pageindex.json", json_encode($pageindex, JSON_PRETTY_PRINT)); - return; - } - - $parent_pagename = substr($pagename, 0, strrpos($pagename, "/")); - $parent_page_filename = "$parent_pagename.md"; - if(!file_exists($parent_page_filename)) - { - // This parent page doesn't exist! Create it and add it to the page index. - touch($parent_page_filename, 0); - - $newentry = new stdClass(); - $newentry->filename = $parent_page_filename; - $newentry->size = 0; - $newentry->lastmodified = 0; - $newentry->lasteditor = "none"; - $pageindex->$parent_pagename = $newentry; - } - - check_subpage_parents($parent_pagename); -} - -/* - * @summary makes a path safe - * - * @details paths may only contain alphanumeric characters, spaces, underscores, and dashes - */ -function makepathsafe($string) -{ - return preg_replace("/[^0-9a-zA-Z\_\-\ \/]/i", "", $string); -} - -/* - * @summary Hides an email address from bots by adding random html entities. - * - * @returns The mangled email address. - */ -function hide_email($str) -{ - $hidden_email = ""; - for($i = 0; $i < strlen($str); $i++) - { - if($str[$i] == "@") - { - $hidden_email .= "&#" . ord("@") . ";"; - continue; - } - if(rand(0, 1) == 0) - $hidden_email .= $str[$i]; - else - $hidden_email .= "&#" . ord($str[$i]) . ";"; - } - - return $hidden_email; -} - -/////////////////////////////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////// Security and Consistency Measures //////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////// - -/* - * Sort out the pageindex. We create it if it doesn't exist, and load and parse - * it if it does. - */ -if(!file_exists("./pageindex.json")) -{ - $existingpages = glob_recursive("*.md"); - $pageindex = new stdClass(); - // We use a for loop here because foreach doesn't loop over new values inserted - // while we were looping - for($i = 0; $i < count($existingpages); $i++) - { - $pagefilename = $existingpages[$i]; - - // Create a new entry - $newentry = new stdClass(); - $newentry->filename = utf8_encode($pagefilename); // Store the filename - $newentry->size = filesize($pagefilename); // Store the page size - $newentry->lastmodified = filemtime($pagefilename); // Store the date last modified - // Todo find a way to keep the last editor independent of the page index - $newentry->lasteditor = utf8_encode("unknown"); // Set the editor to "unknown" - // Extract the name of the (sub)page without the ".md" - $pagekey = utf8_encode(substr($pagefilename, 0, -3)); - - // Subpage parent checker - if(strpos($pagekey, "/") !== false) - { - // We have a sub page people - // Work out what our direct parent's key must be in order to check to - // make sure that it actually exists. If it doesn't, then we need to - // create it. - $subpage_parent_key = substr($pagekey, 0, strrpos($pagekey, "/")); - $subpage_parent_filename = "$subpage_parent_key.md"; - if(array_search($subpage_parent_filename, $existingpages) === false) - { - // Our parent page doesn't acutally exist - create it - touch($subpage_parent_filename, 0); - // Furthermore, we should add this page to the list of existing pages - // in order for it to be indexed - $existingpages[] = $subpage_parent_filename; - } - } - - // Store the new entry in the new page index - $pageindex->$pagekey = $newentry; - } - file_put_contents("./pageindex.json", json_encode($pageindex, JSON_PRETTY_PRINT)); - unset($existingpages); -} -else -{ - $pageindex = json_decode(file_get_contents("./pageindex.json")); -} - -// Work around an Opera + Syntastic bug where there is no margin at the left hand side if there isn't a query string when accessing a .php file -if(!isset($_GET["action"]) and !isset($_GET["page"])) -{ - http_response_code(302); - header("location: index.php?action=$settings->defaultaction&page=$defaultpage"); - exit(); -} - -// Make sure that the action is set -if(!isset($_GET["action"])) - $_GET["action"] = $settings->defaultaction; -// Make sure that the page is set -if(!isset($_GET["page"]) or strlen($_GET["page"]) === 0) - $_GET["page"] = $settings->defaultpage; - -// Redirect the user to the safe version of the path if they entered an unsafe character -if(makepathsafe($_GET["page"]) !== $_GET["page"]) -{ - http_response_code(301); - header("location: index.php?action=" . rawurlencode($_GET["action"]) . "&page=" . makepathsafe($_GET["page"])); - header("x-requested-page: " . $_GET["page"]); - header("x-actual-page: " . makepathsafe($_GET["page"])); - exit(); -} -$page = $_GET["page"]; - -/////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////// HTML fragments ////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////// -class page_renderer -{ - public static $html_template = " - - - - {title} - - - - {header-html} - - - {body} - - - -"; - - public static $main_content_template = "{navigation-bar} -

{sitename}

-
- {content} -
- - - {navigation-bar-bottom} - {all-pages-datalist}"; - public static $minimal_content_template = "
{content}
- "; - - // An array of functions that have been registered to process the - // find / replace array before the page is rendered. Note that the function - // should take a *reference* to an array as its only argument. - protected static $part_processors = []; - - // Registers a function as a part post processor. - public static function register_part_preprocessor($function) - { - // Make sure that the function we are about to register is valid - if(!is_callable($function)) - { - http_response_code(500); - $admin_name = $settings->admindetails["name"]; - $admin_email = hide_email($settings->admindetails["email"]); - exit(page_renderer::render("$settings->sitename - Module Error", "

$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 $admin_email.")); - } - - self::$part_processors[] = $function; - - return true; - } - - public static function render($title, $content, $body_template = false) - { - global $settings, $start_time; - - if($body_template === false) - $body_template = self::$main_content_template; - - $parts = [ - "{body}" => $body_template, - - "{sitename}" => $settings->sitename, - "{favicon-url}" => $settings->favicon, - "{header-html}" => self::get_css_as_html(), - - "{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"), - - "{admin-details-name}" => $settings->admindetails["name"], - "{admin-details-email}" => $settings->admindetails["email"], - - "{admins-name-list}" => implode(", ", $settings->admins), - - "{generation-date}" => date("l jS \of F Y \a\\t h:ia T"), - - "{all-pages-datalist}" => self::generate_all_pages_datalist() - ]; - - // Pass the parts through the part processors - foreach(self::$part_processors as $function) - { - $function($parts); - } - - $result = self::$html_template; - $result = str_replace("{body}", $parts["{body}"], $result); - - $result = str_replace(array_keys($parts), array_values($parts), $result); - - $result = str_replace([ - "{title}", - "{content}" - ], [ - $title, - $content - ], $result); - - $result = str_replace("{generation-time-taken}", microtime(true) - $start_time, $result); - return $result; - } - public static function render_main($title, $content) - { - return self::render($title, $content, self::$main_content_template); - } - public static function render_minimal($title, $content) - { - return self::render($title, $content, self::$minimal_content_template); - } - - - public static function get_css_as_html() - { - global $settings; - - if(preg_match("/^[^\/]*\/\/|^\//", $settings->css)) - return ""; - else - return ""; - } - - public static $nav_divider = " | "; - - /* - * @summary Function to render a navigation bar from an array of links. See - * $settings->nav_links for format information. - * - * @param $nav_links - The links to add to the navigation bar. - * @param $nav_links_extra - The extra nav links to add to the "More..." - * menu. - */ - public static function render_navigation_bar($nav_links, $nav_links_extra, $class = "") - { - global $settings, $user, $isloggedin, $page; - $result = "

"; - return $result; - } - public static function render_username($name) - { - global $settings; - $result = ""; - if(in_array($name, $settings->admins)) - $result .= $settings->admindisplaychar; - $result .= $name; - - return $result; - } - - public static function generate_all_pages_datalist() - { - global $pageindex; - - $result = "\n"; - foreach($pageindex as $pagename => $pagedetails) - { - $result .= "\t\t\t"; - - return $result; - } -} - -////////////////////////// -/// Module functions /// -////////////////////////// -// These functions are // -// used by modules to // -// register themselves // -// or new pages. // -////////////////////////// -$modules = []; // List that contains all the loaded modules -// Function to register a module -function register_module($moduledata) -{ - global $modules; - //echo("registering module\n"); - //var_dump($moduledata); - $modules[] = $moduledata; -} - -// Function to register an action handler -$actions = new stdClass(); -function add_action($action_name, $func) -{ - global $actions; - //echo("adding $action_name\n"); - $actions->$action_name = $func; -} - -// Function to register a new parser. If multiple parsers are registered then -// only the last parser registered will actually be used. -$parse_page_source = function() { - throw new Exception("No parser registered!"); -}; -function add_parser($parser_code) -{ - global $parse_page_source; - $parse_page_source = $parser_code; -} - -////////////////////////////////////////////////////////////////// - - - -register_module([ - "name" => "Password hashing action", - "version" => "0.5", - "author" => "Starbeamrainbowlabs", - "description" => "Adds a utility action (that anyone can use) called hash that hashes a given string. Useful when changing a user's password.", - "id" => "action-hash", - "code" => function() { - add_action("hash", function() { - if(!isset($_GET["string"])) - { - http_response_code(422); - exit(page_renderer::render_main("Missing parameter", "

The GET parameter string must be specified.

-

It is strongly recommended that you utilise this page via a private or incognito window in order to prevent your password from appearing in your browser history.

")); - } - else - { - exit(page_renderer::render_main("Hashed string", "

" . $_GET["string"] . "" . hash("sha256", $_GET["string"] . "

"))); - } - }); - } -]); - - - - -register_module([ - "name" => "Sidebar", - "version" => "0.2", - "author" => "Starbeamrainbowlabs", - "description" => "Adds a sidebar to the left hand side of every page. Add '\$settings->sidebar_show = true;' to your configuration, or append '&sidebar=yes' to the url to enable. Adding to the url sets a cookie to remember your setting.", - "id" => "extra-sidebar", - "code" => function() { - $show_sidebar = false; - - // Show the sidebar if it is enabled in the settings - if(isset($settings->sidebar_show) && $settings->sidebar_show === true) - $show_sidebar = true; - - // Also show and persist the sidebar if the special GET parameter - // sidebar is seet - if(!$show_sidebar && isset($_GET["sidebar"])) - { - $show_sidebar = true; - // Set a cookie to persist the display of the sidebar - setcookie("sidebar_show", "true", time() + (60 * 60 * 24 * 30)); - } - - // Show the sidebar if the cookie is set - if(!$show_sidebar && isset($_COOKIE["sidebar_show"])) - $show_sidebar = true; - - // Delete the cookie and hide the sidebar if the special GET paramter - // nosidebar is set - if(isset($_GET["nosidebar"])) - { - $show_sidebar = false; - unset($_COOKIE["sidebar_show"]); - setcookie("sidebar_show", null, time() - 3600); - } - - page_renderer::register_part_preprocessor(function(&$parts) use ($show_sidebar) { - global $settings, $pageindex; - - if($show_sidebar && !isset($_GET["printable"])) - { - // Show the sidebar - $exec_start = microtime(true); - - // Sort the pageindex - $sorted_pageindex = get_object_vars($pageindex); - ksort($sorted_pageindex, SORT_NATURAL); - - $sidebar_contents = ""; - $sidebar_contents .= render_sidebar($sorted_pageindex); - - $parts["{body}"] = " -
" . $parts["{body}"] . "
- - "; - } - }); - } -]); - -/* - * @summary Renders the sidebar for a given pageindex. - * - * @param $pageindex {array} - The pageindex to render the sidebar for - * @param $root_pagename {string} - The pagename that should be considered the root of the rendering. You don't usually need to use this, it is used by the algorithm itself since it is recursive. - * - * @returns {string} A HTML rendering of the sidebar for the given pageindex - */ -function render_sidebar($pageindex, $root_pagename = "") -{ - global $settings; - - $result = " $details) - { - // If we have a valid root pagename, and it isn't present at the - // beginning of the current pagename, skip it - if($root_pagename !== "" && strpos($pagename, $root_pagename) !== 0) - continue; - - // The current page is the same as the root page, skip it - if($pagename == $root_pagename) - continue; - - - // If the part of the current pagename that comes after the root - // pagename has a slash in it, skip it as it is a sub-sub page. - if(strpos(substr($pagename, strlen($root_pagename)), "/") !== false) - continue; - - $result .= "
  • $pagename\n"; - $result .= render_sidebar($pageindex, $pagename); - $result .= "
  • \n"; - } - $result .= "\n"; - - return $result == "\n" ? "" : $result; -} - - - - -register_module([ - "name" => "Credits", - "version" => "0.6", - "author" => "Starbeamrainbowlabs", - "description" => "Adds the credits page. You *must* have this module :D", - "id" => "page-credits", - "code" => function() { - add_action("credits", function() { - global $settings, $version, $pageindex, $modules; - - $credits = [ - "Code" => [ - "author" => "Starbeamrainbowlabs", - "author_url" => "https://starbeamrmainbowlabs.com/", - "thing_url" => "https://github.com/sbrl/Pepprminty-Wiki" - ], - "Slightly modified version of Slimdown" => [ - "author" => "Johnny Broadway", - "author_url" => "https://github.com/jbroadway", - "thing_url" => "https://gist.github.com/jbroadway/2836900" - ], - "Default Favicon" => [ - "author" => "bluefrog23", - "author_url" => "https://openclipart.org/user-detail/bluefrog23/", - "thing_url" => "https://openclipart.org/detail/19571/peppermint-candy-by-bluefrog23" - ], - "Bug Reports" => [ - "author" => "nibreh", - "author_url" => "https://github.com/nibreh/", - "thing_url" => "" - ] - ]; - $credits_html = ""; - - $title = "Credits - $settings->sitename"; - $content = "

    $settings->sitename credits

    -

    $settings->sitename is powered by Pepperminty Wiki - an entire wiki packed inside a single file, which was built by Starbeamrainbowlabs, and can be found on GitHub (contributors will ablso be listed here in the future).

    -

    Main Credits

    - $credits_html -

    Site status

    - - - - - -
    Site name:$settings->sitename (Update - Administrators only, Export as zip - Check for permission first)
    Pepperminty Wiki version:$version
    Number of pages:" . count(get_object_vars($pageindex)) . "
    Number of modules:" . count($modules) . "
    "; - exit(page_renderer::render_main($title, $content)); - }); - } -]); - - - - -register_module([ - "name" => "Page deleter", - "version" => "0.5", - "author" => "Starbeamrainbowlabs", - "description" => "Adds an action to allow administrators to delete pages.", - "id" => "page-delete", - "code" => function() { - add_action("delete", function() { - global $pageindex, $settings, $page, $isadmin; - if(!$settings->editing) - { - exit(page_renderer::render_main("Deleting $page - error", "

    You tried to delete $page, but editing is disabled on this wiki.

    -

    If you wish to delete this page, please re-enable editing on this wiki first.

    -

    Go back to $page.

    -

    Nothing has been changed.

    ")); - } - if(!$isadmin) - { - exit(page_renderer::render_main("Deleting $page - error", "

    You tried to delete $page, but you are not an admin so you don't have permission to do that.

    -

    You should try logging in as an admin.

    ")); - } - if(!isset($_GET["delete"]) or $_GET["delete"] !== "yes") - { - exit(page_renderer::render_main("Deleting $page", "

    You are about to delete $page. You can't undo this!

    -

    Click here to delete $page.

    -

    Click here to go back.")); - } - unset($pageindex->$page); //delete the page from the page index - file_put_contents("./pageindex.json", json_encode($pageindex, JSON_PRETTY_PRINT)); //save the new page index - unlink("./$page.md"); //delete the page from the disk - - exit(page_renderer::render_main("Deleting $page - $settings->sitename", "

    $page has been deleted. Go back to the main page.

    ")); - }); - } -]); - - - - -register_module([ - "name" => "Page editor", - "version" => "0.8", - "author" => "Starbeamrainbowlabs", - "description" => "Allows you to edit pages by adding the edit and save actions. You should probably include this one.", - "id" => "page-edit", - - "code" => function() { - - /* - * _ _ _ - * ___ __| (_) |_ - * / _ \/ _` | | __| - * | __/ (_| | | |_ - * \___|\__,_|_|\__| - * %edit% - */ - add_action("edit", function() { - global $pageindex, $settings, $page, $isloggedin; - - $filename = "$page.md"; - $creatingpage = !isset($pageindex->$page); - if((isset($_GET["newpage"]) and $_GET["newpage"] == "true") or $creatingpage) - { - $title = "Creating $page"; - } - else - { - $title = "Editing $page"; - } - - $pagetext = ""; - if(isset($pageindex->$page)) - { - $pagetext = file_get_contents($filename); - } - - if((!$isloggedin and !$settings->anonedits) or !$settings->editing) - { - if(!$creatingpage) - { - // The page already exists - let the user view the page source - exit(page_renderer::render_main("Viewing source for $page", "

    $settings->sitename does not allow anonymous users to make edits. You can view the source of $page below, but you can't edit it.

    ")); - } - else - { - http_response_code(404); - exit(page_renderer::render_main("404 - $page", "

    The page $page does not exist, but you do not have permission to create it.

    If you haven't already, perhaps you should try logging in.

    ")); - } - } - - $content = "

    $title

    "; - if(!$isloggedin and $settings->anonedits) - { - $content .= "

    Warning: You are not logged in! Your IP address may be recorded.

    "; - } - $content .= "
    - - -
    "; - exit(page_renderer::render_main("$title - $settings->sitename", $content)); - }); - - /* - * - * ___ __ ___ _____ - * / __|/ _` \ \ / / _ \ - * \__ \ (_| |\ V / __/ - * |___/\__,_| \_/ \___| - * %save% - */ - add_action("save", function() { - global $pageindex, $settings, $page, $isloggedin, $user; - if(!$settings->editing) - { - header("location: index.php?page=$page"); - exit(page_renderer::render_main("Error saving edit", "

    Editing is currently disabled on this wiki.

    ")); - } - if(!$isloggedin and !$settings->anonedits) - { - http_response_code(403); - header("refresh: 5; url=index.php?page=$page"); - exit("You are not logged in, so you are not allowed to save pages on $settings->sitename. Redirecting in 5 seconds...."); - } - if(!isset($_POST["content"])) - { - http_response_code(400); - header("refresh: 5; url=index.php?page=$page"); - exit("Bad request: No content specified."); - } - - // Make sure that the directory in which the page needs to be saved exists - if(!is_dir(dirname("$page.md"))) - { - // Recursively create the directory if needed - mkdir(dirname("$page.md"), null, true); - } - - - if(file_put_contents("$page.md", htmlentities($_POST["content"]), ENT_QUOTES) !== false) - { - // Make sure that this page's parents exist - check_subpage_parents($page); - - //update the page index - if(!isset($pageindex->$page)) - { - $pageindex->$page = new stdClass(); - $pageindex->$page->filename = "$page.md"; - } - $pageindex->$page->size = strlen($_POST["content"]); - $pageindex->$page->lastmodified = time(); - if($isloggedin) - $pageindex->$page->lasteditor = utf8_encode($user); - else - $pageindex->$page->lasteditor = utf8_encode("anonymous"); - - file_put_contents("./pageindex.json", json_encode($pageindex, JSON_PRETTY_PRINT)); - - if(isset($_GET["newpage"])) - http_response_code(201); - else - http_response_code(200); - - header("location: index.php?page=$page&edit_status=success"); - exit(); - } - else - { - http_response_code(507); - exit(page_renderer::render_main("Error saving page - $settings->sitename", "

    $settings->sitename failed to write your changes to the disk. Your changes have not been saved, but you might be able to recover your edit by pressing the back button in your browser.

    -

    Please tell the administrator of this wiki (" . $settings->admindetails["name"] . ") about this problem.

    ")); - } - }); - } -]); - - - - -register_module([ - "name" => "Export", - "version" => "0.1", - "author" => "Starbeamrainbowlabs", - "description" => "Adds a page that you can use to export your wiki as a .zip file. Uses \$settings->export_only_allow_admins, which controls whether only admins are allowed to export the wiki.", - "id" => "page-export", - "code" => function() { - add_action("export", function() { - global $settings, $pageindex, $isadmin; - - if($settings->export_allow_only_admins && !$isadmin) - { - http_response_code(401); - exit(page_renderer::render("Export error - $settings->sitename", "Only administrators of $settings->sitename are allowed to export the wiki as a zip. Return to the $settings->defaultpage.")); - } - - $tmpfilename = tempnam(sys_get_temp_dir(), "pepperminty-wiki-"); - - $zip = new ZipArchive(); - - if($zip->open($tmpfilename, ZipArchive::CREATE) !== true) - { - http_response_code(507); - exit(page_renderer::render("Export error - $settings->sitename", "Pepperminty Wiki was unable to open a temporary file to store the exported data in. Please contact $settings->sitename's administrator (" . $settings->admindetails["name"] . " at " . hide_email($settings->admindetails["email"]) . ") for assistance.")); - } - - foreach($pageindex as $entry) - { - $zip->addFile("./$entry->filename", $entry->filename); - } - - if($zip->close() !== true) - { - http_response_code(500); - exit(page_renderer::render("Export error - $settings->sitename", "Pepperminty wiki was unable to close the temporary zip file after creating it. Please contact $settings->sitename's administrator (" . $settings->admindetails["name"] . " at " . hide_email($settings->admindetails["email"]) . ") for assistance.")); - } - - header("content-type: application/zip"); - header("content-disposition: attachment; filename=$settings->sitename-export.zip"); - header("content-length: " . filesize($tmpfilename)); - - $zip_handle = fopen($tmpfilename, "rb"); - fpassthru($zip_handle); - fclose($zip_handle); - unlink($tmpfilename); - }); - } -]); - - - - -register_module([ - "name" => "Help page", - "version" => "0.6", - "author" => "Starbeamrainbowlabs", - "description" => "Adds the help action. You really want this one.", - "id" => "page-help", - "code" => function() { - add_action("help", function() { - global $settings, $version; - - $title = "Help - $settings->sitename"; - $content = "

    $settings->sitename Help

    -

    Welcome to $settings->sitename!

    -

    $settings->sitename is powered by Pepperminty wiki, a complete wiki in a box you can drop into your server.

    -

    Navigating

    -

    All the navigation links can be found in the top right corner, along with a box in which you can type a page name and hit enter to be taken to that page (if your site administrator has enabled it).

    -

    In order to edit pages on $settings->sitename, you probably need to be logged in. If you do not already have an account you will need to ask $settings->sitename's administrator for an account since there is not registration form. Note that the $settings->sitename's administrator may have changed these settings to allow anonymous edits.

    -

    Editing

    -

    $settings->sitename's editor uses a modified version of slimdown, a flavour of markdown that is implementated using regular expressions. See the credits page for more information and links to the original source for this. A quick reference can be found below:

    - - - - - - - - - - - - - - - - - -
    Type ThisTo get this
    _italics_italics
    *bold*bold
    ~~Strikethrough~~Strikethough
    `code`code
    # Heading

    Heading

    ## Sub Heading

    Sub Heading

    [[Internal Link]]Internal Link
    [[Display Text|Internal Link]]Display Text
    [Display text](//google.com/)Display Text
    > Blockquote
    > Some text
    Blockquote
    Some text
    - Apples
    * Oranges
    • Apples
    • Oranges
    1. This is
    2. an ordered list
    1. This is
    2. an ordered list
    - --- -
    ![Alt text](//starbeamrainbowlabs.com/favicon-small.png)Alt text
    - -

    In addition, the following extra syntax is supported for images:

    - -
    Size the image to at most 250 pixels wide:
    -![Alt text](//starbeamrainbowlabs.com/favicon-small.png 250px)
    -
    -Size the image to at most 120px wide and have it float at the right ahnd size of the page:
    -![Alt text](//starbeamrainbowlabs.com/favicon-small.png 120px right)
    - -

    Administrator Actions

    -

    By default, the delete and move actions are shown on the nav bar. These can be used by administrators to delete or move pages.

    -

    The other thing admininistrators can do is update the wiki (provided they know the site's secret). This page can be found here: Update $settings->sitename.

    -

    $settings->sitename is currently running on Pepperminty Wiki $version

    "; - exit(page_renderer::render_main($title, $content)); - }); - } -]); - - - - -register_module([ - "name" => "Page list", - "version" => "0.6", - "author" => "Starbeamrainbowlabs", - "description" => "Adds a page that lists all the pages in the index along with their metadata.", - "id" => "page-list", - "code" => function() { - add_action("list", function() { - global $pageindex, $settings; - - $sorted_pageindex = get_object_vars($pageindex); - ksort($sorted_pageindex, SORT_NATURAL); - $title = "All Pages"; - $content = "

    $title on $settings->sitename

    - - - - - - - \n"; - // todo list the pages in alphabetical order - foreach($sorted_pageindex as $pagename => $pagedetails) - { - $content .= "\t\t - - - - - - \n"; - } - $content .= "
    Page NameSizeLast EditorLast Edit Time
    $pagename" . human_filesize($pagedetails->size) . "$pagedetails->lasteditor" . human_time_since($pagedetails->lastmodified) . " (" . date("l jS \of F Y \a\\t h:ia T", $pagedetails->lastmodified) . ")
    "; - exit(page_renderer::render_main("$title - $settings->sitename", $content)); - }); - } -]); - - - - -register_module([ - "name" => "Login", - "version" => "0.5", - "author" => "Starbeamrainbowlabs", - "description" => "Adds a pair of actions (login and checklogin) that allow users to login. You need this one if you want your users to be able to login.", - "id" => "page-login", - "code" => function() { - /* - * _ _ - * | | ___ __ _(_)_ __ - * | |/ _ \ / _` | | '_ \ - * | | (_) | (_| | | | | | - * |_|\___/ \__, |_|_| |_| - * |___/ %login% - */ - add_action("login", function() { - global $settings; - $title = "Login to $settings->sitename"; - $content = "

    Login to $settings->sitename

    \n"; - if(isset($_GET["failed"])) - $content .= "\t\t

    Login failed.

    \n"; - $content .= "\t\t
    - - -
    - - -
    - -
    "; - exit(page_renderer::render_main($title, $content)); - }); - - /* - * _ _ _ _ - * ___| |__ ___ ___| | _| | ___ __ _(_)_ __ - * / __| '_ \ / _ \/ __| |/ / |/ _ \ / _` | | '_ \ - * | (__| | | | __/ (__| <| | (_) | (_| | | | | | - * \___|_| |_|\___|\___|_|\_\_|\___/ \__, |_|_| |_| - * %checklogin% |___/ - */ - add_action("checklogin", function() { - global $settings; - - //actually do the login - if(isset($_POST["user"]) and isset($_POST["pass"])) - { - //the user wants to log in - $user = $_POST["user"]; - $pass = $_POST["pass"]; - if($settings->users[$user] == hash("sha256", $pass)) - { - $isloggedin = true; - $expiretime = time() + 60*60*24*30; //30 days from now - $_SESSION["$settings->sessionprefix-user"] = $user; - $_SESSION["$settings->sessionprefix-pass"] = hash("sha256", $pass); - $_SESSION["$settings->sessionprefix-expiretime"] = $expiretime; - //redirect to wherever the user was going - http_response_code(302); - if(isset($_POST["goto"])) - header("location: " . $_POST["returnto"]); - else - header("location: index.php"); - exit(); - } - else - { - http_response_code(302); - header("location: index.php?action=login&failed=yes"); - exit(); - } - } - else - { - http_response_code(302); - header("location: index.php?action=login&failed=yes&badrequest=yes"); - exit(); - } - }); - } -]); - - - -register_module([ - "name" => "Logout", - "version" => "0.5", - "author" => "Starbeamrainbowlabs", - "description" => "Adds an action to let users user out. For security reasons it is wise to add this module since logging in automatically opens a session that is valid for 30 days.", - "id" => "page-logout", - "code" => function() { - add_action("logout", function() { - global $user, $pass, $isloggedin; - $isloggedin = false; - unset($user); - unset($pass); - //clear the session variables - $_SESSION = []; - session_destroy(); - - exit(page_renderer::render_main("Logout Successful", "

    Logout Successful

    -

    Logout Successful. You can login again here.

    ")); - }); - } -]); - - - - -register_module([ - "name" => "Page mover", - "version" => "0.5", - "author" => "Starbeamrainbowlabs", - "description" => "Adds an action to allow administrators to move pages.", - "id" => "page-move", - "code" => function() { - add_action("move", function() { - global $pageindex, $settings, $page, $isadmin; - if(!$settings->editing) - { - exit(page_renderer::render_main("Moving $page - error", "

    You tried to move $page, but editing is disabled on this wiki.

    -

    If you wish to move this page, please re-enable editing on this wiki first.

    -

    Go back to $page.

    -

    Nothing has been changed.

    ")); - } - if(!$isadmin) - { - exit(page_renderer::render_main("Moving $page - Error", "

    You tried to move $page, but you do not have permission to do that.

    -

    You should try logging in as an admin.

    ")); - } - - if(!isset($_GET["new_name"]) or strlen($_GET["new_name"]) == 0) - exit(page_renderer::render_main("Moving $page", "

    Moving $page

    -
    - - - -
    - - -
    - -
    ")); - - $new_name = makepathsafe($_GET["new_name"]); - - if(!isset($pageindex->$page)) - exit(page_renderer::render_main("Moving $page - Error", "

    You tried to move $page to $new_name, but the page with the name $page does not exist in the first place.

    -

    Nothing has been changed.

    ")); - - if($page == $new_name) - exit(page_renderer::render_main("Moving $page - Error", "

    You tried to move $page, but the new name you gave is the same as it's current name.

    -

    It is possible that you tried to use some characters in the new name that are not allowed and were removed.

    -

    Page names may only contain alphanumeric characters, dashes, and underscores.

    ")); - - //move the page in the page index - $pageindex->$new_name = new stdClass(); - foreach($pageindex->$page as $key => $value) - { - $pageindex->$new_name->$key = $value; - } - unset($pageindex->$page); - file_put_contents("./pageindex.json", json_encode($pageindex, JSON_PRETTY_PRINT)); - - //move the page on the disk - rename("$page.md", "$new_name.md"); - - exit(page_renderer::render_main("Moving $page", "

    $page has been moved to $new_name successfully.

    ")); - }); - } -]); - - - -register_module([ - "name" => "Update", - "version" => "0.6", - "author" => "Starbeamrainbowlabs", - "description" => "Adds an update page that downloads the latest stable version of Pepperminty Wiki. This module is currently outdated as it doesn't save your module preferences.", - "id" => "page-update", - "code" => function() { - add_action("update", function() { - global $settings, $isadmin; - - if(!$isadmin) - { - http_response_code(401); - exit(page_renderer::render_main("Update - Error", "

    You must be an administrator to do that.

    ")); - } - - if(!isset($_GET["do"]) or $_GET["do"] !== "true") - { - exit(page_renderer::render_main("Update $settings->sitename", "

    This page allows you to update $settings->sitename.

    -

    Currently, $settings->sitename is using $settings->version of Pepperminty Wiki.

    -

    This script will automatically download and install the latest version of Pepperminty Wiki from the url of your choice (see settings), regardless of whether an update is actually needed (version checking isn't implemented yet).

    -

    To update $settings->sitename, fill out the form below and click click the update button.

    -

    Note that a backup system has not been implemented yet! If this script fails you will loose your wiki's code and have to re-build it.

    -
    - - - - - -
    ")); - } - - if(!isset($_GET["secret"]) or $_GET["secret"] !== $settings->sitesecret) - { - exit(page_renderer::render_main("Update $settings->sitename - Error", "

    You forgot to enter $settings->sitename's secret code or entered it incorrectly. $settings->sitename's secret can be found in the settings portion of index.php.

    ")); - } - - $settings_separator = "/////////////// Do not edit below this line unless you know what you are doing! ///////////////"; - - $log = "Beginning update...\n"; - - $log .= "I am " . __FILE__ . ".\n"; - $oldcode = file_get_contents(__FILE__); - $log .= "Fetching new code..."; - $newcode = file_get_contents($settings->updateurl); - $log .= "done.\n"; - - $log .= "Rewriting " . __FILE__ . "..."; - $settings = substr($oldcode, 0, strpos($oldcode, $settings_separator)); - $code = substr($newcode, strpos($newcode, $settings_separator)); - $result = $settings . $code; - $log .= "done.\n"; - - $log .= "Saving..."; - file_put_contents(__FILE__, $result); - $log .= "done.\n"; - - $log .= "Update complete. I am now running on the latest version of Pepperminty Wiki."; - $log .= "The version number that I have updated to can be found on the credits or help ages."; - - exit(page_renderer::render_main("Update - Success", "")); - }); - } -]); - - - -register_module([ - "name" => "Page viewer", - "version" => "0.8", - "author" => "Starbeamrainbowlabs", - "description" => "Allows you to view pages. You should include this one.", - "id" => "page-view", - "code" => function() { - add_action("view", function() { - global $pageindex, $settings, $page, $parse_page_source; - - // Check to make sure that the page exists - if(!isset($pageindex->$page)) - { - // todo make this intelligent so we only redirect if the user is acutally able to create the page - if($settings->editing) - { - // Editing is enabled, redirect to the editing page - http_response_code(307); // Temporary redirect - header("location: index.php?action=edit&newpage=yes&page=" . rawurlencode($page)); - exit(); - } - else - { - // Editing is disabled, show an error message - http_response_code(404); - exit(page_renderer::render_main("$page - 404 - $settings->sitename", "

    $page does not exist.

    Since editing is currently disabled on this wiki, you may not create this page. If you feel that this page should exist, try contacting this wiki's Administrator.

    ")); - } - } - $title = "$page - $settings->sitename"; - $content = "

    $page

    "; - - $parsing_start = microtime(true); - - $content .= $parse_page_source(file_get_contents("$page.md")); - - if($settings->show_subpages) - { - $subpages = get_object_vars(get_subpages($pageindex, $page)); - - if(count($subpages) > 0) - { - $content .= "
    "; - $content .= "Subpages: "; - foreach($subpages as $subpage => $times_removed) - { - if($times_removed <= $settings->subpages_display_depth) - { - $content .= "$subpage, "; - } - } - // Remove the last comma from the content - $content = substr($content, 0, -2); - } - } - - $content .= "\n\t\t\n"; - - if(isset($_GET["printable"]) and $_GET["printable"] === "yes") - exit(page_renderer::render_minimal($title, $content)); - else - exit(page_renderer::render_main($title, $content)); - }); - } -]); - - - - -register_module([ - "name" => "Default Parser", - "version" => "0.7", - "author" => "Johnny Broadway & Starbeamrainbowlabs", - "description" => "The default parser for Pepperminty Wiki. Based on Johnny Broadway's Slimdown (with more than a few modifications). This parser's features are documented in the help page.", - "id" => "parser-default", - "code" => function() { - add_parser(function($markdown) { - return Slimdown::render($markdown); - }); - } -]); - -//////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////// Slimdown ///////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// %slimdown% // -//////////////////////////////////////////////////////////////////////////////////////////// -/** - * Slimdown - A very basic regex-based Markdown parser. Supports the - * following elements (and can be extended via Slimdown::add_rule()): - * - * - Headers - * - Links - * - Bold - * - Emphasis - * - Deletions - * - Quotes - * - Inline code - * - Blockquotes - * - Ordered/unordered lists - * - Horizontal rules - * - * Author: Johnny Broadway - * Website: https://gist.github.com/jbroadway/2836900 - * License: MIT - */ - -/** - * Modified by Starbeamrainbowlabs (starbeamrainbowlabs) - * - * Changed bold to use single asterisks - * Changed italics to use single underscores - * Added one to add the heading levels (no

    tags allowed) - * Added wiki style internal link parsing - * Added wiki style internal link parsing with display text - * Added image support - */ -class Slimdown { - public static $rules = array ( - '/\r\n/' => "\n", // new line normalisation - '/(#+)(.*)/' => 'self::header', // headers - '/(\*)(.*?)\1/' => '\2', // bold - '/(_)(.*?)\1/' => '\2', // emphasis - - // todo test these - '/!\[(.*)\]\(([^\s]+)\s(\d+.+)\s(left|right)\)/' => '\1', // images with size - '/!\[(.*)\]\(([^\s]+)\s(\d+.+)\)/' => '\1', // images with size - '/!\[(.*)\]\((.*)\)/' => '\1', // basic images - // todo end - - '/\[\[([a-zA-Z0-9\_\- ]+)\|([a-zA-Z0-9\_\- ]+)\]\]/' => '\2', //internal links with display text - '/\[\[([a-zA-Z0-9\_\- ]+)\]\]/' => '\1', //internal links - '/\[([^\[]+)\]\(([^\)]+)\)/' => '\1', // links - '/\~\~(.*?)\~\~/' => '\1', // del - '/\:\"(.*?)\"\:/' => '\1', // quote - '/`(.*?)`/' => '\1', // inline code - '/\n\s*(\*|-)(.*)/' => 'self::ul_list', // ul lists - '/\n[0-9]+\.(.*)/' => 'self::ol_list', // ol lists - '/\n(>|\>)(.*)/' => 'self::blockquote', // blockquotes - '/\n-{3,}/' => "\n
    ", // horizontal rule - '/\n([^\n]+)\n\n/' => 'self::para', // add paragraphs - '/<\/ul>\s?
      /' => '', // fix extra ul - '/<\/ol>\s?
        /' => '', // fix extra ol - '/<\/blockquote>
        /' => "\n" // fix extra blockquote - ); - private static function para ($regs) { - $line = $regs[1]; - $trimmed = trim ($line); - if (preg_match ('/^<\/?(ul|ol|li|h|p|bl)/', $trimmed)) { - return "\n" . $line . "\n"; - } - return sprintf ("\n

        %s

        \n", $trimmed); - } - private static function ul_list ($regs) { - $item = $regs[2]; - return sprintf ("\n
          \n\t
        • %s
        • \n
        ", trim($item)); - } - private static function ol_list ($regs) { - $item = $regs[1]; - return sprintf ("\n
          \n\t
        1. %s
        2. \n
        ", trim($item)); - } - private static function blockquote ($regs) { - $item = $regs[2]; - return sprintf ("\n
        %s
        ", trim($item)); - } - private static function header ($regs) { - list ($tmp, $chars, $header) = $regs; - $level = strlen ($chars); - return sprintf ('%s', $level + 1, trim($header), $level + 1); - } - - /** - * Add a rule. - */ - public static function add_rule ($regex, $replacement) { - self::$rules[$regex] = $replacement; - } - /** - * Render some Markdown into HTML. - */ - public static function render ($text) { - foreach (self::$rules as $regex => $replacement) { - if (is_callable ( $replacement)) { - $text = preg_replace_callback ($regex, $replacement, $text); - } else { - $text = preg_replace ($regex, $replacement, $text); - } - } - return trim ($text); - } -} -//////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////// - - - -// %next_module% // - - -// Execute each module's code -foreach($modules as $moduledata) -{ - $moduledata["code"](); -} -// Make sure that the credits page exists -if(!isset($actions->credits)) -{ - exit(page_renderer::render_main("Error - $settings->$sitename", "

        No credits page detected. The credits page is a required module!

        ")); -} - -// Perform the appropriate action -$action_name = strtolower($_GET["action"]); -if(isset($actions->$action_name)) -{ - $req_action_data = $actions->$action_name; - $req_action_data(); -} -else -{ - exit(page_renderer::render_main("Error - $settings->sitename", "

        No action called " . strtolower($_GET["action"]) ." has been registered. Perhaps you are missing a module?

        ")); -} -?> + + +/////////////////////////////////////////////////////////////////////////////////////////////// +/////////////// Do not edit below this line unless you know what you are doing! /////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// +$version = "0.7"; +session_start(); +///////// Login System ///////// +//clear expired sessions +if(isset($_SESSION["$settings->sessionprefix-expiretime"]) and + $_SESSION["$settings->sessionprefix-expiretime"] < time()) +{ + //clear the session variables + $_SESSION = []; + session_destroy(); +} + +if(!isset($_SESSION[$settings->sessionprefix . "-user"]) and + !isset($_SESSION[$settings->sessionprefix . "-pass"])) +{ + //the user is not logged in + $isloggedin = false; +} +else +{ + $user = $_SESSION[$settings->sessionprefix . "-user"]; + $pass = $_SESSION[$settings->sessionprefix . "-pass"]; + if($settings->users[$user] == $pass) + { + //the user is logged in + $isloggedin = true; + } + else + { + //the user's login details are invalid (what is going on here?) + //unset the session variables, treat them as an anonymous user, and get out of here + $isloggedin = false; + unset($user); + unset($pass); + //clear the session data + $_SESSION = []; //delete al lthe variables + session_destroy(); //destroy the session + } +} +//check to see if the currently logged in user is an admin +$isadmin = false; +if($isloggedin) +{ + foreach($settings->admins as $admin_username) + { + if($admin_username == $user) + { + $isadmin = true; + break; + } + } +} +/////// Login System End /////// + +/////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////// Functions //////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////// + +/* + * @summary Converts a filesize into a human-readable string. + * @source http://php.net/manual/en/function.filesize.php#106569 + * @editor Starbeamrainbowlabs + * + * @param $bytes - The number of bytes to convert. + * @param $decimals - The number of decimal places to preserve. + */ +function human_filesize($bytes, $decimals = 2) +{ + $sz = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "YB", "ZB"]; + $factor = floor((strlen($bytes) - 1) / 3); + return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . @$sz[$factor]; +} +/* + * @summary Calculates the time sincce a particular timestamp and returns a + * human-readable result. + * @source http://snippets.pro/snippet/137-php-convert-the-timestamp-to-human-readable-format/ + * + * @param $time - The timestamp to convert. + * + * @returns {string} - The time since the given timestamp pas a human-readable string. + */ +function human_time_since($time) +{ + $timediff = time() - $time; + $tokens = array ( + 31536000 => 'year', + 2592000 => 'month', + 604800 => 'week', + 86400 => 'day', + 3600 => 'hour', + 60 => 'minute', + 1 => 'second' + ); + foreach ($tokens as $unit => $text) { + if ($timediff < $unit) continue; + $numberOfUnits = floor($timediff / $unit); + return $numberOfUnits.' '.$text.(($numberOfUnits>1)?'s':'').' ago'; + } +} + +/* + * @summary A recursive glob() function. + * + * @param $pattern - The glob pattern to use to find filenames. + * @param $flags - The glob flags to use when finding filenames. + * + * @returns {array} - An array of the filepaths that match the given glob. + */ +// From http://in.php.net/manual/en/function.glob.php#106595 +function glob_recursive($pattern, $flags = 0) +{ + $files = glob($pattern, $flags); + foreach (glob(dirname($pattern).'/*', GLOB_ONLYDIR|GLOB_NOSORT) as $dir) + { + $prefix = "$dir/"; + // Remove the "./" from the beginning if it exists + if(substr($prefix, 0, 2) == "./") $prefix = substr($prefix, 2); + $files = array_merge($files, glob_recursive($prefix . basename($pattern), $flags)); + } + return $files; +} + +/* + * @summary Gets a list of all the sub pagess of the current page. + * + * @param $pageindex - The pageindex to use to search. + * @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. + */ +function get_subpages($pageindex, $pagename) +{ + $pagenames = get_object_vars($pageindex); + $result = new stdClass(); + + $stem = "$pagename/"; + $stem_length = strlen($stem); + foreach($pagenames as $entry => $value) + { + if(substr($entry, 0, $stem_length) == $stem) + { + // We found a subpage + + // Extract the subpage's key relative to the page that we are searching for + $subpage_relative_key = substr($entry, $stem_length, -3); + // Calculate how many times removed the current subpage is from the current page. 0 = direct descendant. + $times_removed = substr_count($subpage_relative_key, "/"); + // Store the name of the subpage we found + $result->$entry = $times_removed; + } + } + + unset($pagenames); + return $result; +} + +/* + * @summary Makes sure that a subpage's parents exist. Note this doesn't check the pagename itself. + * + * @param The pagename to check. + * + */ +function check_subpage_parents($pagename) +{ + global $pageindex; + // Save the new pageindex and return if there aren't any more parent pages to check + if(strpos($pagename, "/") === false) + { + file_put_contents("./pageindex.json", json_encode($pageindex, JSON_PRETTY_PRINT)); + return; + } + + $parent_pagename = substr($pagename, 0, strrpos($pagename, "/")); + $parent_page_filename = "$parent_pagename.md"; + if(!file_exists($parent_page_filename)) + { + // This parent page doesn't exist! Create it and add it to the page index. + touch($parent_page_filename, 0); + + $newentry = new stdClass(); + $newentry->filename = $parent_page_filename; + $newentry->size = 0; + $newentry->lastmodified = 0; + $newentry->lasteditor = "none"; + $pageindex->$parent_pagename = $newentry; + } + + check_subpage_parents($parent_pagename); +} + +/* + * @summary makes a path safe + * + * @details paths may only contain alphanumeric characters, spaces, underscores, and dashes + */ +function makepathsafe($string) +{ + return preg_replace("/[^0-9a-zA-Z\_\-\ \/]/i", "", $string); +} + +/* + * @summary Hides an email address from bots by adding random html entities. + * + * @returns The mangled email address. + */ +function hide_email($str) +{ + $hidden_email = ""; + for($i = 0; $i < strlen($str); $i++) + { + if($str[$i] == "@") + { + $hidden_email .= "&#" . ord("@") . ";"; + continue; + } + if(rand(0, 1) == 0) + $hidden_email .= $str[$i]; + else + $hidden_email .= "&#" . ord($str[$i]) . ";"; + } + + return $hidden_email; +} + +/////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////// Security and Consistency Measures //////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////// + +/* + * Sort out the pageindex. We create it if it doesn't exist, and load and parse + * it if it does. + */ +if(!file_exists("./pageindex.json")) +{ + $existingpages = glob_recursive("*.md"); + $pageindex = new stdClass(); + // We use a for loop here because foreach doesn't loop over new values inserted + // while we were looping + for($i = 0; $i < count($existingpages); $i++) + { + $pagefilename = $existingpages[$i]; + + // Create a new entry + $newentry = new stdClass(); + $newentry->filename = utf8_encode($pagefilename); // Store the filename + $newentry->size = filesize($pagefilename); // Store the page size + $newentry->lastmodified = filemtime($pagefilename); // Store the date last modified + // Todo find a way to keep the last editor independent of the page index + $newentry->lasteditor = utf8_encode("unknown"); // Set the editor to "unknown" + // Extract the name of the (sub)page without the ".md" + $pagekey = utf8_encode(substr($pagefilename, 0, -3)); + + // Subpage parent checker + if(strpos($pagekey, "/") !== false) + { + // We have a sub page people + // Work out what our direct parent's key must be in order to check to + // make sure that it actually exists. If it doesn't, then we need to + // create it. + $subpage_parent_key = substr($pagekey, 0, strrpos($pagekey, "/")); + $subpage_parent_filename = "$subpage_parent_key.md"; + if(array_search($subpage_parent_filename, $existingpages) === false) + { + // Our parent page doesn't acutally exist - create it + touch($subpage_parent_filename, 0); + // Furthermore, we should add this page to the list of existing pages + // in order for it to be indexed + $existingpages[] = $subpage_parent_filename; + } + } + + // Store the new entry in the new page index + $pageindex->$pagekey = $newentry; + } + file_put_contents("./pageindex.json", json_encode($pageindex, JSON_PRETTY_PRINT)); + unset($existingpages); +} +else +{ + $pageindex = json_decode(file_get_contents("./pageindex.json")); +} + +// Work around an Opera + Syntastic bug where there is no margin at the left hand side if there isn't a query string when accessing a .php file +if(!isset($_GET["action"]) and !isset($_GET["page"])) +{ + http_response_code(302); + header("location: index.php?action=$settings->defaultaction&page=$defaultpage"); + exit(); +} + +// Make sure that the action is set +if(!isset($_GET["action"])) + $_GET["action"] = $settings->defaultaction; +// Make sure that the page is set +if(!isset($_GET["page"]) or strlen($_GET["page"]) === 0) + $_GET["page"] = $settings->defaultpage; + +// Redirect the user to the safe version of the path if they entered an unsafe character +if(makepathsafe($_GET["page"]) !== $_GET["page"]) +{ + http_response_code(301); + header("location: index.php?action=" . rawurlencode($_GET["action"]) . "&page=" . makepathsafe($_GET["page"])); + header("x-requested-page: " . $_GET["page"]); + header("x-actual-page: " . makepathsafe($_GET["page"])); + exit(); +} +$page = $_GET["page"]; + +/////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////// HTML fragments ////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////// +class page_renderer +{ + public static $html_template = " + + + + {title} + + + + {header-html} + + + {body} + + + +"; + + public static $main_content_template = "{navigation-bar} +

        {sitename}

        +
        + {content} +
        + +
        +

        Powered by Pepperminty Wiki, which was built by Starbeamrainbowlabs. Send bugs to 'bugs at starbeamrainbowlabs dot com' or open an issue on github.

        +

        Your local friendly administrators are {admins-name-list}. +

        This wiki is managed by {admin-details-name}.

        +
        + {navigation-bar-bottom} + {all-pages-datalist}"; + public static $minimal_content_template = "
        {content}
        +
        +
        +

        From {sitename}, which is managed by {admin-details-name}.

        +

        Timed at {generation-date} +

        Powered by Pepperminty Wiki.

        +
        "; + + // An array of functions that have been registered to process the + // find / replace array before the page is rendered. Note that the function + // should take a *reference* to an array as its only argument. + protected static $part_processors = []; + + // Registers a function as a part post processor. + public static function register_part_preprocessor($function) + { + // Make sure that the function we are about to register is valid + if(!is_callable($function)) + { + http_response_code(500); + $admin_name = $settings->admindetails["name"]; + $admin_email = hide_email($settings->admindetails["email"]); + exit(page_renderer::render("$settings->sitename - Module Error", "

        $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 $admin_email.")); + } + + self::$part_processors[] = $function; + + return true; + } + + public static function render($title, $content, $body_template = false) + { + global $settings, $start_time; + + if($body_template === false) + $body_template = self::$main_content_template; + + $parts = [ + "{body}" => $body_template, + + "{sitename}" => $settings->sitename, + "{favicon-url}" => $settings->favicon, + "{header-html}" => self::get_css_as_html(), + + "{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"), + + "{admin-details-name}" => $settings->admindetails["name"], + "{admin-details-email}" => $settings->admindetails["email"], + + "{admins-name-list}" => implode(", ", $settings->admins), + + "{generation-date}" => date("l jS \of F Y \a\\t h:ia T"), + + "{all-pages-datalist}" => self::generate_all_pages_datalist() + ]; + + // Pass the parts through the part processors + foreach(self::$part_processors as $function) + { + $function($parts); + } + + $result = self::$html_template; + $result = str_replace("{body}", $parts["{body}"], $result); + + $result = str_replace(array_keys($parts), array_values($parts), $result); + + $result = str_replace([ + "{title}", + "{content}" + ], [ + $title, + $content + ], $result); + + $result = str_replace("{generation-time-taken}", microtime(true) - $start_time, $result); + return $result; + } + public static function render_main($title, $content) + { + return self::render($title, $content, self::$main_content_template); + } + public static function render_minimal($title, $content) + { + return self::render($title, $content, self::$minimal_content_template); + } + + + public static function get_css_as_html() + { + global $settings; + + if(preg_match("/^[^\/]*\/\/|^\//", $settings->css)) + return ""; + else + return ""; + } + + public static $nav_divider = " | "; + + /* + * @summary Function to render a navigation bar from an array of links. See + * $settings->nav_links for format information. + * + * @param $nav_links - The links to add to the navigation bar. + * @param $nav_links_extra - The extra nav links to add to the "More..." + * menu. + */ + public static function render_navigation_bar($nav_links, $nav_links_extra, $class = "") + { + global $settings, $user, $isloggedin, $page; + $result = "

        "; + return $result; + } + public static function render_username($name) + { + global $settings; + $result = ""; + if(in_array($name, $settings->admins)) + $result .= $settings->admindisplaychar; + $result .= $name; + + return $result; + } + + public static function generate_all_pages_datalist() + { + global $pageindex; + + $result = "\n"; + foreach($pageindex as $pagename => $pagedetails) + { + $result .= "\t\t\t"; + + return $result; + } +} + +////////////////////////// +/// Module functions /// +////////////////////////// +// These functions are // +// used by modules to // +// register themselves // +// or new pages. // +////////////////////////// +$modules = []; // List that contains all the loaded modules +// Function to register a module +function register_module($moduledata) +{ + global $modules; + //echo("registering module\n"); + //var_dump($moduledata); + $modules[] = $moduledata; +} + +// Function to register an action handler +$actions = new stdClass(); +function add_action($action_name, $func) +{ + global $actions; + //echo("adding $action_name\n"); + $actions->$action_name = $func; +} + +// Function to register a new parser. If multiple parsers are registered then +// only the last parser registered will actually be used. +$parse_page_source = function() { + throw new Exception("No parser registered!"); +}; +function add_parser($parser_code) +{ + global $parse_page_source; + $parse_page_source = $parser_code; +} + +////////////////////////////////////////////////////////////////// + + + +register_module([ + "name" => "Password hashing action", + "version" => "0.5", + "author" => "Starbeamrainbowlabs", + "description" => "Adds a utility action (that anyone can use) called hash that hashes a given string. Useful when changing a user's password.", + "id" => "action-hash", + "code" => function() { + add_action("hash", function() { + if(!isset($_GET["string"])) + { + http_response_code(422); + exit(page_renderer::render_main("Missing parameter", "

        The GET parameter string must be specified.

        +

        It is strongly recommended that you utilise this page via a private or incognito window in order to prevent your password from appearing in your browser history.

        ")); + } + else + { + exit(page_renderer::render_main("Hashed string", "

        " . $_GET["string"] . "" . hash("sha256", $_GET["string"] . "

        "))); + } + }); + } +]); + + + + +register_module([ + "name" => "Sidebar", + "version" => "0.2", + "author" => "Starbeamrainbowlabs", + "description" => "Adds a sidebar to the left hand side of every page. Add '\$settings->sidebar_show = true;' to your configuration, or append '&sidebar=yes' to the url to enable. Adding to the url sets a cookie to remember your setting.", + "id" => "extra-sidebar", + "code" => function() { + $show_sidebar = false; + + // Show the sidebar if it is enabled in the settings + if(isset($settings->sidebar_show) && $settings->sidebar_show === true) + $show_sidebar = true; + + // Also show and persist the sidebar if the special GET parameter + // sidebar is seet + if(!$show_sidebar && isset($_GET["sidebar"])) + { + $show_sidebar = true; + // Set a cookie to persist the display of the sidebar + setcookie("sidebar_show", "true", time() + (60 * 60 * 24 * 30)); + } + + // Show the sidebar if the cookie is set + if(!$show_sidebar && isset($_COOKIE["sidebar_show"])) + $show_sidebar = true; + + // Delete the cookie and hide the sidebar if the special GET paramter + // nosidebar is set + if(isset($_GET["nosidebar"])) + { + $show_sidebar = false; + unset($_COOKIE["sidebar_show"]); + setcookie("sidebar_show", null, time() - 3600); + } + + page_renderer::register_part_preprocessor(function(&$parts) use ($show_sidebar) { + global $settings, $pageindex; + + if($show_sidebar && !isset($_GET["printable"])) + { + // Show the sidebar + $exec_start = microtime(true); + + // Sort the pageindex + $sorted_pageindex = get_object_vars($pageindex); + ksort($sorted_pageindex, SORT_NATURAL); + + $sidebar_contents = ""; + $sidebar_contents .= render_sidebar($sorted_pageindex); + + $parts["{body}"] = " +
        " . $parts["{body}"] . "
        + + "; + } + }); + } +]); + +/* + * @summary Renders the sidebar for a given pageindex. + * + * @param $pageindex {array} - The pageindex to render the sidebar for + * @param $root_pagename {string} - The pagename that should be considered the root of the rendering. You don't usually need to use this, it is used by the algorithm itself since it is recursive. + * + * @returns {string} A HTML rendering of the sidebar for the given pageindex + */ +function render_sidebar($pageindex, $root_pagename = "") +{ + global $settings; + + $result = " $details) + { + // If we have a valid root pagename, and it isn't present at the + // beginning of the current pagename, skip it + if($root_pagename !== "" && strpos($pagename, $root_pagename) !== 0) + continue; + + // The current page is the same as the root page, skip it + if($pagename == $root_pagename) + continue; + + + // If the part of the current pagename that comes after the root + // pagename has a slash in it, skip it as it is a sub-sub page. + if(strpos(substr($pagename, strlen($root_pagename)), "/") !== false) + continue; + + $result .= "
      1. $pagename\n"; + $result .= render_sidebar($pageindex, $pagename); + $result .= "
      2. \n"; + } + $result .= "
    \n"; + + return $result == "
      \n" ? "" : $result; +} + + + + +register_module([ + "name" => "Credits", + "version" => "0.6", + "author" => "Starbeamrainbowlabs", + "description" => "Adds the credits page. You *must* have this module :D", + "id" => "page-credits", + "code" => function() { + add_action("credits", function() { + global $settings, $version, $pageindex, $modules; + + $credits = [ + "Code" => [ + "author" => "Starbeamrainbowlabs", + "author_url" => "https://starbeamrmainbowlabs.com/", + "thing_url" => "https://github.com/sbrl/Pepprminty-Wiki" + ], + "Slightly modified version of Slimdown" => [ + "author" => "Johnny Broadway", + "author_url" => "https://github.com/jbroadway", + "thing_url" => "https://gist.github.com/jbroadway/2836900" + ], + "Default Favicon" => [ + "author" => "bluefrog23", + "author_url" => "https://openclipart.org/user-detail/bluefrog23/", + "thing_url" => "https://openclipart.org/detail/19571/peppermint-candy-by-bluefrog23" + ], + "Bug Reports" => [ + "author" => "nibreh", + "author_url" => "https://github.com/nibreh/", + "thing_url" => "" + ] + ]; + $credits_html = "
        \n"; + foreach($credits as $thing => $author_details) + { + $credits_html .= "
      • "; + $credits_html .= "$thing by "; + $credits_html .= "" . $author_details["author"] . ""; + $credits_html .= "
      • \n"; + } + $credits_html .= "
      "; + + $title = "Credits - $settings->sitename"; + $content = "

      $settings->sitename credits

      +

      $settings->sitename is powered by Pepperminty Wiki - an entire wiki packed inside a single file, which was built by Starbeamrainbowlabs, and can be found on GitHub (contributors will ablso be listed here in the future).

      +

      Main Credits

      + $credits_html +

      Site status

      + + + + + +
      Site name:$settings->sitename (Update - Administrators only, Export as zip - Check for permission first)
      Pepperminty Wiki version:$version
      Number of pages:" . count(get_object_vars($pageindex)) . "
      Number of modules:" . count($modules) . "
      "; + exit(page_renderer::render_main($title, $content)); + }); + } +]); + + + + +register_module([ + "name" => "Page deleter", + "version" => "0.5", + "author" => "Starbeamrainbowlabs", + "description" => "Adds an action to allow administrators to delete pages.", + "id" => "page-delete", + "code" => function() { + add_action("delete", function() { + global $pageindex, $settings, $page, $isadmin; + if(!$settings->editing) + { + exit(page_renderer::render_main("Deleting $page - error", "

      You tried to delete $page, but editing is disabled on this wiki.

      +

      If you wish to delete this page, please re-enable editing on this wiki first.

      +

      Go back to $page.

      +

      Nothing has been changed.

      ")); + } + if(!$isadmin) + { + exit(page_renderer::render_main("Deleting $page - error", "

      You tried to delete $page, but you are not an admin so you don't have permission to do that.

      +

      You should try logging in as an admin.

      ")); + } + if(!isset($_GET["delete"]) or $_GET["delete"] !== "yes") + { + exit(page_renderer::render_main("Deleting $page", "

      You are about to delete $page. You can't undo this!

      +

      Click here to delete $page.

      +

      Click here to go back.")); + } + unset($pageindex->$page); //delete the page from the page index + file_put_contents("./pageindex.json", json_encode($pageindex, JSON_PRETTY_PRINT)); //save the new page index + unlink("./$page.md"); //delete the page from the disk + + exit(page_renderer::render_main("Deleting $page - $settings->sitename", "

      $page has been deleted. Go back to the main page.

      ")); + }); + } +]); + + + + +register_module([ + "name" => "Page editor", + "version" => "0.8", + "author" => "Starbeamrainbowlabs", + "description" => "Allows you to edit pages by adding the edit and save actions. You should probably include this one.", + "id" => "page-edit", + + "code" => function() { + + /* + * _ _ _ + * ___ __| (_) |_ + * / _ \/ _` | | __| + * | __/ (_| | | |_ + * \___|\__,_|_|\__| + * %edit% + */ + add_action("edit", function() { + global $pageindex, $settings, $page, $isloggedin; + + $filename = "$page.md"; + $creatingpage = !isset($pageindex->$page); + if((isset($_GET["newpage"]) and $_GET["newpage"] == "true") or $creatingpage) + { + $title = "Creating $page"; + } + else + { + $title = "Editing $page"; + } + + $pagetext = ""; + if(isset($pageindex->$page)) + { + $pagetext = file_get_contents($filename); + } + + if((!$isloggedin and !$settings->anonedits) or !$settings->editing) + { + if(!$creatingpage) + { + // The page already exists - let the user view the page source + exit(page_renderer::render_main("Viewing source for $page", "

      $settings->sitename does not allow anonymous users to make edits. You can view the source of $page below, but you can't edit it.

      ")); + } + else + { + http_response_code(404); + exit(page_renderer::render_main("404 - $page", "

      The page $page does not exist, but you do not have permission to create it.

      If you haven't already, perhaps you should try logging in.

      ")); + } + } + + $content = "

      $title

      "; + if(!$isloggedin and $settings->anonedits) + { + $content .= "

      Warning: You are not logged in! Your IP address may be recorded.

      "; + } + $content .= "
      + + +
      "; + exit(page_renderer::render_main("$title - $settings->sitename", $content)); + }); + + /* + * + * ___ __ ___ _____ + * / __|/ _` \ \ / / _ \ + * \__ \ (_| |\ V / __/ + * |___/\__,_| \_/ \___| + * %save% + */ + add_action("save", function() { + global $pageindex, $settings, $page, $isloggedin, $user; + if(!$settings->editing) + { + header("location: index.php?page=$page"); + exit(page_renderer::render_main("Error saving edit", "

      Editing is currently disabled on this wiki.

      ")); + } + if(!$isloggedin and !$settings->anonedits) + { + http_response_code(403); + header("refresh: 5; url=index.php?page=$page"); + exit("You are not logged in, so you are not allowed to save pages on $settings->sitename. Redirecting in 5 seconds...."); + } + if(!isset($_POST["content"])) + { + http_response_code(400); + header("refresh: 5; url=index.php?page=$page"); + exit("Bad request: No content specified."); + } + + // Make sure that the directory in which the page needs to be saved exists + if(!is_dir(dirname("$page.md"))) + { + // Recursively create the directory if needed + mkdir(dirname("$page.md"), null, true); + } + + + if(file_put_contents("$page.md", htmlentities($_POST["content"]), ENT_QUOTES) !== false) + { + // Make sure that this page's parents exist + check_subpage_parents($page); + + //update the page index + if(!isset($pageindex->$page)) + { + $pageindex->$page = new stdClass(); + $pageindex->$page->filename = "$page.md"; + } + $pageindex->$page->size = strlen($_POST["content"]); + $pageindex->$page->lastmodified = time(); + if($isloggedin) + $pageindex->$page->lasteditor = utf8_encode($user); + else + $pageindex->$page->lasteditor = utf8_encode("anonymous"); + + file_put_contents("./pageindex.json", json_encode($pageindex, JSON_PRETTY_PRINT)); + + if(isset($_GET["newpage"])) + http_response_code(201); + else + http_response_code(200); + + header("location: index.php?page=$page&edit_status=success"); + exit(); + } + else + { + http_response_code(507); + exit(page_renderer::render_main("Error saving page - $settings->sitename", "

      $settings->sitename failed to write your changes to the disk. Your changes have not been saved, but you might be able to recover your edit by pressing the back button in your browser.

      +

      Please tell the administrator of this wiki (" . $settings->admindetails["name"] . ") about this problem.

      ")); + } + }); + } +]); + + + + +register_module([ + "name" => "Export", + "version" => "0.1", + "author" => "Starbeamrainbowlabs", + "description" => "Adds a page that you can use to export your wiki as a .zip file. Uses \$settings->export_only_allow_admins, which controls whether only admins are allowed to export the wiki.", + "id" => "page-export", + "code" => function() { + add_action("export", function() { + global $settings, $pageindex, $isadmin; + + if($settings->export_allow_only_admins && !$isadmin) + { + http_response_code(401); + exit(page_renderer::render("Export error - $settings->sitename", "Only administrators of $settings->sitename are allowed to export the wiki as a zip. Return to the $settings->defaultpage.")); + } + + $tmpfilename = tempnam(sys_get_temp_dir(), "pepperminty-wiki-"); + + $zip = new ZipArchive(); + + if($zip->open($tmpfilename, ZipArchive::CREATE) !== true) + { + http_response_code(507); + exit(page_renderer::render("Export error - $settings->sitename", "Pepperminty Wiki was unable to open a temporary file to store the exported data in. Please contact $settings->sitename's administrator (" . $settings->admindetails["name"] . " at " . hide_email($settings->admindetails["email"]) . ") for assistance.")); + } + + foreach($pageindex as $entry) + { + $zip->addFile("./$entry->filename", $entry->filename); + } + + if($zip->close() !== true) + { + http_response_code(500); + exit(page_renderer::render("Export error - $settings->sitename", "Pepperminty wiki was unable to close the temporary zip file after creating it. Please contact $settings->sitename's administrator (" . $settings->admindetails["name"] . " at " . hide_email($settings->admindetails["email"]) . ") for assistance.")); + } + + header("content-type: application/zip"); + header("content-disposition: attachment; filename=$settings->sitename-export.zip"); + header("content-length: " . filesize($tmpfilename)); + + $zip_handle = fopen($tmpfilename, "rb"); + fpassthru($zip_handle); + fclose($zip_handle); + unlink($tmpfilename); + }); + } +]); + + + + +register_module([ + "name" => "Help page", + "version" => "0.6", + "author" => "Starbeamrainbowlabs", + "description" => "Adds the help action. You really want this one.", + "id" => "page-help", + "code" => function() { + add_action("help", function() { + global $settings, $version; + + $title = "Help - $settings->sitename"; + $content = "

      $settings->sitename Help

      +

      Welcome to $settings->sitename!

      +

      $settings->sitename is powered by Pepperminty wiki, a complete wiki in a box you can drop into your server.

      +

      Navigating

      +

      All the navigation links can be found in the top right corner, along with a box in which you can type a page name and hit enter to be taken to that page (if your site administrator has enabled it).

      +

      In order to edit pages on $settings->sitename, you probably need to be logged in. If you do not already have an account you will need to ask $settings->sitename's administrator for an account since there is not registration form. Note that the $settings->sitename's administrator may have changed these settings to allow anonymous edits.

      +

      Editing

      +

      $settings->sitename's editor uses a modified version of slimdown, a flavour of markdown that is implementated using regular expressions. See the credits page for more information and links to the original source for this. A quick reference can be found below:

      + + + + + + + + + + + + + + + + + +
      Type ThisTo get this
      _italics_italics
      *bold*bold
      ~~Strikethrough~~Strikethough
      `code`code
      # Heading

      Heading

      ## Sub Heading

      Sub Heading

      [[Internal Link]]Internal Link
      [[Display Text|Internal Link]]Display Text
      [Display text](//google.com/)Display Text
      > Blockquote
      > Some text
      Blockquote
      Some text
      - Apples
      * Oranges
      • Apples
      • Oranges
      1. This is
      2. an ordered list
      1. This is
      2. an ordered list
      + --- +
      ![Alt text](//starbeamrainbowlabs.com/favicon-small.png)Alt text
      + +

      In addition, the following extra syntax is supported for images:

      + +
      Size the image to at most 250 pixels wide:
      +![Alt text](//starbeamrainbowlabs.com/favicon-small.png 250px)
      +
      +Size the image to at most 120px wide and have it float at the right ahnd size of the page:
      +![Alt text](//starbeamrainbowlabs.com/favicon-small.png 120px right)
      + +

      Administrator Actions

      +

      By default, the delete and move actions are shown on the nav bar. These can be used by administrators to delete or move pages.

      +

      The other thing admininistrators can do is update the wiki (provided they know the site's secret). This page can be found here: Update $settings->sitename.

      +

      $settings->sitename is currently running on Pepperminty Wiki $version

      "; + exit(page_renderer::render_main($title, $content)); + }); + } +]); + + + + +register_module([ + "name" => "Page list", + "version" => "0.6", + "author" => "Starbeamrainbowlabs", + "description" => "Adds a page that lists all the pages in the index along with their metadata.", + "id" => "page-list", + "code" => function() { + add_action("list", function() { + global $pageindex, $settings; + + $sorted_pageindex = get_object_vars($pageindex); + ksort($sorted_pageindex, SORT_NATURAL); + $title = "All Pages"; + $content = "

      $title on $settings->sitename

      + + + + + + + \n"; + // todo list the pages in alphabetical order + foreach($sorted_pageindex as $pagename => $pagedetails) + { + $content .= "\t\t + + + + + + \n"; + } + $content .= "
      Page NameSizeLast EditorLast Edit Time
      $pagename" . human_filesize($pagedetails->size) . "$pagedetails->lasteditor" . human_time_since($pagedetails->lastmodified) . " (" . date("l jS \of F Y \a\\t h:ia T", $pagedetails->lastmodified) . ")
      "; + exit(page_renderer::render_main("$title - $settings->sitename", $content)); + }); + } +]); + + + + +register_module([ + "name" => "Login", + "version" => "0.5", + "author" => "Starbeamrainbowlabs", + "description" => "Adds a pair of actions (login and checklogin) that allow users to login. You need this one if you want your users to be able to login.", + "id" => "page-login", + "code" => function() { + /* + * _ _ + * | | ___ __ _(_)_ __ + * | |/ _ \ / _` | | '_ \ + * | | (_) | (_| | | | | | + * |_|\___/ \__, |_|_| |_| + * |___/ %login% + */ + add_action("login", function() { + global $settings; + $title = "Login to $settings->sitename"; + $content = "

      Login to $settings->sitename

      \n"; + if(isset($_GET["failed"])) + $content .= "\t\t

      Login failed.

      \n"; + $content .= "\t\t
      + + +
      + + +
      + +
      "; + exit(page_renderer::render_main($title, $content)); + }); + + /* + * _ _ _ _ + * ___| |__ ___ ___| | _| | ___ __ _(_)_ __ + * / __| '_ \ / _ \/ __| |/ / |/ _ \ / _` | | '_ \ + * | (__| | | | __/ (__| <| | (_) | (_| | | | | | + * \___|_| |_|\___|\___|_|\_\_|\___/ \__, |_|_| |_| + * %checklogin% |___/ + */ + add_action("checklogin", function() { + global $settings; + + //actually do the login + if(isset($_POST["user"]) and isset($_POST["pass"])) + { + //the user wants to log in + $user = $_POST["user"]; + $pass = $_POST["pass"]; + if($settings->users[$user] == hash("sha256", $pass)) + { + $isloggedin = true; + $expiretime = time() + 60*60*24*30; //30 days from now + $_SESSION["$settings->sessionprefix-user"] = $user; + $_SESSION["$settings->sessionprefix-pass"] = hash("sha256", $pass); + $_SESSION["$settings->sessionprefix-expiretime"] = $expiretime; + //redirect to wherever the user was going + http_response_code(302); + if(isset($_POST["goto"])) + header("location: " . $_POST["returnto"]); + else + header("location: index.php"); + exit(); + } + else + { + http_response_code(302); + header("location: index.php?action=login&failed=yes"); + exit(); + } + } + else + { + http_response_code(302); + header("location: index.php?action=login&failed=yes&badrequest=yes"); + exit(); + } + }); + } +]); + + + +register_module([ + "name" => "Logout", + "version" => "0.5", + "author" => "Starbeamrainbowlabs", + "description" => "Adds an action to let users user out. For security reasons it is wise to add this module since logging in automatically opens a session that is valid for 30 days.", + "id" => "page-logout", + "code" => function() { + add_action("logout", function() { + global $user, $pass, $isloggedin; + $isloggedin = false; + unset($user); + unset($pass); + //clear the session variables + $_SESSION = []; + session_destroy(); + + exit(page_renderer::render_main("Logout Successful", "

      Logout Successful

      +

      Logout Successful. You can login again here.

      ")); + }); + } +]); + + + + +register_module([ + "name" => "Page mover", + "version" => "0.5", + "author" => "Starbeamrainbowlabs", + "description" => "Adds an action to allow administrators to move pages.", + "id" => "page-move", + "code" => function() { + add_action("move", function() { + global $pageindex, $settings, $page, $isadmin; + if(!$settings->editing) + { + exit(page_renderer::render_main("Moving $page - error", "

      You tried to move $page, but editing is disabled on this wiki.

      +

      If you wish to move this page, please re-enable editing on this wiki first.

      +

      Go back to $page.

      +

      Nothing has been changed.

      ")); + } + if(!$isadmin) + { + exit(page_renderer::render_main("Moving $page - Error", "

      You tried to move $page, but you do not have permission to do that.

      +

      You should try logging in as an admin.

      ")); + } + + if(!isset($_GET["new_name"]) or strlen($_GET["new_name"]) == 0) + exit(page_renderer::render_main("Moving $page", "

      Moving $page

      +
      + + + +
      + + +
      + +
      ")); + + $new_name = makepathsafe($_GET["new_name"]); + + if(!isset($pageindex->$page)) + exit(page_renderer::render_main("Moving $page - Error", "

      You tried to move $page to $new_name, but the page with the name $page does not exist in the first place.

      +

      Nothing has been changed.

      ")); + + if($page == $new_name) + exit(page_renderer::render_main("Moving $page - Error", "

      You tried to move $page, but the new name you gave is the same as it's current name.

      +

      It is possible that you tried to use some characters in the new name that are not allowed and were removed.

      +

      Page names may only contain alphanumeric characters, dashes, and underscores.

      ")); + + //move the page in the page index + $pageindex->$new_name = new stdClass(); + foreach($pageindex->$page as $key => $value) + { + $pageindex->$new_name->$key = $value; + } + unset($pageindex->$page); + file_put_contents("./pageindex.json", json_encode($pageindex, JSON_PRETTY_PRINT)); + + //move the page on the disk + rename("$page.md", "$new_name.md"); + + exit(page_renderer::render_main("Moving $page", "

      $page has been moved to $new_name successfully.

      ")); + }); + } +]); + + + +register_module([ + "name" => "Update", + "version" => "0.6", + "author" => "Starbeamrainbowlabs", + "description" => "Adds an update page that downloads the latest stable version of Pepperminty Wiki. This module is currently outdated as it doesn't save your module preferences.", + "id" => "page-update", + "code" => function() { + add_action("update", function() { + global $settings, $isadmin; + + if(!$isadmin) + { + http_response_code(401); + exit(page_renderer::render_main("Update - Error", "

      You must be an administrator to do that.

      ")); + } + + if(!isset($_GET["do"]) or $_GET["do"] !== "true") + { + exit(page_renderer::render_main("Update $settings->sitename", "

      This page allows you to update $settings->sitename.

      +

      Currently, $settings->sitename is using $settings->version of Pepperminty Wiki.

      +

      This script will automatically download and install the latest version of Pepperminty Wiki from the url of your choice (see settings), regardless of whether an update is actually needed (version checking isn't implemented yet).

      +

      To update $settings->sitename, fill out the form below and click click the update button.

      +

      Note that a backup system has not been implemented yet! If this script fails you will loose your wiki's code and have to re-build it.

      +
      + + + + + +
      ")); + } + + if(!isset($_GET["secret"]) or $_GET["secret"] !== $settings->sitesecret) + { + exit(page_renderer::render_main("Update $settings->sitename - Error", "

      You forgot to enter $settings->sitename's secret code or entered it incorrectly. $settings->sitename's secret can be found in the settings portion of index.php.

      ")); + } + + $settings_separator = "/////////////// Do not edit below this line unless you know what you are doing! ///////////////"; + + $log = "Beginning update...\n"; + + $log .= "I am " . __FILE__ . ".\n"; + $oldcode = file_get_contents(__FILE__); + $log .= "Fetching new code..."; + $newcode = file_get_contents($settings->updateurl); + $log .= "done.\n"; + + $log .= "Rewriting " . __FILE__ . "..."; + $settings = substr($oldcode, 0, strpos($oldcode, $settings_separator)); + $code = substr($newcode, strpos($newcode, $settings_separator)); + $result = $settings . $code; + $log .= "done.\n"; + + $log .= "Saving..."; + file_put_contents(__FILE__, $result); + $log .= "done.\n"; + + $log .= "Update complete. I am now running on the latest version of Pepperminty Wiki."; + $log .= "The version number that I have updated to can be found on the credits or help ages."; + + exit(page_renderer::render_main("Update - Success", "
      • " . implode("
      • ", explode("\n", $log)) . "
      ")); + }); + } +]); + + + +register_module([ + "name" => "Page viewer", + "version" => "0.8", + "author" => "Starbeamrainbowlabs", + "description" => "Allows you to view pages. You should include this one.", + "id" => "page-view", + "code" => function() { + add_action("view", function() { + global $pageindex, $settings, $page, $parse_page_source; + + // Check to make sure that the page exists + if(!isset($pageindex->$page)) + { + // todo make this intelligent so we only redirect if the user is acutally able to create the page + if($settings->editing) + { + // Editing is enabled, redirect to the editing page + http_response_code(307); // Temporary redirect + header("location: index.php?action=edit&newpage=yes&page=" . rawurlencode($page)); + exit(); + } + else + { + // Editing is disabled, show an error message + http_response_code(404); + exit(page_renderer::render_main("$page - 404 - $settings->sitename", "

      $page does not exist.

      Since editing is currently disabled on this wiki, you may not create this page. If you feel that this page should exist, try contacting this wiki's Administrator.

      ")); + } + } + $title = "$page - $settings->sitename"; + $content = "

      $page

      "; + + $parsing_start = microtime(true); + + $content .= $parse_page_source(file_get_contents("$page.md")); + + if($settings->show_subpages) + { + $subpages = get_object_vars(get_subpages($pageindex, $page)); + + if(count($subpages) > 0) + { + $content .= "
      "; + $content .= "Subpages: "; + foreach($subpages as $subpage => $times_removed) + { + if($times_removed <= $settings->subpages_display_depth) + { + $content .= "$subpage, "; + } + } + // Remove the last comma from the content + $content = substr($content, 0, -2); + } + } + + $content .= "\n\t\t\n"; + + if(isset($_GET["printable"]) and $_GET["printable"] === "yes") + exit(page_renderer::render_minimal($title, $content)); + else + exit(page_renderer::render_main($title, $content)); + }); + } +]); + + + + +register_module([ + "name" => "Default Parser", + "version" => "0.7", + "author" => "Johnny Broadway & Starbeamrainbowlabs", + "description" => "The default parser for Pepperminty Wiki. Based on Johnny Broadway's Slimdown (with more than a few modifications). This parser's features are documented in the help page.", + "id" => "parser-default", + "code" => function() { + add_parser(function($markdown) { + return Slimdown::render($markdown); + }); + } +]); + +//////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////// Slimdown ///////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// %slimdown% // +//////////////////////////////////////////////////////////////////////////////////////////// +/** + * Slimdown - A very basic regex-based Markdown parser. Supports the + * following elements (and can be extended via Slimdown::add_rule()): + * + * - Headers + * - Links + * - Bold + * - Emphasis + * - Deletions + * - Quotes + * - Inline code + * - Blockquotes + * - Ordered/unordered lists + * - Horizontal rules + * + * Author: Johnny Broadway + * Website: https://gist.github.com/jbroadway/2836900 + * License: MIT + */ + +/** + * Modified by Starbeamrainbowlabs (starbeamrainbowlabs) + * + * Changed bold to use single asterisks + * Changed italics to use single underscores + * Added one to add the heading levels (no

      tags allowed) + * Added wiki style internal link parsing + * Added wiki style internal link parsing with display text + * Added image support + */ +class Slimdown { + public static $rules = array ( + '/\r\n/' => "\n", // new line normalisation + '/(#+)(.*)/' => 'self::header', // headers + '/(\*)(.*?)\1/' => '\2', // bold + '/(_)(.*?)\1/' => '\2', // emphasis + + // todo test these + '/!\[(.*)\]\(([^\s]+)\s(\d+.+)\s(left|right)\)/' => '\1', // images with size + '/!\[(.*)\]\(([^\s]+)\s(\d+.+)\)/' => '\1', // images with size + '/!\[(.*)\]\((.*)\)/' => '\1', // basic images + // todo end + + '/\[\[([a-zA-Z0-9\_\- ]+)\|([a-zA-Z0-9\_\- ]+)\]\]/' => '\2', //internal links with display text + '/\[\[([a-zA-Z0-9\_\- ]+)\]\]/' => '\1', //internal links + '/\[([^\[]+)\]\(([^\)]+)\)/' => '\1', // links + '/\~\~(.*?)\~\~/' => '\1', // del + '/\:\"(.*?)\"\:/' => '\1', // quote + '/`(.*?)`/' => '\1', // inline code + '/\n\s*(\*|-)(.*)/' => 'self::ul_list', // ul lists + '/\n[0-9]+\.(.*)/' => 'self::ol_list', // ol lists + '/\n(>|\>)(.*)/' => 'self::blockquote', // blockquotes + '/\n-{3,}/' => "\n
      ", // horizontal rule + '/\n([^\n]+)\n\n/' => 'self::para', // add paragraphs + '/<\/ul>\s?
        /' => '', // fix extra ul + '/<\/ol>\s?
          /' => '', // fix extra ol + '/<\/blockquote>
          /' => "\n" // fix extra blockquote + ); + private static function para ($regs) { + $line = $regs[1]; + $trimmed = trim ($line); + if (preg_match ('/^<\/?(ul|ol|li|h|p|bl)/', $trimmed)) { + return "\n" . $line . "\n"; + } + return sprintf ("\n

          %s

          \n", $trimmed); + } + private static function ul_list ($regs) { + $item = $regs[2]; + return sprintf ("\n
            \n\t
          • %s
          • \n
          ", trim($item)); + } + private static function ol_list ($regs) { + $item = $regs[1]; + return sprintf ("\n
            \n\t
          1. %s
          2. \n
          ", trim($item)); + } + private static function blockquote ($regs) { + $item = $regs[2]; + return sprintf ("\n
          %s
          ", trim($item)); + } + private static function header ($regs) { + list ($tmp, $chars, $header) = $regs; + $level = strlen ($chars); + return sprintf ('%s', $level + 1, trim($header), $level + 1); + } + + /** + * Add a rule. + */ + public static function add_rule ($regex, $replacement) { + self::$rules[$regex] = $replacement; + } + /** + * Render some Markdown into HTML. + */ + public static function render ($text) { + foreach (self::$rules as $regex => $replacement) { + if (is_callable ( $replacement)) { + $text = preg_replace_callback ($regex, $replacement, $text); + } else { + $text = preg_replace ($regex, $replacement, $text); + } + } + return trim ($text); + } +} +//////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////// + + + +// %next_module% // + + +// Execute each module's code +foreach($modules as $moduledata) +{ + $moduledata["code"](); +} +// Make sure that the credits page exists +if(!isset($actions->credits)) +{ + exit(page_renderer::render_main("Error - $settings->$sitename", "

          No credits page detected. The credits page is a required module!

          ")); +} + +// Perform the appropriate action +$action_name = strtolower($_GET["action"]); +if(isset($actions->$action_name)) +{ + $req_action_data = $actions->$action_name; + $req_action_data(); +} +else +{ + exit(page_renderer::render_main("Error - $settings->sitename", "

          No action called " . strtolower($_GET["action"]) ." has been registered. Perhaps you are missing a module?

          ")); +} +?> diff --git a/core.php b/core.php index 1201b9b..7c44965 100644 --- a/core.php +++ b/core.php @@ -1,613 +1,613 @@ -sessionprefix-expiretime"]) and - $_SESSION["$settings->sessionprefix-expiretime"] < time()) -{ - //clear the session variables - $_SESSION = []; - session_destroy(); -} - -if(!isset($_SESSION[$settings->sessionprefix . "-user"]) and - !isset($_SESSION[$settings->sessionprefix . "-pass"])) -{ - //the user is not logged in - $isloggedin = false; -} -else -{ - $user = $_SESSION[$settings->sessionprefix . "-user"]; - $pass = $_SESSION[$settings->sessionprefix . "-pass"]; - if($settings->users[$user] == $pass) - { - //the user is logged in - $isloggedin = true; - } - else - { - //the user's login details are invalid (what is going on here?) - //unset the session variables, treat them as an anonymous user, and get out of here - $isloggedin = false; - unset($user); - unset($pass); - //clear the session data - $_SESSION = []; //delete al lthe variables - session_destroy(); //destroy the session - } -} -//check to see if the currently logged in user is an admin -$isadmin = false; -if($isloggedin) -{ - foreach($settings->admins as $admin_username) - { - if($admin_username == $user) - { - $isadmin = true; - break; - } - } -} -/////// Login System End /////// - -/////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////// Functions //////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////// - -/* - * @summary Converts a filesize into a human-readable string. - * @source http://php.net/manual/en/function.filesize.php#106569 - * @editor Starbeamrainbowlabs - * - * @param $bytes - The number of bytes to convert. - * @param $decimals - The number of decimal places to preserve. - */ -function human_filesize($bytes, $decimals = 2) -{ - $sz = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "YB", "ZB"]; - $factor = floor((strlen($bytes) - 1) / 3); - return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . @$sz[$factor]; -} -/* - * @summary Calculates the time sincce a particular timestamp and returns a - * human-readable result. - * @source http://snippets.pro/snippet/137-php-convert-the-timestamp-to-human-readable-format/ - * - * @param $time - The timestamp to convert. - * - * @returns {string} - The time since the given timestamp pas a human-readable string. - */ -function human_time_since($time) -{ - $timediff = time() - $time; - $tokens = array ( - 31536000 => 'year', - 2592000 => 'month', - 604800 => 'week', - 86400 => 'day', - 3600 => 'hour', - 60 => 'minute', - 1 => 'second' - ); - foreach ($tokens as $unit => $text) { - if ($timediff < $unit) continue; - $numberOfUnits = floor($timediff / $unit); - return $numberOfUnits.' '.$text.(($numberOfUnits>1)?'s':'').' ago'; - } -} - -/* - * @summary A recursive glob() function. - * - * @param $pattern - The glob pattern to use to find filenames. - * @param $flags - The glob flags to use when finding filenames. - * - * @returns {array} - An array of the filepaths that match the given glob. - */ -// From http://in.php.net/manual/en/function.glob.php#106595 -function glob_recursive($pattern, $flags = 0) -{ - $files = glob($pattern, $flags); - foreach (glob(dirname($pattern).'/*', GLOB_ONLYDIR|GLOB_NOSORT) as $dir) - { - $prefix = "$dir/"; - // Remove the "./" from the beginning if it exists - if(substr($prefix, 0, 2) == "./") $prefix = substr($prefix, 2); - $files = array_merge($files, glob_recursive($prefix . basename($pattern), $flags)); - } - return $files; -} - -/* - * @summary Gets a list of all the sub pagess of the current page. - * - * @param $pageindex - The pageindex to use to search. - * @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. - */ -function get_subpages($pageindex, $pagename) -{ - $pagenames = get_object_vars($pageindex); - $result = new stdClass(); - - $stem = "$pagename/"; - $stem_length = strlen($stem); - foreach($pagenames as $entry => $value) - { - if(substr($entry, 0, $stem_length) == $stem) - { - // We found a subpage - - // Extract the subpage's key relative to the page that we are searching for - $subpage_relative_key = substr($entry, $stem_length, -3); - // Calculate how many times removed the current subpage is from the current page. 0 = direct descendant. - $times_removed = substr_count($subpage_relative_key, "/"); - // Store the name of the subpage we found - $result->$entry = $times_removed; - } - } - - unset($pagenames); - return $result; -} - -/* - * @summary Makes sure that a subpage's parents exist. Note this doesn't check the pagename itself. - * - * @param The pagename to check. - * - */ -function check_subpage_parents($pagename) -{ - global $pageindex; - // Save the new pageindex and return if there aren't any more parent pages to check - if(strpos($pagename, "/") === false) - { - file_put_contents("./pageindex.json", json_encode($pageindex, JSON_PRETTY_PRINT)); - return; - } - - $parent_pagename = substr($pagename, 0, strrpos($pagename, "/")); - $parent_page_filename = "$parent_pagename.md"; - if(!file_exists($parent_page_filename)) - { - // This parent page doesn't exist! Create it and add it to the page index. - touch($parent_page_filename, 0); - - $newentry = new stdClass(); - $newentry->filename = $parent_page_filename; - $newentry->size = 0; - $newentry->lastmodified = 0; - $newentry->lasteditor = "none"; - $pageindex->$parent_pagename = $newentry; - } - - check_subpage_parents($parent_pagename); -} - -/* - * @summary makes a path safe - * - * @details paths may only contain alphanumeric characters, spaces, underscores, and dashes - */ -function makepathsafe($string) -{ - return preg_replace("/[^0-9a-zA-Z\_\-\ \/]/i", "", $string); -} - -/* - * @summary Hides an email address from bots by adding random html entities. - * - * @returns The mangled email address. - */ -function hide_email($str) -{ - $hidden_email = ""; - for($i = 0; $i < strlen($str); $i++) - { - if($str[$i] == "@") - { - $hidden_email .= "&#" . ord("@") . ";"; - continue; - } - if(rand(0, 1) == 0) - $hidden_email .= $str[$i]; - else - $hidden_email .= "&#" . ord($str[$i]) . ";"; - } - - return $hidden_email; -} - -/////////////////////////////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////// Security and Consistency Measures //////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////// - -/* - * Sort out the pageindex. We create it if it doesn't exist, and load and parse - * it if it does. - */ -if(!file_exists("./pageindex.json")) -{ - $existingpages = glob_recursive("*.md"); - $pageindex = new stdClass(); - // We use a for loop here because foreach doesn't loop over new values inserted - // while we were looping - for($i = 0; $i < count($existingpages); $i++) - { - $pagefilename = $existingpages[$i]; - - // Create a new entry - $newentry = new stdClass(); - $newentry->filename = utf8_encode($pagefilename); // Store the filename - $newentry->size = filesize($pagefilename); // Store the page size - $newentry->lastmodified = filemtime($pagefilename); // Store the date last modified - // Todo find a way to keep the last editor independent of the page index - $newentry->lasteditor = utf8_encode("unknown"); // Set the editor to "unknown" - // Extract the name of the (sub)page without the ".md" - $pagekey = utf8_encode(substr($pagefilename, 0, -3)); - - // Subpage parent checker - if(strpos($pagekey, "/") !== false) - { - // We have a sub page people - // Work out what our direct parent's key must be in order to check to - // make sure that it actually exists. If it doesn't, then we need to - // create it. - $subpage_parent_key = substr($pagekey, 0, strrpos($pagekey, "/")); - $subpage_parent_filename = "$subpage_parent_key.md"; - if(array_search($subpage_parent_filename, $existingpages) === false) - { - // Our parent page doesn't acutally exist - create it - touch($subpage_parent_filename, 0); - // Furthermore, we should add this page to the list of existing pages - // in order for it to be indexed - $existingpages[] = $subpage_parent_filename; - } - } - - // Store the new entry in the new page index - $pageindex->$pagekey = $newentry; - } - file_put_contents("./pageindex.json", json_encode($pageindex, JSON_PRETTY_PRINT)); - unset($existingpages); -} -else -{ - $pageindex = json_decode(file_get_contents("./pageindex.json")); -} - -// Work around an Opera + Syntastic bug where there is no margin at the left hand side if there isn't a query string when accessing a .php file -if(!isset($_GET["action"]) and !isset($_GET["page"])) -{ - http_response_code(302); - header("location: index.php?action=$settings->defaultaction&page=$defaultpage"); - exit(); -} - -// Make sure that the action is set -if(!isset($_GET["action"])) - $_GET["action"] = $settings->defaultaction; -// Make sure that the page is set -if(!isset($_GET["page"]) or strlen($_GET["page"]) === 0) - $_GET["page"] = $settings->defaultpage; - -// Redirect the user to the safe version of the path if they entered an unsafe character -if(makepathsafe($_GET["page"]) !== $_GET["page"]) -{ - http_response_code(301); - header("location: index.php?action=" . rawurlencode($_GET["action"]) . "&page=" . makepathsafe($_GET["page"])); - header("x-requested-page: " . $_GET["page"]); - header("x-actual-page: " . makepathsafe($_GET["page"])); - exit(); -} -$page = $_GET["page"]; - -/////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////// HTML fragments ////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////// -class page_renderer -{ - public static $html_template = " - - - - {title} - - - - {header-html} - - - {body} - - - -"; - - public static $main_content_template = "{navigation-bar} -

          {sitename}

          -
          - {content} -
          - -
          -

          Powered by Pepperminty Wiki, which was built by Starbeamrainbowlabs. Send bugs to 'bugs at starbeamrainbowlabs dot com' or open an issue on github.

          -

          Your local friendly administrators are {admins-name-list}. -

          This wiki is managed by {admin-details-name}.

          -
          - {navigation-bar-bottom} - {all-pages-datalist}"; - public static $minimal_content_template = "
          {content}
          -
          -
          -

          From {sitename}, which is managed by {admin-details-name}.

          -

          Timed at {generation-date} -

          Powered by Pepperminty Wiki.

          -
          "; - - // An array of functions that have been registered to process the - // find / replace array before the page is rendered. Note that the function - // should take a *reference* to an array as its only argument. - protected static $part_processors = []; - - // Registers a function as a part post processor. - public static function register_part_preprocessor($function) - { - // Make sure that the function we are about to register is valid - if(!is_callable($function)) - { - http_response_code(500); - $admin_name = $settings->admindetails["name"]; - $admin_email = hide_email($settings->admindetails["email"]); - exit(page_renderer::render("$settings->sitename - Module Error", "

          $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 $admin_email.")); - } - - self::$part_processors[] = $function; - - return true; - } - - public static function render($title, $content, $body_template = false) - { - global $settings, $start_time; - - if($body_template === false) - $body_template = self::$main_content_template; - - $parts = [ - "{body}" => $body_template, - - "{sitename}" => $settings->sitename, - "{favicon-url}" => $settings->favicon, - "{header-html}" => self::get_css_as_html(), - - "{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"), - - "{admin-details-name}" => $settings->admindetails["name"], - "{admin-details-email}" => $settings->admindetails["email"], - - "{admins-name-list}" => implode(", ", $settings->admins), - - "{generation-date}" => date("l jS \of F Y \a\\t h:ia T"), - - "{all-pages-datalist}" => self::generate_all_pages_datalist() - ]; - - // Pass the parts through the part processors - foreach(self::$part_processors as $function) - { - $function($parts); - } - - $result = self::$html_template; - $result = str_replace("{body}", $parts["{body}"], $result); - - $result = str_replace(array_keys($parts), array_values($parts), $result); - - $result = str_replace([ - "{title}", - "{content}" - ], [ - $title, - $content - ], $result); - - $result = str_replace("{generation-time-taken}", microtime(true) - $start_time, $result); - return $result; - } - public static function render_main($title, $content) - { - return self::render($title, $content, self::$main_content_template); - } - public static function render_minimal($title, $content) - { - return self::render($title, $content, self::$minimal_content_template); - } - - - public static function get_css_as_html() - { - global $settings; - - if(preg_match("/^[^\/]*\/\/|^\//", $settings->css)) - return ""; - else - return ""; - } - - public static $nav_divider = " | "; - - /* - * @summary Function to render a navigation bar from an array of links. See - * $settings->nav_links for format information. - * - * @param $nav_links - The links to add to the navigation bar. - * @param $nav_links_extra - The extra nav links to add to the "More..." - * menu. - */ - public static function render_navigation_bar($nav_links, $nav_links_extra, $class = "") - { - global $settings, $user, $isloggedin, $page; - $result = "

          "; - return $result; - } - public static function render_username($name) - { - global $settings; - $result = ""; - if(in_array($name, $settings->admins)) - $result .= $settings->admindisplaychar; - $result .= $name; - - return $result; - } - - public static function generate_all_pages_datalist() - { - global $pageindex; - - $result = "\n"; - foreach($pageindex as $pagename => $pagedetails) - { - $result .= "\t\t\t"; - - return $result; - } -} - -////////////////////////// -/// Module functions /// -////////////////////////// -// These functions are // -// used by modules to // -// register themselves // -// or new pages. // -////////////////////////// -$modules = []; // List that contains all the loaded modules -// Function to register a module -function register_module($moduledata) -{ - global $modules; - //echo("registering module\n"); - //var_dump($moduledata); - $modules[] = $moduledata; -} - -// Function to register an action handler -$actions = new stdClass(); -function add_action($action_name, $func) -{ - global $actions; - //echo("adding $action_name\n"); - $actions->$action_name = $func; -} - -// Function to register a new parser. If multiple parsers are registered then -// only the last parser registered will actually be used. -$parse_page_source = function() { - throw new Exception("No parser registered!"); -}; -function add_parser($parser_code) -{ - global $parse_page_source; - $parse_page_source = $parser_code; -} - -////////////////////////////////////////////////////////////////// - - -// %next_module% // - - -// Execute each module's code -foreach($modules as $moduledata) -{ - $moduledata["code"](); -} -// Make sure that the credits page exists -if(!isset($actions->credits)) -{ - exit(page_renderer::render_main("Error - $settings->$sitename", "

          No credits page detected. The credits page is a required module!

          ")); -} - -// Perform the appropriate action -$action_name = strtolower($_GET["action"]); -if(isset($actions->$action_name)) -{ - $req_action_data = $actions->$action_name; - $req_action_data(); -} -else -{ - exit(page_renderer::render_main("Error - $settings->sitename", "

          No action called " . strtolower($_GET["action"]) ." has been registered. Perhaps you are missing a module?

          ")); -} -?> +sessionprefix-expiretime"]) and + $_SESSION["$settings->sessionprefix-expiretime"] < time()) +{ + //clear the session variables + $_SESSION = []; + session_destroy(); +} + +if(!isset($_SESSION[$settings->sessionprefix . "-user"]) and + !isset($_SESSION[$settings->sessionprefix . "-pass"])) +{ + //the user is not logged in + $isloggedin = false; +} +else +{ + $user = $_SESSION[$settings->sessionprefix . "-user"]; + $pass = $_SESSION[$settings->sessionprefix . "-pass"]; + if($settings->users[$user] == $pass) + { + //the user is logged in + $isloggedin = true; + } + else + { + //the user's login details are invalid (what is going on here?) + //unset the session variables, treat them as an anonymous user, and get out of here + $isloggedin = false; + unset($user); + unset($pass); + //clear the session data + $_SESSION = []; //delete al lthe variables + session_destroy(); //destroy the session + } +} +//check to see if the currently logged in user is an admin +$isadmin = false; +if($isloggedin) +{ + foreach($settings->admins as $admin_username) + { + if($admin_username == $user) + { + $isadmin = true; + break; + } + } +} +/////// Login System End /////// + +/////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////// Functions //////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////// + +/* + * @summary Converts a filesize into a human-readable string. + * @source http://php.net/manual/en/function.filesize.php#106569 + * @editor Starbeamrainbowlabs + * + * @param $bytes - The number of bytes to convert. + * @param $decimals - The number of decimal places to preserve. + */ +function human_filesize($bytes, $decimals = 2) +{ + $sz = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "YB", "ZB"]; + $factor = floor((strlen($bytes) - 1) / 3); + return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . @$sz[$factor]; +} +/* + * @summary Calculates the time sincce a particular timestamp and returns a + * human-readable result. + * @source http://snippets.pro/snippet/137-php-convert-the-timestamp-to-human-readable-format/ + * + * @param $time - The timestamp to convert. + * + * @returns {string} - The time since the given timestamp pas a human-readable string. + */ +function human_time_since($time) +{ + $timediff = time() - $time; + $tokens = array ( + 31536000 => 'year', + 2592000 => 'month', + 604800 => 'week', + 86400 => 'day', + 3600 => 'hour', + 60 => 'minute', + 1 => 'second' + ); + foreach ($tokens as $unit => $text) { + if ($timediff < $unit) continue; + $numberOfUnits = floor($timediff / $unit); + return $numberOfUnits.' '.$text.(($numberOfUnits>1)?'s':'').' ago'; + } +} + +/* + * @summary A recursive glob() function. + * + * @param $pattern - The glob pattern to use to find filenames. + * @param $flags - The glob flags to use when finding filenames. + * + * @returns {array} - An array of the filepaths that match the given glob. + */ +// From http://in.php.net/manual/en/function.glob.php#106595 +function glob_recursive($pattern, $flags = 0) +{ + $files = glob($pattern, $flags); + foreach (glob(dirname($pattern).'/*', GLOB_ONLYDIR|GLOB_NOSORT) as $dir) + { + $prefix = "$dir/"; + // Remove the "./" from the beginning if it exists + if(substr($prefix, 0, 2) == "./") $prefix = substr($prefix, 2); + $files = array_merge($files, glob_recursive($prefix . basename($pattern), $flags)); + } + return $files; +} + +/* + * @summary Gets a list of all the sub pagess of the current page. + * + * @param $pageindex - The pageindex to use to search. + * @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. + */ +function get_subpages($pageindex, $pagename) +{ + $pagenames = get_object_vars($pageindex); + $result = new stdClass(); + + $stem = "$pagename/"; + $stem_length = strlen($stem); + foreach($pagenames as $entry => $value) + { + if(substr($entry, 0, $stem_length) == $stem) + { + // We found a subpage + + // Extract the subpage's key relative to the page that we are searching for + $subpage_relative_key = substr($entry, $stem_length, -3); + // Calculate how many times removed the current subpage is from the current page. 0 = direct descendant. + $times_removed = substr_count($subpage_relative_key, "/"); + // Store the name of the subpage we found + $result->$entry = $times_removed; + } + } + + unset($pagenames); + return $result; +} + +/* + * @summary Makes sure that a subpage's parents exist. Note this doesn't check the pagename itself. + * + * @param The pagename to check. + * + */ +function check_subpage_parents($pagename) +{ + global $pageindex; + // Save the new pageindex and return if there aren't any more parent pages to check + if(strpos($pagename, "/") === false) + { + file_put_contents("./pageindex.json", json_encode($pageindex, JSON_PRETTY_PRINT)); + return; + } + + $parent_pagename = substr($pagename, 0, strrpos($pagename, "/")); + $parent_page_filename = "$parent_pagename.md"; + if(!file_exists($parent_page_filename)) + { + // This parent page doesn't exist! Create it and add it to the page index. + touch($parent_page_filename, 0); + + $newentry = new stdClass(); + $newentry->filename = $parent_page_filename; + $newentry->size = 0; + $newentry->lastmodified = 0; + $newentry->lasteditor = "none"; + $pageindex->$parent_pagename = $newentry; + } + + check_subpage_parents($parent_pagename); +} + +/* + * @summary makes a path safe + * + * @details paths may only contain alphanumeric characters, spaces, underscores, and dashes + */ +function makepathsafe($string) +{ + return preg_replace("/[^0-9a-zA-Z\_\-\ \/]/i", "", $string); +} + +/* + * @summary Hides an email address from bots by adding random html entities. + * + * @returns The mangled email address. + */ +function hide_email($str) +{ + $hidden_email = ""; + for($i = 0; $i < strlen($str); $i++) + { + if($str[$i] == "@") + { + $hidden_email .= "&#" . ord("@") . ";"; + continue; + } + if(rand(0, 1) == 0) + $hidden_email .= $str[$i]; + else + $hidden_email .= "&#" . ord($str[$i]) . ";"; + } + + return $hidden_email; +} + +/////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////// Security and Consistency Measures //////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////// + +/* + * Sort out the pageindex. We create it if it doesn't exist, and load and parse + * it if it does. + */ +if(!file_exists("./pageindex.json")) +{ + $existingpages = glob_recursive("*.md"); + $pageindex = new stdClass(); + // We use a for loop here because foreach doesn't loop over new values inserted + // while we were looping + for($i = 0; $i < count($existingpages); $i++) + { + $pagefilename = $existingpages[$i]; + + // Create a new entry + $newentry = new stdClass(); + $newentry->filename = utf8_encode($pagefilename); // Store the filename + $newentry->size = filesize($pagefilename); // Store the page size + $newentry->lastmodified = filemtime($pagefilename); // Store the date last modified + // Todo find a way to keep the last editor independent of the page index + $newentry->lasteditor = utf8_encode("unknown"); // Set the editor to "unknown" + // Extract the name of the (sub)page without the ".md" + $pagekey = utf8_encode(substr($pagefilename, 0, -3)); + + // Subpage parent checker + if(strpos($pagekey, "/") !== false) + { + // We have a sub page people + // Work out what our direct parent's key must be in order to check to + // make sure that it actually exists. If it doesn't, then we need to + // create it. + $subpage_parent_key = substr($pagekey, 0, strrpos($pagekey, "/")); + $subpage_parent_filename = "$subpage_parent_key.md"; + if(array_search($subpage_parent_filename, $existingpages) === false) + { + // Our parent page doesn't acutally exist - create it + touch($subpage_parent_filename, 0); + // Furthermore, we should add this page to the list of existing pages + // in order for it to be indexed + $existingpages[] = $subpage_parent_filename; + } + } + + // Store the new entry in the new page index + $pageindex->$pagekey = $newentry; + } + file_put_contents("./pageindex.json", json_encode($pageindex, JSON_PRETTY_PRINT)); + unset($existingpages); +} +else +{ + $pageindex = json_decode(file_get_contents("./pageindex.json")); +} + +// Work around an Opera + Syntastic bug where there is no margin at the left hand side if there isn't a query string when accessing a .php file +if(!isset($_GET["action"]) and !isset($_GET["page"])) +{ + http_response_code(302); + header("location: index.php?action=$settings->defaultaction&page=$defaultpage"); + exit(); +} + +// Make sure that the action is set +if(!isset($_GET["action"])) + $_GET["action"] = $settings->defaultaction; +// Make sure that the page is set +if(!isset($_GET["page"]) or strlen($_GET["page"]) === 0) + $_GET["page"] = $settings->defaultpage; + +// Redirect the user to the safe version of the path if they entered an unsafe character +if(makepathsafe($_GET["page"]) !== $_GET["page"]) +{ + http_response_code(301); + header("location: index.php?action=" . rawurlencode($_GET["action"]) . "&page=" . makepathsafe($_GET["page"])); + header("x-requested-page: " . $_GET["page"]); + header("x-actual-page: " . makepathsafe($_GET["page"])); + exit(); +} +$page = $_GET["page"]; + +/////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////// HTML fragments ////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////// +class page_renderer +{ + public static $html_template = " + + + + {title} + + + + {header-html} + + + {body} + + + +"; + + public static $main_content_template = "{navigation-bar} +

          {sitename}

          +
          + {content} +
          + +
          +

          Powered by Pepperminty Wiki, which was built by Starbeamrainbowlabs. Send bugs to 'bugs at starbeamrainbowlabs dot com' or open an issue on github.

          +

          Your local friendly administrators are {admins-name-list}. +

          This wiki is managed by {admin-details-name}.

          +
          + {navigation-bar-bottom} + {all-pages-datalist}"; + public static $minimal_content_template = "
          {content}
          +
          +
          +

          From {sitename}, which is managed by {admin-details-name}.

          +

          Timed at {generation-date} +

          Powered by Pepperminty Wiki.

          +
          "; + + // An array of functions that have been registered to process the + // find / replace array before the page is rendered. Note that the function + // should take a *reference* to an array as its only argument. + protected static $part_processors = []; + + // Registers a function as a part post processor. + public static function register_part_preprocessor($function) + { + // Make sure that the function we are about to register is valid + if(!is_callable($function)) + { + http_response_code(500); + $admin_name = $settings->admindetails["name"]; + $admin_email = hide_email($settings->admindetails["email"]); + exit(page_renderer::render("$settings->sitename - Module Error", "

          $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 $admin_email.")); + } + + self::$part_processors[] = $function; + + return true; + } + + public static function render($title, $content, $body_template = false) + { + global $settings, $start_time; + + if($body_template === false) + $body_template = self::$main_content_template; + + $parts = [ + "{body}" => $body_template, + + "{sitename}" => $settings->sitename, + "{favicon-url}" => $settings->favicon, + "{header-html}" => self::get_css_as_html(), + + "{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"), + + "{admin-details-name}" => $settings->admindetails["name"], + "{admin-details-email}" => $settings->admindetails["email"], + + "{admins-name-list}" => implode(", ", $settings->admins), + + "{generation-date}" => date("l jS \of F Y \a\\t h:ia T"), + + "{all-pages-datalist}" => self::generate_all_pages_datalist() + ]; + + // Pass the parts through the part processors + foreach(self::$part_processors as $function) + { + $function($parts); + } + + $result = self::$html_template; + $result = str_replace("{body}", $parts["{body}"], $result); + + $result = str_replace(array_keys($parts), array_values($parts), $result); + + $result = str_replace([ + "{title}", + "{content}" + ], [ + $title, + $content + ], $result); + + $result = str_replace("{generation-time-taken}", microtime(true) - $start_time, $result); + return $result; + } + public static function render_main($title, $content) + { + return self::render($title, $content, self::$main_content_template); + } + public static function render_minimal($title, $content) + { + return self::render($title, $content, self::$minimal_content_template); + } + + + public static function get_css_as_html() + { + global $settings; + + if(preg_match("/^[^\/]*\/\/|^\//", $settings->css)) + return ""; + else + return ""; + } + + public static $nav_divider = " | "; + + /* + * @summary Function to render a navigation bar from an array of links. See + * $settings->nav_links for format information. + * + * @param $nav_links - The links to add to the navigation bar. + * @param $nav_links_extra - The extra nav links to add to the "More..." + * menu. + */ + public static function render_navigation_bar($nav_links, $nav_links_extra, $class = "") + { + global $settings, $user, $isloggedin, $page; + $result = "

          "; + return $result; + } + public static function render_username($name) + { + global $settings; + $result = ""; + if(in_array($name, $settings->admins)) + $result .= $settings->admindisplaychar; + $result .= $name; + + return $result; + } + + public static function generate_all_pages_datalist() + { + global $pageindex; + + $result = "\n"; + foreach($pageindex as $pagename => $pagedetails) + { + $result .= "\t\t\t"; + + return $result; + } +} + +////////////////////////// +/// Module functions /// +////////////////////////// +// These functions are // +// used by modules to // +// register themselves // +// or new pages. // +////////////////////////// +$modules = []; // List that contains all the loaded modules +// Function to register a module +function register_module($moduledata) +{ + global $modules; + //echo("registering module\n"); + //var_dump($moduledata); + $modules[] = $moduledata; +} + +// Function to register an action handler +$actions = new stdClass(); +function add_action($action_name, $func) +{ + global $actions; + //echo("adding $action_name\n"); + $actions->$action_name = $func; +} + +// Function to register a new parser. If multiple parsers are registered then +// only the last parser registered will actually be used. +$parse_page_source = function() { + throw new Exception("No parser registered!"); +}; +function add_parser($parser_code) +{ + global $parse_page_source; + $parse_page_source = $parser_code; +} + +////////////////////////////////////////////////////////////////// + + +// %next_module% // + + +// Execute each module's code +foreach($modules as $moduledata) +{ + $moduledata["code"](); +} +// Make sure that the credits page exists +if(!isset($actions->credits)) +{ + exit(page_renderer::render_main("Error - $settings->$sitename", "

          No credits page detected. The credits page is a required module!

          ")); +} + +// Perform the appropriate action +$action_name = strtolower($_GET["action"]); +if(isset($actions->$action_name)) +{ + $req_action_data = $actions->$action_name; + $req_action_data(); +} +else +{ + exit(page_renderer::render_main("Error - $settings->sitename", "

          No action called " . strtolower($_GET["action"]) ." has been registered. Perhaps you are missing a module?

          ")); +} +?> diff --git a/download.php b/download.php index 4912471..e20cf30 100644 --- a/download.php +++ b/download.php @@ -1,90 +1,90 @@ - - - - - Pepperminty Wiki Download - - -

          Pepperminty Wiki Download

          - - -

          Module selector

          -

          Choose the modules that you want to include in your installation of Pepperminty Wiki.

          - -

          - - -

          - - - - - - - - - - - - - - - - - - "); - - } - ?> -
          NameDescriptionAuthorVersionLast Updated
          $module->description$module->author$module->version" . date("D jS M Y", $module->lastupdate) . "
          - -
          -
          - - - -
          - -

          - Pepperminty Wiki was built by Starbeamrainbowlabs. The code is available on GitHub. -

          -

          - Other contributors: (none yet! Contribute and I will put your name here) -

          - - - - - - - - + + + + + Pepperminty Wiki Download + + +

          Pepperminty Wiki Download

          + + +

          Module selector

          +

          Choose the modules that you want to include in your installation of Pepperminty Wiki.

          + +

          + + +

          + + + + + + + + + + + + + + + + + + "); + + } + ?> +
          NameDescriptionAuthorVersionLast Updated
          $module->description$module->author$module->version" . date("D jS M Y", $module->lastupdate) . "
          + +
          +
          + + + +
          + +

          + Pepperminty Wiki was built by Starbeamrainbowlabs. The code is available on GitHub. +

          +

          + Other contributors: (none yet! Contribute and I will put your name here) +

          + + + + + + + + \ No newline at end of file diff --git a/modules/action-hash.php b/modules/action-hash.php index 791920a..c4eaf95 100644 --- a/modules/action-hash.php +++ b/modules/action-hash.php @@ -1,24 +1,24 @@ - "Password hashing action", - "version" => "0.5", - "author" => "Starbeamrainbowlabs", - "description" => "Adds a utility action (that anyone can use) called hash that hashes a given string. Useful when changing a user's password.", - "id" => "action-hash", - "code" => function() { - add_action("hash", function() { - if(!isset($_GET["string"])) - { - http_response_code(422); - exit(page_renderer::render_main("Missing parameter", "

          The GET parameter string must be specified.

          -

          It is strongly recommended that you utilise this page via a private or incognito window in order to prevent your password from appearing in your browser history.

          ")); - } - else - { - exit(page_renderer::render_main("Hashed string", "

          " . $_GET["string"] . "" . hash("sha256", $_GET["string"] . "

          "))); - } - }); - } -]); - -?> + "Password hashing action", + "version" => "0.5", + "author" => "Starbeamrainbowlabs", + "description" => "Adds a utility action (that anyone can use) called hash that hashes a given string. Useful when changing a user's password.", + "id" => "action-hash", + "code" => function() { + add_action("hash", function() { + if(!isset($_GET["string"])) + { + http_response_code(422); + exit(page_renderer::render_main("Missing parameter", "

          The GET parameter string must be specified.

          +

          It is strongly recommended that you utilise this page via a private or incognito window in order to prevent your password from appearing in your browser history.

          ")); + } + else + { + exit(page_renderer::render_main("Hashed string", "

          " . $_GET["string"] . "" . hash("sha256", $_GET["string"] . "

          "))); + } + }); + } +]); + +?> diff --git a/modules/extra-sidebar.php b/modules/extra-sidebar.php index 835e373..d2a79e5 100644 --- a/modules/extra-sidebar.php +++ b/modules/extra-sidebar.php @@ -1,109 +1,109 @@ - "Sidebar", - "version" => "0.2", - "author" => "Starbeamrainbowlabs", - "description" => "Adds a sidebar to the left hand side of every page. Add '\$settings->sidebar_show = true;' to your configuration, or append '&sidebar=yes' to the url to enable. Adding to the url sets a cookie to remember your setting.", - "id" => "extra-sidebar", - "code" => function() { - $show_sidebar = false; - - // Show the sidebar if it is enabled in the settings - if(isset($settings->sidebar_show) && $settings->sidebar_show === true) - $show_sidebar = true; - - // Also show and persist the sidebar if the special GET parameter - // sidebar is seet - if(!$show_sidebar && isset($_GET["sidebar"])) - { - $show_sidebar = true; - // Set a cookie to persist the display of the sidebar - setcookie("sidebar_show", "true", time() + (60 * 60 * 24 * 30)); - } - - // Show the sidebar if the cookie is set - if(!$show_sidebar && isset($_COOKIE["sidebar_show"])) - $show_sidebar = true; - - // Delete the cookie and hide the sidebar if the special GET paramter - // nosidebar is set - if(isset($_GET["nosidebar"])) - { - $show_sidebar = false; - unset($_COOKIE["sidebar_show"]); - setcookie("sidebar_show", null, time() - 3600); - } - - page_renderer::register_part_preprocessor(function(&$parts) use ($show_sidebar) { - global $settings, $pageindex; - - if($show_sidebar && !isset($_GET["printable"])) - { - // Show the sidebar - $exec_start = microtime(true); - - // Sort the pageindex - $sorted_pageindex = get_object_vars($pageindex); - ksort($sorted_pageindex, SORT_NATURAL); - - $sidebar_contents = ""; - $sidebar_contents .= render_sidebar($sorted_pageindex); - - $parts["{body}"] = " -
          " . $parts["{body}"] . "
          - - "; - } - }); - } -]); - -/* - * @summary Renders the sidebar for a given pageindex. - * - * @param $pageindex {array} - The pageindex to render the sidebar for - * @param $root_pagename {string} - The pagename that should be considered the root of the rendering. You don't usually need to use this, it is used by the algorithm itself since it is recursive. - * - * @returns {string} A HTML rendering of the sidebar for the given pageindex - */ -function render_sidebar($pageindex, $root_pagename = "") -{ - global $settings; - - $result = " $details) - { - // If we have a valid root pagename, and it isn't present at the - // beginning of the current pagename, skip it - if($root_pagename !== "" && strpos($pagename, $root_pagename) !== 0) - continue; - - // The current page is the same as the root page, skip it - if($pagename == $root_pagename) - continue; - - - // If the part of the current pagename that comes after the root - // pagename has a slash in it, skip it as it is a sub-sub page. - if(strpos(substr($pagename, strlen($root_pagename)), "/") !== false) - continue; - - $result .= "
        1. $pagename\n"; - $result .= render_sidebar($pageindex, $pagename); - $result .= "
        2. \n"; - } - $result .= "
      \n"; - - return $result == "
        \n" ? "" : $result; -} - -?> + "Sidebar", + "version" => "0.2", + "author" => "Starbeamrainbowlabs", + "description" => "Adds a sidebar to the left hand side of every page. Add '\$settings->sidebar_show = true;' to your configuration, or append '&sidebar=yes' to the url to enable. Adding to the url sets a cookie to remember your setting.", + "id" => "extra-sidebar", + "code" => function() { + $show_sidebar = false; + + // Show the sidebar if it is enabled in the settings + if(isset($settings->sidebar_show) && $settings->sidebar_show === true) + $show_sidebar = true; + + // Also show and persist the sidebar if the special GET parameter + // sidebar is seet + if(!$show_sidebar && isset($_GET["sidebar"])) + { + $show_sidebar = true; + // Set a cookie to persist the display of the sidebar + setcookie("sidebar_show", "true", time() + (60 * 60 * 24 * 30)); + } + + // Show the sidebar if the cookie is set + if(!$show_sidebar && isset($_COOKIE["sidebar_show"])) + $show_sidebar = true; + + // Delete the cookie and hide the sidebar if the special GET paramter + // nosidebar is set + if(isset($_GET["nosidebar"])) + { + $show_sidebar = false; + unset($_COOKIE["sidebar_show"]); + setcookie("sidebar_show", null, time() - 3600); + } + + page_renderer::register_part_preprocessor(function(&$parts) use ($show_sidebar) { + global $settings, $pageindex; + + if($show_sidebar && !isset($_GET["printable"])) + { + // Show the sidebar + $exec_start = microtime(true); + + // Sort the pageindex + $sorted_pageindex = get_object_vars($pageindex); + ksort($sorted_pageindex, SORT_NATURAL); + + $sidebar_contents = ""; + $sidebar_contents .= render_sidebar($sorted_pageindex); + + $parts["{body}"] = " +
        " . $parts["{body}"] . "
        + + "; + } + }); + } +]); + +/* + * @summary Renders the sidebar for a given pageindex. + * + * @param $pageindex {array} - The pageindex to render the sidebar for + * @param $root_pagename {string} - The pagename that should be considered the root of the rendering. You don't usually need to use this, it is used by the algorithm itself since it is recursive. + * + * @returns {string} A HTML rendering of the sidebar for the given pageindex + */ +function render_sidebar($pageindex, $root_pagename = "") +{ + global $settings; + + $result = " $details) + { + // If we have a valid root pagename, and it isn't present at the + // beginning of the current pagename, skip it + if($root_pagename !== "" && strpos($pagename, $root_pagename) !== 0) + continue; + + // The current page is the same as the root page, skip it + if($pagename == $root_pagename) + continue; + + + // If the part of the current pagename that comes after the root + // pagename has a slash in it, skip it as it is a sub-sub page. + if(strpos(substr($pagename, strlen($root_pagename)), "/") !== false) + continue; + + $result .= "
      • $pagename\n"; + $result .= render_sidebar($pageindex, $pagename); + $result .= "
      • \n"; + } + $result .= "\n"; + + return $result == "
          \n" ? "" : $result; +} + +?> diff --git a/modules/page-credits.php b/modules/page-credits.php index 5c1083e..5727b2f 100644 --- a/modules/page-credits.php +++ b/modules/page-credits.php @@ -1,61 +1,61 @@ - "Credits", - "version" => "0.6", - "author" => "Starbeamrainbowlabs", - "description" => "Adds the credits page. You *must* have this module :D", - "id" => "page-credits", - "code" => function() { - add_action("credits", function() { - global $settings, $version, $pageindex, $modules; - - $credits = [ - "Code" => [ - "author" => "Starbeamrainbowlabs", - "author_url" => "https://starbeamrmainbowlabs.com/", - "thing_url" => "https://github.com/sbrl/Pepprminty-Wiki" - ], - "Slightly modified version of Slimdown" => [ - "author" => "Johnny Broadway", - "author_url" => "https://github.com/jbroadway", - "thing_url" => "https://gist.github.com/jbroadway/2836900" - ], - "Default Favicon" => [ - "author" => "bluefrog23", - "author_url" => "https://openclipart.org/user-detail/bluefrog23/", - "thing_url" => "https://openclipart.org/detail/19571/peppermint-candy-by-bluefrog23" - ], - "Bug Reports" => [ - "author" => "nibreh", - "author_url" => "https://github.com/nibreh/", - "thing_url" => "" - ] - ]; - $credits_html = "
            \n"; - foreach($credits as $thing => $author_details) - { - $credits_html .= "
          • "; - $credits_html .= "$thing by "; - $credits_html .= "" . $author_details["author"] . ""; - $credits_html .= "
          • \n"; - } - $credits_html .= "
          "; - - $title = "Credits - $settings->sitename"; - $content = "

          $settings->sitename credits

          -

          $settings->sitename is powered by Pepperminty Wiki - an entire wiki packed inside a single file, which was built by Starbeamrainbowlabs, and can be found on GitHub (contributors will ablso be listed here in the future).

          -

          Main Credits

          - $credits_html -

          Site status

          - - - - - -
          Site name:$settings->sitename (Update - Administrators only, Export as zip - Check for permission first)
          Pepperminty Wiki version:$version
          Number of pages:" . count(get_object_vars($pageindex)) . "
          Number of modules:" . count($modules) . "
          "; - exit(page_renderer::render_main($title, $content)); - }); - } -]); - -?> + "Credits", + "version" => "0.6", + "author" => "Starbeamrainbowlabs", + "description" => "Adds the credits page. You *must* have this module :D", + "id" => "page-credits", + "code" => function() { + add_action("credits", function() { + global $settings, $version, $pageindex, $modules; + + $credits = [ + "Code" => [ + "author" => "Starbeamrainbowlabs", + "author_url" => "https://starbeamrmainbowlabs.com/", + "thing_url" => "https://github.com/sbrl/Pepprminty-Wiki" + ], + "Slightly modified version of Slimdown" => [ + "author" => "Johnny Broadway", + "author_url" => "https://github.com/jbroadway", + "thing_url" => "https://gist.github.com/jbroadway/2836900" + ], + "Default Favicon" => [ + "author" => "bluefrog23", + "author_url" => "https://openclipart.org/user-detail/bluefrog23/", + "thing_url" => "https://openclipart.org/detail/19571/peppermint-candy-by-bluefrog23" + ], + "Bug Reports" => [ + "author" => "nibreh", + "author_url" => "https://github.com/nibreh/", + "thing_url" => "" + ] + ]; + $credits_html = "
            \n"; + foreach($credits as $thing => $author_details) + { + $credits_html .= "
          • "; + $credits_html .= "$thing by "; + $credits_html .= "" . $author_details["author"] . ""; + $credits_html .= "
          • \n"; + } + $credits_html .= "
          "; + + $title = "Credits - $settings->sitename"; + $content = "

          $settings->sitename credits

          +

          $settings->sitename is powered by Pepperminty Wiki - an entire wiki packed inside a single file, which was built by Starbeamrainbowlabs, and can be found on GitHub (contributors will ablso be listed here in the future).

          +

          Main Credits

          + $credits_html +

          Site status

          + + + + + +
          Site name:$settings->sitename (Update - Administrators only, Export as zip - Check for permission first)
          Pepperminty Wiki version:$version
          Number of pages:" . count(get_object_vars($pageindex)) . "
          Number of modules:" . count($modules) . "
          "; + exit(page_renderer::render_main($title, $content)); + }); + } +]); + +?> diff --git a/modules/page-delete.php b/modules/page-delete.php index 65216e9..d4d2e77 100644 --- a/modules/page-delete.php +++ b/modules/page-delete.php @@ -1,38 +1,38 @@ - "Page deleter", - "version" => "0.5", - "author" => "Starbeamrainbowlabs", - "description" => "Adds an action to allow administrators to delete pages.", - "id" => "page-delete", - "code" => function() { - add_action("delete", function() { - global $pageindex, $settings, $page, $isadmin; - if(!$settings->editing) - { - exit(page_renderer::render_main("Deleting $page - error", "

          You tried to delete $page, but editing is disabled on this wiki.

          -

          If you wish to delete this page, please re-enable editing on this wiki first.

          -

          Go back to $page.

          -

          Nothing has been changed.

          ")); - } - if(!$isadmin) - { - exit(page_renderer::render_main("Deleting $page - error", "

          You tried to delete $page, but you are not an admin so you don't have permission to do that.

          -

          You should try logging in as an admin.

          ")); - } - if(!isset($_GET["delete"]) or $_GET["delete"] !== "yes") - { - exit(page_renderer::render_main("Deleting $page", "

          You are about to delete $page. You can't undo this!

          -

          Click here to delete $page.

          -

          Click here to go back.")); - } - unset($pageindex->$page); //delete the page from the page index - file_put_contents("./pageindex.json", json_encode($pageindex, JSON_PRETTY_PRINT)); //save the new page index - unlink("./$page.md"); //delete the page from the disk - - exit(page_renderer::render_main("Deleting $page - $settings->sitename", "

          $page has been deleted. Go back to the main page.

          ")); - }); - } -]); - -?> + "Page deleter", + "version" => "0.5", + "author" => "Starbeamrainbowlabs", + "description" => "Adds an action to allow administrators to delete pages.", + "id" => "page-delete", + "code" => function() { + add_action("delete", function() { + global $pageindex, $settings, $page, $isadmin; + if(!$settings->editing) + { + exit(page_renderer::render_main("Deleting $page - error", "

          You tried to delete $page, but editing is disabled on this wiki.

          +

          If you wish to delete this page, please re-enable editing on this wiki first.

          +

          Go back to $page.

          +

          Nothing has been changed.

          ")); + } + if(!$isadmin) + { + exit(page_renderer::render_main("Deleting $page - error", "

          You tried to delete $page, but you are not an admin so you don't have permission to do that.

          +

          You should try logging in as an admin.

          ")); + } + if(!isset($_GET["delete"]) or $_GET["delete"] !== "yes") + { + exit(page_renderer::render_main("Deleting $page", "

          You are about to delete $page. You can't undo this!

          +

          Click here to delete $page.

          +

          Click here to go back.")); + } + unset($pageindex->$page); //delete the page from the page index + file_put_contents("./pageindex.json", json_encode($pageindex, JSON_PRETTY_PRINT)); //save the new page index + unlink("./$page.md"); //delete the page from the disk + + exit(page_renderer::render_main("Deleting $page - $settings->sitename", "

          $page has been deleted. Go back to the main page.

          ")); + }); + } +]); + +?> diff --git a/modules/page-edit.php b/modules/page-edit.php index f7a4533..79ee5e7 100644 --- a/modules/page-edit.php +++ b/modules/page-edit.php @@ -1,139 +1,139 @@ - "Page editor", - "version" => "0.8", - "author" => "Starbeamrainbowlabs", - "description" => "Allows you to edit pages by adding the edit and save actions. You should probably include this one.", - "id" => "page-edit", - - "code" => function() { - - /* - * _ _ _ - * ___ __| (_) |_ - * / _ \/ _` | | __| - * | __/ (_| | | |_ - * \___|\__,_|_|\__| - * %edit% - */ - add_action("edit", function() { - global $pageindex, $settings, $page, $isloggedin; - - $filename = "$page.md"; - $creatingpage = !isset($pageindex->$page); - if((isset($_GET["newpage"]) and $_GET["newpage"] == "true") or $creatingpage) - { - $title = "Creating $page"; - } - else - { - $title = "Editing $page"; - } - - $pagetext = ""; - if(isset($pageindex->$page)) - { - $pagetext = file_get_contents($filename); - } - - if((!$isloggedin and !$settings->anonedits) or !$settings->editing) - { - if(!$creatingpage) - { - // The page already exists - let the user view the page source - exit(page_renderer::render_main("Viewing source for $page", "

          $settings->sitename does not allow anonymous users to make edits. You can view the source of $page below, but you can't edit it.

          ")); - } - else - { - http_response_code(404); - exit(page_renderer::render_main("404 - $page", "

          The page $page does not exist, but you do not have permission to create it.

          If you haven't already, perhaps you should try logging in.

          ")); - } - } - - $content = "

          $title

          "; - if(!$isloggedin and $settings->anonedits) - { - $content .= "

          Warning: You are not logged in! Your IP address may be recorded.

          "; - } - $content .= "
          - - -
          "; - exit(page_renderer::render_main("$title - $settings->sitename", $content)); - }); - - /* - * - * ___ __ ___ _____ - * / __|/ _` \ \ / / _ \ - * \__ \ (_| |\ V / __/ - * |___/\__,_| \_/ \___| - * %save% - */ - add_action("save", function() { - global $pageindex, $settings, $page, $isloggedin, $user; - if(!$settings->editing) - { - header("location: index.php?page=$page"); - exit(page_renderer::render_main("Error saving edit", "

          Editing is currently disabled on this wiki.

          ")); - } - if(!$isloggedin and !$settings->anonedits) - { - http_response_code(403); - header("refresh: 5; url=index.php?page=$page"); - exit("You are not logged in, so you are not allowed to save pages on $settings->sitename. Redirecting in 5 seconds...."); - } - if(!isset($_POST["content"])) - { - http_response_code(400); - header("refresh: 5; url=index.php?page=$page"); - exit("Bad request: No content specified."); - } - - // Make sure that the directory in which the page needs to be saved exists - if(!is_dir(dirname("$page.md"))) - { - // Recursively create the directory if needed - mkdir(dirname("$page.md"), null, true); - } - - - if(file_put_contents("$page.md", htmlentities($_POST["content"]), ENT_QUOTES) !== false) - { - // Make sure that this page's parents exist - check_subpage_parents($page); - - //update the page index - if(!isset($pageindex->$page)) - { - $pageindex->$page = new stdClass(); - $pageindex->$page->filename = "$page.md"; - } - $pageindex->$page->size = strlen($_POST["content"]); - $pageindex->$page->lastmodified = time(); - if($isloggedin) - $pageindex->$page->lasteditor = utf8_encode($user); - else - $pageindex->$page->lasteditor = utf8_encode("anonymous"); - - file_put_contents("./pageindex.json", json_encode($pageindex, JSON_PRETTY_PRINT)); - - if(isset($_GET["newpage"])) - http_response_code(201); - else - http_response_code(200); - - header("location: index.php?page=$page&edit_status=success"); - exit(); - } - else - { - http_response_code(507); - exit(page_renderer::render_main("Error saving page - $settings->sitename", "

          $settings->sitename failed to write your changes to the disk. Your changes have not been saved, but you might be able to recover your edit by pressing the back button in your browser.

          -

          Please tell the administrator of this wiki (" . $settings->admindetails["name"] . ") about this problem.

          ")); - } - }); - } -]); - -?> + "Page editor", + "version" => "0.8", + "author" => "Starbeamrainbowlabs", + "description" => "Allows you to edit pages by adding the edit and save actions. You should probably include this one.", + "id" => "page-edit", + + "code" => function() { + + /* + * _ _ _ + * ___ __| (_) |_ + * / _ \/ _` | | __| + * | __/ (_| | | |_ + * \___|\__,_|_|\__| + * %edit% + */ + add_action("edit", function() { + global $pageindex, $settings, $page, $isloggedin; + + $filename = "$page.md"; + $creatingpage = !isset($pageindex->$page); + if((isset($_GET["newpage"]) and $_GET["newpage"] == "true") or $creatingpage) + { + $title = "Creating $page"; + } + else + { + $title = "Editing $page"; + } + + $pagetext = ""; + if(isset($pageindex->$page)) + { + $pagetext = file_get_contents($filename); + } + + if((!$isloggedin and !$settings->anonedits) or !$settings->editing) + { + if(!$creatingpage) + { + // The page already exists - let the user view the page source + exit(page_renderer::render_main("Viewing source for $page", "

          $settings->sitename does not allow anonymous users to make edits. You can view the source of $page below, but you can't edit it.

          ")); + } + else + { + http_response_code(404); + exit(page_renderer::render_main("404 - $page", "

          The page $page does not exist, but you do not have permission to create it.

          If you haven't already, perhaps you should try logging in.

          ")); + } + } + + $content = "

          $title

          "; + if(!$isloggedin and $settings->anonedits) + { + $content .= "

          Warning: You are not logged in! Your IP address may be recorded.

          "; + } + $content .= "
          + + +
          "; + exit(page_renderer::render_main("$title - $settings->sitename", $content)); + }); + + /* + * + * ___ __ ___ _____ + * / __|/ _` \ \ / / _ \ + * \__ \ (_| |\ V / __/ + * |___/\__,_| \_/ \___| + * %save% + */ + add_action("save", function() { + global $pageindex, $settings, $page, $isloggedin, $user; + if(!$settings->editing) + { + header("location: index.php?page=$page"); + exit(page_renderer::render_main("Error saving edit", "

          Editing is currently disabled on this wiki.

          ")); + } + if(!$isloggedin and !$settings->anonedits) + { + http_response_code(403); + header("refresh: 5; url=index.php?page=$page"); + exit("You are not logged in, so you are not allowed to save pages on $settings->sitename. Redirecting in 5 seconds...."); + } + if(!isset($_POST["content"])) + { + http_response_code(400); + header("refresh: 5; url=index.php?page=$page"); + exit("Bad request: No content specified."); + } + + // Make sure that the directory in which the page needs to be saved exists + if(!is_dir(dirname("$page.md"))) + { + // Recursively create the directory if needed + mkdir(dirname("$page.md"), null, true); + } + + + if(file_put_contents("$page.md", htmlentities($_POST["content"]), ENT_QUOTES) !== false) + { + // Make sure that this page's parents exist + check_subpage_parents($page); + + //update the page index + if(!isset($pageindex->$page)) + { + $pageindex->$page = new stdClass(); + $pageindex->$page->filename = "$page.md"; + } + $pageindex->$page->size = strlen($_POST["content"]); + $pageindex->$page->lastmodified = time(); + if($isloggedin) + $pageindex->$page->lasteditor = utf8_encode($user); + else + $pageindex->$page->lasteditor = utf8_encode("anonymous"); + + file_put_contents("./pageindex.json", json_encode($pageindex, JSON_PRETTY_PRINT)); + + if(isset($_GET["newpage"])) + http_response_code(201); + else + http_response_code(200); + + header("location: index.php?page=$page&edit_status=success"); + exit(); + } + else + { + http_response_code(507); + exit(page_renderer::render_main("Error saving page - $settings->sitename", "

          $settings->sitename failed to write your changes to the disk. Your changes have not been saved, but you might be able to recover your edit by pressing the back button in your browser.

          +

          Please tell the administrator of this wiki (" . $settings->admindetails["name"] . ") about this problem.

          ")); + } + }); + } +]); + +?> diff --git a/modules/page-export.php b/modules/page-export.php index f64dfa9..ebd61c9 100644 --- a/modules/page-export.php +++ b/modules/page-export.php @@ -1,51 +1,51 @@ - "Export", - "version" => "0.1", - "author" => "Starbeamrainbowlabs", - "description" => "Adds a page that you can use to export your wiki as a .zip file. Uses \$settings->export_only_allow_admins, which controls whether only admins are allowed to export the wiki.", - "id" => "page-export", - "code" => function() { - add_action("export", function() { - global $settings, $pageindex, $isadmin; - - if($settings->export_allow_only_admins && !$isadmin) - { - http_response_code(401); - exit(page_renderer::render("Export error - $settings->sitename", "Only administrators of $settings->sitename are allowed to export the wiki as a zip. Return to the $settings->defaultpage.")); - } - - $tmpfilename = tempnam(sys_get_temp_dir(), "pepperminty-wiki-"); - - $zip = new ZipArchive(); - - if($zip->open($tmpfilename, ZipArchive::CREATE) !== true) - { - http_response_code(507); - exit(page_renderer::render("Export error - $settings->sitename", "Pepperminty Wiki was unable to open a temporary file to store the exported data in. Please contact $settings->sitename's administrator (" . $settings->admindetails["name"] . " at " . hide_email($settings->admindetails["email"]) . ") for assistance.")); - } - - foreach($pageindex as $entry) - { - $zip->addFile("./$entry->filename", $entry->filename); - } - - if($zip->close() !== true) - { - http_response_code(500); - exit(page_renderer::render("Export error - $settings->sitename", "Pepperminty wiki was unable to close the temporary zip file after creating it. Please contact $settings->sitename's administrator (" . $settings->admindetails["name"] . " at " . hide_email($settings->admindetails["email"]) . ") for assistance.")); - } - - header("content-type: application/zip"); - header("content-disposition: attachment; filename=$settings->sitename-export.zip"); - header("content-length: " . filesize($tmpfilename)); - - $zip_handle = fopen($tmpfilename, "rb"); - fpassthru($zip_handle); - fclose($zip_handle); - unlink($tmpfilename); - }); - } -]); - -?> + "Export", + "version" => "0.1", + "author" => "Starbeamrainbowlabs", + "description" => "Adds a page that you can use to export your wiki as a .zip file. Uses \$settings->export_only_allow_admins, which controls whether only admins are allowed to export the wiki.", + "id" => "page-export", + "code" => function() { + add_action("export", function() { + global $settings, $pageindex, $isadmin; + + if($settings->export_allow_only_admins && !$isadmin) + { + http_response_code(401); + exit(page_renderer::render("Export error - $settings->sitename", "Only administrators of $settings->sitename are allowed to export the wiki as a zip. Return to the $settings->defaultpage.")); + } + + $tmpfilename = tempnam(sys_get_temp_dir(), "pepperminty-wiki-"); + + $zip = new ZipArchive(); + + if($zip->open($tmpfilename, ZipArchive::CREATE) !== true) + { + http_response_code(507); + exit(page_renderer::render("Export error - $settings->sitename", "Pepperminty Wiki was unable to open a temporary file to store the exported data in. Please contact $settings->sitename's administrator (" . $settings->admindetails["name"] . " at " . hide_email($settings->admindetails["email"]) . ") for assistance.")); + } + + foreach($pageindex as $entry) + { + $zip->addFile("./$entry->filename", $entry->filename); + } + + if($zip->close() !== true) + { + http_response_code(500); + exit(page_renderer::render("Export error - $settings->sitename", "Pepperminty wiki was unable to close the temporary zip file after creating it. Please contact $settings->sitename's administrator (" . $settings->admindetails["name"] . " at " . hide_email($settings->admindetails["email"]) . ") for assistance.")); + } + + header("content-type: application/zip"); + header("content-disposition: attachment; filename=$settings->sitename-export.zip"); + header("content-length: " . filesize($tmpfilename)); + + $zip_handle = fopen($tmpfilename, "rb"); + fpassthru($zip_handle); + fclose($zip_handle); + unlink($tmpfilename); + }); + } +]); + +?> diff --git a/modules/page-help.php b/modules/page-help.php index a776015..cf149b7 100644 --- a/modules/page-help.php +++ b/modules/page-help.php @@ -1,61 +1,61 @@ - "Help page", - "version" => "0.6", - "author" => "Starbeamrainbowlabs", - "description" => "Adds the help action. You really want this one.", - "id" => "page-help", - "code" => function() { - add_action("help", function() { - global $settings, $version; - - $title = "Help - $settings->sitename"; - $content = "

          $settings->sitename Help

          -

          Welcome to $settings->sitename!

          -

          $settings->sitename is powered by Pepperminty wiki, a complete wiki in a box you can drop into your server.

          -

          Navigating

          -

          All the navigation links can be found in the top right corner, along with a box in which you can type a page name and hit enter to be taken to that page (if your site administrator has enabled it).

          -

          In order to edit pages on $settings->sitename, you probably need to be logged in. If you do not already have an account you will need to ask $settings->sitename's administrator for an account since there is not registration form. Note that the $settings->sitename's administrator may have changed these settings to allow anonymous edits.

          -

          Editing

          -

          $settings->sitename's editor uses a modified version of slimdown, a flavour of markdown that is implementated using regular expressions. See the credits page for more information and links to the original source for this. A quick reference can be found below:

          - - - - - - - - - - - - - - - - - -
          Type ThisTo get this
          _italics_italics
          *bold*bold
          ~~Strikethrough~~Strikethough
          `code`code
          # Heading

          Heading

          ## Sub Heading

          Sub Heading

          [[Internal Link]]Internal Link
          [[Display Text|Internal Link]]Display Text
          [Display text](//google.com/)Display Text
          > Blockquote
          > Some text
          Blockquote
          Some text
          - Apples
          * Oranges
          • Apples
          • Oranges
          1. This is
          2. an ordered list
          1. This is
          2. an ordered list
          - --- -
          ![Alt text](//starbeamrainbowlabs.com/favicon-small.png)Alt text
          - -

          In addition, the following extra syntax is supported for images:

          - -
          Size the image to at most 250 pixels wide:
          -![Alt text](//starbeamrainbowlabs.com/favicon-small.png 250px)
          -
          -Size the image to at most 120px wide and have it float at the right ahnd size of the page:
          -![Alt text](//starbeamrainbowlabs.com/favicon-small.png 120px right)
          - -

          Administrator Actions

          -

          By default, the delete and move actions are shown on the nav bar. These can be used by administrators to delete or move pages.

          -

          The other thing admininistrators can do is update the wiki (provided they know the site's secret). This page can be found here: Update $settings->sitename.

          -

          $settings->sitename is currently running on Pepperminty Wiki $version

          "; - exit(page_renderer::render_main($title, $content)); - }); - } -]); - -?> + "Help page", + "version" => "0.6", + "author" => "Starbeamrainbowlabs", + "description" => "Adds the help action. You really want this one.", + "id" => "page-help", + "code" => function() { + add_action("help", function() { + global $settings, $version; + + $title = "Help - $settings->sitename"; + $content = "

          $settings->sitename Help

          +

          Welcome to $settings->sitename!

          +

          $settings->sitename is powered by Pepperminty wiki, a complete wiki in a box you can drop into your server.

          +

          Navigating

          +

          All the navigation links can be found in the top right corner, along with a box in which you can type a page name and hit enter to be taken to that page (if your site administrator has enabled it).

          +

          In order to edit pages on $settings->sitename, you probably need to be logged in. If you do not already have an account you will need to ask $settings->sitename's administrator for an account since there is not registration form. Note that the $settings->sitename's administrator may have changed these settings to allow anonymous edits.

          +

          Editing

          +

          $settings->sitename's editor uses a modified version of slimdown, a flavour of markdown that is implementated using regular expressions. See the credits page for more information and links to the original source for this. A quick reference can be found below:

          + + + + + + + + + + + + + + + + + +
          Type ThisTo get this
          _italics_italics
          *bold*bold
          ~~Strikethrough~~Strikethough
          `code`code
          # Heading

          Heading

          ## Sub Heading

          Sub Heading

          [[Internal Link]]Internal Link
          [[Display Text|Internal Link]]Display Text
          [Display text](//google.com/)Display Text
          > Blockquote
          > Some text
          Blockquote
          Some text
          - Apples
          * Oranges
          • Apples
          • Oranges
          1. This is
          2. an ordered list
          1. This is
          2. an ordered list
          + --- +
          ![Alt text](//starbeamrainbowlabs.com/favicon-small.png)Alt text
          + +

          In addition, the following extra syntax is supported for images:

          + +
          Size the image to at most 250 pixels wide:
          +![Alt text](//starbeamrainbowlabs.com/favicon-small.png 250px)
          +
          +Size the image to at most 120px wide and have it float at the right ahnd size of the page:
          +![Alt text](//starbeamrainbowlabs.com/favicon-small.png 120px right)
          + +

          Administrator Actions

          +

          By default, the delete and move actions are shown on the nav bar. These can be used by administrators to delete or move pages.

          +

          The other thing admininistrators can do is update the wiki (provided they know the site's secret). This page can be found here: Update $settings->sitename.

          +

          $settings->sitename is currently running on Pepperminty Wiki $version

          "; + exit(page_renderer::render_main($title, $content)); + }); + } +]); + +?> diff --git a/modules/page-list.php b/modules/page-list.php index 6883397..24403d1 100644 --- a/modules/page-list.php +++ b/modules/page-list.php @@ -1,40 +1,40 @@ - "Page list", - "version" => "0.6", - "author" => "Starbeamrainbowlabs", - "description" => "Adds a page that lists all the pages in the index along with their metadata.", - "id" => "page-list", - "code" => function() { - add_action("list", function() { - global $pageindex, $settings; - - $sorted_pageindex = get_object_vars($pageindex); - ksort($sorted_pageindex, SORT_NATURAL); - $title = "All Pages"; - $content = "

          $title on $settings->sitename

          - - - - - - - \n"; - // todo list the pages in alphabetical order - foreach($sorted_pageindex as $pagename => $pagedetails) - { - $content .= "\t\t - - - - - - \n"; - } - $content .= "
          Page NameSizeLast EditorLast Edit Time
          $pagename" . human_filesize($pagedetails->size) . "$pagedetails->lasteditor" . human_time_since($pagedetails->lastmodified) . " (" . date("l jS \of F Y \a\\t h:ia T", $pagedetails->lastmodified) . ")
          "; - exit(page_renderer::render_main("$title - $settings->sitename", $content)); - }); - } -]); - -?> + "Page list", + "version" => "0.6", + "author" => "Starbeamrainbowlabs", + "description" => "Adds a page that lists all the pages in the index along with their metadata.", + "id" => "page-list", + "code" => function() { + add_action("list", function() { + global $pageindex, $settings; + + $sorted_pageindex = get_object_vars($pageindex); + ksort($sorted_pageindex, SORT_NATURAL); + $title = "All Pages"; + $content = "

          $title on $settings->sitename

          + + + + + + + \n"; + // todo list the pages in alphabetical order + foreach($sorted_pageindex as $pagename => $pagedetails) + { + $content .= "\t\t + + + + + + \n"; + } + $content .= "
          Page NameSizeLast EditorLast Edit Time
          $pagename" . human_filesize($pagedetails->size) . "$pagedetails->lasteditor" . human_time_since($pagedetails->lastmodified) . " (" . date("l jS \of F Y \a\\t h:ia T", $pagedetails->lastmodified) . ")
          "; + exit(page_renderer::render_main("$title - $settings->sitename", $content)); + }); + } +]); + +?> diff --git a/modules/page-login.php b/modules/page-login.php index cdc6993..9f9553a 100644 --- a/modules/page-login.php +++ b/modules/page-login.php @@ -1,83 +1,83 @@ - "Login", - "version" => "0.5", - "author" => "Starbeamrainbowlabs", - "description" => "Adds a pair of actions (login and checklogin) that allow users to login. You need this one if you want your users to be able to login.", - "id" => "page-login", - "code" => function() { - /* - * _ _ - * | | ___ __ _(_)_ __ - * | |/ _ \ / _` | | '_ \ - * | | (_) | (_| | | | | | - * |_|\___/ \__, |_|_| |_| - * |___/ %login% - */ - add_action("login", function() { - global $settings; - $title = "Login to $settings->sitename"; - $content = "

          Login to $settings->sitename

          \n"; - if(isset($_GET["failed"])) - $content .= "\t\t

          Login failed.

          \n"; - $content .= "\t\t
          - - -
          - - -
          - -
          "; - exit(page_renderer::render_main($title, $content)); - }); - - /* - * _ _ _ _ - * ___| |__ ___ ___| | _| | ___ __ _(_)_ __ - * / __| '_ \ / _ \/ __| |/ / |/ _ \ / _` | | '_ \ - * | (__| | | | __/ (__| <| | (_) | (_| | | | | | - * \___|_| |_|\___|\___|_|\_\_|\___/ \__, |_|_| |_| - * %checklogin% |___/ - */ - add_action("checklogin", function() { - global $settings; - - //actually do the login - if(isset($_POST["user"]) and isset($_POST["pass"])) - { - //the user wants to log in - $user = $_POST["user"]; - $pass = $_POST["pass"]; - if($settings->users[$user] == hash("sha256", $pass)) - { - $isloggedin = true; - $expiretime = time() + 60*60*24*30; //30 days from now - $_SESSION["$settings->sessionprefix-user"] = $user; - $_SESSION["$settings->sessionprefix-pass"] = hash("sha256", $pass); - $_SESSION["$settings->sessionprefix-expiretime"] = $expiretime; - //redirect to wherever the user was going - http_response_code(302); - if(isset($_POST["goto"])) - header("location: " . $_POST["returnto"]); - else - header("location: index.php"); - exit(); - } - else - { - http_response_code(302); - header("location: index.php?action=login&failed=yes"); - exit(); - } - } - else - { - http_response_code(302); - header("location: index.php?action=login&failed=yes&badrequest=yes"); - exit(); - } - }); - } -]); -?> + "Login", + "version" => "0.5", + "author" => "Starbeamrainbowlabs", + "description" => "Adds a pair of actions (login and checklogin) that allow users to login. You need this one if you want your users to be able to login.", + "id" => "page-login", + "code" => function() { + /* + * _ _ + * | | ___ __ _(_)_ __ + * | |/ _ \ / _` | | '_ \ + * | | (_) | (_| | | | | | + * |_|\___/ \__, |_|_| |_| + * |___/ %login% + */ + add_action("login", function() { + global $settings; + $title = "Login to $settings->sitename"; + $content = "

          Login to $settings->sitename

          \n"; + if(isset($_GET["failed"])) + $content .= "\t\t

          Login failed.

          \n"; + $content .= "\t\t
          + + +
          + + +
          + +
          "; + exit(page_renderer::render_main($title, $content)); + }); + + /* + * _ _ _ _ + * ___| |__ ___ ___| | _| | ___ __ _(_)_ __ + * / __| '_ \ / _ \/ __| |/ / |/ _ \ / _` | | '_ \ + * | (__| | | | __/ (__| <| | (_) | (_| | | | | | + * \___|_| |_|\___|\___|_|\_\_|\___/ \__, |_|_| |_| + * %checklogin% |___/ + */ + add_action("checklogin", function() { + global $settings; + + //actually do the login + if(isset($_POST["user"]) and isset($_POST["pass"])) + { + //the user wants to log in + $user = $_POST["user"]; + $pass = $_POST["pass"]; + if($settings->users[$user] == hash("sha256", $pass)) + { + $isloggedin = true; + $expiretime = time() + 60*60*24*30; //30 days from now + $_SESSION["$settings->sessionprefix-user"] = $user; + $_SESSION["$settings->sessionprefix-pass"] = hash("sha256", $pass); + $_SESSION["$settings->sessionprefix-expiretime"] = $expiretime; + //redirect to wherever the user was going + http_response_code(302); + if(isset($_POST["goto"])) + header("location: " . $_POST["returnto"]); + else + header("location: index.php"); + exit(); + } + else + { + http_response_code(302); + header("location: index.php?action=login&failed=yes"); + exit(); + } + } + else + { + http_response_code(302); + header("location: index.php?action=login&failed=yes&badrequest=yes"); + exit(); + } + }); + } +]); +?> diff --git a/modules/page-logout.php b/modules/page-logout.php index 4d10250..1450ecf 100644 --- a/modules/page-logout.php +++ b/modules/page-logout.php @@ -1,24 +1,24 @@ - "Logout", - "version" => "0.5", - "author" => "Starbeamrainbowlabs", - "description" => "Adds an action to let users user out. For security reasons it is wise to add this module since logging in automatically opens a session that is valid for 30 days.", - "id" => "page-logout", - "code" => function() { - add_action("logout", function() { - global $user, $pass, $isloggedin; - $isloggedin = false; - unset($user); - unset($pass); - //clear the session variables - $_SESSION = []; - session_destroy(); - - exit(page_renderer::render_main("Logout Successful", "

          Logout Successful

          -

          Logout Successful. You can login again here.

          ")); - }); - } -]); - -?> + "Logout", + "version" => "0.5", + "author" => "Starbeamrainbowlabs", + "description" => "Adds an action to let users user out. For security reasons it is wise to add this module since logging in automatically opens a session that is valid for 30 days.", + "id" => "page-logout", + "code" => function() { + add_action("logout", function() { + global $user, $pass, $isloggedin; + $isloggedin = false; + unset($user); + unset($pass); + //clear the session variables + $_SESSION = []; + session_destroy(); + + exit(page_renderer::render_main("Logout Successful", "

          Logout Successful

          +

          Logout Successful. You can login again here.

          ")); + }); + } +]); + +?> diff --git a/modules/page-move.php b/modules/page-move.php index bea1076..3b61eed 100644 --- a/modules/page-move.php +++ b/modules/page-move.php @@ -1,64 +1,64 @@ - "Page mover", - "version" => "0.5", - "author" => "Starbeamrainbowlabs", - "description" => "Adds an action to allow administrators to move pages.", - "id" => "page-move", - "code" => function() { - add_action("move", function() { - global $pageindex, $settings, $page, $isadmin; - if(!$settings->editing) - { - exit(page_renderer::render_main("Moving $page - error", "

          You tried to move $page, but editing is disabled on this wiki.

          -

          If you wish to move this page, please re-enable editing on this wiki first.

          -

          Go back to $page.

          -

          Nothing has been changed.

          ")); - } - if(!$isadmin) - { - exit(page_renderer::render_main("Moving $page - Error", "

          You tried to move $page, but you do not have permission to do that.

          -

          You should try logging in as an admin.

          ")); - } - - if(!isset($_GET["new_name"]) or strlen($_GET["new_name"]) == 0) - exit(page_renderer::render_main("Moving $page", "

          Moving $page

          -
          - - - -
          - - -
          - -
          ")); - - $new_name = makepathsafe($_GET["new_name"]); - - if(!isset($pageindex->$page)) - exit(page_renderer::render_main("Moving $page - Error", "

          You tried to move $page to $new_name, but the page with the name $page does not exist in the first place.

          -

          Nothing has been changed.

          ")); - - if($page == $new_name) - exit(page_renderer::render_main("Moving $page - Error", "

          You tried to move $page, but the new name you gave is the same as it's current name.

          -

          It is possible that you tried to use some characters in the new name that are not allowed and were removed.

          -

          Page names may only contain alphanumeric characters, dashes, and underscores.

          ")); - - //move the page in the page index - $pageindex->$new_name = new stdClass(); - foreach($pageindex->$page as $key => $value) - { - $pageindex->$new_name->$key = $value; - } - unset($pageindex->$page); - file_put_contents("./pageindex.json", json_encode($pageindex, JSON_PRETTY_PRINT)); - - //move the page on the disk - rename("$page.md", "$new_name.md"); - - exit(page_renderer::render_main("Moving $page", "

          $page has been moved to $new_name successfully.

          ")); - }); - } -]); -?> + "Page mover", + "version" => "0.5", + "author" => "Starbeamrainbowlabs", + "description" => "Adds an action to allow administrators to move pages.", + "id" => "page-move", + "code" => function() { + add_action("move", function() { + global $pageindex, $settings, $page, $isadmin; + if(!$settings->editing) + { + exit(page_renderer::render_main("Moving $page - error", "

          You tried to move $page, but editing is disabled on this wiki.

          +

          If you wish to move this page, please re-enable editing on this wiki first.

          +

          Go back to $page.

          +

          Nothing has been changed.

          ")); + } + if(!$isadmin) + { + exit(page_renderer::render_main("Moving $page - Error", "

          You tried to move $page, but you do not have permission to do that.

          +

          You should try logging in as an admin.

          ")); + } + + if(!isset($_GET["new_name"]) or strlen($_GET["new_name"]) == 0) + exit(page_renderer::render_main("Moving $page", "

          Moving $page

          +
          + + + +
          + + +
          + +
          ")); + + $new_name = makepathsafe($_GET["new_name"]); + + if(!isset($pageindex->$page)) + exit(page_renderer::render_main("Moving $page - Error", "

          You tried to move $page to $new_name, but the page with the name $page does not exist in the first place.

          +

          Nothing has been changed.

          ")); + + if($page == $new_name) + exit(page_renderer::render_main("Moving $page - Error", "

          You tried to move $page, but the new name you gave is the same as it's current name.

          +

          It is possible that you tried to use some characters in the new name that are not allowed and were removed.

          +

          Page names may only contain alphanumeric characters, dashes, and underscores.

          ")); + + //move the page in the page index + $pageindex->$new_name = new stdClass(); + foreach($pageindex->$page as $key => $value) + { + $pageindex->$new_name->$key = $value; + } + unset($pageindex->$page); + file_put_contents("./pageindex.json", json_encode($pageindex, JSON_PRETTY_PRINT)); + + //move the page on the disk + rename("$page.md", "$new_name.md"); + + exit(page_renderer::render_main("Moving $page", "

          $page has been moved to $new_name successfully.

          ")); + }); + } +]); +?> diff --git a/modules/page-update.php b/modules/page-update.php index dd82009..766bab6 100644 --- a/modules/page-update.php +++ b/modules/page-update.php @@ -1,66 +1,66 @@ - "Update", - "version" => "0.6", - "author" => "Starbeamrainbowlabs", - "description" => "Adds an update page that downloads the latest stable version of Pepperminty Wiki. This module is currently outdated as it doesn't save your module preferences.", - "id" => "page-update", - "code" => function() { - add_action("update", function() { - global $settings, $isadmin; - - if(!$isadmin) - { - http_response_code(401); - exit(page_renderer::render_main("Update - Error", "

          You must be an administrator to do that.

          ")); - } - - if(!isset($_GET["do"]) or $_GET["do"] !== "true") - { - exit(page_renderer::render_main("Update $settings->sitename", "

          This page allows you to update $settings->sitename.

          -

          Currently, $settings->sitename is using $settings->version of Pepperminty Wiki.

          -

          This script will automatically download and install the latest version of Pepperminty Wiki from the url of your choice (see settings), regardless of whether an update is actually needed (version checking isn't implemented yet).

          -

          To update $settings->sitename, fill out the form below and click click the update button.

          -

          Note that a backup system has not been implemented yet! If this script fails you will loose your wiki's code and have to re-build it.

          -
          - - - - - -
          ")); - } - - if(!isset($_GET["secret"]) or $_GET["secret"] !== $settings->sitesecret) - { - exit(page_renderer::render_main("Update $settings->sitename - Error", "

          You forgot to enter $settings->sitename's secret code or entered it incorrectly. $settings->sitename's secret can be found in the settings portion of index.php.

          ")); - } - - $settings_separator = "/////////////// Do not edit below this line unless you know what you are doing! ///////////////"; - - $log = "Beginning update...\n"; - - $log .= "I am " . __FILE__ . ".\n"; - $oldcode = file_get_contents(__FILE__); - $log .= "Fetching new code..."; - $newcode = file_get_contents($settings->updateurl); - $log .= "done.\n"; - - $log .= "Rewriting " . __FILE__ . "..."; - $settings = substr($oldcode, 0, strpos($oldcode, $settings_separator)); - $code = substr($newcode, strpos($newcode, $settings_separator)); - $result = $settings . $code; - $log .= "done.\n"; - - $log .= "Saving..."; - file_put_contents(__FILE__, $result); - $log .= "done.\n"; - - $log .= "Update complete. I am now running on the latest version of Pepperminty Wiki."; - $log .= "The version number that I have updated to can be found on the credits or help ages."; - - exit(page_renderer::render_main("Update - Success", "
          • " . implode("
          • ", explode("\n", $log)) . "
          ")); - }); - } -]); -?> + "Update", + "version" => "0.6", + "author" => "Starbeamrainbowlabs", + "description" => "Adds an update page that downloads the latest stable version of Pepperminty Wiki. This module is currently outdated as it doesn't save your module preferences.", + "id" => "page-update", + "code" => function() { + add_action("update", function() { + global $settings, $isadmin; + + if(!$isadmin) + { + http_response_code(401); + exit(page_renderer::render_main("Update - Error", "

          You must be an administrator to do that.

          ")); + } + + if(!isset($_GET["do"]) or $_GET["do"] !== "true") + { + exit(page_renderer::render_main("Update $settings->sitename", "

          This page allows you to update $settings->sitename.

          +

          Currently, $settings->sitename is using $settings->version of Pepperminty Wiki.

          +

          This script will automatically download and install the latest version of Pepperminty Wiki from the url of your choice (see settings), regardless of whether an update is actually needed (version checking isn't implemented yet).

          +

          To update $settings->sitename, fill out the form below and click click the update button.

          +

          Note that a backup system has not been implemented yet! If this script fails you will loose your wiki's code and have to re-build it.

          +
          + + + + + +
          ")); + } + + if(!isset($_GET["secret"]) or $_GET["secret"] !== $settings->sitesecret) + { + exit(page_renderer::render_main("Update $settings->sitename - Error", "

          You forgot to enter $settings->sitename's secret code or entered it incorrectly. $settings->sitename's secret can be found in the settings portion of index.php.

          ")); + } + + $settings_separator = "/////////////// Do not edit below this line unless you know what you are doing! ///////////////"; + + $log = "Beginning update...\n"; + + $log .= "I am " . __FILE__ . ".\n"; + $oldcode = file_get_contents(__FILE__); + $log .= "Fetching new code..."; + $newcode = file_get_contents($settings->updateurl); + $log .= "done.\n"; + + $log .= "Rewriting " . __FILE__ . "..."; + $settings = substr($oldcode, 0, strpos($oldcode, $settings_separator)); + $code = substr($newcode, strpos($newcode, $settings_separator)); + $result = $settings . $code; + $log .= "done.\n"; + + $log .= "Saving..."; + file_put_contents(__FILE__, $result); + $log .= "done.\n"; + + $log .= "Update complete. I am now running on the latest version of Pepperminty Wiki."; + $log .= "The version number that I have updated to can be found on the credits or help ages."; + + exit(page_renderer::render_main("Update - Success", "
          • " . implode("
          • ", explode("\n", $log)) . "
          ")); + }); + } +]); +?> diff --git a/modules/page-view.php b/modules/page-view.php index b4fc649..646c06b 100644 --- a/modules/page-view.php +++ b/modules/page-view.php @@ -1,67 +1,67 @@ - "Page viewer", - "version" => "0.8", - "author" => "Starbeamrainbowlabs", - "description" => "Allows you to view pages. You should include this one.", - "id" => "page-view", - "code" => function() { - add_action("view", function() { - global $pageindex, $settings, $page, $parse_page_source; - - // Check to make sure that the page exists - if(!isset($pageindex->$page)) - { - // todo make this intelligent so we only redirect if the user is acutally able to create the page - if($settings->editing) - { - // Editing is enabled, redirect to the editing page - http_response_code(307); // Temporary redirect - header("location: index.php?action=edit&newpage=yes&page=" . rawurlencode($page)); - exit(); - } - else - { - // Editing is disabled, show an error message - http_response_code(404); - exit(page_renderer::render_main("$page - 404 - $settings->sitename", "

          $page does not exist.

          Since editing is currently disabled on this wiki, you may not create this page. If you feel that this page should exist, try contacting this wiki's Administrator.

          ")); - } - } - $title = "$page - $settings->sitename"; - $content = "

          $page

          "; - - $parsing_start = microtime(true); - - $content .= $parse_page_source(file_get_contents("$page.md")); - - if($settings->show_subpages) - { - $subpages = get_object_vars(get_subpages($pageindex, $page)); - - if(count($subpages) > 0) - { - $content .= "
          "; - $content .= "Subpages: "; - foreach($subpages as $subpage => $times_removed) - { - if($times_removed <= $settings->subpages_display_depth) - { - $content .= "$subpage, "; - } - } - // Remove the last comma from the content - $content = substr($content, 0, -2); - } - } - - $content .= "\n\t\t\n"; - - if(isset($_GET["printable"]) and $_GET["printable"] === "yes") - exit(page_renderer::render_minimal($title, $content)); - else - exit(page_renderer::render_main($title, $content)); - }); - } -]); - -?> + "Page viewer", + "version" => "0.8", + "author" => "Starbeamrainbowlabs", + "description" => "Allows you to view pages. You should include this one.", + "id" => "page-view", + "code" => function() { + add_action("view", function() { + global $pageindex, $settings, $page, $parse_page_source; + + // Check to make sure that the page exists + if(!isset($pageindex->$page)) + { + // todo make this intelligent so we only redirect if the user is acutally able to create the page + if($settings->editing) + { + // Editing is enabled, redirect to the editing page + http_response_code(307); // Temporary redirect + header("location: index.php?action=edit&newpage=yes&page=" . rawurlencode($page)); + exit(); + } + else + { + // Editing is disabled, show an error message + http_response_code(404); + exit(page_renderer::render_main("$page - 404 - $settings->sitename", "

          $page does not exist.

          Since editing is currently disabled on this wiki, you may not create this page. If you feel that this page should exist, try contacting this wiki's Administrator.

          ")); + } + } + $title = "$page - $settings->sitename"; + $content = "

          $page

          "; + + $parsing_start = microtime(true); + + $content .= $parse_page_source(file_get_contents("$page.md")); + + if($settings->show_subpages) + { + $subpages = get_object_vars(get_subpages($pageindex, $page)); + + if(count($subpages) > 0) + { + $content .= "
          "; + $content .= "Subpages: "; + foreach($subpages as $subpage => $times_removed) + { + if($times_removed <= $settings->subpages_display_depth) + { + $content .= "$subpage, "; + } + } + // Remove the last comma from the content + $content = substr($content, 0, -2); + } + } + + $content .= "\n\t\t\n"; + + if(isset($_GET["printable"]) and $_GET["printable"] === "yes") + exit(page_renderer::render_minimal($title, $content)); + else + exit(page_renderer::render_main($title, $content)); + }); + } +]); + +?> diff --git a/modules/parser-default.php b/modules/parser-default.php index b904c2a..f0ffdbe 100644 --- a/modules/parser-default.php +++ b/modules/parser-default.php @@ -1,127 +1,127 @@ - "Default Parser", - "version" => "0.7", - "author" => "Johnny Broadway & Starbeamrainbowlabs", - "description" => "The default parser for Pepperminty Wiki. Based on Johnny Broadway's Slimdown (with more than a few modifications). This parser's features are documented in the help page.", - "id" => "parser-default", - "code" => function() { - add_parser(function($markdown) { - return Slimdown::render($markdown); - }); - } -]); - -//////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////// Slimdown ///////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// %slimdown% // -//////////////////////////////////////////////////////////////////////////////////////////// -/** - * Slimdown - A very basic regex-based Markdown parser. Supports the - * following elements (and can be extended via Slimdown::add_rule()): - * - * - Headers - * - Links - * - Bold - * - Emphasis - * - Deletions - * - Quotes - * - Inline code - * - Blockquotes - * - Ordered/unordered lists - * - Horizontal rules - * - * Author: Johnny Broadway - * Website: https://gist.github.com/jbroadway/2836900 - * License: MIT - */ - -/** - * Modified by Starbeamrainbowlabs (starbeamrainbowlabs) - * - * Changed bold to use single asterisks - * Changed italics to use single underscores - * Added one to add the heading levels (no

          tags allowed) - * Added wiki style internal link parsing - * Added wiki style internal link parsing with display text - * Added image support - */ -class Slimdown { - public static $rules = array ( - '/\r\n/' => "\n", // new line normalisation - '/(#+)(.*)/' => 'self::header', // headers - '/(\*)(.*?)\1/' => '\2', // bold - '/(_)(.*?)\1/' => '\2', // emphasis - - // todo test these - '/!\[(.*)\]\(([^\s]+)\s(\d+.+)\s(left|right)\)/' => '\1', // images with size - '/!\[(.*)\]\(([^\s]+)\s(\d+.+)\)/' => '\1', // images with size - '/!\[(.*)\]\((.*)\)/' => '\1', // basic images - // todo end - - '/\[\[([a-zA-Z0-9\_\- ]+)\|([a-zA-Z0-9\_\- ]+)\]\]/' => '\2', //internal links with display text - '/\[\[([a-zA-Z0-9\_\- ]+)\]\]/' => '\1', //internal links - '/\[([^\[]+)\]\(([^\)]+)\)/' => '\1', // links - '/\~\~(.*?)\~\~/' => '\1', // del - '/\:\"(.*?)\"\:/' => '\1', // quote - '/`(.*?)`/' => '\1', // inline code - '/\n\s*(\*|-)(.*)/' => 'self::ul_list', // ul lists - '/\n[0-9]+\.(.*)/' => 'self::ol_list', // ol lists - '/\n(>|\>)(.*)/' => 'self::blockquote', // blockquotes - '/\n-{3,}/' => "\n
          ", // horizontal rule - '/\n([^\n]+)\n\n/' => 'self::para', // add paragraphs - '/<\/ul>\s?
            /' => '', // fix extra ul - '/<\/ol>\s?
              /' => '', // fix extra ol - '/<\/blockquote>
              /' => "\n" // fix extra blockquote - ); - private static function para ($regs) { - $line = $regs[1]; - $trimmed = trim ($line); - if (preg_match ('/^<\/?(ul|ol|li|h|p|bl)/', $trimmed)) { - return "\n" . $line . "\n"; - } - return sprintf ("\n

              %s

              \n", $trimmed); - } - private static function ul_list ($regs) { - $item = $regs[2]; - return sprintf ("\n
                \n\t
              • %s
              • \n
              ", trim($item)); - } - private static function ol_list ($regs) { - $item = $regs[1]; - return sprintf ("\n
                \n\t
              1. %s
              2. \n
              ", trim($item)); - } - private static function blockquote ($regs) { - $item = $regs[2]; - return sprintf ("\n
              %s
              ", trim($item)); - } - private static function header ($regs) { - list ($tmp, $chars, $header) = $regs; - $level = strlen ($chars); - return sprintf ('%s', $level + 1, trim($header), $level + 1); - } - - /** - * Add a rule. - */ - public static function add_rule ($regex, $replacement) { - self::$rules[$regex] = $replacement; - } - /** - * Render some Markdown into HTML. - */ - public static function render ($text) { - foreach (self::$rules as $regex => $replacement) { - if (is_callable ( $replacement)) { - $text = preg_replace_callback ($regex, $replacement, $text); - } else { - $text = preg_replace ($regex, $replacement, $text); - } - } - return trim ($text); - } -} -//////////////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////// - -?> + "Default Parser", + "version" => "0.7", + "author" => "Johnny Broadway & Starbeamrainbowlabs", + "description" => "The default parser for Pepperminty Wiki. Based on Johnny Broadway's Slimdown (with more than a few modifications). This parser's features are documented in the help page.", + "id" => "parser-default", + "code" => function() { + add_parser(function($markdown) { + return Slimdown::render($markdown); + }); + } +]); + +//////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////// Slimdown ///////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// %slimdown% // +//////////////////////////////////////////////////////////////////////////////////////////// +/** + * Slimdown - A very basic regex-based Markdown parser. Supports the + * following elements (and can be extended via Slimdown::add_rule()): + * + * - Headers + * - Links + * - Bold + * - Emphasis + * - Deletions + * - Quotes + * - Inline code + * - Blockquotes + * - Ordered/unordered lists + * - Horizontal rules + * + * Author: Johnny Broadway + * Website: https://gist.github.com/jbroadway/2836900 + * License: MIT + */ + +/** + * Modified by Starbeamrainbowlabs (starbeamrainbowlabs) + * + * Changed bold to use single asterisks + * Changed italics to use single underscores + * Added one to add the heading levels (no

              tags allowed) + * Added wiki style internal link parsing + * Added wiki style internal link parsing with display text + * Added image support + */ +class Slimdown { + public static $rules = array ( + '/\r\n/' => "\n", // new line normalisation + '/(#+)(.*)/' => 'self::header', // headers + '/(\*)(.*?)\1/' => '\2', // bold + '/(_)(.*?)\1/' => '\2', // emphasis + + // todo test these + '/!\[(.*)\]\(([^\s]+)\s(\d+.+)\s(left|right)\)/' => '\1', // images with size + '/!\[(.*)\]\(([^\s]+)\s(\d+.+)\)/' => '\1', // images with size + '/!\[(.*)\]\((.*)\)/' => '\1', // basic images + // todo end + + '/\[\[([a-zA-Z0-9\_\- ]+)\|([a-zA-Z0-9\_\- ]+)\]\]/' => '\2', //internal links with display text + '/\[\[([a-zA-Z0-9\_\- ]+)\]\]/' => '\1', //internal links + '/\[([^\[]+)\]\(([^\)]+)\)/' => '\1', // links + '/\~\~(.*?)\~\~/' => '\1', // del + '/\:\"(.*?)\"\:/' => '\1', // quote + '/`(.*?)`/' => '\1', // inline code + '/\n\s*(\*|-)(.*)/' => 'self::ul_list', // ul lists + '/\n[0-9]+\.(.*)/' => 'self::ol_list', // ol lists + '/\n(>|\>)(.*)/' => 'self::blockquote', // blockquotes + '/\n-{3,}/' => "\n
              ", // horizontal rule + '/\n([^\n]+)\n\n/' => 'self::para', // add paragraphs + '/<\/ul>\s?
                /' => '', // fix extra ul + '/<\/ol>\s?
                  /' => '', // fix extra ol + '/<\/blockquote>
                  /' => "\n" // fix extra blockquote + ); + private static function para ($regs) { + $line = $regs[1]; + $trimmed = trim ($line); + if (preg_match ('/^<\/?(ul|ol|li|h|p|bl)/', $trimmed)) { + return "\n" . $line . "\n"; + } + return sprintf ("\n

                  %s

                  \n", $trimmed); + } + private static function ul_list ($regs) { + $item = $regs[2]; + return sprintf ("\n
                    \n\t
                  • %s
                  • \n
                  ", trim($item)); + } + private static function ol_list ($regs) { + $item = $regs[1]; + return sprintf ("\n
                    \n\t
                  1. %s
                  2. \n
                  ", trim($item)); + } + private static function blockquote ($regs) { + $item = $regs[2]; + return sprintf ("\n
                  %s
                  ", trim($item)); + } + private static function header ($regs) { + list ($tmp, $chars, $header) = $regs; + $level = strlen ($chars); + return sprintf ('%s', $level + 1, trim($header), $level + 1); + } + + /** + * Add a rule. + */ + public static function add_rule ($regex, $replacement) { + self::$rules[$regex] = $replacement; + } + /** + * Render some Markdown into HTML. + */ + public static function render ($text) { + foreach (self::$rules as $regex => $replacement) { + if (is_callable ( $replacement)) { + $text = preg_replace_callback ($regex, $replacement, $text); + } else { + $text = preg_replace ($regex, $replacement, $text); + } + } + return trim ($text); + } +} +//////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////// + +?> diff --git a/rebuild_module_index.php b/rebuild_module_index.php index 4c1eb59..19bf2b5 100644 --- a/rebuild_module_index.php +++ b/rebuild_module_index.php @@ -1,32 +1,32 @@ - $settings["name"], - "version" => $settings["version"], - "author" => $settings["author"], - "description" => $settings["description"], - "id" => $settings["id"], - "lastupdate" => filemtime("modules/" . $settings["id"] . ".php") - ]; - $module_index[] = $newmodule; -} - -foreach($modules as $filename) -{ - echo("Processing $filename\n"); - require($filename); -} - -echo("*** Processing Complete ***\n"); - -echo("Writing new module index to disk..."); -file_put_contents("module_index.json", json_encode($module_index, JSON_PRETTY_PRINT)); -echo("done\n"); - -?> + $settings["name"], + "version" => $settings["version"], + "author" => $settings["author"], + "description" => $settings["description"], + "id" => $settings["id"], + "lastupdate" => filemtime("modules/" . $settings["id"] . ".php") + ]; + $module_index[] = $newmodule; +} + +foreach($modules as $filename) +{ + echo("Processing $filename\n"); + require($filename); +} + +echo("*** Processing Complete ***\n"); + +echo("Writing new module index to disk..."); +file_put_contents("module_index.json", json_encode($module_index, JSON_PRETTY_PRINT)); +echo("done\n"); + +?> diff --git a/start-server.bat b/start-server.bat index 542ae7f..9f1d0dd 100644 --- a/start-server.bat +++ b/start-server.bat @@ -1 +1 @@ -php -S [::]:4569 +php -S [::]:4569