diff --git a/.gitignore b/.gitignore
index c46d453..03d07bf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,6 +19,8 @@ idindex.json
invindex.json
# The recent changes list
recent-changes.json
+# The new settings file
+peppermint.json
# The automatically downloaded parsedown files
Parsedown.php
diff --git a/Changelog.md b/Changelog.md
index 294dc21..31c5384 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -1,19 +1,30 @@
# Changelog
-## v0.12-dev
+## v0.12-beta2
+
+### Changed
+ - Changed revision display text ("Revision created by..." -> "Revision saved by...")
+
+## v0.12-beta1
+
+### Added
+ - Page history! Currently you can't do anything with the previous revisions - that will come in a future release.
- Implemented delayed indexing (#66)
- Added the time a page was last modified to the footer (#67)
- Added unified diff to edit conflict resolution pages (#64)
- Added image captions (#65)
- Added short syntax for images (#24)
+
+### Changed
- Added text "Tag List: " to tag listing pages
- - Page history! Currently you can't do anything with the previous revisions - that will come in a future release.
- Added checkerboard pattern behind transparent images on mouse hover on their preview pages.
- Improved support for SVGS.
- SVGs are sent as-is instead of a preview image unless `$settings->render_svg_previews` is set to `true`.
- Added code to find the dimensions of an SVG.
- - Fixed an issue where you wouldn't be redirected correctly if you typed your password incorrectly
- Reduced the amount of space that the login bit in the top left takes up.
+
+### Fixed
- Fixed a bug in the idindex generator.
+ - Fixed an issue where you wouldn't be redirected correctly if you typed your password incorrectly
## v0.11
diff --git a/build/index.php b/build/index.php
index bf5d21b..da6b40e 100644
--- a/build/index.php
+++ b/build/index.php
@@ -1,305 +1,305 @@
- * Rendering: MathJax (https://www.mathjax.org/)
- * Bug reports:
- * #2 - Incorrect closing tag - nibreh
\nBy submitting your edit or uploading your file, you are agreeing to release your changes under this license. Also note that if you don't want your work to be edited by other users of this site, please don't submit it here!"},
- "admindisplaychar": {"type": "text", "description": "The string that is prepended before an admin's name on the nav bar. Defaults to a diamond shape (◆).", "default": "◆"},
- "protectedpagechar": {"type": "text", "description": "The string that is prepended a page's name in the page title if it is protected. Defaults to a lock symbol. (🔒)", "default": "🔒"},
- "editing": {"type": "checkbox", "description": "Whether editing is enabled.", "default": true},
- "anonedits": {"type": "checkbox", "description": "Whether users who aren't logged in are allowed to edit your wiki.", "default": false},
- "maxpagesize": {"type": "number", "description": "The maximum page size in characters.", "default": 135000},
- "parser": {"type": "text", "description": "The parser to use when rendering pages. Defaults to an extended version of parsedown (http://parsedown.org/)", "default": "parsedown"},
- "clean_raw_html": {"type": "checkbox", "description": "Whether page sources should be cleaned of HTML before rendering. It is STRONGLY recommended that you keep this option turned on.", "default": true},
- "enable_math_rendering": {"type": "checkbox", "description": "Whether to enable client side rendering of mathematical expressions with MathJax (https://www.mathjax.org/). Math expressions should be enclosed inside of dollar signs ($). Turn off if you don't use it.", "default": true},
- "users": {"type": "map", "description": "An array of usernames and passwords - passwords should be hashed with sha256 (or sha3 if you have that option turned on)", "default": {
- "admin": "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8",
- "user": "873ac9ffea4dd04fa719e8920cd6938f0c23cd678af330939cff53c3d2855f34"
- }},
- "admins": {"type": "array", "description": "An array of usernames that are administrators. Administrators can delete and move pages.", "default": [ "admin" ]},
- "use_sha3": {"type": "checkbox", "description": "Whether to use the new sha3 hashing algorithm for passwords etc.", "default": false},
- "require_login_view": {"type": "checkbox", "description": "Whether to require that users login before they do anything else. Best used with the data_storage_dir option.", "default": false},
- "data_storage_dir": {"type": "text", "description": "The directory in which to store all files, except the main index.php.", "default": "."},
- "delayed_indexing_time": {"type": "number", "description": "The amount of time, in seconds, that pages should be blocked from being indexed by search engines after their last edit. Aka delayed indexing.", "default": 0},
- "nav_links": {"type": "array", "description": "
An array of links and display text to display at the top of the site.
Format: \"Display Text\": \"Link\"
You can also use strings here and they will be printed as-is, except the following special strings:
user-status
- Expands to the user's login information. e.g. \"Logged in as {name}. | Logout\", or e.g. \"Browsing as Anonymous. | Login\".search
- Expands to a search box.divider
- Expands to a divider to separate stuff.more
- Expands to the \"More...\" submenu.An array of links and display text to display at the top of the site.
Format: \"Display Text\": \"Link\"
You can also use strings here and they will be printed as-is, except the following special strings:
user-status
- Expands to the user's login information. e.g. \"Logged in as {name}. | Logout\", or e.g. \"Browsing as Anonymous. | Login\".search
- Expands to a search box.divider
- Expands to a divider to separate stuff.more
- Expands to the \"More...\" submenu.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" => "Page protection", - "version" => "0.2", - "author" => "Starbeamrainbowlabs", - "description" => "Exposes Pepperminty Wiki's new page protection mechanism and makes the protect button in the 'More...' menu on the top bar work.", - "id" => "action-protect", - "code" => function() { - /** - * @api {get} ?action=protect&page={pageName} Toggle the protection of a page. - * @apiName Protect - * @apiGroup Page - * @apiPermission Moderator - * - * @apiParam {string} page The page name to toggle the protection of. - */ - - /* - * ██████ ██████ ██████ ████████ ███████ ██████ ████████ - * ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ - * ██████ ██████ ██ ██ ██ █████ ██ ██ - * ██ ██ ██ ██ ██ ██ ██ ██ ██ - * ██ ██ ██ ██████ ██ ███████ ██████ ██ - */ - add_action("protect", function() { - global $env, $pageindex, $paths, $settings; - - // Make sure that the user is logged in as an admin / mod. - if($env->is_admin) - { - // They check out ok, toggle the page's protection. - $page = $env->page; - - if(!isset($pageindex->$page->protect)) - { - $pageindex->$page->protect = true; - } - else if($pageindex->$page->protect === true) - { - $pageindex->$page->protect = false; - } - else if($pageindex->$page->protect === false) - { - $pageindex->$page->protect = true; - } - - // Save the pageindex - file_put_contents($paths->pageindex, json_encode($pageindex, JSON_PRETTY_PRINT)); - - $state = ($pageindex->$page->protect ? "enabled" : "disabled"); - $title = "Page protection $state."; - exit(page_renderer::render_main($title, "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.6", - "author" => "Starbeamrainbowlabs", - "description" => "Adds a 'raw' action that shows you the raw source of a page.", - "id" => "action-raw", - "code" => function() { - global $settings; - /** - * @api {get} ?action=raw&page={pageName} Get the raw source code of a page - * @apiName RawSource - * @apiGroup Page - * @apiPermission Anonymous - * - * @apiParam {string} page The page to return the source of. - */ - - /* - * ██████ █████ ██ ██ - * ██ ██ ██ ██ ██ ██ - * ██████ ███████ ██ █ ██ - * ██ ██ ██ ██ ██ ███ ██ - * ██ ██ ██ ██ ███ ███ - */ - add_action("raw", function() { - global $env; - - 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.
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.
None yet! Try making a few changes and then check back here.
\n"; + } + + echo(page_renderer::render("Recent Changes - $settings->sitename", $content)); + }); + + register_save_preprocessor(function(&$pageinfo, &$newsource, &$oldsource) { + global $env, $settings, $paths; + + // Work out the old and new page lengths + $oldsize = strlen($oldsource); + $newsize = strlen($newsource); + // Calculate the page length difference + $size_diff = $newsize - $oldsize; + + $newchange = [ + "type" => "edit", + "timestamp" => time(), + "page" => $env->page, + "user" => $env->user, + "newsize" => $newsize, + "sizediff" => $size_diff + ]; + if($oldsize == 0) + $newchange["newpage"] = true; + + add_recent_change($newchange); + }); + + add_help_section("800-raw-page-content", "Recent Changes", "The recent changes page displays a list of all the most recent changes that have happened around $settings->sitename, arranged in chronological order. It can be found in the \"More...\" menu in the top right by default.
+Each entry displays the name of the page in question, who edited it, how long ago they did so, and the number of characters added or removed. Pages that currently redirect to another page are shown in italics, and hovering over the time since the edit wil show the exact time that the edit was made.
"); + } +]); + +/** + * Adds a new recent change to the recent changes file. + * @param array $rchange The new change to add. + */ +function add_recent_change($rchange) +{ + global $settings, $paths; + + $recentchanges = json_decode(file_get_contents($paths->recentchanges), true); + array_unshift($recentchanges, $rchange); + + // Limit the number of entries in the recent changes file if we've + // been asked to. + if(isset($settings->max_recent_changes)) + $recentchanges = array_slice($recentchanges, -$settings->max_recent_changes); + + // Save the recent changes file back to disk + file_put_contents($paths->recentchanges, json_encode($recentchanges, JSON_PRETTY_PRINT)); +} + +function render_recent_changes($recent_changes) +{ + global $pageindex; + + // Cache the number of recent changes we are dealing with + $rchange_count = count($recent_changes); + + // Group changes made on the same page and the same day together + for($i = 0; $i < $rchange_count; $i++) + { + for($s = $i + 1; $s < $rchange_count; $s++) + { + // Break out if we have reached the end of the day we are scanning + if(date("dmY", $recent_changes[$i]->timestamp) !== date("dmY", $recent_changes[$s]->timestamp)) + break; + + // If we have found a change that has been made on the same page as + // the one that we are scanning for, move it up next to the change + // we are scanning for. + if($recent_changes[$i]->page == $recent_changes[$s]->page) + { + // FUTURE: We may need to remove and insert instead of swapping changes around if this causes some changes to appear out of order. + $temp = $recent_changes[$i + 1]; + $recent_changes[$i + 1] = $recent_changes[$s]; + $recent_changes[$s] = $temp; + $i++; + } + } + } + + $content = "None yet! Try making a few changes and then check back here.
\n"; - } - - echo(page_renderer::render("Recent Changes - $settings->sitename", $content)); - }); - - register_save_preprocessor(function(&$pageinfo, &$newsource, &$oldsource) { - global $env, $settings, $paths; - - // Work out the old and new page lengths - $oldsize = strlen($oldsource); - $newsize = strlen($newsource); - // Calculate the page length difference - $size_diff = $newsize - $oldsize; - - $newchange = [ - "type" => "edit", - "timestamp" => time(), - "page" => $env->page, - "user" => $env->user, - "newsize" => $newsize, - "sizediff" => $size_diff - ]; - if($oldsize == 0) - $newchange["newpage"] = true; - - add_recent_change($newchange); - }); - - add_help_section("800-raw-page-content", "Recent Changes", "The recent changes page displays a list of all the most recent changes that have happened around $settings->sitename, arranged in chronological order. It can be found in the \"More...\" menu in the top right by default.
-Each entry displays the name of the page in question, who edited it, how long ago they did so, and the number of characters added or removed. Pages that currently redirect to another page are shown in italics, and hovering over the time since the edit wil show the exact time that the edit was made.
"); - } -]); - -/** - * Adds a new recent change to the recent changes file. - * @param array $rchange The new change to add. - */ -function add_recent_change($rchange) -{ - global $settings, $paths; - - $recentchanges = json_decode(file_get_contents($paths->recentchanges), true); - array_unshift($recentchanges, $rchange); - - // Limit the number of entries in the recent changes file if we've - // been asked to. - if(isset($settings->max_recent_changes)) - $recentchanges = array_slice($recentchanges, -$settings->max_recent_changes); - - // Save the recent changes file back to disk - file_put_contents($paths->recentchanges, json_encode($recentchanges, JSON_PRETTY_PRINT)); -} - -function render_recent_changes($recent_changes) -{ - global $pageindex; - - // Cache the number of recent changes we are dealing with - $rchange_count = count($recent_changes); - - // Group changes made on the same page and the same day together - for($i = 0; $i < $rchange_count; $i++) - { - for($s = $i + 1; $s < $rchange_count; $s++) - { - // Break out if we have reached the end of the day we are scanning - if(date("dmY", $recent_changes[$i]->timestamp) !== date("dmY", $recent_changes[$s]->timestamp)) - break; - - // If we have found a change that has been made on the same page as - // the one that we are scanning for, move it up next to the change - // we are scanning for. - if($recent_changes[$i]->page == $recent_changes[$s]->page) - { - // FUTURE: We may need to remove and insert instead of swapping changes around if this causes some changes to appear out of order. - $temp = $recent_changes[$i + 1]; - $recent_changes[$i + 1] = $recent_changes[$s]; - $recent_changes[$s] = $temp; - $i++; - } - } - } - - $content = "$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 "; - if((!$settings->anonedits && !$env->is_logged_in) || !$settings->editing) - { - $content .= "do not have permission to create it."; - if(!$env->is_logged_in) - { - $content .= " You could try logging in."; - } - } - else - { - $content .= "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 name, 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); - - if(!in_array($mime_type, $settings->upload_allowed_file_types)) - { - http_response_code(415); - exit(page_renderer::render("Unknown file type - Upload error - $settings->sitename", "
$settings->sitename recieved the file you tried to upload successfully, but detected that the type of file you uploaded is not in the allowed file types list. The file has been discarded.
-The file you tried to upload appeared to be of type $mime_type
, but $settings->sitename currently only allows the uploading of the following file types: " . implode("
, ", $settings->upload_allowed_file_types) . "
.
Go back to the Main Page.
")); - } - - // Perform appropriate checks based on the *real* filetype - switch(substr($mime_type, 0, strpos($mime_type, "/"))) - { - case "image": - $extra_data = []; - // Check SVG uploads with a special function - $imagesize = $mime_type !== "image/svg+xml" ? getimagesize($temp_filename, $extra_data) : upload_check_svg($temp_filename); - - // 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", "Although the file that you uploaded appears to be an image, $settings->sitename has been unable to determine it's dimensions. The uploaded file has been discarded. Go back to try again.
-You may wish to consider opening an issue against Pepperminty Wiki (the software that powers $settings->sitename) if this isn't the first time that you have seen this message.
")); - } - break; - } - - $file_extension = system_mime_type_extension($mime_type); - - // Override the detected file extension if a file extension - // is explicitly specified in the settings - if(isset($settings->mime_mappings_overrides[$mime_type])) - $file_extension = $settings->mime_mappings_overrides[$mime_type]; - - if(in_array($file_extension, [ "php", ".htaccess", "asp" ])) - { - http_response_code(415); - exit(page_renderer::render("Upload Error - $settings->sitename", "The file you uploaded appears to be dangerous and has been discarded. Please contact $settings->sitename's administrator for assistance.
-Additional information: The file uploaded appeared to be of type $mime_type
, which mapped onto the extension $file_extension
. This file extension has the potential to be executed accidentally by the web server.
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 either is a configuration error, or $settings->sitename has been attacked. Please contact " . $settings->admindetails_name . ", 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; - - // Generate a revision to keep the page history up to date - if(module_exists("feature-history")) - { - $oldsource = ""; // Only variables can be passed by reference, not literals - history_add_revision($entry, $description, $oldsource, false); - } - - // Save the pageindex - file_put_contents($paths->pageindex, json_encode($pageindex, JSON_PRETTY_PRINT)); - - if(module_exists("feature-recent-changes")) - { - add_recent_change([ - "type" => "upload", - "timestamp" => time(), - "page" => $new_filename, - "user" => $env->user, - "filesize" => filesize($entry->uploadedfilepath) - ]); - } - - header("location: ?action=view&page=$new_filename&upload=success"); - - break; - } - }); - - /** - * @api {get} ?action=preview&page={pageName}[&size={someSize}] Get a preview of a file - * @apiName PreviewFile - * @apiGroup Upload - * @apiPermission Anonymous - * - * @apiParam {string} page The name of the file to preview. - * @apiParam {number} size Optional. The size fo the resulting preview. Will be clamped to fit within the bounds specified in the wiki's settings. May also be set to the keyword 'original', which will cause the original file to be returned with it's appropriate mime type instead. - * - * @apiError PreviewNoFileError No file was found associated with the specified page. - * @apiError PreviewUnknownFileTypeError Pepperminty Wiki was unable to generate a preview for the requested file's type. - */ - - /* - * ██████ ██████ ███████ ██ ██ ██ ███████ ██ ██ - * ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ - * ██████ ██████ █████ ██ ██ ██ █████ ██ █ ██ - * ██ ██ ██ ██ ██ ██ ██ ██ ██ ███ ██ - * ██ ██ ██ ███████ ████ ██ ███████ ███ ███ - */ - add_action("preview", function() { - global $settings, $env, $pageindex, $start_time; - - if(empty($pageindex->{$env->page}->uploadedfilepath)) - { - $im = errorimage("The page '$env->page' doesn't have an associated file."); - header("content-type: image/png"); - imagepng($im); - exit(); - } - - $filepath = $env->storage_prefix . $pageindex->{$env->page}->uploadedfilepath; - $mime_type = $pageindex->{$env->page}->uploadedfilemime; - - // If the size is set or original, then send (or redirect to) the original image - // Also do the same for SVGs if svg rendering is disabled. - if(isset($_GET["size"]) and $_GET["size"] == "original" or - (empty($settings->render_svg_previews) && $mime_type == "image/svg+xml")) - { - // 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"]; - - /// ETag handling /// - // Generate the etag and send it to the client - $preview_etag = sha1("$output_mime|$target_size|$filepath|$mime_type"); - $allheaders = getallheaders(); - $allheaders = array_change_key_case($allheaders, CASE_LOWER); - if(!isset($allheaders["if-none-match"])) - { - header("etag: $preview_etag"); - } - else - { - if($allheaders["if-none-match"] === $preview_etag) - { - http_response_code(304); - header("x-generation-time: " . (microtime(true) - $start_time)); - exit(); - } - } - /// ETag handling end /// - - /* Disabled until we work out what to do about caching previews * - $previewFilename = "$filepath.preview.$outputFormat"; - if($target_size === $settings->default_preview_size) - { - // The request is for the default preview size - // Check to see if we have a preview pre-rendered - - } - */ - - $preview = new Imagick(); - switch(substr($mime_type, 0, strpos($mime_type, "/"))) - { - case "image": - $preview->readImage($filepath); - break; - - case "application": - if($mime_type == "application/pdf") - { - $preview = new imagick(); - $preview->readImage("{$filepath}[0]"); - $preview->setResolution(300,300); - $preview->setImageColorspace(255); - break; - } - - case "video": - case "audio": - if($settings->data_storage_dir == ".") - { - // The data storage directory is the current directory - // Redirect to the file isntead - http_response_code(307); - header("location: " . $pageindex->{$env->page}->uploadedfilepath); - exit(); - } - // TODO: Add support for ranges here. - // 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(); - break; - - default: - http_response_code(501); - $preview = errorimage("Unrecognised file type '$mime_type'.", $target_size); - header("content-type: image/png"); - imagepng($preview); - exit(); - } - - // Scale the image down to the target size - $preview->resizeImage($target_size, $target_size, imagick::FILTER_LANCZOS, 1, true); - - // Send the completed preview image to the user - header("content-type: $output_mime"); - header("x-generation-time: " . (microtime(true) - $start_time) . "s"); - $outputFormat = substr($output_mime, strpos($output_mime, "/") + 1); - $preview->setImageFormat($outputFormat); - echo($preview->getImageBlob()); - /* Disabled while we work out what to do about caching previews * - // Save a preview file if there isn't one alreaddy - if(!file_exists($previewFilename)) - file_put_contents($previewFilename, $preview->getImageBlob()); - */ - }); - - /* - * ██████ ██████ ███████ ██ ██ ██ ███████ ██ ██ - * ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ - * ██████ ██████ █████ ██ ██ ██ █████ ██ █ ██ - * ██ ██ ██ ██ ██ ██ ██ ██ ██ ███ ██ - * ██ ██ ██ ███████ ████ ██ ███████ ███ ███ - * - * ██████ ██ ███████ ██████ ██ █████ ██ ██ ███████ ██████ - * ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ - * ██ ██ ██ ███████ ██████ ██ ███████ ████ █████ ██████ - * ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ - * ██████ ██ ███████ ██ ███████ ██ ██ ██ ███████ ██ ██ - */ - page_renderer::register_part_preprocessor(function(&$parts) { - global $pageindex, $env, $settings; - // Don't do anything if the action isn't view - if($env->action !== "view") - return; - - 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 = $mime_type !== "image/svg+xml" ? getimagesize($env->storage_prefix . $filepath) : getsvgsize($env->storage_prefix . $filepath); - $fileTypeDisplay = substr($mime_type, 0, strpos($mime_type, "/")); - $previewUrl = "?action=preview&size=$settings->default_preview_size&page=" . rawurlencode($env->page); - - $preview_html = ""; - switch($fileTypeDisplay) - { - case "application": - case "image": - if($mime_type == "application/pdf") - $fileTypeDisplay = "file"; - - $preview_sizes = [ 256, 512, 768, 1024, 1440 ]; - $preview_html .= "\t\t\t"; - break; - - case "video": - $preview_html .= "\t\t\t"; - break; - - case "audio": - $preview_html .= "\t\t\t"; - } - - $fileInfo = []; - $fileInfo["Name"] = str_replace("File/", "", $filepath); - $fileInfo["Type"] = $mime_type; - $fileInfo["Size"] = human_filesize(filesize($filepath)); - switch($fileTypeDisplay) - { - case "image": - $dimensionsKey = $mime_type !== "image/svg+xml" ? "Original demensions" : "Native size"; - $fileInfo[$dimensionsKey] = "$dimensions[0] x $dimensions[1]"; - break; - } - $fileInfo["Uploaded by"] = $pageindex->{$env->page}->lasteditor; - - $preview_html .= "\t\t\t$displayName | $displayValue |
---|
$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 upload_check_svg($temp_filename) -{ - global $settings; - // Check for script tags - if(strpos(file_get_contents($temp_filename), "