2023-01-25 22:29:19 +01:00
< ? php
/*
2023-06-28 18:27:49 +02:00
* spmenu - wiki
2023-01-25 22:29:19 +01:00
*
* Copyright ( C ) 2007 - 2011 Steven Frank < http :// stevenf . com />
2023-06-28 18:27:49 +02:00
* Copyright ( C ) 2023 speedie < speedie @ speedie . site >
2023-01-25 22:29:19 +01:00
*
2023-06-28 18:27:49 +02:00
* See LICENSE file for copyright and license details .
2023-01-25 22:29:19 +01:00
*/
spl_autoload_register ( function ( $class ){
require str_replace ( '\\' , DIRECTORY_SEPARATOR , ltrim ( $class , '\\' )) . '.php' ;
});
2023-01-31 22:34:58 +01:00
use md\MarkdownExtra ;
require_once " config.php " ;
2023-01-25 22:29:19 +01:00
2023-06-28 23:21:36 +02:00
function __ ( $label , $alt_word = null ) {
2023-06-28 18:21:07 +02:00
return is_null ( $alt_word ) ? $label : $alt_word ;
2023-01-31 22:34:58 +01:00
}
2023-01-25 22:29:19 +01:00
2023-06-28 18:04:36 +02:00
function truncate ( $text , $chars ) {
if ( strlen ( $text ) <= $chars ) {
return $text ;
}
$text = $text . " " ;
$text = substr ( $text , 0 , $chars );
$text = substr ( $text , 0 , strrpos ( $text , ' ' ));
$text = $text . " ... " ;
return $text ;
}
2023-06-28 23:21:36 +02:00
function printHeader ( $title , $action , $html , $bodyclass = " " ) {
2023-06-28 18:04:36 +02:00
// TODO: Improve this garbage, I suck at PHP and this is just stuff I found on the internet.
2023-06-28 19:28:22 +02:00
if ( META_DESC ) {
$nhtml = $html ;
$nhtml = preg_replace ( '@<p\b[^>]*>(?=.*?<a\b[^>]*>).*?<\@p>@si' , '' , $nhtml );
$nhtml = preg_replace ( '@<(li)[^>]*?>.*?</\\1>@si' , '' , $nhtml );
$nhtml = preg_replace ( '@<(ul)[^>]*?>.*?</\\1>@si' , '' , $nhtml );
$nhtml = strip_tags ( $nhtml );
$nhtml = preg_replace ( '/\s*$^\s*/m' , " \n " , $nhtml );
$nhtml = truncate ( $nhtml , 512 );
}
2023-06-28 18:04:36 +02:00
2023-06-28 23:21:36 +02:00
print " <!DOCTYPE html> \n " ;
2023-06-28 18:21:07 +02:00
print " <html lang= \" en \" > \n " ;
2023-06-28 19:28:22 +02:00
if ( ENABLE_HEAD ) {
print " <head> \n " ;
if ( META_ENC ) {
print " <meta charset= \" UTF-8 \" > \n " ;
}
if ( META_DESC ) {
print " <meta name= \" description \" content= \" $nhtml\ " > \n " ;
}
if ( META_VIEWPORT ) {
print " <meta name= \" viewport \" content= \" width=device-width, initial-scale=1 \" /> \n " ;
}
if ( ENABLE_FAVICON ) {
print " <link rel= \" icon \" href= \" /icons/fav.svg \" /> \n " ;
}
if ( ENABLE_CSS ) {
print " <link type= \" text/css \" rel= \" stylesheet \" href= \" " . BASE_URI . " / " . CSS_FILE . " \" /> \n " ;
}
if ( ENABLE_TITLE ) {
print " <title> " . PAGE_TITLE . " $title </title> \n " ;
}
print " </head> \n " ;
}
2023-01-31 22:34:58 +01:00
print " <body " . ( $bodyclass != " " ? " class= \" $bodyclass\ " " : " " ). " > \n " ;
}
2023-06-28 23:21:36 +02:00
function printFooter () {
2023-06-28 19:34:45 +02:00
if ( ENABLE_FOOTER_HARDCODED ) {
2023-06-28 19:28:22 +02:00
print " </body> \n " ;
print " <p class= \" footer \" >Wiki licensed under the <a href= \" https://git.speedie.site/speedie/spmenu-wiki/raw/branch/master/LICENSE \" >MIT</a> license. Articles and images licensed under the CC-BY-SA 4.0 license. <a href= \" https://git.speedie.site/speedie/spmenu-wiki \" >Source code</a></p> " ;
print " </html> " ;
2023-06-28 19:34:45 +02:00
} else if ( ENABLE_FOOTER_FILE && FOOTER_FILE != '' ) {
print " </body> \n " ;
include ( FOOTER_FILE );
2023-06-28 19:28:22 +02:00
}
2023-01-31 22:34:58 +01:00
}
2023-06-28 23:21:36 +02:00
function descLengthSort ( $val_1 , $val_2 ) {
2023-01-31 22:34:58 +01:00
$firstVal = strlen ( $val_1 );
$secondVal = strlen ( $val_2 );
return ( $firstVal > $secondVal ) ?
- 1 : ( ( $firstVal < $secondVal ) ? 1 : 0 );
2023-01-25 22:29:19 +01:00
}
2023-06-28 23:21:36 +02:00
function getAllPageNames ( $path = " " ) {
2023-01-31 22:34:58 +01:00
$filenames = array ();
$dir = opendir ( PAGES_PATH . " / $path " );
2023-06-28 23:21:36 +02:00
while ( $filename = readdir ( $dir ) ) {
if ( $filename [ 0 ] == " . " ) {
2023-01-31 22:34:58 +01:00
continue ;
}
2023-06-28 23:21:36 +02:00
if ( is_dir ( PAGES_PATH . " / $path / $filename " ) ) {
2023-01-31 22:34:58 +01:00
array_push ( $filenames , ... getAllPageNames ( " $path / $filename " ) );
continue ;
}
2023-06-28 23:21:36 +02:00
if ( preg_match ( " / " . PAGES_EXT . " $ / " , $filename ) != 1 ) {
2023-01-31 22:34:58 +01:00
continue ;
}
2023-06-28 23:21:36 +02:00
2023-01-31 22:34:58 +01:00
$filename = substr ( $filename , 0 , - ( strlen ( PAGES_EXT ) + 1 ) );
$filenames [] = substr ( " $path / $filename " , 1 );
}
closedir ( $dir );
return $filenames ;
2023-01-25 22:29:19 +01:00
}
2023-06-28 23:21:36 +02:00
function fileNameForPage ( $page ) {
2023-01-31 22:34:58 +01:00
return PAGES_PATH . " / $page . " . PAGES_EXT ;
2023-01-25 22:29:19 +01:00
}
2023-06-28 23:21:36 +02:00
function sanitizeFilename ( $inFileName ) {
2023-01-31 22:34:58 +01:00
return str_replace ( array ( '~' , '..' , '\\' , ':' , '|' , '&' ), '-' , $inFileName );
2023-01-25 22:29:19 +01:00
}
2023-06-28 23:21:36 +02:00
function pageURL ( $page ) {
2023-01-31 22:34:58 +01:00
return SELF . VIEW . " / " . str_replace ( " %2F " , " / " , str_replace ( " %23 " , " # " , urlencode ( sanitizeFilename ( $page ))));
}
2023-01-25 22:29:19 +01:00
2023-06-28 23:21:36 +02:00
function pageLink ( $page , $title , $attributes = " " ) {
2023-01-31 22:34:58 +01:00
return " <a href= \" " . pageURL ( $page ) . " \" $attributes > $title </a> " ;
}
2023-01-25 22:29:19 +01:00
2023-06-28 23:21:36 +02:00
function redirectWithMessage ( $page , $msg ) {
2023-01-31 22:34:58 +01:00
$_SESSION [ " msg " ] = $msg ;
header ( " HTTP/1.1 303 See Other " );
header ( " Location: " . pageURL ( $page ) );
exit ;
}
2023-01-25 22:29:19 +01:00
2023-06-28 23:21:36 +02:00
function checkedExecute ( & $msg , $cmd ) {
2023-01-31 22:34:58 +01:00
$returnValue = 0 ;
$output = '' ;
exec ( $cmd , $output , $returnValue );
2023-06-28 23:21:36 +02:00
if ( $returnValue != 0 ) {
2023-01-31 22:34:58 +01:00
$msg .= " <br/>Error executing command " . $cmd . " (return value: " . $returnValue . " ): " . implode ( " " , $output );
2023-01-25 22:29:19 +01:00
}
2023-06-28 23:21:36 +02:00
2023-01-31 22:34:58 +01:00
return ( $returnValue == 0 );
}
2023-01-25 22:29:19 +01:00
2023-06-28 23:21:36 +02:00
function gitChangeHandler ( $commitmsg , & $msg ) {
if ( ! GIT_COMMIT_ENABLED ) {
2023-01-31 22:34:58 +01:00
return ;
}
2023-06-28 23:21:36 +02:00
if ( checkedExecute ( $msg , " cd " . PAGES_PATH . " && git add -A && git commit -m " . escapeshellarg ( $commitmsg ))) {
2023-01-31 22:34:58 +01:00
checkedExecute ( $msg , " cd " . PAGES_PATH . " && git push " );
2023-01-25 22:29:19 +01:00
}
2023-01-31 22:34:58 +01:00
}
2023-01-25 22:29:19 +01:00
2023-06-28 23:21:36 +02:00
function toHTMLID ( $noid ) {
2023-01-31 22:34:58 +01:00
return str_replace ( " " , " - " , $noid );
2023-01-25 22:29:19 +01:00
}
2023-06-28 23:21:36 +02:00
function toHTML ( $inText ) {
2023-01-31 22:34:58 +01:00
$parser = new MarkdownExtra ;
$parser -> no_markup = true ;
$outHTML = $parser -> transform ( $inText );
2023-06-20 00:58:42 +02:00
2023-06-28 23:21:36 +02:00
preg_match_all ( " / \ [ \ [(.*?) \ ] \ ]/ " , $outHTML , $matches , PREG_PATTERN_ORDER );
for ( $i = 0 ; $i < count ( $matches [ 0 ]); $i ++ ) {
2023-01-31 22:34:58 +01:00
$fullLinkText = $matches [ 1 ][ $i ];
$linkTitleSplit = explode ( '|' , $fullLinkText );
$linkedPage = $linkTitleSplit [ 0 ]; // split away an eventual link text
$linkText = ( count ( $linkTitleSplit ) > 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 );
}
2023-06-28 23:21:36 +02:00
2023-01-31 22:34:58 +01:00
$outHTML = preg_replace ( " / \ { \ { (.*?) \ } \ }/ " , " <img src= \" " . BASE_URI . " /images/ \\ 1 \" alt= \" \\ 1 \" /> " , $outHTML );
2023-06-28 23:21:36 +02:00
preg_match_all ( " /<h([1-4])>(.*?)< \ /h \\ 1>/ " , $outHTML , $matches , PREG_PATTERN_ORDER );
for ( $i = 0 ; $i < count ( $matches [ 0 ]); $i ++ ) {
2023-01-31 22:34:58 +01:00
$prefix = " <h " . $matches [ 1 ][ $i ] . " > " ;
$caption = $matches [ 2 ][ $i ];
$suffix = substr_replace ( $prefix , " / " , 1 , 0 );
$outHTML = str_replace ( " $prefix $caption $suffix " ,
" $prefix <a id= \" " . toHTMLID ( $caption ) . " \" > $caption </a> $suffix " , $outHTML );
}
2023-06-28 23:21:36 +02:00
2023-01-31 22:34:58 +01:00
return $outHTML ;
2023-01-25 22:29:19 +01:00
}
2023-01-31 22:34:58 +01:00
$action = isset ( $_REQUEST [ 'action' ]) ? $_REQUEST [ 'action' ] : 'view' ;
$newPage = " " ;
$text = " " ;
$html = " " ;
2023-06-28 23:21:36 +02:00
if ( $action === 'view' ) {
2023-01-31 22:34:58 +01:00
$page = preg_match ( '@^/@' , @ $_SERVER [ " PATH_INFO " ]) ?
urldecode ( substr ( $_SERVER [ " PATH_INFO " ], 1 )) : urldecode ( @ $_REQUEST [ 'page' ]);
$page = sanitizeFilename ( $page );
2023-06-28 23:21:36 +02:00
if ( $page == " " ) {
2023-01-31 22:34:58 +01:00
$page = DEFAULT_PAGE ;
}
2023-06-28 23:21:36 +02:00
2023-01-31 22:34:58 +01:00
$filename = fileNameForPage ( $page );
2023-06-28 18:06:21 +02:00
2023-06-28 23:21:36 +02:00
if ( file_exists ( $filename ) ) {
2023-01-31 22:34:58 +01:00
$text = file_get_contents ( $filename );
2023-06-28 23:21:36 +02:00
} else {
2023-06-28 18:04:36 +02:00
$newPage = NULL ;
include ( '404.php' );
die ();
2023-01-31 22:34:58 +01:00
}
}
2023-06-28 18:06:21 +02:00
2023-01-31 22:34:58 +01:00
$oldgitmsg = " " ;
$triedSave = false ;
2023-06-28 23:21:36 +02:00
if ( $action === 'all' && ENABLE_ALL ) {
2023-01-31 22:34:58 +01:00
$pageNames = getAllPageNames ();
2023-01-25 22:29:19 +01:00
$filelist = array ();
2023-01-31 22:34:58 +01:00
$sortBy = isset ( $_REQUEST [ 'sortBy' ]) ? $_REQUEST [ 'sortBy' ] : 'name' ;
2023-06-28 23:21:36 +02:00
if ( ! in_array ( $sortBy , array ( 'name' , 'recent' ))) {
2023-01-31 22:34:58 +01:00
$sortBy = 'name' ;
2023-01-25 22:29:19 +01:00
}
2023-06-28 23:21:36 +02:00
if ( $sortBy === 'name' ) {
2023-01-31 22:34:58 +01:00
natcasesort ( $pageNames );
2023-06-28 23:21:36 +02:00
foreach ( $pageNames as $page ) {
2023-01-31 22:34:58 +01:00
$filelist [ $page ] = filemtime ( fileNameForPage ( $page ));
}
2023-06-28 23:21:36 +02:00
} else {
foreach ( $pageNames as $page ) {
2023-01-31 22:34:58 +01:00
$filelist [ $page ] = filemtime ( fileNameForPage ( $page ));
}
2023-06-28 23:21:36 +02:00
2023-01-31 22:34:58 +01:00
arsort ( $filelist , SORT_NUMERIC );
}
2023-06-28 23:21:36 +02:00
2023-06-28 23:08:33 +02:00
$html .= " <p> " . __ ( 'Total' ) . " : " . count ( $pageNames ) . " " . __ ( " articles " ) . " </p> " ;
2023-01-31 22:34:58 +01:00
$html .= " <table><thead> " ;
$html .= " <tr> " .
" <td> " . (( $sortBy != 'name' ) ? ( " <a href= \" " . SELF . " ?action=all&sortBy=name \" >Name</a> " ) : " <span class= \" sortBy \" > " . __ ( 'Name' ) . " </span> " ) . " </td> " .
" <td> " . (( $sortBy != 'recent' ) ? ( " <a href= \" " . SELF . " ?action=all&sortBy=recent \" > " . __ ( 'Modified' ) . " </a> " ) : " <span class= \" sortBy \" > " . __ ( 'Modified' ) . " </span> " ) . " </td> " .
" </tr></thead><tbody> " ;
$date_format = __ ( 'date_format' , TITLE_DATE );
2023-06-28 23:21:36 +02:00
foreach ( $filelist as $pageName => $pageDate ) {
2023-01-31 22:34:58 +01:00
$html .= " <tr> " .
" <td> " . pageLink ( $pageName , $pageName ) . " </td> " .
" <td valign= \" top \" ><nobr> " . date ( $date_format , $pageDate ) . " </nobr></td> " .
" </tr> \n " ;
}
$html .= " </tbody></table> \n " ;
2023-06-28 23:21:36 +02:00
} else if ( $action === 'search' && ENABLE_SEARCH ) {
2023-01-31 22:34:58 +01:00
$matches = 0 ;
$q = $_REQUEST [ 'q' ];
$html .= " <h1>Search: $q </h1> \n " ;
2023-01-25 22:29:19 +01:00
2023-06-28 23:21:36 +02:00
if ( trim ( $q ) != " " ) {
2023-01-31 22:34:58 +01:00
$html .= " <ul> \n " ;
$pagenames = getAllPageNames ();
$found = FALSE ;
$matchingPages = array ();
2023-06-28 23:21:36 +02:00
foreach ( $pagenames as $searchPage ) {
if ( $searchPage === $q ) {
2023-01-31 22:34:58 +01:00
$found = TRUE ;
}
2023-06-28 23:21:36 +02:00
if ( preg_match ( " / { $q } /i " , $searchPage )) {
2023-01-31 22:34:58 +01:00
array_unshift ( $matchingPages , $searchPage );
++ $matches ;
2023-06-28 23:21:36 +02:00
} else {
2023-01-31 22:34:58 +01:00
$text = file_get_contents ( fileNameForPage ( $searchPage ));
2023-06-28 23:21:36 +02:00
if ( preg_match ( " / { $q } /i " , $text ) ) {
2023-01-31 22:34:58 +01:00
$matchingPages [] = $searchPage ;
++ $matches ;
}
}
}
2023-06-28 23:21:36 +02:00
foreach ( $matchingPages as $page ) {
2023-01-31 22:34:58 +01:00
$link = pageLink ( $page , $page , ( $page === $q ) ? " class= \" literalMatch \" " : " " );
$html .= " <li> $link </li> \n " ;
}
2023-06-28 23:21:36 +02:00
if ( ! $found ) {
2023-01-31 22:34:58 +01:00
$html .= " <li> " . pageLink ( $q , __ ( 'Create page' ) . " ' $q ' " , " class= \" noexist \" " ) . " </li> " ;
2023-01-25 22:29:19 +01:00
}
2023-06-28 23:21:36 +02:00
2023-01-31 22:34:58 +01:00
$html .= " </ul> \n " ;
2023-01-25 22:29:19 +01:00
}
2023-06-28 23:21:36 +02:00
2023-01-31 22:34:58 +01:00
$html .= " <p> $matches " . __ ( 'matches' ) . " </p> \n " ;
2023-06-28 23:21:36 +02:00
} else {
2023-01-31 22:34:58 +01:00
$html .= empty ( $text ) ? '' : toHTML ( $text );
}
$datetime = '' ;
2023-01-25 22:29:19 +01:00
2023-06-28 23:21:36 +02:00
if (( $action === 'all' ) && ENABLE_ALL ) {
2023-01-31 22:34:58 +01:00
$title = __ ( " All " );
2023-06-28 23:21:36 +02:00
} else if ( $action === 'search' && ENABLE_SEARCH ) {
2023-01-31 22:34:58 +01:00
$title = __ ( " Search " );
2023-06-28 23:21:36 +02:00
} else if ( $filename != '' ) {
2023-06-20 00:58:42 +02:00
$title = $page ;
2023-01-31 22:34:58 +01:00
$date_format = __ ( 'date_format' , TITLE_DATE );
2023-06-28 23:21:36 +02:00
if ( $date_format ) {
2023-01-31 22:34:58 +01:00
$datetime = " <span class= \" titledate \" > " . date ( $date_format , @ filemtime ( $filename )) . " </span> " ;
}
2023-06-28 23:21:36 +02:00
} else {
2023-01-31 22:34:58 +01:00
$title = __ ( $action );
}
header ( " Cache-Control: no-cache, must-revalidate " ); // HTTP/1.1
header ( " Expires: Mon, 26 Jul 1997 05:00:00 GMT " ); // Date in the past
2023-06-28 18:04:36 +02:00
printHeader ( $title , $action , $html );
2023-06-28 19:28:22 +02:00
if ( ENABLE_TITLEBAR ) {
print " <div class= \" titlebar \" ><span class= \" title \" > $title </span> $datetime " ;
print " </div> \n " ;
}
if ( ENABLE_TOOLBAR ) {
print " <div class= \" toolbar \" > \n " ;
if ( ENABLE_HOME_ICON ) {
print " <a href= \" " . SELF . " \" ><img src= \" /icons/home.svg \" alt= \" " . __ ( DEFAULT_PAGE ) . " \" title= \" " . __ ( DEFAULT_PAGE ) . " \" class= \" icon \" ></a> \n " ;
}
if ( ENABLE_ALL_ICON ) {
print " <a href= \" " . SELF . " ?action=all \" ><img src= \" /icons/list.svg \" alt= \" " . __ ( 'All' ) . " \" title= \" " . __ ( 'All' ) . " \" class= \" icon \" ></a> \n " ;
}
if ( ENABLE_SEARCH ) {
print " <form method= \" post \" action= \" " . SELF . " ?action=search \" > \n " ;
print " <input class= \" search \" placeholder= \" " . __ ( 'Search' ) . " \" size= \" 20 \" id= \" search \" type= \" text \" name= \" q \" /> \n </form> \n " ;
}
print " </div> \n " ;
}
2023-06-28 23:21:36 +02:00
if ( SIDEBAR_PAGE != '' && ENABLE_SIDEBAR ) {
2023-01-31 22:34:58 +01:00
print " <div class= \" sidebar \" > \n \n " ;
$sidebarFile = fileNameForPage ( SIDEBAR_PAGE );
2023-06-28 23:21:36 +02:00
if ( file_exists ( $sidebarFile )) {
2023-01-31 22:34:58 +01:00
$text = file_get_contents ( $sidebarFile );
2023-06-28 23:21:36 +02:00
} else {
2023-01-31 22:34:58 +01:00
$text = __ ( 'Sidebar file could not be found' ) . " ( $sidebarFile ) " ;
2023-01-25 22:29:19 +01:00
}
2023-06-28 23:21:36 +02:00
2023-01-31 22:34:58 +01:00
print toHTML ( $text );
print " </div> \n " ;
}
2023-06-28 23:21:36 +02:00
2023-01-31 22:34:58 +01:00
print " <div class= \" main \" > \n \n " ;
2023-06-28 23:21:36 +02:00
if ( isset ( $_SESSION [ 'msg' ]) && $_SESSION [ 'msg' ] != '' ) {
2023-01-31 22:34:58 +01:00
print " <div class= \" note \" > " . $_SESSION [ 'msg' ] . " </div> " ;
unset ( $_SESSION [ 'msg' ]);
2023-01-25 22:29:19 +01:00
}
2023-06-28 23:21:36 +02:00
2023-01-25 22:29:19 +01:00
print " $html\n " ;
2023-01-31 22:34:58 +01:00
print " </div> \n " ;
2023-06-28 23:21:36 +02:00
2023-01-31 22:34:58 +01:00
printFooter ();