There isn't a page on $settings->sitename with that name. However, you could search for this page name in other pages.
Alternatively, you could create this page.
")); } // Redirect the user to the login page if: // - A login is required to view this wiki // - The user isn't already requesting the login page // Note we use $_GET here because $env->action isn't populated at this point if($settings->require_login_view === true && // If this site requires a login in order to view pages !$env->is_logged_in && // And the user isn't logged in !in_array($_GET["action"], [ "login", "checklogin" ])) // And the user isn't trying to login { // Redirect the user to the login page http_response_code(307); $url = "?action=login&returnto=" . rawurlencode($_SERVER["REQUEST_URI"]) . "&required=true"; header("location: $url"); exit(page_renderer::render("Login required - $settings->sitename", "$settings->sitename requires that you login before you are able to access it.
")); } ////////////////////////////////////// ////////////////////////////////////// ////////////////////////// /// 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; } /** * Checks to see whether a module with the given id exists. * @param string $id The id to search for. * @return bool Whether a module is currently loaded with the given id. */ function module_exists($id) { global $modules; foreach($modules as $module) { if($module["id"] == $id) return true; } return false; } // 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. $parsers = [ "none" => function() { throw new Exception("No parser registered!"); } ]; function add_parser($name, $parser_code) { global $parsers; if(isset($parsers[$name])) throw new Exception("Can't register parser with name '$name' because a parser with that name already exists."); $parsers[$name] = $parser_code; } function parse_page_source($source) { global $settings, $parsers; if(!isset($parsers[$settings->parser])) exit(page_renderer::render_main("Parsing error - $settings->sitename", "Parsing some page source data failed. This is most likely because $settings->sitename has the parser setting set incorrectly. Please contact " . $settings->admindetails["name"] . ", your $settings->sitename Administrator.")); /* Not needed atm because escaping happens when saving, not when rendering * if($settings->clean_raw_html) $source = htmlentities($source, ENT_QUOTES | ENT_HTML5); */ return $parsers[$settings->parser]($source); } // Function to register a new proprocessor that will be executed just before // an edit is saved. $save_preprocessors = []; function register_save_preprocessor($func) { global $save_preprocessors; $save_preprocessors[] = $func; } $help_sections = []; function add_help_section($index, $title, $content) { global $help_sections; $help_sections[$index] = [ "title" => $title, "content" => $content ]; } ////////////////////////////////////////////////////////////////// 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() { global $settings; 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", "Algorithm: " . ($settings->use_sha3 ? "sha3" : "sha256") . "
\n" . $_GET["string"] . "
→ " . hash_password($_GET["string"]) . "
Page protection for $env->page has been $state.
Go back.")); } else { exit(page_renderer::render_main("Error protecting page", "
You are not allowed to protect pages because you are not logged in as a mod or admin. Please try logging out if you are logged in and then try logging in as an administrator.
")); } }); } ]); register_module([ "name" => "Raw page source", "version" => "0.5", "author" => "Starbeamrainbowlabs", "description" => "Adds a 'raw' action that shows you the raw source of a page.", "id" => "action-raw", "code" => function() { global $settings; /* * ██████ █████ ██ ██ * ██ ██ ██ ██ ██ ██ * ██████ ███████ ██ █ ██ * ██ ██ ██ ██ ██ ███ ██ * ██ ██ ██ ██ ███ ███ */ add_action("raw", function() { global $env; http_response_code(307); header("x-filename: " . rawurlencode($env->page) . ".md"); header("content-type: text/markdown"); exit(file_get_contents("$env->storage_prefix$env->page.md")); exit(); }); add_help_section("800-raw-page-content", "Viewing Raw Page Content", "Although you can use the edit page to view a page's source, you can also ask $settings->sitename to send you the raw page source and nothing else. This feature is intented for those who want to automate their interaction with $settings->sitename.
To use this feature, navigate to the page for which you want to see the source, and then alter the action
parameter in the url's query string to be raw
. If the action
parameter doesn't exist, add it. Note that when used on an file's page this action will return the source of the description and not the file itself.
$settings->sitename has an optional sidebar which displays a list of all the current pages (but not subpages) that it is currently hosting. It may or may not be enabled.
If it isn't enabled, it can be enabled for your current browser only by appending sidebar=yes
to the current page's query string.
$settings->sitename supports redirect pages. To create a redirect page, enter something like # REDIRECT [[pagename]]
on the first line of the redirect page's content. This must appear as the first line of the page, with no whitespace before it. You can include content beneath the redirect if you want, too (such as a reason for redirecting the page).
You didn't specify any search terms. Try typing some into the box above.
")); $search_start = microtime(true); $invindex = search::load_invindex($paths->searchindex); $results = search::query_invindex($_GET["query"], $invindex); $search_end = microtime(true) - $search_start; $title = $_GET["query"] . " - Search results - $settings->sitename"; $content = "There's a page on $settings->sitename called $query.
"; } else { $content .= "There isn't a page called $query on $settings->sitename, but you can create it.
"; } $i = 0; // todo use $_GET["offset"] and $_GET["result-count"] or something foreach($results as $result) { $link = "?page=" . rawurlencode($result["pagename"]); $pagesource = file_get_contents($env->storage_prefix . $result["pagename"] . ".md"); $context = search::extract_context($_GET["query"], $pagesource); $context = search::highlight_context($_GET["query"], $context); /*if(strlen($context) == 0) { $context = search::strip_markup(file_get_contents("$env->page.md", null, null, null, $settings->search_characters_context * 2)); if($pageindex->{$env->page}->size > $settings->search_characters_context * 2) $context .= "..."; }*/ // We add 1 to $i here to convert it from an index to a result // number as people expect it to start from 1 $content .= "$context
\n"; $content .= "You can't upload anything at the moment because $settings->sitename has uploads disabled. Try contacting " . $settings->admindetails["name"] . ", your site Administrator. Go back.
")); if(!$env->is_logged_in) exit(page_renderer::render("Upload Error - $settings->sitename", "You are not currently logged in, so you can't upload anything.
Try logging in first.
")); exit(page_renderer::render("Upload - $settings->sitename", "Select an image below, and then type a name for it in the box. This server currently supports uploads up to " . human_filesize(get_max_upload_size()) . " in size.
$settings->sitename currently supports uploading of the following file types: " . implode(", ", $settings->upload_allowed_file_types) . ".
")); break; case "POST": // Recieve file // Make sure uploads are enabled if(!$settings->upload_enabled) { unlink($_FILES["file"]["tmp_name"]); http_response_code(412); exit(page_renderer::render("Upload failed - $settings->sitename", "Your upload couldn't be processed because uploads are currently disabled on $settings->sitename. Go back to the main page.
")); } // Make sure that the user is logged in if(!$env->is_logged_in) { unlink($_FILES["file"]["tmp_name"]); http_response_code(401); exit(page_renderer::render("Upload failed - $settings->sitename", "Your upload couldn't be processed because you are not logged in.
Try logging in first.")); } // Calculate the target ename, removing any characters we // are unsure about. $target_name = makepathsafe($_POST["name"]); $temp_filename = $_FILES["file"]["tmp_name"]; $mimechecker = finfo_open(FILEINFO_MIME_TYPE); $mime_type = finfo_file($mimechecker, $temp_filename); finfo_close($mimechecker); // Perform appropriate checks based on the *real* filetype switch(substr($mime_type, 0, strpos($mime_type, "/"))) { case "image": $extra_data = []; $imagesize = getimagesize($temp_filename, $extra_data); // Make sure that the image size is defined if(!is_int($imagesize[0]) or !is_int($imagesize[1])) { http_response_code(415); exit(page_renderer::render("Upload Error - $settings->sitename", "
The file that you uploaded doesn't appear to be an image. $settings->sitename currently only supports uploading images (videos coming soon). Go back to try again.
")); } break; case "video": http_response_code(501); exit(page_renderer::render("Upload Error - $settings->sitename", "You uploaded a video, but $settings->sitename doesn't support them yet. Please try again later.
")); default: http_response_code(415); exit(page_renderer::render("Upload Error - $settings->sitename", "You uploaded an unnknown file type which couldn't be processed. $settings->sitename thinks that the file you uploaded was a(n) '$mime_type', which isn't supported.
")); } $file_extension = system_mime_type_extension($mime_type); $new_filename = "$paths->upload_file_prefix$target_name.$file_extension"; $new_description_filename = "$new_filename.md"; if(isset($pageindex->$new_filename)) exit(page_renderer::render("Upload Error - $settings->sitename", "A page or file has already been uploaded with the name '$new_filename'. Try deleting it first. If you do not have permission to delete things, try contacting one of the moderators.
")); if(!file_exists("Files")) mkdir("Files", 0664); if(!move_uploaded_file($temp_filename, $env->storage_prefix . $new_filename)) { http_response_code(409); exit(page_renderer::render("Upload Error - $settings->sitename", "The file you uploaded was valid, but $settings->sitename couldn't verify that it was tampered with during the upload process. This probably means that $settings->sitename has been attacked. Please contact " . $settings->admindetails . ", your $settings->sitename Administrator.
")); } $description = $_POST["description"]; // Escape the raw html in the provided description if the setting is enabled if($settings->clean_raw_html) $description = htmlentities($description, ENT_QUOTES); file_put_contents($env->storage_prefix . $new_description_filename, $description); // Construct a new entry for the pageindex $entry = new stdClass(); // Point to the description's filepath since this property // should point to a markdown file $entry->filename = $new_description_filename; $entry->size = strlen($description); $entry->lastmodified = time(); $entry->lasteditor = $env->user; $entry->uploadedfile = true; $entry->uploadedfilepath = $new_filename; $entry->uploadedfilemime = $mime_type; // Add the new entry to the pageindex // Assign the new entry to the image's filepath as that // should be the page name. $pageindex->$new_filename = $entry; // Save the pageindex file_put_contents($paths->pageindex, json_encode($pageindex, JSON_PRETTY_PRINT)); header("location: ?action=view&page=$new_filename&upload=success"); break; } }); /* * ██████ ██████ ███████ ██ ██ ██ ███████ ██ ██ * ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ * ██████ ██████ █████ ██ ██ ██ █████ ██ █ ██ * ██ ██ ██ ██ ██ ██ ██ ██ ██ ███ ██ * ██ ██ ██ ███████ ████ ██ ███████ ███ ███ */ add_action("preview", function() { global $settings, $env, $pageindex; $filepath = $env->storage_prefix . $pageindex->{$env->page}->uploadedfilepath; $mime_type = $pageindex->{$env->page}->uploadedfilemime; if(isset($_GET["size"]) and $_GET["size"] == "original") { // Get the file size $filesize = filesize($filepath); // Send some headers header("content-length: $filesize"); header("content-type: $mime_type"); // Open the file and send it to the user $handle = fopen($filepath, "rb"); fpassthru($handle); fclose($handle); exit(); } // Determine the target size of the image $target_size = 512; if(isset($_GET["size"])) $target_size = intval($_GET["size"]); if($target_size < $settings->min_preview_size) $target_size = $settings->min_preview_size; if($target_size > $settings->max_preview_size) $target_size = $settings->max_preview_size; // Determine the output file type $output_mime = $settings->preview_file_type; if(isset($_GET["type"]) and in_array($_GET["type"], [ "image/png", "image/jpeg", "image/webp" ])) $output_mime = $_GET["type"]; switch(substr($mime_type, 0, strpos($mime_type, "/"))) { case "image": $image = false; switch($mime_type) { case "image/jpeg": $image = imagecreatefromjpeg($filepath); break; case "image/gif": $image = imagecreatefromgif($filepath); break; case "image/png": $image = imagecreatefrompng($filepath); break; case "image/webp": $image = imagecreatefromwebp($filepath); break; default: http_response_code(415); $image = errorimage("Unsupported image type."); break; } $raw_width = imagesx($image); $raw_height = imagesy($image); $preview_image = resize_image($image, $target_size); header("content-type: $output_mime"); switch($output_mime) { case "image/jpeg": imagejpeg($preview_image); break; case "image/png": imagepng($preview_image); break; default: case "image/webp": imagewebp($preview_image); break; } imagedestroy($preview_image); break; default: http_response_code(501); exit("Unrecognised file type."); } }); page_renderer::register_part_preprocessor(function(&$parts) { global $pageindex, $env, $settings; // Todo add the preview to the top of the page here, but only if the current action is view and we are on a page that is a file if(isset($pageindex->{$env->page}->uploadedfile) and $pageindex->{$env->page}->uploadedfile == true) { // We are looking at a page that is paired with an uploaded file $filepath = $pageindex->{$env->page}->uploadedfilepath; $mime_type = $pageindex->{$env->page}->uploadedfilemime; $dimensions = getimagesize($env->storage_prefix . $filepath); $preview_sizes = [ 256, 512, 768, 1024, 1440 ]; $preview_html = "Name | " . str_replace("File/", "", $filepath) . " |
---|---|
Type | $mime_type |
Size | " . human_filesize(filesize($filepath)) . " |
Original dimensions | $dimensions[0] x $dimensions[1] |
Uploaded by | " . $pageindex->{$env->page}->lasteditor . " |
$settings->sitename supports the uploading of files, though it is up to " . $settings->admindetails["name"] . ", $settings->sitename's administrator as to whether it is enabled or not (uploads are currently " . (($settings->upload_enabled) ? "enabled" : "disabled") . ").
Currently Pepperminty Wiki (the software that $settings->sitename uses) only supports the uploading of images, although more file types should be supported in the future (open an issue on GitHub if you are interested in support for more file types).
Uploading a file is actually quite simple. Click the "Upload" option in the "More..." menu to go to the upload page. The upload page will tell you what types of file $settings->sitename allows, and the maximum supported filesize for files that you upload (this is usually set by the web server that the wiki is running on).
Use the file chooser to select the file that you want to upload, and then decide on a name for it. Note that the name that you choose should not include the file extension, as this will be determined automatically. Enter a description that will appear on the file's page, and then click upload.
"); } ]); //// Pair of functions to calculate the actual maximum upload size supported by the server //// Lifted from Drupal by @meustrus from Stackoverflow. Link to answer: //// http://stackoverflow.com/a/25370978/1460422 // Returns a file size limit in bytes based on the PHP upload_max_filesize // and post_max_size function get_max_upload_size() { static $max_size = -1; if ($max_size < 0) { // Start with post_max_size. $max_size = parse_size(ini_get('post_max_size')); // If upload_max_size is less, then reduce. Except if upload_max_size is // zero, which indicates no limit. $upload_max = parse_size(ini_get('upload_max_filesize')); if ($upload_max > 0 && $upload_max < $max_size) { $max_size = $upload_max; } } return $max_size; } function parse_size($size) { $unit = preg_replace('/[^bkmgtpezy]/i', '', $size); // Remove the non-unit characters from the size. $size = preg_replace('/[^0-9\.]/', '', $size); // Remove the non-numeric characters from the size. if ($unit) { // Find the position of the unit in the ordered string which is the power of magnitude to multiply a kilobyte by. return round($size * pow(1024, stripos('bkmgtpezy', $unit[0]))); } else { return round($size); } } function errorimage($text) { $width = 640; $height = 480; $image = imagecreatetruecolor($width, $height); imagefill($image, 0, 0, imagecolorallocate($image, 238, 232, 242)); // Set the background to #eee8f2 $fontwidth = imagefontwidth(3); imagetext($image, 3, ($width / 2) - (($fontwidth * strlen($text)) / 2), ($height / 2) - (imagefontheight(3) / 2), $text, imagecolorallocate($image, 17, 17, 17) // #111111 ); return $image; } function resize_image($image, $size) { $cur_width = imagesx($image); $cur_height = imagesy($image); if($cur_width < $size and $cur_height < $size) return $image; $width_ratio = $size / $cur_width; $height_ratio = $size / $cur_height; $ratio = min($width_ratio, $height_ratio); $new_height = floor($cur_height * $ratio); $new_width = floor($cur_width * $ratio); header("x-resize-to: $new_width x $new_height\n"); return imagescale($image, $new_width, $new_height); } 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 renderer //// $credits_html = "Name | Version | Author | Description |
---|---|---|---|
" . $module["name"] . " | " . $module["version"] . " | " . $module["author"] . " | " . $module["description"] . " |
$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).
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) . " |
You tried to delete $env->page, but editing is disabled on this wiki.
If you wish to delete this page, please re-enable editing on this wiki first.
Nothing has been changed.
")); } if(!$env->is_admin) { exit(page_renderer::render_main("Deleting $env->page - error", "You tried to delete $env->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 $env->page", "You are about to delete $env->page. You can't undo this!
Click here to delete $env->page.
Click here to go back.")); } $page = $env->page; // Delete the associated file if it exists if(!empty($pageindex->$page->uploadedfile)) { unlink($env->storage_prefix . $pageindex->$page->uploadedfilepath); } // Delete the page from the page index unset($pageindex->$page); // Save the new page index file_put_contents($paths->pageindex, json_encode($pageindex, JSON_PRETTY_PRINT)); // Remove the page's name from the id index ids::deletepagename($env->page); // Delete the page from the search index, if that module is installed if(module_exists("feature-search")) { $pageid = ids::getid($env->page); $invindex = search::load_invindex($paths->searchindex); search::delete_entry($invindex, $pageid); search::save_invindex($paths->searchindex, $invindex); } // Delete the page from the disk unlink("$env->storage_prefix$env->page.md"); exit(page_renderer::render_main("Deleting $env->page - $settings->sitename", "
$env->page has been deleted. Go back to the main page.
")); }); // Register a help section add_help_section("60-delete", "Deleting Pages", "If you are logged in as an adminitrator, then you have the power to delete pages. To do this, click "Delete" in the "More..." menu when browsing the pge you wish to delete. When you are sure that you want to delete the page, click the given link.
Warning: Once a page has been deleted, you can't bring it back! You will need to recover it from your backup, if you have one (which you really should).
"); } ]); register_module([ "name" => "Page editor", "version" => "0.13", "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() { global $settings; /* * _ _ _ * ___ __| (_) |_ * / _ \/ _` | | __| * | __/ (_| | | |_ * \___|\__,_|_|\__| * %edit% */ add_action("edit", function() { global $pageindex, $settings, $env; $filename = "$env->storage_prefix$env->page.md"; $page = $env->page; $creatingpage = !isset($pageindex->$page); if((isset($_GET["newpage"]) and $_GET["newpage"] == "true") or $creatingpage) { $title = "Creating $env->page"; } else { $title = "Editing $env->page"; } $pagetext = ""; if(isset($pageindex->$page)) { $pagetext = file_get_contents($filename); } if((!$env->is_logged_in and !$settings->anonedits) or // if we aren't logged in and anonymous edits are disbled !$settings->editing or// or editing is disabled ( isset($pageindex->$page) and // the page exists isset($pageindex->$page->protect) and // the protect property exists $pageindex->$page->protect and // the protect property is true !$env->is_admin // the user isn't an admin ) ) { if(!$creatingpage) { // The page already exists - let the user view the page source exit(page_renderer::render_main("Viewing source for $env->page", "$settings->sitename does not allow anonymous users to make edits. If you are in fact logged in, then this page is probably protected, and you aren't an administrator or moderator. You can view the source of $env->page below, but you can't edit it.
")); } else { http_response_code(404); exit(page_renderer::render_main("404 - $env->page", "The page $env->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 = "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, $env, $save_preprocessors, $paths; if(!$settings->editing) { header("location: index.php?page=$env->page"); exit(page_renderer::render_main("Error saving edit", "Editing is currently disabled on this wiki.
")); } if(!$env->is_logged_in and !$settings->anonedits) { http_response_code(403); header("refresh: 5; url=index.php?page=$env->page"); exit("You are not logged in, so you are not allowed to save pages on $settings->sitename. Redirecting in 5 seconds...."); } $page = $env->page; if(( isset($pageindex->$page) and isset($pageindex->page->protect) and $pageindex->$page->protect ) and !$env->is_admin) { http_response_code(403); header("refresh: 5; url=index.php?page=$env->page"); exit("$env->page is protected, and you aren't logged in as an administrator or moderator. Your edit was not saved. Redirecting in 5 seconds..."); } if(!isset($_POST["content"])) { http_response_code(400); header("refresh: 5; url=index.php?page=$env->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("$env->storage_prefix$env->page.md"))) { // Recursively create the directory if needed mkdir(dirname("$env->storage_prefix$env->page.md"), null, true); } // Read in the new page content $pagedata = $_POST["content"]; // Santise it if necessary if($settings->clean_raw_html) $pagedata = htmlentities($pagedata, ENT_QUOTES); // Read in the new page tags, so long as there are actually some tags to read in $page_tags = []; if(strlen(trim($_POST["tags"])) > 0) { $page_tags = explode(",", $_POST["tags"]); // Trim off all the whitespace foreach($page_tags as &$tag) $tag = trim($tag); } // Update the inverted search index // Construct an index for the old and new page content $oldindex = []; if(file_exists("$env->page.md")) $oldindex = search::index(file_get_contents("$env->page.md")); $newindex = search::index($pagedata); // Compare the indexes of the old and new content $additions = []; $removals = []; search::compare_indexes($oldindex, $newindex, $additions, $removals); // Load in the inverted index $invindex = search::load_invindex("./invindex.json"); // Merge the changes into the inverted index search::merge_into_invindex($invindex, ids::getid($env->page), $additions, $removals); // Save the inverted index back to disk search::save_invindex("invindex.json", $invindex); if(file_put_contents("$env->storage_prefix$env->page.md", $pagedata) !== false) { $page = $env->page; // 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 = "$env->page.md"; } $pageindex->$page->size = strlen($_POST["content"]); $pageindex->$page->lastmodified = time(); if($env->is_logged_in) $pageindex->$page->lasteditor = utf8_encode($env->user); else $pageindex->$page->lasteditor = utf8_encode("anonymous"); $pageindex->$page->tags = $page_tags; // A hack to resave the pagedata if the preprocessors have // changed it. We need this because the preprocessors *must* // run _after_ the pageindex has been updated. $pagedata_orig = $pagedata; // Execute all the preprocessors foreach($save_preprocessors as $func) { $func($pageindex->$page, $pagedata); } if($pagedata !== $pagedata_orig) file_put_contents("$env->storage_prefix$env->page.md", $pagedata); file_put_contents($paths->pageindex, json_encode($pageindex, JSON_PRETTY_PRINT)); if(isset($_GET["newpage"])) http_response_code(201); else http_response_code(200); // header("content-type: text/plain"); header("location: index.php?page=$env->page&edit_status=success&redirect=no"); 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 server's 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.
")); } }); add_help_section("15-editing", "Editing", "To edit a page on $settings->sitename, click the edit button on the top bar. Note that you will 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 no registration form. Note that the $settings->sitename's administrator may have changed these settings to allow anonymous edits.
Editing is simple. The edit page has a sizeable box that contains a page's current contents. Once you are done altering it, add or change the comma separated list of tags in the field below the editor and then click save page.
A reference to the syntax that $settings->sitename supports can be found below.
"); } ]); register_module([ "name" => "Export", "version" => "0.4", "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() { global $settings; /* * ███████ ██ ██ ██████ ██████ ██████ ████████ * ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ * █████ ███ ██████ ██ ██ ██████ ██ * ██ ██ ██ ██ ██ ██ ██ ██ ██ * ███████ ██ ██ ██ ██████ ██ ██ ██ */ add_action("export", function() { global $settings, $pageindex, $env; if($settings->export_allow_only_admins && !$env->is_admin) { 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("$env->storage_prefix$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); }); // Add a section to the help page add_help_section("50-export", "Exporting", "$settings->sitename supports exporting the entire wiki's content as a zip. Note that you may need to be a moderator in order to do this. Also note that you should check for permission before doing so, even if you are able to export without asking.
To perform an export, go to the credits page and click "Export as zip - Check for permission first".
"); } ]); register_module([ "name" => "Help page", "version" => "0.7", "author" => "Starbeamrainbowlabs", "description" => "Adds the help action. You really want this one.", "id" => "page-help", "code" => function() { global $settings; /* * ██ ██ ███████ ██ ██████ * ██ ██ ██ ██ ██ ██ * ███████ █████ ██ ██████ * ██ ██ ██ ██ ██ * ██ ██ ███████ ███████ ██ */ add_action("help", function() { global $settings, $version, $help_sections; // Sort the help sections by key ksort($help_sections, SORT_NATURAL); if(isset($_GET["dev"]) and $_GET["dev"] == "yes") { $title = "Developers Help - $settings->sitename"; $content = "$settings->sitename runs on Pepperminty Wiki, an entire wiki packed into a single file. This page contains some information that developers may find useful.
A full guide to developing a Pepperminty Wiki module can be found on GitHub.
The following help sections are currently registered:
Index | Title | Length |
---|---|---|
$index | " . $section["title"] . " | " . human_filesize(strlen($section["content"])) . " |
Welcome to $settings->sitename!
$settings->sitename is powered by Pepperminty Wiki, a complete wiki in a box you can drop into your server.
"; // todo Insert a table of contents here? foreach($help_sections as $index => $section) { // Todo add a button that you can click to get a permanent link // to this section. $content .= "All the navigation links can be found on the top bar, along with a search box (if your site administrator has enabled it). There is also a "More..." menu in the top right that contains some additional links that you may fine useful.
This page, along with the credits page, can be found on the bar at the bottom of every page.
"); add_help_section("999-extra", "Extra Information", "You can find out whch version of Pepperminty Wiki $settings->sitename is using by visiting the credits page.
Information for developers can be found on this page.
"); } ]); register_module([ "name" => "Page list", "version" => "0.9", "author" => "Starbeamrainbowlabs", "description" => "Adds a page that lists all the pages in the index along with their metadata.", "id" => "page-list", "code" => function() { global $settings; /* * ██ ██ ███████ ████████ * ██ ██ ██ ██ * ██ ██ ███████ ██ * ██ ██ ██ ██ * ███████ ██ ███████ ██ */ add_action("list", function() { global $pageindex, $settings; $title = "All Pages"; $content = "(All tags)
\n"; exit(page_renderer::render("$tag - Page List - $settings->sitename", $content)); }); add_help_section("30-all-pages-tags", "Listing pages and tags", "All the pages and tags on $settings->sitename are listed on a pair of paegs to aid navigation. The list of all pages on $settings->sitename can be found by clicking "All Pages" on the top bar. The list of all the tags currently in use can be found by clicking "All Tags" in the "More..." menu in the top right.
Each tag on either page can be clicked, and leads to a list of all pages that possess that particular tag.
A page's last known editor is also shown next to each entry on a list of pages, along with the last known size (which should correct, unless it was changed outside of $settings->sitename) and the time since the last modification (hovering over this will show the exact time that the last modification was made in a tooltip).
"); } ]); function generate_page_list($pagelist) { global $pageindex; // ✎ ✎ 🕒 🕒 $result = "Login failed.
\n"; if(isset($_GET["required"])) $content .= "\t\t$settings->sitename requires that you login before continuing.
\n"; $content .= "\t\t\n"; exit(page_renderer::render_main($title, $content)); }); /* * _ _ _ _ * ___| |__ ___ ___| | _| | ___ __ _(_)_ __ * / __| '_ \ / _ \/ __| |/ / |/ _ \ / _` | | '_ \ * | (__| | | | __/ (__| <| | (_) | (_| | | | | | * \___|_| |_|\___|\___|_|\_\_|\___/ \__, |_|_| |_| * %checklogin% |___/ */ add_action("checklogin", function() { global $settings, $env; //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_password($pass)) { $env->is_logged_in = true; $expiretime = time() + 60*60*24*30; //30 days from now $_SESSION["$settings->sessionprefix-user"] = $user; $_SESSION["$settings->sessionprefix-pass"] = hash_password($pass); $_SESSION["$settings->sessionprefix-expiretime"] = $expiretime; //redirect to wherever the user was going http_response_code(302); if(isset($_GET["returnto"])) header("location: " . $_GET["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 a section on logging in on the help page. add_help_section("30-login", "Logging in", "In order to edit $settings->sitename and have your edit attributed to you, you need to be logged in. Depending on the settings, logging in may be a required step if you want to edit at all. Thankfully, loggging in is not hard. Simply click the "Login" link in the top left, type your username and password, and then click login.
If you do not have an account yet and would like one, try contacting " . $settings->admindetails["name"] . ", $settings->sitename's administrator and ask them nicely to see if they can create you an account.
"); } ]); /* * @summary Hashes the given password according to the current settings defined * in $settings. * * @param $pass {string} The password to hash. * * @returns {string} The hashed password. Uses sha3 if $settings->use_sha3 is * enabled, or sha256 otherwise. */ function hash_password($pass) { global $settings; if($settings->use_sha3) { return sha3($pass, 256); } else { return hash("sha256", $pass); } } register_module([ "name" => "Logout", "version" => "0.6", "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 $env; $env->is_logged_in = false; unset($env->user); unset($env->pass); //clear the session variables $_SESSION = []; session_destroy(); exit(page_renderer::render_main("Logout Successful", "Logout Successful. You can login again here.
")); }); } ]); register_module([ "name" => "Page mover", "version" => "0.8", "author" => "Starbeamrainbowlabs", "description" => "Adds an action to allow administrators to move pages.", "id" => "page-move", "code" => function() { global $settings; /* * ███ ███ ██████ ██ ██ ███████ * ████ ████ ██ ██ ██ ██ ██ * ██ ████ ██ ██ ██ ██ ██ █████ * ██ ██ ██ ██ ██ ██ ██ ██ * ██ ██ ██████ ████ ███████ */ add_action("move", function() { global $pageindex, $settings, $env, $paths; if(!$settings->editing) { exit(page_renderer::render_main("Moving $env->page - error", "You tried to move $env->page, but editing is disabled on this wiki.
If you wish to move this page, please re-enable editing on this wiki first.
Nothing has been changed.
")); } if(!$env->is_admin) { exit(page_renderer::render_main("Moving $env->page - Error", "You tried to move $env->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 $env->page", "You tried to move $env->page to $new_name, but the page with the name $env->page does not exist in the first place.
Nothing has been changed.
")); if($env->page == $new_name) exit(page_renderer::render_main("Moving $env->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); $pageindex->$new_name->filename = $new_name; // If this page has an associated file, then we should move that too if(!empty($pageindex->$new_name->uploadedfile)) { // Update the filepath to point to the description and not the image $pageindex->$new_name->filename = $pageindex->$new_name->filename . ".md"; // Move the file in the pageindex $pageindex->$new_name->uploadedfilepath = $new_name; // Move the file on disk rename($env->storage_prefix . $env->page, $env->storage_prefix . $new_name); } file_put_contents($paths->pageindex, json_encode($pageindex, JSON_PRETTY_PRINT)); // Move the page on the disk rename("$env->storage_prefix$env->page.md", "$env->storage_prefix$new_name.md"); // Move the page in the id index ids::movepagename($page, $new_name); // Exit with a nice message exit(page_renderer::render_main("Moving $env->page", "$env->page has been moved to $new_name successfully.
")); }); // Register a help section add_help_section("60-move", "Moving Pages", "If you are logged in as an adminitrator, then you have the power to move pages. To do this, click "Delete" in the "More..." menu when browsing the pge you wish to move. Type in the new name of the page, and then click "Move Page".
"); } ]); register_module([ "name" => "Update", "version" => "0.6.1", "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, $env; if(!$env->is_admin) { 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
.
" . __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", "$env->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.
")); } } // Perform a redirect if the requested page is a redirect page if(isset($pageindex->$page->redirect) && $pageindex->$page->redirect === true) { $send_redirect = true; if(isset($_GET["redirect"]) && $_GET["redirect"] == "no") $send_redirect = false; if($send_redirect) { // Todo send an explanatory page along with the redirect http_response_code(307); header("location: ?action=$env->action&page=" . $pageindex->$page->redirect_target . "&redirected_from=$env->page"); exit(); } } $title = "$env->page - $settings->sitename"; if(isset($pageindex->$page->protect) && $pageindex->$page->protect === true) $title = $settings->protectedpagechar . $title; $content = "Redirected from " . $_GET["redirected_from"] . ".
"; $parsing_start = microtime(true); $content .= parse_page_source(file_get_contents("$env->storage_prefix$env->page.md")); if(!empty($pageindex->$page->tags)) { $content .= " \n"; } /*else { $content .= "\n"; }*/ if($settings->show_subpages) { $subpages = get_object_vars(get_subpages($pageindex, $env->page)); if(count($subpages) > 0) { $content .= "$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 This | To get this |
---|---|
_italics_ | italics |
*bold* | bold |
~~Strikethrough~~ | |
`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 | Blockquote |
- Apples |
|
1. This is |
|
---
| |
![Alt text](//starbeamrainbowlabs.com/favicon-small.png) |
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)
");
}
]);
/***********************************************************************
* ███████ ██ ██ ███ ███ ██████ ██████ ██ ██ ███ ██ *
* ██ ██ ██ ████ ████ ██ ██ ██ ██ ██ ██ ████ ██ *
* ███████ ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ █ ██ ██ ██ ██ *
* ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ███ ██ ██ ██ ██ *
* ███████ ███████ ██ ██ ██ ██████ ██████ ███ ███ ██ ████ *
***********************************************************************/
/**
* 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 \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/' => "\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
", trim($item)); } private static function ol_list ($regs) { $item = $regs[1]; return sprintf ("\n- %s
\n\n\t
", trim($item)); } private static function blockquote ($regs) { $item = $regs[2]; return sprintf ("\n- %s
\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 = $env->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?
")); } ?>