2014-12-25 20:31:01 +00:00
< ? php
$start_time = time ( true );
2014-12-26 11:06:37 +00:00
{ settings }
2014-12-25 20:31:01 +00:00
///////////////////////////////////////////////////////////////////////////////////////////////
/////////////// Do not edit below this line unless you know what you are doing! ///////////////
///////////////////////////////////////////////////////////////////////////////////////////////
2015-05-09 09:15:43 +00:00
$version = " 0.5 " ;
2015-01-10 10:52:03 +00:00
session_start ();
2014-12-25 20:31:01 +00:00
///////// Login System /////////
2015-01-10 10:52:03 +00:00
//clear expired sessions
2015-04-09 14:13:07 +00:00
if ( isset ( $_SESSION [ " $settings->sessionprefix -expiretime " ]) and
$_SESSION [ " $settings->sessionprefix -expiretime " ] < time ())
2015-01-10 10:52:03 +00:00
{
//clear the session variables
$_SESSION = [];
session_destroy ();
}
2015-04-09 14:13:07 +00:00
if ( ! isset ( $_SESSION [ $settings -> sessionprefix . " -user " ]) and
! isset ( $_SESSION [ $settings -> sessionprefix . " -pass " ]))
2014-12-25 20:31:01 +00:00
{
//the user is not logged in
$isloggedin = false ;
}
else
{
2015-04-09 14:13:07 +00:00
$user = $_SESSION [ $settings -> sessionprefix . " -user " ];
$pass = $_SESSION [ $settings -> sessionprefix . " -pass " ];
if ( $settings -> users [ $user ] == $pass )
2014-12-25 20:31:01 +00:00
{
//the user is logged in
$isloggedin = true ;
}
else
{
//the user's login details are invalid (what is going on here?)
2015-01-10 10:52:03 +00:00
//unset the session variables, treat them as an anonymous user, and get out of here
2014-12-25 20:31:01 +00:00
$isloggedin = false ;
unset ( $user );
unset ( $pass );
2015-01-10 10:52:03 +00:00
//clear the session data
$_SESSION = []; //delete al lthe variables
session_destroy (); //destroy the session
2014-12-25 20:31:01 +00:00
}
}
2014-12-26 18:14:38 +00:00
//check to see if the currently logged in user is an admin
$isadmin = false ;
if ( $isloggedin )
{
2015-04-09 14:13:07 +00:00
foreach ( $settings -> admins as $admin_username )
2014-12-26 18:14:38 +00:00
{
if ( $admin_username == $user )
{
$isadmin = true ;
break ;
}
}
}
2014-12-25 20:31:01 +00:00
/////// Login System End ///////
///////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////// Security and Consistency Measures ////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////
if ( ! file_exists ( " ./pageindex.json " ))
{
$existingpages = glob ( " *.md " );
$pageindex = new stdClass ();
foreach ( $existingpages as $pagefilename )
{
$newentry = new stdClass ();
$newentry -> filename = utf8_encode ( $pagefilename );
$newentry -> size = filesize ( $pagefilename );
$newentry -> lastmodified = filemtime ( $pagefilename );
$newentry -> lasteditor = utf8_encode ( " unknown " );
$pagekey = utf8_encode ( substr ( $pagefilename , 0 , - 3 ));
$pageindex -> $pagekey = $newentry ;
}
file_put_contents ( " ./pageindex.json " , json_encode ( $pageindex , JSON_PRETTY_PRINT ));
2015-04-09 14:13:07 +00:00
unset ( $existingpages );
2014-12-25 20:31:01 +00:00
}
else
{
$pageindex = json_decode ( file_get_contents ( " ./pageindex.json " ));
}
/*
* @ summary makes a path safe
2014-12-25 20:48:14 +00:00
*
2014-12-25 20:31:01 +00:00
* @ details paths may only contain alphanumeric characters , spaces , underscores , and dashes
*/
function makepathsafe ( $string ) { return preg_replace ( " /[^0-9a-zA-Z \ _ \ - \ ]/i " , " " , $string ); }
/*
* @ summary Hides an email address from bots by adding random html entities .
2014-12-25 20:48:14 +00:00
*
2014-12-25 20:31:01 +00:00
* @ returns The mangled email address .
*/
function hide_email ( $str )
{
$hidden_email = " " ;
for ( $i = 0 ; $i < strlen ( $str ); $i ++ )
{
if ( $str [ $i ] == " @ " )
{
$hidden_email .= " &# " . ord ( " @ " ) . " ; " ;
continue ;
}
if ( rand ( 0 , 1 ) == 0 )
$hidden_email .= $str [ $i ];
else
$hidden_email .= " &# " . ord ( $str [ $i ]) . " ; " ;
}
2014-12-25 20:48:14 +00:00
2014-12-25 20:31:01 +00:00
return $hidden_email ;
}
//Work around an Opera + Syntastic bug where there is no margin at the left hand side if there isn't a query string when accessing a .php file
if ( ! isset ( $_GET [ " action " ]) and ! isset ( $_GET [ " page " ]))
{
http_response_code ( 302 );
2015-04-11 17:30:01 +00:00
header ( " location: index.php?action= $settings->defaultaction &page= $defaultpage " );
2014-12-25 20:31:01 +00:00
exit ();
}
//make sure that the action is set
if ( ! isset ( $_GET [ " action " ]))
2015-05-24 15:17:07 +00:00
$_GET [ " action " ] = $settings -> defaultaction ;
//make sure that the page is set
2014-12-25 20:31:01 +00:00
if ( ! isset ( $_GET [ " page " ]) or strlen ( $_GET [ " page " ]) === 0 )
2015-04-09 14:13:07 +00:00
$_GET [ " page " ] = $settings -> defaultpage ;
2014-12-25 20:31:01 +00:00
//redirect the user to the safe version of the path if they entered an unsafe character
if ( makepathsafe ( $_GET [ " page " ]) !== $_GET [ " page " ])
{
http_response_code ( 301 );
header ( " location: index.php?action= " . rawurlencode ( $_GET [ " action " ]) . " &page= " . makepathsafe ( $_GET [ " page " ]));
header ( " x-requested-page: " . $_GET [ " page " ]);
header ( " x-actual-page: " . makepathsafe ( $_GET [ " page " ]));
exit ();
}
2014-12-27 19:59:32 +00:00
$page = $_GET [ " page " ];
2014-12-25 20:31:01 +00:00
///////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////// HTML fragments //////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
2015-05-24 19:58:51 +00:00
class page_renderer
2014-12-25 20:31:01 +00:00
{
2015-05-24 19:58:51 +00:00
public static $html_template = " <!DOCTYPE html>
< html >
< head >
< meta charset = 'utf-8' />
< title > { title } </ title >
< meta name = 'viewport' content = 'width=device-width, initial-scale=1' />
2015-05-24 20:06:03 +00:00
< link rel = 'shortcut-icon' href = '{favicon-url}' />
2015-05-24 19:58:51 +00:00
{ header - html }
</ head >
< body >
{ body }
<!-- Took { generation - time - taken } seconds to generate -->
</ body >
</ html >
" ;
2014-12-25 20:48:14 +00:00
2015-05-24 19:58:51 +00:00
public static $main_content_template = " { navigation-bar}
< h1 class = 'sitename' > { sitename } </ h1 >
{ content }
< footer >
< p > Powered by Pepperminty Wiki , which was built by < a href = '//starbeamrainbowlabs.com/' > Starbeamrainbowlabs </ a >. Send bugs to 'bugs at starbeamrainbowlabs dot com' or open an issue < a href = '//github.com/sbrl/Pepperminty-Wiki' > on github </ a >.</ p >
< p > Your local friendly administrators are { admins - name - list } .
2015-05-24 20:08:03 +00:00
< p > This wiki is managed by < a href = 'mailto:{admin-details-email}' > { admin - details - name } </ a >.</ p >
2015-05-24 19:58:51 +00:00
</ footer >
{ all - pages - datalist } " ;
public static $minimal_content_template = " { content}
< hr class = 'footerdivider' />
< p >< em > From { sitename }, which is managed by { admin - details - name } .</ em ></ p >
< p >< em > Timed at { generation - date } </ em >
< p >< em > Powered by Pepperminty Wiki .</ em ></ p > " ;
public static function render ( $title , $content , $body_template )
2014-12-25 20:48:14 +00:00
{
2015-05-24 19:58:51 +00:00
global $settings , $start_time ;
$result = self :: $html_template ;
$result = str_replace ( " { body} " , $body_template , $result );
$result = str_replace ([
" { sitename} " ,
" { favicon-url} " ,
" { header-html} " ,
" { navigation-bar} " ,
" { admin-details-name} " ,
" { admin-details-email} " ,
" { admins-name-list} " ,
" { generation-date} " ,
" { all-pages-datalist} "
], [
$settings -> sitename ,
$settings -> favicon ,
self :: get_css_as_html (),
self :: render_navigation_bar (),
$settings -> admindetails [ " name " ],
$settings -> admindetails [ " email " ],
implode ( " , " , $settings -> admins ),
date ( " l jS \ of F Y \ a \\ t h:ia T " ),
self :: generate_all_pages_datalist ()
], $result );
2015-05-24 20:06:03 +00:00
$result = str_replace ([
" { title} " ,
" { content} "
], [
$title ,
$content
], $result );
2015-05-24 19:58:51 +00:00
$result = str_replace ( " { generation-time-taken} " , microtime ( true ) - $start_time , $result );
2015-05-24 20:06:03 +00:00
return $result ;
2014-12-25 20:48:14 +00:00
}
2015-05-24 19:58:51 +00:00
public static function render_main ( $title , $content )
{
2015-05-24 20:01:18 +00:00
return self :: render ( $title , $content , self :: $main_content_template );
2015-05-24 19:58:51 +00:00
}
public static function render_minimal ( $title , $content )
2014-12-25 20:48:14 +00:00
{
2015-05-24 20:01:18 +00:00
return self :: render ( $title , $content , self :: $minimal_content_template );
2014-12-25 20:48:14 +00:00
}
2015-05-24 19:58:51 +00:00
public static function get_css_as_html ()
2014-12-25 20:31:01 +00:00
{
2015-05-24 19:58:51 +00:00
global $settings ;
if ( preg_match ( " /^[^ \ /]* \ / \ /|^ \ // " , $settings -> css ))
return " <link rel='stylesheet' href=' $settings->css ' /> " ;
else
return " <style> $settings->css </style> " ;
2014-12-25 20:31:01 +00:00
}
2014-12-25 20:48:14 +00:00
2015-05-24 19:58:51 +00:00
public static function render_navigation_bar ()
{
2015-05-24 20:06:03 +00:00
global $settings , $user , $isloggedin , $page ;
2015-05-24 19:58:51 +00:00
$result = " <nav> \n " ;
2014-12-25 20:31:01 +00:00
if ( $isloggedin )
2014-12-26 18:14:38 +00:00
{
2015-05-24 19:58:51 +00:00
$result .= " \t \t \t Logged in as " . render_username ( $user ) . " . " ;
$result .= " <a href='index.php?action=logout'>Logout</a>. | \n " ;
2014-12-26 18:14:38 +00:00
}
2014-12-25 20:31:01 +00:00
else
2015-05-24 20:06:03 +00:00
$result .= " \t \t \t Browsing as Anonymous. <a href='index.php?action=login'>Login</a>. | \n " ;
2015-05-24 19:58:51 +00:00
// loop over all the navigation links
2015-04-09 14:13:07 +00:00
foreach ( $settings -> navlinks as $item )
2014-12-25 20:31:01 +00:00
{
2014-12-26 12:19:43 +00:00
if ( is_string ( $item ))
2014-12-25 20:31:01 +00:00
{
2014-12-26 12:19:43 +00:00
//the item is a string
switch ( $item )
{
//keywords
case " search " : //displays a search bar
2015-05-24 19:58:51 +00:00
$result .= " \t \t \t <form method='get' action='index.php' style='display: inline;'><input type='search' name='page' list='allpages' placeholder='Type a page name here and hit enter' /></form> \n " ;
2014-12-26 12:19:43 +00:00
break ;
2015-05-24 15:17:07 +00:00
2014-12-26 12:19:43 +00:00
//it isn't a keyword, so just output it directly
default :
2015-05-24 19:58:51 +00:00
$result .= " \t \t \t $item\n " ;
2014-12-26 12:19:43 +00:00
}
2014-12-25 20:31:01 +00:00
}
else
{
2015-05-24 19:58:51 +00:00
//output the item as a link to a url
$result .= " \t \t \t <a href=' " . str_replace ( " { page} " , $page , $item [ 1 ]) . " '> $item[0] </a> \n " ;
2014-12-25 20:31:01 +00:00
}
}
2015-05-24 15:17:07 +00:00
2015-05-24 19:58:51 +00:00
$result .= " \t \t </nav> " ;
2015-05-24 20:06:03 +00:00
return $result ;
2015-05-24 19:58:51 +00:00
}
public static function render_username ( $name )
{
2015-05-24 20:06:03 +00:00
global $settings ;
2015-05-24 19:58:51 +00:00
$result = " " ;
if ( in_array ( $name , $settings -> admins ))
$result .= $settings -> admindisplaychar ;
$result .= $name ;
return $result ;
}
public static function generate_all_pages_datalist ()
{
global $pageindex ;
2014-12-25 20:48:14 +00:00
2015-05-24 19:58:51 +00:00
$result = " <datalist id='allpages'> \n " ;
2014-12-25 20:31:01 +00:00
foreach ( $pageindex as $pagename => $pagedetails )
{
2015-05-24 20:06:03 +00:00
$result .= " \t \t \t <option value=' $pagename ' /> \n " ;
2014-12-25 20:31:01 +00:00
}
2015-05-24 19:58:51 +00:00
$result = " \t \t </datalist> " ;
return $result ;
2014-12-25 20:31:01 +00:00
}
}
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////// Slimdown /////////////////////////////////////////
2014-12-29 13:51:06 +00:00
////////////////////////////////////////////////////////////////////////////// %slimdown% //
2014-12-25 20:31:01 +00:00
////////////////////////////////////////////////////////////////////////////////////////////
/**
* Slimdown - A very basic regex - based Markdown parser . Supports the
* following elements ( and can be extended via Slimdown :: add_rule ()) :
*
* - Headers
* - Links
* - Bold
* - Emphasis
* - Deletions
* - Quotes
* - Inline code
* - Blockquotes
* - Ordered / unordered lists
* - Horizontal rules
*
* Author : Johnny Broadway < johnny @ johnnybroadway . com >
* Website : https :// gist . github . com / jbroadway / 2836900
* License : MIT
*/
/**
* Modified by Starbeamrainbowlabs ( starbeamrainbowlabs )
2014-12-25 20:48:14 +00:00
*
2014-12-25 20:31:01 +00:00
* Changed bold to use single asterisks
* Changed italics to use single underscores
* Added one to add the heading levels ( no < h1 > tags allowed )
* Added wiki style internal link parsing
* Added wiki style internal link parsing with display text
*/
class Slimdown {
public static $rules = array (
'/\r\n/' => " \n " , // new line normalisation
'/(#+)(.*)/' => 'self::header' , // headers
'/(\*)(.*?)\1/' => '<strong>\2</strong>' , // bold
'/(_)(.*?)\1/' => '<em>\2</em>' , // emphasis
'/\[\[([a-zA-Z0-9\_\- ]+)\|([a-zA-Z0-9\_\- ]+)\]\]/' => '<a href=\'index.php?page=\1\'>\2</a>' , //internal links with display text
'/\[\[([a-zA-Z0-9\_\- ]+)\]\]/' => '<a href=\'index.php?page=\1\'>\1</a>' , //internal links
'/\[([^\[]+)\]\(([^\)]+)\)/' => '<a href=\'\2\' target=\'_blank\'>\1</a>' , // links
'/\~\~(.*?)\~\~/' => '<del>\1</del>' , // del
'/\:\"(.*?)\"\:/' => '<q>\1</q>' , // quote
'/`(.*?)`/' => '<code>\1</code>' , // inline code
2014-12-29 13:51:06 +00:00
'/\n\s*(\*|-)(.*)/' => 'self::ul_list' , // ul lists
2014-12-25 20:31:01 +00:00
'/\n[0-9]+\.(.*)/' => 'self::ol_list' , // ol lists
'/\n(>|\>)(.*)/' => 'self::blockquote' , // blockquotes
'/\n-{3,}/' => " \n <hr /> " , // horizontal rule
'/\n([^\n]+)\n\n/' => 'self::para' , // add paragraphs
'/<\/ul>\s?<ul>/' => '' , // fix extra ul
'/<\/ol>\s?<ol>/' => '' , // fix extra ol
'/<\/blockquote><blockquote>/' => " \n " // fix extra blockquote
);
private static function para ( $regs ) {
$line = $regs [ 1 ];
$trimmed = trim ( $line );
if ( preg_match ( '/^<\/?(ul|ol|li|h|p|bl)/' , $trimmed )) {
return " \n " . $line . " \n " ;
}
return sprintf ( " \n <p>%s</p> \n " , $trimmed );
}
private static function ul_list ( $regs ) {
2014-12-29 13:51:06 +00:00
$item = $regs [ 2 ];
2014-12-25 20:31:01 +00:00
return sprintf ( " \n <ul> \n \t <li>%s</li> \n </ul> " , trim ( $item ));
}
private static function ol_list ( $regs ) {
$item = $regs [ 1 ];
return sprintf ( " \n <ol> \n \t <li>%s</li> \n </ol> " , trim ( $item ));
}
private static function blockquote ( $regs ) {
$item = $regs [ 2 ];
return sprintf ( " \n <blockquote>%s</blockquote> " , trim ( $item ));
}
private static function header ( $regs ) {
list ( $tmp , $chars , $header ) = $regs ;
$level = strlen ( $chars );
return sprintf ( '<h%d>%s</h%d>' , $level + 1 , trim ( $header ), $level + 1 );
}
2015-05-24 15:17:07 +00:00
2014-12-25 20:31:01 +00:00
/**
* Add a rule .
*/
public static function add_rule ( $regex , $replacement ) {
self :: $rules [ $regex ] = $replacement ;
}
/**
* Render some Markdown into HTML .
*/
public static function render ( $text ) {
foreach ( self :: $rules as $regex => $replacement ) {
if ( is_callable ( $replacement )) {
$text = preg_replace_callback ( $regex , $replacement , $text );
} else {
$text = preg_replace ( $regex , $replacement , $text );
}
}
return trim ( $text );
}
}
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////
//////////////// Functions ////////////////
///////////////////////////////////////////
//from http://php.net/manual/en/function.filesize.php#106569
2015-04-09 19:16:17 +00:00
//edited by Starbeamrainbowlabs
2014-12-25 20:31:01 +00:00
function human_filesize ( $bytes , $decimals = 2 )
{
2015-04-09 14:29:29 +00:00
$sz = [ " B " , " KB " , " MB " , " GB " , " TB " , " PB " , " EB " , " YB " , " ZB " ];
2014-12-25 20:31:01 +00:00
$factor = floor (( strlen ( $bytes ) - 1 ) / 3 );
return sprintf ( " %. { $decimals } f " , $bytes / pow ( 1024 , $factor )) . @ $sz [ $factor ];
}
//from http://snippets.pro/snippet/137-php-convert-the-timestamp-to-human-readable-format/
function human_time_since ( $time )
{
$timediff = time () - $time ;
$tokens = array (
31536000 => 'year' ,
2592000 => 'month' ,
604800 => 'week' ,
86400 => 'day' ,
3600 => 'hour' ,
60 => 'minute' ,
1 => 'second'
);
foreach ( $tokens as $unit => $text ) {
if ( $timediff < $unit ) continue ;
$numberOfUnits = floor ( $timediff / $unit );
return $numberOfUnits . ' ' . $text . (( $numberOfUnits > 1 ) ? 's' : '' ) . ' ago' ;
}
}
///////////////////////////////////////////
2015-04-11 17:30:01 +00:00
//////////////////////////
/// Module functions ///
//////////////////////////
// These functions are //
// used by modules to //
// register themselves //
// or new pages. //
//////////////////////////
$modules = []; // list that contains all the loaded modules
// function to register a module
function register_module ( $moduledata )
2014-12-25 20:31:01 +00:00
{
2015-05-08 19:30:32 +00:00
global $modules ;
//echo("registering module\n");
//var_dump($moduledata);
2015-04-11 17:30:01 +00:00
$modules [] = $moduledata ;
}
2014-12-26 12:44:03 +00:00
2015-04-11 17:30:01 +00:00
// function to register an action handler
$actions = new stdClass ();
function add_action ( $action_name , $func )
{
2015-05-08 19:30:32 +00:00
global $actions ;
//echo("adding $action_name\n");
2015-04-11 17:30:01 +00:00
$actions -> $action_name = $func ;
}
2014-12-27 19:59:32 +00:00
2015-04-11 17:30:01 +00:00
//////////////////////////////////////////////////////////////////
2014-12-29 11:41:43 +00:00
2015-04-11 17:30:01 +00:00
// %next_module% //
2014-12-29 11:41:43 +00:00
2015-04-11 17:30:01 +00:00
// execute each module's code
foreach ( $modules as $moduledata )
{
$moduledata [ " code " ]();
}
// make sure that the credits page exists
2015-05-08 19:30:32 +00:00
if ( ! isset ( $actions -> credits ))
2015-04-11 17:30:01 +00:00
{
2015-05-24 20:00:30 +00:00
exit ( page_renderer :: render_main ( " Error - $settings -> $sitename " , " <p>No credits page detected. The credits page is a required module!</p> " ));
2015-04-11 17:30:01 +00:00
}
2014-12-28 10:28:07 +00:00
2015-04-11 17:30:01 +00:00
// Perform the appropriate action
2015-05-08 19:30:32 +00:00
$action_name = strtolower ( $_GET [ " action " ]);
if ( isset ( $actions -> $action_name ))
2015-04-11 17:30:01 +00:00
{
2015-05-08 19:30:32 +00:00
$req_action_data = $actions -> $action_name ;
$req_action_data ();
2015-04-11 17:30:01 +00:00
}
else
{
2015-05-24 20:00:30 +00:00
exit ( page_renderer :: render_main ( " Error - $settings->sitename " , " <p>No action called " . strtolower ( $_GET [ " action " ]) . " has been registered. Perhaps you are missing a module?</p> " ));
2014-12-25 20:31:01 +00:00
}
?>