c4248851dc
i don't mind sharing config.php since its not password protected or anything like that anyway, maybe i'll share everything except config.php in the future.
556 lines
14 KiB
PHP
556 lines
14 KiB
PHP
<?php
|
|
|
|
/*
|
|
* W2
|
|
*
|
|
* Copyright (C) 2007-2011 Steven Frank <http://stevenf.com/>
|
|
*
|
|
* Code may be re-used as long as the above copyright notice is retained.
|
|
* See README.txt for full details.
|
|
*
|
|
* Written with Coda: <http://panic.com/coda/>
|
|
*
|
|
*/
|
|
|
|
// Install PSR-4-compatible class autoloader
|
|
spl_autoload_register(function($class){
|
|
require str_replace('\\', DIRECTORY_SEPARATOR, ltrim($class, '\\')).'.php';
|
|
});
|
|
|
|
|
|
// Get Markdown class
|
|
use mdlibs\MarkdownExtra;
|
|
|
|
|
|
// User configurable options:
|
|
|
|
include_once "config.php";
|
|
|
|
ini_set('session.gc_maxlifetime', W2_SESSION_LIFETIME);
|
|
|
|
session_set_cookie_params(W2_SESSION_LIFETIME);
|
|
session_name(W2_SESSION_NAME);
|
|
session_start();
|
|
|
|
if ( count($allowedIPs) > 0 )
|
|
{
|
|
$ip = $_SERVER['REMOTE_ADDR'];
|
|
$accepted = false;
|
|
|
|
foreach ( $allowedIPs as $allowed )
|
|
{
|
|
if ( strncmp($allowed, $ip, strlen($allowed)) == 0 )
|
|
{
|
|
$accepted = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( !$accepted )
|
|
{
|
|
print "<html><body>Access from IP address $ip is not allowed";
|
|
print "</body></html>";
|
|
exit;
|
|
}
|
|
}
|
|
|
|
if ( REQUIRE_PASSWORD && !isset($_SESSION['password']) )
|
|
{
|
|
if ( !defined('W2_PASSWORD_HASH') || W2_PASSWORD_HASH == '' )
|
|
define('W2_PASSWORD_HASH', sha1(W2_PASSWORD));
|
|
|
|
if ( (isset($_POST['p'])) && (sha1($_POST['p']) == W2_PASSWORD_HASH) )
|
|
$_SESSION['password'] = W2_PASSWORD_HASH;
|
|
else
|
|
{
|
|
print "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n";
|
|
print "<html>\n";
|
|
print "<head>\n";
|
|
print "<link rel=\"apple-touch-icon\" href=\"apple-touch-icon.png\"/>";
|
|
print "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, minimum-scale=1.0, user-scalable=false\" />\n";
|
|
|
|
print "<link type=\"text/css\" rel=\"stylesheet\" href=\"" . BASE_URI . "/" . CSS_FILE ."\" />\n";
|
|
print "<title>Log In</title>\n";
|
|
print "</head>\n";
|
|
print "<body><form method=\"post\">";
|
|
print "<input type=\"password\" name=\"p\">\n";
|
|
print "<input type=\"submit\" value=\"Go\"></form>";
|
|
print "</body></html>";
|
|
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 "<a href=\"" . SELF . VIEW . "/" . htmlentities($link) . "\">" . htmlentities($link) . "</a>";
|
|
else
|
|
return "<a href=\"" . SELF . VIEW . "/" . htmlentities($link) . "\" class=\"missing-link\">" . htmlentities($link) . "</a>";
|
|
}
|
|
|
|
|
|
function _handle_images($match)
|
|
{
|
|
return "<img src=\"" . BASE_URI . "/images/" . htmlentities($match[1]) . "\" alt=\"" . htmlentities($match[1]) . "\" />";
|
|
}
|
|
|
|
|
|
function _handle_message($match)
|
|
{
|
|
return "[<a href=\"message:" . htmlentities($match[1]) . "\">email</a>]";
|
|
}
|
|
|
|
|
|
function printToolbar()
|
|
{
|
|
global $upage, $page, $action;
|
|
|
|
print "<div class=\"toolbar\">";
|
|
print "<a class=\"tool first\" href=\"" . SELF . "?action=edit&page=$upage\">Edit</a> ";
|
|
print "<a class=\"tool\" href=\"" . SELF . "?action=new\">New</a> ";
|
|
|
|
if ( !DISABLE_UPLOADS )
|
|
print "<a class=\"tool\" href=\"" . SELF . VIEW . "?action=upload\">Upload</a> ";
|
|
|
|
print "<a class=\"tool\" href=\"" . SELF . "?action=all_name\">All</a> ";
|
|
print "<a class=\"tool\" href=\"" . SELF . "?action=all_date\">Recent</a> ";
|
|
print "<a class=\"tool\" href=\"" . SELF . "\">". DEFAULT_PAGE . "</a>";
|
|
|
|
if ( REQUIRE_PASSWORD )
|
|
print '<a class="tool" href="' . SELF . '?action=logout">Exit</a>';
|
|
|
|
print "<form method=\"post\" action=\"" . SELF . "?action=search\">\n";
|
|
print "<input class=\"tool\" placeholder=\"Search\" size=\"6\" id=\"search\" type=\"text\" name=\"q\" /></form>\n";
|
|
|
|
print "</div>\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;
|
|
}
|
|
|
|
|
|
function toHTML($inText)
|
|
{
|
|
global $page;
|
|
|
|
$inText = preg_replace("/<[\/]*script>/", "", $inText);
|
|
|
|
$dir = opendir(PAGES_PATH);
|
|
while ( $filename = readdir($dir) )
|
|
{
|
|
if ( $filename[0] == '.' )
|
|
continue;
|
|
|
|
$filename = preg_replace("/(.*?)\.txt/", "\\1", $filename);
|
|
$filenames[] = $filename;
|
|
}
|
|
closedir($dir);
|
|
|
|
uasort($filenames, "descLengthSort");
|
|
|
|
if ( AUTOLINK_PAGE_TITLES )
|
|
{
|
|
foreach ( $filenames as $filename )
|
|
{
|
|
$inText = preg_replace("/(?<![\>\[\/])($filename)(?!\]\>)/im", "<a href=\"" . SELF . VIEW . "/$filename\">\\1</a>", $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 sanitizeFilename($inFileName)
|
|
{
|
|
return str_replace(array('..', '~', '/', '\\', ':'), '-', $inFileName);
|
|
}
|
|
|
|
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 file_put_contents($n, $d)
|
|
{
|
|
$f = @fopen($n, "w");
|
|
|
|
if ( !$f )
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
fwrite($f, $d);
|
|
fclose($f);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
// 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) )
|
|
{
|
|
$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" )
|
|
{
|
|
$action = "edit";
|
|
}
|
|
}
|
|
|
|
if ( $action == "edit" || $action == "new" )
|
|
{
|
|
$formAction = SELF . (($action == 'edit') ? "/$page" : "");
|
|
$html = "<form id=\"edit\" method=\"post\" action=\"$formAction\">\n";
|
|
|
|
if ( $action == "edit" )
|
|
$html .= "<input type=\"hidden\" name=\"page\" value=\"$page\" />\n";
|
|
else
|
|
$html .= "<p>Title: <input id=\"title\" type=\"text\" name=\"page\" /></p>\n";
|
|
|
|
if ( $action == "new" )
|
|
$text = "";
|
|
|
|
$html .= "<p><textarea id=\"text\" name=\"newText\" rows=\"" . EDIT_ROWS . "\">$text</textarea></p>\n";
|
|
$html .= "<p><input type=\"hidden\" name=\"action\" value=\"save\" />";
|
|
$html .= "<input id=\"save\" type=\"submit\" value=\"Save\" />\n";
|
|
$html .= "<input id=\"cancel\" type=\"button\" onclick=\"history.go(-1);\" value=\"Cancel\" /></p>\n";
|
|
$html .= "</form>\n";
|
|
}
|
|
else if ( $action == "logout" )
|
|
{
|
|
destroy_session();
|
|
header("Location: " . SELF);
|
|
exit;
|
|
}
|
|
else if ( $action == "upload" )
|
|
{
|
|
if ( DISABLE_UPLOADS )
|
|
{
|
|
$html = "<p>Image uploading has been disabled on this installation.</p>";
|
|
}
|
|
else
|
|
{
|
|
$html = "<form id=\"upload\" method=\"post\" action=\"" . SELF . "\" enctype=\"multipart/form-data\"><p>\n";
|
|
$html .= "<input type=\"hidden\" name=\"action\" value=\"uploaded\" />";
|
|
$html .= "<input id=\"file\" type=\"file\" name=\"userfile\" />\n";
|
|
$html .= "<input id=\"upload\" type=\"submit\" value=\"Upload\" />\n";
|
|
$html .= "<input id=\"cancel\" type=\"button\" onclick=\"history.go(-1);\" value=\"Cancel\" />\n";
|
|
$html .= "</p></form>\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 = "<p class=\"note\">File '$dstName' uploaded</p>\n";
|
|
}
|
|
else
|
|
{
|
|
$html = "<p class=\"note\">Upload error</p>\n";
|
|
}
|
|
|
|
error_reporting($errLevel);
|
|
} else {
|
|
$html = "<p class=\"note\">Upload error: invalid file type</p>\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 = "<p class=\"note\">Saved</p>\n";
|
|
else
|
|
$html = "<p class=\"note\">Error saving changes! Make sure your web server has write access to " . PAGES_PATH . "</p>\n";
|
|
|
|
$html .= toHTML($newText);
|
|
}
|
|
/*
|
|
else if ( $action == "rename" )
|
|
{
|
|
$html = "<form id=\"rename\" method=\"post\" action=\"" . SELF . "\">";
|
|
$html .= "<p>Title: <input id=\"title\" type=\"text\" name=\"page\" value=\"" . htmlspecialchars($page) . "\" />";
|
|
$html .= "<input id=\"rename\" type=\"submit\" value=\"Rename\">";
|
|
$html .= "<input id=\"cancel\" type=\"button\" onclick=\"history.go(-1);\" value=\"Cancel\" />\n";
|
|
$html .= "<input type=\"hidden\" name=\"action\" value=\"renamed\" />";
|
|
$html .= "<input type=\"hidden\" name=\"prevpage\" value=\"" . htmlspecialchars($page) . "\" />";
|
|
$html .= "</p></form>";
|
|
}
|
|
else if ( $action == "renamed" )
|
|
{
|
|
$pp = $_REQUEST['prevpage'];
|
|
$pg = $_REQUEST['page'];
|
|
|
|
$prevpage = sanitizeFilename($pp);
|
|
$prevpage = urlencode($prevpage);
|
|
|
|
$prevfilename = PAGES_PATH . "/$prevpage.txt";
|
|
|
|
if ( rename($prevfilename, $filename) )
|
|
{
|
|
// Success. Change links in all pages to point to new page
|
|
if ( $dh = opendir(PAGES_PATH) )
|
|
{
|
|
while ( ($file = readdir($dh)) !== false )
|
|
{
|
|
$content = file_get_contents($file);
|
|
$pattern = "/\[\[" . $pp . "\]\]/g";
|
|
preg_replace($pattern, "[[$pg]]", $content);
|
|
file_put_contents($file, $content);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$html = "<p class=\"note\">Error renaming file</p>\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/", "<a href=\"" . SELF . VIEW . "/\\1\">\\1</a>", $file);
|
|
$efile = preg_replace("/(.*?)\.txt/", "<a href=\"?action=edit&page=\\1\">edit</a>", urlencode($file));
|
|
|
|
array_push($filelist, "<tr style=\"background-color: $color;\"><td>$afile</td><td width=\"20\"></td><td>$efile</td></tr>");
|
|
|
|
if ( $color == "#ffffff" )
|
|
$color = "#f4f4f4";
|
|
else
|
|
$color = "#ffffff";
|
|
}
|
|
|
|
closedir($dir);
|
|
|
|
natcasesort($filelist);
|
|
|
|
$html = "<table>";
|
|
|
|
|
|
for ($i = 0; $i < count($filelist); $i++)
|
|
{
|
|
$html .= $filelist[$i];
|
|
}
|
|
|
|
$html .= "</table>\n";
|
|
}
|
|
else if ( $action == "all_date" )
|
|
{
|
|
$html = "<table>\n";
|
|
$dir = opendir(PAGES_PATH);
|
|
$filelist = array();
|
|
while ( $file = readdir($dir) )
|
|
{
|
|
if ( $file[0] == "." )
|
|
continue;
|
|
|
|
$filelist[preg_replace("/(.*?)\.txt/", "<a href=\"" . SELF . VIEW . "/\\1\">\\1</a>", $file)] = filemtime(PAGES_PATH . "/$file");
|
|
}
|
|
|
|
closedir($dir);
|
|
|
|
$color = "#ffffff";
|
|
arsort($filelist, SORT_NUMERIC);
|
|
|
|
foreach ($filelist as $key => $value)
|
|
{
|
|
$html .= "<tr style=\"background-color: $color;\"><td valign=\"top\">$key</td><td width=\"20\"></td><td valign=\"top\"><nobr>" . date(TITLE_DATE_NO_TIME, $value) . "</nobr></td></tr>\n";
|
|
|
|
if ( $color == "#ffffff" )
|
|
$color = "#f4f4f4";
|
|
else
|
|
$color = "#ffffff";
|
|
}
|
|
$html .= "</table>\n";
|
|
}
|
|
else if ( $action == "search" )
|
|
{
|
|
$matches = 0;
|
|
$q = $_REQUEST['q'];
|
|
$html = "<h1>Search: $q</h1>\n<ul>\n";
|
|
|
|
if ( trim($q) != "" )
|
|
{
|
|
$dir = opendir(PAGES_PATH);
|
|
|
|
while ( $file = readdir($dir) )
|
|
{
|
|
if ( $file[0] == "." )
|
|
continue;
|
|
|
|
$text = file_get_contents(PAGES_PATH . "/$file");
|
|
|
|
if ( preg_match("/{$q}/i", $text) || preg_match("/{$q}/i", $file) )
|
|
{
|
|
++$matches;
|
|
$file = preg_replace("/(.*?)\.txt/", "<a href=\"" . SELF . VIEW . "/\\1\">\\1</a>", $file);
|
|
$html .= "<li>$file</li>\n";
|
|
}
|
|
}
|
|
|
|
closedir($dir);
|
|
}
|
|
|
|
$html .= "</ul>\n";
|
|
$html .= "<p>$matches matched</p>\n";
|
|
}
|
|
else
|
|
{
|
|
$html = toHTML($text);
|
|
}
|
|
|
|
$datetime = '';
|
|
|
|
if ( ($action == "all_name") || ($action == "all_date"))
|
|
$title = "All Pages";
|
|
|
|
else if ( $action == "upload" )
|
|
$title = "Upload Image";
|
|
|
|
else if ( $action == "new" )
|
|
$title = "New";
|
|
|
|
else if ( $action == "search" )
|
|
$title = "Search";
|
|
|
|
else
|
|
{
|
|
$title = $page;
|
|
|
|
if ( TITLE_DATE )
|
|
{
|
|
$datetime = "<span class=\"titledate\">" . date(TITLE_DATE, @filemtime($filename)) . "</span>";
|
|
}
|
|
}
|
|
|
|
// Disable caching on the client (the iPhone is pretty agressive about this
|
|
// and it can cause problems with the editing function)
|
|
|
|
header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
|
|
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); // Date in the past
|
|
|
|
print "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n";
|
|
print "<html>\n";
|
|
print "<head>\n";
|
|
print "<link rel=\"apple-touch-icon\" href=\"apple-touch-icon.png\"/>";
|
|
print "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, minimum-scale=1.0, user-scalable=false\" />\n";
|
|
|
|
print "<link type=\"text/css\" rel=\"stylesheet\" href=\"" . BASE_URI . "/" . CSS_FILE ."\" />\n";
|
|
print "<title>$title</title>\n";
|
|
print "</head>\n";
|
|
print "<body>\n";
|
|
print "<div class=\"titlebar\">$title <span style=\"font-weight: normal;\">$datetime</span></div>\n";
|
|
|
|
printToolbar();
|
|
|
|
print "<div class=\"main\">\n";
|
|
print "$html\n";
|
|
print "</div>\n";
|
|
|
|
print "</body>\n";
|
|
print "</html>\n";
|
|
|
|
?>
|