diff --git a/README.md b/README.md new file mode 100644 index 0000000..37d3756 --- /dev/null +++ b/README.md @@ -0,0 +1,60 @@ +# W2 wiki + +W2 wiki is a web-based, wiki-like notepad that you can host yourself. + + +## Notable features: + +- Elegant text markup: + - Uses [Markdown Syntax](https://github.com/codeling/w2wiki/blob/master/pages/MarkdownSyntax.md). + - It supports double-brackets [[like this]] to link to another page in the wiki by title + - It supports double-braces {{like this}} to link to an uploaded image +- Minimalistic but functional interface: + - Fits to screen nicely when viewed on iPhone, with custom icon for adding to home screen + - HTML5 compliant output +- Title & content search +- Filesystem storage (no database required) in plain Markdown text files. +- Rudimentary git integration to commit & push each page edit +- Localization support (currently en/ja translations available) +- Image uploading support +- Optionally password-protected +- Unlike cloud / hosted solutions, you retain control of your data +- Written in PHP for portability and hackability +- Extremely compact (only a few .php files and a .css file) + + +## Installation & Configuration + +See [Installation instructions](https://github.com/codeling/w2wiki/blob/master/INSTALL.md). + + +## Security Notice + +In its current form, W2 wiki is not security-hardened; it's recommended to only run on an additionally secured server (e.g. in a small, private network for one user only; and secured behind a VPN and/or HTTPS with basic authentication). + + +## License + +W2 is licensed under the [MIT license](https://github.com/codeling/w2wiki/blob/master/LICENSE). + + +## Acknowledgements + +Originally written by [Steven Frank](https://github.com/panicsteve/w2wiki) and others, with modifications by +- [44uk](https://github.com/44uk/w2wiki) +- [knee-cola](https://github.com/knee-cola/w2wiki) +- [namvan](https://github.com/namvan/w2wiki) +- [nickodell](https://github.com/nickodell/w2wiki) +- [pilem](https://github.com/pilem/w2) + +W2 wiki uses [PHP Markdown](https://github.com/michelf/php-markdown) by Michel Fortin for rendering Markdown to HTML. + +The [Markdown syntax](https://github.com/codeling/w2wiki/blob/master/pages/MarkdownSyntax.md) description is taken from [daringfireball.net](https://daringfireball.net/projects/markdown/syntax). + +Maintainer of this fork is [codeling](https://github.com/codeling/w2wiki). + + +## Reporting Bugs + +Please report bugs in [the github issue tracker](https://github.com/codeling/w2wiki/issues) of this fork. + diff --git a/config.php b/config.php index 5c31aaa..6e2bf81 100644 --- a/config.php +++ b/config.php @@ -1,11 +1,10 @@ - * Code may be re-used as long as the above copyright notice is retained. - * See README.txt for full details. + * See README.md for full details. * * Written with Coda: * @@ -15,19 +14,24 @@ // Site layout settings // -------------------- -// BASE_PATH -// -// The base system path to W2. You only need to change this if we guess wrong. -// You should not use a trailing slash. - -define('BASE_PATH', getcwd()); - // PAGES_PATH // // The path to the raw text documents maintained by W2 // You should not use a trailing slash. -define('PAGES_PATH', BASE_PATH . '/pages'); +define('PAGES_PATH', dirname(__FILE__). '/pages'); + +// UPLOAD_FOLDER +// +// The subfolder in PAGES_PATH that uploads get stored to +define('UPLOAD_FOLDER', 'images'); + +// PAGES_EXT +// +// The extension of the Markdown files in the PAGES_PATH +// folder which are displayed by W2 +define('PAGES_EXT', 'md'); + // BASE_URI // @@ -62,6 +66,18 @@ define('DEFAULT_PAGE', 'Home'); define('CSS_FILE', 'index.css'); +// SIDEBAR_FILE +// +// The name of the page to be shown as sidebar (leave empty to disable sidebar feature) + +define ('SIDEBAR_PAGE', '_sidebar'); + +// PAGE_TITLE +// +// A title prepended to the title head tag of all pages of the wiki + +define ('PAGE_TITLE', 'Wiki: '); + // -------------------- // File upload settings // -------------------- @@ -77,14 +93,14 @@ define('DISABLE_UPLOADS', false); // Acceptable file types for file uploads. This is a good idea for security. // Value is a comma-separated string of MIME types. -define('VALID_UPLOAD_TYPES', 'image/jpeg,image/pjpeg,image/png,image/gif,application/pdf,application/zip,application/x-diskcopy'); +define('VALID_UPLOAD_TYPES', 'image/jpeg,image/pjpeg,image/png,image/gif,application/pdf'); // VALID_UPLOAD_EXTS // // Acceptable filename extensions for file uploads // Value is a comma-separated string of filename extensions (case-sensitive!) -define('VALID_UPLOAD_EXTS', 'jpg,jpeg,png,gif,pdf,zip,dmg'); +define('VALID_UPLOAD_EXTS', 'jpg,jpeg,png,gif,pdf'); // ------------------ // Interface settings @@ -95,6 +111,8 @@ define('VALID_UPLOAD_EXTS', 'jpg,jpeg,png,gif,pdf,zip,dmg'); // The format to use when displaying page modification times. // See the manual for the PHP 'date()' function for the specification: // http://php.net/manual/en/function.date.php +// Note that these settings are overridden by the +// date_format/date_format_no_time in the used locale! define('TITLE_DATE', 'j-M-Y g:i A'); define('TITLE_DATE_NO_TIME', 'j-M-Y'); @@ -113,13 +131,6 @@ define('EDIT_ROWS', 18); define('AUTOLINK_PAGE_TITLES', false); -// COLORIZE_MISSING_PAGES -// -// Automatically highlights as red links, any linked pages which are -// not yet written. Existing but blank pages are not colorized. This -// might degrade performance if you have thousands of links on a page. - -define('COLORIZE_MISSING_PAGES', true); // ----------------------------- // Security and session settings @@ -170,4 +181,36 @@ define('W2_SESSION_LIFETIME', 60 * 60 * 24 * 30); define('W2_SESSION_NAME', 'W2'); -?> + +// ----------------------------- +// Git Integration +// ----------------------------- + +// GIT_COMMIT_ENABLED +// +// Enable/Disable committing changes in page folder to local git repository + +define('GIT_COMMIT_ENABLED', false); + +// GIT_PUSH_ENABLED +// +// Enable/Disable pushing changes in page folder to a remote git repository + +define('GIT_PUSH_ENABLED', false); + + +// ----------------------------- +// Locale and encoding settings +// ----------------------------- + +// W2_CHARSET +// +// Value for meta charset. + +define('W2_CHARSET', 'UTF-8'); + +// W2_LOCALE +// +// Name for locale. + +define('W2_LOCALE', 'en'); diff --git a/icons/close.svg b/icons/close.svg new file mode 100644 index 0000000..4d8b37e --- /dev/null +++ b/icons/close.svg @@ -0,0 +1,12 @@ + + + + + + + diff --git a/icons/delete-dark.svg b/icons/delete-dark.svg new file mode 100644 index 0000000..9c33315 --- /dev/null +++ b/icons/delete-dark.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/icons/delete.svg b/icons/delete.svg new file mode 100644 index 0000000..9c33315 --- /dev/null +++ b/icons/delete.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/icons/edit-dark.svg b/icons/edit-dark.svg new file mode 100644 index 0000000..255b07d --- /dev/null +++ b/icons/edit-dark.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/icons/edit.svg b/icons/edit.svg new file mode 100644 index 0000000..611d77a --- /dev/null +++ b/icons/edit.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/icons/format-text-bold.svg b/icons/format-text-bold.svg new file mode 100644 index 0000000..1b2b8e4 --- /dev/null +++ b/icons/format-text-bold.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/icons/format-text-code.svg b/icons/format-text-code.svg new file mode 100644 index 0000000..ae5e15e --- /dev/null +++ b/icons/format-text-code.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/icons/format-text-italic.svg b/icons/format-text-italic.svg new file mode 100644 index 0000000..d051ff2 --- /dev/null +++ b/icons/format-text-italic.svg @@ -0,0 +1,13 @@ + + + + + + diff --git a/icons/home.svg b/icons/home.svg new file mode 100644 index 0000000..27d5580 --- /dev/null +++ b/icons/home.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/icons/internet.png b/icons/internet.png new file mode 100644 index 0000000..56991f2 Binary files /dev/null and b/icons/internet.png differ diff --git a/icons/link-dark.svg b/icons/link-dark.svg new file mode 100644 index 0000000..36db492 --- /dev/null +++ b/icons/link-dark.svg @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/icons/link.svg b/icons/link.svg new file mode 100644 index 0000000..9381210 --- /dev/null +++ b/icons/link.svg @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/icons/list.svg b/icons/list.svg new file mode 100644 index 0000000..02605c1 --- /dev/null +++ b/icons/list.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/icons/new.svg b/icons/new.svg new file mode 100644 index 0000000..2f81e2f --- /dev/null +++ b/icons/new.svg @@ -0,0 +1,13 @@ + + + + + + diff --git a/icons/rename-dark.svg b/icons/rename-dark.svg new file mode 100644 index 0000000..9d31cc1 --- /dev/null +++ b/icons/rename-dark.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + diff --git a/icons/rename.svg b/icons/rename.svg new file mode 100644 index 0000000..e8570f9 --- /dev/null +++ b/icons/rename.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + diff --git a/icons/upload.svg b/icons/upload.svg new file mode 100644 index 0000000..c6ec427 --- /dev/null +++ b/icons/upload.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/icons/w2-icon.png b/icons/w2-icon.png new file mode 100644 index 0000000..9df16f6 Binary files /dev/null and b/icons/w2-icon.png differ diff --git a/images/.gitignore b/images/.gitignore new file mode 100644 index 0000000..6f40c4d --- /dev/null +++ b/images/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything +* +# except this file +!.gitignore diff --git a/index.css b/index.css index 0024ed2..81e7093 100644 --- a/index.css +++ b/index.css @@ -8,32 +8,26 @@ * * Written with Coda: * + * colors icons: + * 240,240,240 + * dark: 15, 15, 15 */ -.main { - background-color: #000000; - color: #ffffff; -} - -body { - background-color: #000000; -} - * { font-family: Monospace; - font-size: 11px; margin: 0; padding: 0; + font-size: 11px; } -a { - color: #6666ff; +body { + background-color: #222222; } blockquote { background-color: #0f070f; - margin: 0px 0px 12px 20px; - padding-top: 4px 10px 4px 10px; + margin: 4px 4px 12px 20px; + padding: 4px 10px 4px 10px; } form { @@ -45,21 +39,26 @@ li { } h1 { - font-size: 20px; + font-size: 2em; font-weight: bold; - margin-bottom: 8px; + margin-bottom: 4px; + /*margin-top: .6em;*/ } h2 { - font-size: 16px; + font-size: 1.2em; font-weight: bold; - margin-bottom: 8px; + margin-bottom: 4px; + margin-top: .5em; } h3 { - font-size: 13px; + font-size: 1.2em; font-weight: bold; - margin-bottom: 8px; +} +h3, h4, h5, h6 { + margin-top: .4em; + margin-bottom: 4px; } hr { @@ -71,29 +70,32 @@ hr { margin-bottom: 12px; } -ul { - padding-left: 12px; - margin-left: 12px; - margin-bottom: 12px; - list-style-position: inside; +ul, +ol { + margin-top: .5em; + margin-left: 1em; + padding-left: 1em; + list-style-position: outside; } -ol { - margin-left: 12px; - margin-bottom: 12px; - padding-left: 12px; - list-style-position: inside; +ul li, ol li { + padding-left: .5em; +} + +li > ul, li > ol +{ + margin-top: 0; } p { - margin: 12px 12px 12px 12px; + margin-top: .5em; } pre { - font-family: Monospace, monospace; - font-size: 11px; - margin-left: 12px; - margin-bottom: 12px; + font-family: Monospace; + margin-left: 0; + margin-bottom: .5em; + margin-top: .5em; /* stroke each browser so that they wrap lines in the pre tag */ white-space: pre-wrap; /* css-3 */ @@ -101,84 +103,279 @@ pre { white-space: -pre-wrap; /* Opera 4-6 */ white-space: -o-pre-wrap; /* Opera 7 */ word-wrap: break-word; /* Internet Explorer 5.5+ */ + + background: #000000; + border: 1px dotted gray; + padding: .2em .2em .2em .4em; } code { - font-family: Monospace, monospace; - font-size: 11px; + font-family: Monospace; + background: #000000; + color: #bbbbbb; + padding: .1em .1em .1em .2em; } table { border-collapse: collapse; -} - -table, td { + padding: .2em; + max-width: 99%; background-color: #000000; - padding: 2px; + color: #dddddd; +} + th { + text-align: left; + } + td, th { + padding: .1em 1em .1em .1em; + word-break: break-all; + background: #000000; + } + thead { + border-bottom: 1px solid black; + font-weight: bold; + } + thead td a { + text-decoration:none; + } + thead td span.sortBy:after { + content: "\25BC"; + } + tr:nth-child(even) { + background: #e4e4e4; + } + tr:nth-child(odd) { + background: #eeeeee; + } +.pageActions { + padding-left: 8px; + padding-right: 8px; } textarea { - font-family: Monospace, Courier, monospace; - font-size: 11px; - width: 99%; + font-family: Monospace; + width: 75%; background-color: #000011; - color: #ffffff; + color: #ffffff; +} + @media (max-width: 600px), (orientation: portrait) { + textarea { + width: 99%; + } + } + +input[type="text"], +textarea { + padding: 2px; +} + +input { + font-family: Monospace; +} + +input#gitmsg +{ + width: 60%; } .main { - padding: 8px; + padding: .3em .3em .3em 1em; + background-color: #000000; + color: #ffffff; +} + +/* the globe */ +.main a[href^="http"]::after { + /*content: url('/icons/internet.png');*/ +} + +.main a.literalMatch { + font-weight: bold; + color: #00f; +} + +.main a.noexist { + color: #b00 !important; +} + +.login { + margin: 40px auto; + max-width: 650px; + line-height: 1.4; } .note { background-color: #000011; padding: 4px; - margin: 0 8px 8px 8px; + margin: .5em 0 .5em 0; color: #9999bb; border: solid 1px #9999bb; + width: 75%; } + @media (max-width: 600px), (orientation: portrait) { + .note { + width: 99%; + } + } .titlebar { background-color: #111111; color: #ffffff; +} + +.titlebar span.title { font-size: 10px; font-weight: bold; } .titledate { - font-size: 10px; + font-size: 0.90em; color: #777777; + margin-left: 1em; + margin-right: 1em; } .toolbar { - background-color: #222222; + background-color: #222222; position: sticky; top: 0; - font-size: 8px; + font-size: 2px; } -a.tool { - font-size: 11px; - margin-right: 8px; +.toolbar > a, .titlebar > a { + font-size: 0.90em; + margin-right: 1em; color: #eeeeee; + text-decoration: none; + font-weight: normal; } -a.missing-link { - color: #ed123e; +.toolbar > a:hover, .titlebar > a:hover { + text-decoration: underline; } -input { - background-color: #111111; - color: #ffffff; +.sidebar { + float: right; +} +.sidebar, .linkshere { + margin-right: 5px; + margin-top: 5px; + padding: 4px; + border: solid 1px #666644; +} +.sidebar ul { + margin-top: 0; + margin-left: 4px; +} +.linkshere { + width: 50%; + margin-left: 5px; +} + @media (max-width: 600px), (orientation: portrait) { + .sidebar, .linkshere { + margin-left: 5px; + float: none; + width: auto; + } + } +input.search { +/* font-size: 0.95em;*/ + color: #000000; + width: 5em; + padding: .1em; } -input.tool { - font-size: 11px; - background-color: #222222; - color: #ffffff; +input.search:focus { + width: 15em; +} + +input.pagename { + width: 20em; +} + +input[type="button"], +input[type="submit"] { + border:none; + border-radius: 3px; + padding: .5em 1em; + cursor: pointer; + margin-right: .5em; +} +#maxsizelabel { + margin-right: 1em; +} + +input[type="submit"] { + /*background-color: rgb(22, 101, 201);*/ + background-color: #222222; + color: white; +} +input[type="button"] { + background-color: rgb(220, 220, 220); +} + +input[type="submit"]:hover { + /*background-color: rgb(69, 135, 226);*/ + background-color: #222222; +} +input[type="button"]:hover { + background-color: rgb(200, 200, 200); } img { - max-width: 50%; - height: auto; + max-width: 50%; + height: auto; +} + +#drawer { + display: inline-block; + position: absolute; + width: 300px; + background-color: rgb(240, 240, 240); + opacity: 0.5; + border: 1px solid black; + border-radius: 5px; + padding: 0; + cursor: move; +} +#drawer h5 { + border-bottom: 1px solid black; + padding: 4px; +} +#drawer div { + padding: 4px; +} +#drawer:hover { + opacity: 1.0; +} +.inactive { + display: none !important; +} +img.icon { + width: 1.5em; + vertical-align: middle; +} +a > img.icon:hover, a > span.icongroup:hover { + outline: 1px outset white; +} +a > img.icon:active, a > span.icongroup:active { + outline: 1px inset white; +} +.rightaligned +{ + float: right; +} + +input.search { + border-color: #222222; + border-width: 0px; + background-color: #222222; + color: #ffffff; + width: 165px +} + +.sidebar { + color: #aaaaaa; + border-color: #aaaaaa; } diff --git a/index.css.2 b/index.css.2 new file mode 100644 index 0000000..c9de0d3 --- /dev/null +++ b/index.css.2 @@ -0,0 +1,362 @@ +/* + * W2 + * + * Copyright (C) 2007-2011 Steven Frank + * + * Code may be re-used as long as the above copyright notice is retained. + * See README.txt for full details. + * + * Written with Coda: + * + * colors icons: + * 240,240,240 + * dark: 15, 15, 15 + */ + +* { + font-family: Monospace; + margin: 0; + padding: 0; + font-size: 11px; +} + +body { + background-color: #eeeeee; +} + +blockquote { + background-color: #0f070f; + margin: 4px 4px 12px 20px; + padding: 4px 10px 4px 10px; +} + +form { + display: inline; +} + +li { + line-height: 1.5em; +} + +h1 { + font-size: 2em; + font-weight: bold; + margin-bottom: 4px; + margin-top: .6em; +} + +h2 { + font-size: 1.6em; + font-weight: bold; + margin-bottom: 4px; + margin-top: .5em; +} + +h3 { + font-size: 1.2em; + font-weight: bold; +} +h3, h4, h5, h6 { + margin-top: .4em; + margin-bottom: 4px; +} + +hr { + border-top: 1px solid #222222; + border-bottom: 0; + border-left: 0; + border-right: 0; + margin-top: 12px; + margin-bottom: 12px; +} + +ul, +ol { + margin-top: .5em; + margin-left: 1em; + padding-left: 1em; + list-style-position: outside; +} + +ul li, ol li { + padding-left: .5em; +} + +li > ul, li > ol +{ + margin-top: 0; +} + +p { + margin-top: .5em; +} + +pre { + font-family: Monospace; + margin-left: 0; + margin-bottom: .5em; + margin-top: .5em; + + /* stroke each browser so that they wrap lines in the pre tag */ + white-space: pre-wrap; /* css-3 */ + white-space: -moz-pre-wrap; /* Mozilla, since 1999 */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + word-wrap: break-word; /* Internet Explorer 5.5+ */ + + background: #ffc; + border: 1px dotted gray; + padding: .2em .2em .2em .4em; +} + +code { + font-family: Monospace; + background: #ffc; + padding: .1em .1em 0 .2em; +} + +table { + border-collapse: collapse; + padding: .2em; + max-width: 99%; + background-color: #000000; + color: #ffffff; +} + th { + text-align: left; + } + td, th { + padding: .1em 1em .1em .1em; + word-break: break-all; + } + thead { + border-bottom: 1px solid black; + font-weight: bold; + } + thead td a { + text-decoration:none; + } + thead td span.sortBy:after { + content: "\25BC"; + } + tr:nth-child(even) { + background: #e4e4e4; + } + tr:nth-child(odd) { + background: #eeeeee; + } +.pageActions { + padding-left: 8px; + padding-right: 8px; +} + +textarea { + font-family: Monospace; + width: 75%; + background-color: #000011; + color: #ffffff; +} + @media (max-width: 600px), (orientation: portrait) { + textarea { + width: 99%; + } + } + +input[type="text"], +textarea { + padding: 2px; +} + +input#gitmsg +{ + width: 60%; +} + +.main { + padding: .3em .3em .3em 1em; + background-color: #000000; + color: #ffffff; +} + +.main a[href^="http"]::after { + content: url('/icons/internet.png'); +} + +.main a.literalMatch { + font-weight: bold; + color: #00f; +} + +.main a.noexist { + color: #b00 !important; +} + +.login { + margin: 40px auto; + max-width: 650px; + line-height: 1.4; +} + +.note { + background-color: #000011; + padding: 4px; + margin: .5em 0 .5em 0; + color: #9999bb; + border: solid 1px #9999bb; + width: 75%; +} + @media (max-width: 600px), (orientation: portrait) { + .note { + width: 99%; + } + } + +.titlebar { + background-color: #111111; + color: #ffffff; +} + +.titlebar span.title { + font-size: 10px; + font-weight: bold; +} + +.titledate { + font-size: 0.90em; + color: #777777; + margin-left: 1em; + margin-right: 1em; +} + +.toolbar { + background-color: #222222; + position: sticky; + top: 0; + font-size: 8px; +} + +.toolbar > a, .titlebar > a { + font-size: 0.90em; + margin-right: 1em; + color: #eeeeee; + text-decoration: none; + font-weight: normal; +} + +.toolbar > a:hover, .titlebar > a:hover { + text-decoration: underline; +} + +.sidebar { + float: right; +} +.sidebar, .linkshere { + margin-right: 5px; + margin-top: 5px; + padding: 4px; + border: solid 1px #666644; +} +.sidebar ul { + margin-top: 0; + margin-left: 4px; +} +.linkshere { + width: 50%; + margin-left: 5px; +} + @media (max-width: 600px), (orientation: portrait) { + .sidebar, .linkshere { + margin-left: 5px; + float: none; + width: auto; + } + } + +input.search { +/* font-size: 0.95em;*/ + color: #000000; + width: 5em; + padding: .1em; +} + +input.search:focus { + width: 15em; +} + +input.pagename { + width: 20em; +} + +input[type="button"], +input[type="submit"] { + border:none; + border-radius: 3px; + padding: .5em 1em; + cursor: pointer; + margin-right: .5em; +} +#maxsizelabel { + margin-right: 1em; +} + +input[type="submit"] { + background-color: rgb(30, 101, 201); + color: white; +} +input[type="button"] { + background-color: rgb(220, 220, 220); +} + +input[type="submit"]:hover { + background-color: rgb(69, 135, 226); +} +input[type="button"]:hover { + background-color: rgb(200, 200, 200); +} + +img { + max-width: 100%; + height: auto; +} + +#drawer { + display: inline-block; + position: absolute; + width: 300px; + background-color: rgb(240, 240, 240); + opacity: 0.5; + border: 1px solid black; + border-radius: 5px; + padding: 0; + cursor: move; +} +#drawer h5 { + border-bottom: 1px solid black; + padding: 4px; +} +#drawer div { + padding: 4px; +} +#drawer:hover { + opacity: 1.0; +} +.inactive { + display: none !important; +} +img.icon { + width: 1.5em; + vertical-align: middle; +} +a > img.icon:hover, a > span.icongroup:hover { + outline: 1px outset white; +} +a > img.icon:active, a > span.icongroup:active { + outline: 1px inset white; +} +a.missing-link { + color: #ba0000; +} +.rightaligned +{ + float: right; +} diff --git a/index.php b/index.php index cc6e599..7596e5b 100644 --- a/index.php +++ b/index.php @@ -1,5 +1,5 @@ 0 ) { $ip = $_SERVER['REMOTE_ADDR']; @@ -48,12 +69,77 @@ if ( count($allowedIPs) > 0 ) if ( !$accepted ) { - print "Access from IP address $ip is not allowed"; - print ""; + print "Access from IP address $ip is not allowed"; exit; } } +function printHeader($title, $action, $bodyclass="") +{ + print "\n"; + print "\n"; + print " \n"; + print " \n"; + print " \n"; + print " \n"; + print " \n"; + print " ".PAGE_TITLE."$title\n"; + print " \n"; + print " \n"; +} + +function printFooter() +{ + print " \n"; + print ""; +} + +function printDrawer() +{ + print "
\n". + " \"".__('Close')."\"\n". + "
".__('Markdown Syntax Helper')."
\n". + "
\n". + "# ".__('Header')." 1
". + "## ".__('Header')." 2
". + "### ".__('Header')." 3
". + "#### ".__('Header')." 4
". + "##### ".__('Header')." 5
". + "###### ".__('Header')." 6
". + "
". + "*".__('Emphasize')."* - ".__('Emphasize')."
". + "_".__('Emphasize')."* - ".__('Emphasize')."
". + "**".__('Bold')."** - ".__('Bold')."
". + "__".__('Bold')."__ - ".__('Bold')."
". + "
". + "[[Link to page]]
". + "<http://example.com/>
". + "[link text](http://url)

". + "{{image.jpg}}
". + "![Alt text](/images/image.jpg)
". + "![Alt text](/images/image.jpg \"Optional title\")
". + "
". + "- Unordered list
". + "+ Unordered list
". + "* Unordered list
". + "1. Ordered list
". + "
". + "> Blockquote
".//
Blockquotes
\n". + "```Code```
". //
Code
\n\n". + "`inline-code`

". + "*** Horizontal rule
". + "--- Horizontal rule
\n". + "
\n". + "
\n". + " \n". + " \n". + " \"".__('Formatting\n". + " \"".__('Formatting\n". + " \"".__('Formatting\n". + " \n". + " \n"; +} + if ( REQUIRE_PASSWORD && !isset($_SESSION['password']) ) { if ( !defined('W2_PASSWORD_HASH') || W2_PASSWORD_HASH == '' ) @@ -63,493 +149,796 @@ if ( REQUIRE_PASSWORD && !isset($_SESSION['password']) ) $_SESSION['password'] = W2_PASSWORD_HASH; else { - print "\n"; - print "\n"; - print "\n"; - print ""; - print "\n"; - - print "\n"; - print "Log In\n"; - print "\n"; - print "
"; - print "\n"; - print "
"; - print ""; + printHeader( __('Log In'), '', "login"); + print "

" . __('Log In') . "

\n"; + print "
\n"; + print " ".__('Password') . ": \n"; + print " \n"; + print "
\n"; + printFooter(); exit; } } // Support functions -function _handle_links($match) -{ - $link = $match[1]; - if ( COLORIZE_MISSING_PAGES ) { - $link_page = sanitizeFilename($link); - $link_filename = PAGES_PATH . "/$link_page.txt"; - $link_page_exists = file_exists($link_filename); - } else { - $link_page_exists = true; - } - if ($link_page_exists) - return "" . htmlentities($link) . ""; - else - return "" . htmlentities($link) . ""; -} - - -function _handle_images($match) -{ - return "\"""; -} - - -function _handle_message($match) -{ - return "[email]"; -} - - -function printToolbar() -{ - global $upage, $page, $action; - - print "
"; - print "Edit "; - print "New "; - - if ( !DISABLE_UPLOADS ) - print "Upload "; - - print "All "; - print "Recent "; - print "". DEFAULT_PAGE . ""; - - if ( REQUIRE_PASSWORD ) - print 'Exit'; - - print "
\n"; - print "
\n"; - - print "
\n"; -} - - function descLengthSort($val_1, $val_2) { - $retVal = 0; - $firstVal = strlen($val_1); $secondVal = strlen($val_2); - - if ( $firstVal > $secondVal ) - $retVal = -1; - - else if ( $firstVal < $secondVal ) - $retVal = 1; - - return $retVal; + return ( $firstVal > $secondVal ) ? + -1 : ( ( $firstVal < $secondVal ) ? 1 : 0); } - -function toHTML($inText) +function getAllPageNames($path = "") { - global $page; - - $inText = preg_replace("/<[\/]*script>/", "", $inText); - - $dir = opendir(PAGES_PATH); + $filenames = array(); + $dir = opendir(PAGES_PATH . "/$path" ); while ( $filename = readdir($dir) ) { - if ( $filename[0] == '.' ) + if ( $filename[0] == "." ) + { continue; - - $filename = preg_replace("/(.*?)\.txt/", "\\1", $filename); - $filenames[] = $filename; + } + if ( is_dir( PAGES_PATH . "/$path/$filename" ) ) + { + array_push($filenames, ...getAllPageNames( "$path/$filename" ) ); + continue; + } + if ( preg_match("/".PAGES_EXT."$/", $filename) != 1) + { + continue; + } + $filename = substr($filename, 0, -(strlen(PAGES_EXT)+1) ); + $filenames[] = substr("$path/$filename", 1); } closedir($dir); + return $filenames; +} - uasort($filenames, "descLengthSort"); +function fileNameForPage($page) +{ + return PAGES_PATH . "/$page." . PAGES_EXT; +} - if ( AUTOLINK_PAGE_TITLES ) - { - foreach ( $filenames as $filename ) - { - $inText = preg_replace("/(?\[\/])($filename)(?!\]\>)/im", "\\1", $inText); - } - } - - $inText = preg_replace_callback("/\[\[(.*?)\]\]/", '_handle_links', $inText); - $inText = preg_replace_callback("/\{\{(.*?)\}\}/", '_handle_images', $inText); - $inText = preg_replace_callback("/message:(.*?)\s/", '_handle_message', $inText); - - $html = MarkdownExtra::defaultTransform($inText); - $inText = htmlentities($inText); - - return $html; +function imageLinkText($imgName) +{ + return "![".__("Image Description")."](/".UPLOAD_FOLDER."/$imgName)"; } function sanitizeFilename($inFileName) { - return str_replace(array('..', '~', '/', '\\', ':'), '-', $inFileName); + return str_replace(array('~', '..', '\\', ':', '|', '&'), '-', $inFileName); +} + +function pageURL($page) +{ + return SELF . VIEW . "/".str_replace("%2F", "/", str_replace("%23", "#", urlencode(sanitizeFilename($page)))); +} + +function pageLink($page, $title, $attributes="") +{ + return "$title"; + /* wip + $link_page = $match[1]; + $link_filename = PAGES_PATH . "/$link_page.txt"; + $link_page_exists = file_exists($link_filename); + if ($link_page_exists) + return "$title"; + else + //return "" . htmlentities($link_page) . ""; + return "$title"; + */ +} + +function redirectWithMessage($page, $msg) +{ + $_SESSION["msg"] = $msg; + header("HTTP/1.1 303 See Other"); + header("Location: " . pageURL($page) ); + exit; +} + +function checkedExecute(&$msg, $cmd) +{ + $returnValue = 0; + $output = ''; + exec($cmd, $output, $returnValue); + if ($returnValue != 0) + { + $msg .= "
Error executing command ".$cmd." (return value: ".$returnValue."): ".implode(" ", $output); + } + return ($returnValue == 0); +} + +function gitChangeHandler($commitmsg, &$msg) +{ + if (!GIT_COMMIT_ENABLED) + { + return; + } + if (checkedExecute($msg, "cd ".PAGES_PATH." && git add -A && git commit -m ".escapeshellarg($commitmsg))) + { + if (!GIT_PUSH_ENABLED) + { + return; + } + checkedExecute($msg, "cd ".PAGES_PATH." && git push"); + } +} + +function toHTMLID($noid) +{ // in HTML5, only spaces aren't allowed + return str_replace(" ", "-", $noid); +} + +function toHTML($inText) +{ + $parser = new MarkdownExtra; + $parser->no_markup = true; + $outHTML = $parser->transform($inText); + if ( AUTOLINK_PAGE_TITLES ) + { + $pagenames = getAllPageNames(); + uasort($pagenames, "descLengthSort"); + foreach ( $pagenames as $pageName ) + { + // match pageName, but only if it isn't inside another word or inside braces (as in "[$pageName]"). + $outHTML = preg_replace("/(? 1) ? $linkTitleSplit[1] : $linkedPage; + $pagePart = explode('#', $linkedPage)[0]; // split away an eventual anchor part + $linkedFilename = fileNameForPage(sanitizeFilename($pagePart)); + $exists = file_exists($linkedFilename); + $outHTML = str_replace("[[$fullLinkText]]", + pageLink($linkedPage, $linkText, ($exists? "" : " class=\"noexist\"")), $outHTML); + } + $outHTML = preg_replace("/\{\{(.*?)\}\}/", "\"\\1\"", $outHTML); + + // add an anchor in all title tags (h1/2/3/4): + preg_match_all( + "/(.*?)<\/h\\1>/", + $outHTML, + $matches, + PREG_PATTERN_ORDER + ); + for ($i = 0; $i < count($matches[0]); $i++) + { + $prefix = ""; + $caption = $matches[2][$i]; + $suffix = substr_replace($prefix, "/", 1, 0); + $outHTML = str_replace("$prefix$caption$suffix", + "$prefix$caption$suffix", $outHTML); + } + return $outHTML; } function destroy_session() { if ( isset($_COOKIE[session_name()]) ) + { setcookie(session_name(), '', time() - 42000, '/'); - + } session_destroy(); unset($_SESSION["password"]); unset($_SESSION); } -// Support PHP4 by defining file_put_contents if it doesn't already exist - -if ( !function_exists('file_put_contents') ) +function getPageActions($page, $action, $imgSuffix) { - function file_put_contents($n, $d) - { - $f = @fopen($n, "w"); - - if ( !$f ) + $pageActions = array('edit', 'delete', 'rename'); + $pageActionNames = array(__('Edit'), __('Delete'), __('Rename')); + $result = ''; + for ($i = 0; $i < count($pageActions); $i++ ) + { + if ($action != $pageActions[$i]) { - return false; + $result .= " \"".$pageActionNames[$i]."\"\n"; } - else - { - fwrite($f, $d); - fclose($f); - return true; - } - } + } + $result .= " \"".__('Show\n"; + return $result; } -// Support PHP 8.1 by setting two predefined variables to empty strings if -// not already defined. Fixes a bunch of deprecation warnings. - -if (!isset($_SERVER["PATH_INFO"])) - $_SERVER["PATH_INFO"] = ''; -if (!isset($_REQUEST['page'])) - $_REQUEST['page'] = ''; - // Main code -if ( isset($_REQUEST['action']) ) - $action = $_REQUEST['action']; -else - $action = 'view'; - -// Look for page name following the script name in the URL, like this: -// http://stevenf.com/w2demo/index.php/Markdown%20Syntax -// -// Otherwise, get page name from 'page' request variable. - -if ( preg_match('@^/@', @$_SERVER["PATH_INFO"]) ) - $page = sanitizeFilename(substr($_SERVER["PATH_INFO"], 1)); -else - $page = sanitizeFilename(@$_REQUEST['page']); - -$upage = urlencode($page); - -if ( $page == "" ) - $page = DEFAULT_PAGE; - -$filename = PAGES_PATH . "/$page.txt"; - -if ( file_exists($filename) ) +$action = isset($_REQUEST['action']) ? $_REQUEST['action'] : 'view'; +$newPage = ""; +$text = ""; +$html = ""; +if ($action === 'view' || $action === 'edit' || $action === 'save' || $action === 'rename' || $action === 'delete') { - $text = file_get_contents($filename); -} -else -{ - if ( $action != "save" && $action != "all_name" && $action != "all_date" && $action != "upload" && $action != "new" && $action != "logout" && $action != "uploaded" && $action != "search" && $action != "view" ) + // Look for page name following the script name in the URL, like this: + // http://stevenf.com/w2demo/index.php/Markdown%20Syntax + // + // Otherwise, get page name from 'page' request variable. + + $page = preg_match('@^/@', @$_SERVER["PATH_INFO"]) ? + urldecode(substr($_SERVER["PATH_INFO"], 1)) : urldecode(@$_REQUEST['page']); + $page = sanitizeFilename($page); + if ( $page == "" ) { - $action = "edit"; + $page = DEFAULT_PAGE; + } + $filename = fileNameForPage($page); +} +if ($action === 'view' || $action === 'edit') +{ + if ( file_exists($filename) ) + { + $text = file_get_contents($filename); + } + else + { + $newPage = $page; + $action = 'new'; } } - -if ( $action == "edit" || $action == "new" ) +$oldgitmsg = ""; +$triedSave = false; +if ( $action == 'save' ) { - $formAction = SELF . (($action == 'edit') ? "/$page" : ""); - $html = "
\n"; - - if ( $action == "edit" ) - $html .= "\n"; + $msg = ''; + $newText = $_REQUEST['newText']; + $isNew = $_REQUEST['isNew']; + if ($isNew) + { + $page = str_replace(array('|','#'), '', $page); + $filename = fileNameForPage($page); + } + if ($isNew && file_exists($filename)) + { + $msg .= "Error creating page '$page' - it already exists! Please choose a different name, or edit the existing page (this discards current text!)!\n"; + $action = 'new'; + $text = $newText; + $newPage = $page; + if (GIT_COMMIT_ENABLED) + { + $oldgitmsg = $_REQUEST['gitmsg']; + } + $triedSave = true; + } else - $html .= "

Title:

\n"; - - if ( $action == "new" ) - $text = ""; - - $html .= "

\n"; - $html .= "

"; - $html .= "\n"; - $html .= "

\n"; - $html .= "
\n"; + { + $errLevel = error_reporting(0); + if ( !file_exists( dirname($filename) ) ) { + mkdir(dirname($filename), 0755, true); + } + $success = file_put_contents($filename, $newText); + error_reporting($errLevel); + if ( $success === FALSE) + { + $msg .= "Error saving changes! Make sure your web server has write access to " . PAGES_PATH . "\n"; + $action = ($isNew ? 'new' : 'edit'); + $text = $newText; + $newPage = $page; + if (GIT_COMMIT_ENABLED) + { + $oldgitmsg = $_REQUEST['gitmsg']; + } + $triedSave = true; + } + else + { + $msg .= ($isNew ? __('Created'): __('Saved')); + $usermsg = $_REQUEST['gitmsg']; + $commitmsg = $page . ($usermsg !== '' ? (": ".$usermsg) : ($isNew ? " created" : " changed")); + gitChangeHandler($commitmsg, $msg); + } + } + redirectWithMessage($page, $msg); } -else if ( $action == "logout" ) + +if ( $action === 'edit' || $action === 'new' ) +{ + $formAction = SELF . (($action === 'edit') ? "/$page" : ""); + $html .= "
\n"; + + if ( $action === 'edit' ) + { + $html .= "\n"; + } + else + { + if ($newPage != "" && !$triedSave) + { + $html .= "
". __('Creating new page since no page with given title exists!') ; + // check if similar page exists... + $pageNames = getAllPageNames(); + foreach($pageNames as $pageName) + { + if (levenshtein(strtoupper($newPage), strtoupper($pageName)) < sqrt(min(strlen($newPage), strlen($pageName))) ) + { + $html .= "
Note: Found similar page ".pageLink($pageName, $pageName).". Maybe you meant to edit this instead?"; + } + } + $html .= "
\n"; + } + $html .= "

" . __('Title') . ":

\n"; + + } + + $html .= "

\n"; + if (GIT_COMMIT_ENABLED) + { + $html .= "

Message:

\n"; + } + + $html .= "

\n"; + $html .= "\n"; + $html .= ''."\n"; + $html .= ''."\n"; + $html .= "

\n"; +} +else if ( $action === 'logout' ) { destroy_session(); header("Location: " . SELF); exit; } -else if ( $action == "upload" ) +else if ( $action === 'upload' ) { if ( DISABLE_UPLOADS ) { - $html = "

Image uploading has been disabled on this installation.

"; + $html .= '

' . __('Image uploading has been disabled on this installation.') . '

'; } else { - $html = "

\n"; - $html .= ""; - $html .= "\n"; - $html .= "\n"; - $html .= "\n"; - $html .= "

\n"; + $html .= "

\n". + "". + "\n". + ''. + ''. + ''. + ''. + ''."\n". + ''."\n"; + "

\n"; } -} -else if ( $action == "uploaded" ) -{ - if ( !DISABLE_UPLOADS ) - { - $dstName = sanitizeFilename($_FILES['userfile']['name']); - $fileType = $_FILES['userfile']['type']; - preg_match('/\.([^.]+)$/', $dstName, $matches); - $fileExt = isset($matches[1]) ? $matches[1] : null; - - if (in_array($fileType, explode(',', VALID_UPLOAD_TYPES)) && - in_array($fileExt, explode(',', VALID_UPLOAD_EXTS))) - { - $errLevel = error_reporting(0); - - if ( move_uploaded_file($_FILES['userfile']['tmp_name'], - BASE_PATH . "/images/$dstName") === true ) - { - $html = "

File '$dstName' uploaded

\n"; - } - else - { - $html = "

Upload error

\n"; - } - - error_reporting($errLevel); - } else { - $html = "

Upload error: invalid file type

\n"; - } - } - - $html .= toHTML($text); -} -else if ( $action == "save" ) -{ - $newText = $_REQUEST['newText']; - - $errLevel = error_reporting(0); - $success = file_put_contents($filename, $newText); - error_reporting($errLevel); - - if ( $success ) - $html = "

Saved

\n"; - else - $html = "

Error saving changes! Make sure your web server has write access to " . PAGES_PATH . "

\n"; - - $html .= toHTML($newText); -} + // list files in UPLOAD_FOLDER + $path = PAGES_PATH . "/". UPLOAD_FOLDER . "/*"; + $imgNames = glob($path); + natcasesort($imgNames); + $html .= "

".__('Total').": ".count($imgNames)." ".__('images')."

"; + $html .= ""; + $html .= "". /* -else if ( $action == "rename" ) + "". + "". + */ "". + ""; + $date_format = __('date_format', TITLE_DATE); + foreach ($imgNames as $imgName) + { + $html .= "". + "". + "". + "". + "". + "\n"; + } + $html .= "
".(($sortBy!='name')?("Name"):"Name")."".(($sortBy!='recent')?("Modified"):"Modified")."".__("Name")."".__("Usage")."".__("Modified")."".__("Action")."
".basename($imgName)."
".imageLinkText(basename($imgName))."
".date($date_format, filemtime($imgName))."".__('Delete')."
\n"; +} +else if ( $action === 'uploaded' ) { - $html = "
"; - $html .= "

Title: "; - $html .= ""; + if ( DISABLE_UPLOADS ) + { + die('Invalid access. Uploads are disabled in the configuration.'); + } + $dstName = sanitizeFilename($_FILES['userfile']['name']); + $dstName = str_replace(" ", "_", $dstName); // image display currently doesn't like spaces! + $fileType = $_FILES['userfile']['type']; + preg_match('/\.([^.]+)$/', $dstName, $matches); + $fileExt = isset($matches[1]) ? $matches[1] : null; + $imgExts = array('jpg','jpeg','png','gif'); + $msg = ''; + if (in_array($fileType, explode(',', VALID_UPLOAD_TYPES)) && + in_array($fileExt, explode(',', VALID_UPLOAD_EXTS))) + { + $path = PAGES_PATH . "/". UPLOAD_FOLDER . "/$dstName"; + $resize = isset($_POST['resize']) && $_POST['resize'] === 'true'; + $doResize = $resize && in_array($fileExt, $imgExts); + if ($doResize) + { + $exif = exif_read_data($_FILES['userfile']['tmp_name']); + $size = getimagesize($_FILES['userfile']['tmp_name']); + $maxsize = intval($_POST['maxsize']); + $doResize = ($size[0] > $maxsize || $size[1] > $maxsize); + if ($doResize) + { + $msg .= "trying to resize"; + $finalPath = $path; + $path = substr($path, 0, strlen($path)-strlen($fileExt)-1) . "-tmp-resize." . $fileExt; + } + } + $errLevel = error_reporting(0); + if ( move_uploaded_file($_FILES['userfile']['tmp_name'], $path) === true ) + { + $msg = "File '$dstName' uploaded! "; + if ($doResize) + { + $newSize = array(0, 0); + $idx0 = ($size[0] > $size[1]) ? 0 : 1; + $idx1 = ($idx0 == 0) ? 1 : 0; + $newSize[$idx0] = $maxsize; + $newSize[$idx1] = (int)round($size[$idx1] * $maxsize / $size[$idx0]); + $src = imagecreatefromstring(file_get_contents($path)); + $dst = imagecreatetruecolor($newSize[0], $newSize[1]); + if (!imagecopyresampled($dst, $src, 0, 0, 0, 0, $newSize[0], $newSize[1], $size[0], $size[1])) + { + $msg .= "Resizing file failed!"; + } + imagedestroy( $src ); + if(!empty($exif['Orientation'])) + { + switch($exif['Orientation']) + { + case 8: + $msg .= "Image rotated by +90°. "; + $rot = imagerotate($dst,90,0); + break; + case 3: + $msg .= "Image rotated by 180°. "; + $rot = imagerotate($dst,180,0); + break; + case 6: + $msg .= "Image rotated by -90°. "; + $rot = imagerotate($dst,-90,0); + break; + default: + $msg .= "Unknown EXIF orientation specification: ".$exif['Orientation']."!"; + break; + } + if ($rot === false) + { + $msg .= "Rotation failed!"; + } + else + { + imagedestroy( $dst ); + $dst = $rot; + } + } + if ($fileExt === 'png') + { + imagepng($dst, $finalPath); + } + else if ($fileExt === 'jpg' || $fileExt === 'jpeg') + { + imagejpeg($dst, $finalPath); + } + else if ($fileExt === 'gif') + { + imagegif($dst, $finalPath); + } + unlink($path); + imagedestroy( $dst ); + } + gitChangeHandler($msg, $msg); + $msg .= " ($size[0]x$size[1]".(($doResize)?", resized to $newSize[0]x$newSize[1]":"").") successfully! Use

".imageLinkText($dstName)."
to refer to it!"; + } + else + { + $error_code = $_FILES['userfile']['error']; + if ( $error_code === 0 ) { + // Likely a permissions issue + $msg .= __('Upload error') .": Can't write to ".$path."

\n". + "Check that your permissions are set correctly."; + } else { + // Give generic error message + $msg .= __('Upload error').", error #".$error_code."

\n". + "Please see here for more information.

\n". + "If you see this message, please file a bug to improve w2wiki"; + } + } + error_reporting($errLevel); + } + else + { + $msg .= __('Upload error: invalid file type'); + } + redirectWithMessage(DEFAULT_PAGE, $msg); +} +else if ( $action === 'rename' || $action === 'delete' || $action === 'imgDelete') +{ + if ($action === 'imgDelete') + { + $page = sanitizeFilename(urldecode($_REQUEST['imgName'])); + } + $actionName = ($action === 'delete' || $action === 'imgDelete')?__('Delete'):__('Rename'); + $html .= ""; + $html .= "

".$actionName." $page ". + (($action==='rename')? (__('to')." ") : "?") . "

"; + $html .= "

"; $html .= "\n"; - $html .= ""; - $html .= ""; + $html .= ""; + $html .= ""; $html .= "

"; } -else if ( $action == "renamed" ) +else if ( $action === 'renamed' || $action === 'deleted') { - $pp = $_REQUEST['prevpage']; - $pg = $_REQUEST['page']; - - $prevpage = sanitizeFilename($pp); - $prevpage = urlencode($prevpage); - - $prevfilename = PAGES_PATH . "/$prevpage.txt"; - - if ( rename($prevfilename, $filename) ) + // TODO: prevent relative filenames from being injected + $oldPageName = sanitizeFilename($_POST['oldPageName']); + $newPageName = ($action === 'deleted') ? "": sanitizeFilename($_POST['newPageName']); + $msg = ''; + if ($action === 'deleted') { - // Success. Change links in all pages to point to new page - if ( $dh = opendir(PAGES_PATH) ) + $success = unlink(fileNameForPage($oldPageName)); + } + else + { + $success = rename(fileNameForPage($oldPageName), fileNameForPage($newPageName)); + } + if ($success) + { + $message = ($action === 'deleted') ? "Removed $oldPageName." : + "Renamed $oldPageName to $newPageName."; + $msg .= $message; + // Change links in all pages to point to new page + $pagenames = getAllPageNames(); + $changedPages = array(); + foreach ($pagenames as $replacePage) { - while ( ($file = readdir($dh)) !== false ) + $content = file_get_contents(fileNameForPage($replacePage)); + $count = 0; + $regexSaveOldPageName = str_replace("/", "\\/", $oldPageName); + $newContent = preg_replace("/\[\[$regexSaveOldPageName([|#].*\]\]|\]\])/", + (($action === 'deleted') ? "" : "[[$newPageName\\1"), + $content, -1, $count); + if ($count > 0) // if something changed { - $content = file_get_contents($file); - $pattern = "/\[\[" . $pp . "\]\]/g"; - preg_replace($pattern, "[[$pg]]", $content); - file_put_contents($file, $content); + $changedPages[] = $replacePage." ($count ".__('matches').")"; + file_put_contents(fileNameForPage($replacePage), $newContent); } } + if (count($changedPages) > 0) + { + $msg .= "
\n".__('Updated links in the following pages:')."\n
  • "; + $msg .= implode("
  • ", $changedPages); + $msg .= "
"; + } + gitChangeHandler($message, $msg); + $page = $newPageName; + } + else + { + $msg .= ($action === 'deleted') ? __('Error deleting file'): __('Error renaming file'); + $page = $oldPageName; + } + if ($action === 'deleted' && $success) + { + $page = DEFAULT_PAGE; + } + redirectWithMessage($page, $msg); +} +else if ( $action === 'imgDeleted') +{ + // TODO: prevent relative filenames from being injected + $oldPageName = sanitizeFilename($_REQUEST['oldPageName']); + $imgPath = PAGES_PATH . "/". UPLOAD_FOLDER . "/". $oldPageName; + $success = unlink($imgPath); + if ($success) + { + $msg = __('Image deleted'); + gitChangeHandler($msg, $msg); + $msg .= " (".$imgPath.")"; + } + else + { + $msg = __('Error deleting image'); + $msg .= " (".$imgPath.")"; + } + redirectWithMessage(DEFAULT_PAGE, $msg); +} +else if ( $action === 'all' ) +{ + $pageNames = getAllPageNames(); + $filelist = array(); + $sortBy = isset($_REQUEST['sortBy']) ? $_REQUEST['sortBy'] : 'name'; + if (!in_array($sortBy, array('name', 'recent'))) + { + $sortBy = 'name'; + } + if ($sortBy === 'name') + { + natcasesort($pageNames); + foreach($pageNames as $page) + { + $filelist[$page] = filemtime(fileNameForPage($page)); + } } else { - $html = "

Error renaming file

\n"; - } -} -*/ -else if ( $action == "all_name" ) -{ - $dir = opendir(PAGES_PATH); - $filelist = array(); - - $color = "#ffffff"; - - while ( $file = readdir($dir) ) - { - if ( $file[0] == "." ) - continue; - - $afile = preg_replace("/(.*?)\.txt/", "\\1", $file); - $efile = preg_replace("/(.*?)\.txt/", "edit", urlencode($file)); - - array_push($filelist, "$afile$efile"); - - if ( $color == "#ffffff" ) - $color = "#f4f4f4"; - else - $color = "#ffffff"; - } - - closedir($dir); - - natcasesort($filelist); - - $html = ""; - - - for ($i = 0; $i < count($filelist); $i++) - { - $html .= $filelist[$i]; - } - - $html .= "
\n"; -} -else if ( $action == "all_date" ) -{ - $html = "\n"; - $dir = opendir(PAGES_PATH); - $filelist = array(); - while ( $file = readdir($dir) ) - { - if ( $file[0] == "." ) - continue; - - $filelist[preg_replace("/(.*?)\.txt/", "\\1", $file)] = filemtime(PAGES_PATH . "/$file"); - } - - closedir($dir); - - $color = "#ffffff"; - arsort($filelist, SORT_NUMERIC); - - foreach ($filelist as $key => $value) - { - $html .= "\n"; - - if ( $color == "#ffffff" ) - $color = "#f4f4f4"; - else - $color = "#ffffff"; - } - $html .= "
$key" . date(TITLE_DATE_NO_TIME, $value) . "
\n"; -} -else if ( $action == "search" ) -{ - $matches = 0; - $q = $_REQUEST['q']; - $html = "

Search: $q

\n