<?php
#################################################################################
#                                                                               #
#   This program is free software; you can redistribute it and/or modify        #
#   it under the terms of the GNU General Public License as published by        #
#   the Free Software Foundation; either version 2 of the License, or           #
#   (at your option) any later version.                                         #
#                                                                               #
#   This program is distributed in the hope that it will be useful,             #
#   but WITHOUT ANY WARRANTY; without even the implied warranty of              #
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
#   GNU General Public License for more details.                                #
#                                                                               #
#   You should have received a copy of the GNU General Public License           #
#   along with this program; if not, write to the Free Software                 #
#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA   #
#                                                                               #
#################################################################################

// Installation Instructions:
//
// Just save wiki.phps as wiki.php in your web directory and make sure that
// your web server is able to read and write the file. If you want a backup
// functionality, create a folder named 'history' at the place where wiki.php
// lives. Don't forget to give proper write rights to this folder.
//
// If you work with htacces, you can define an array named AUTHORS with a 
// list of persons which are allowed to modify this wiki:
//   - when no array named AUTHORS is defined, everybody can write. This is default.
//   - when an array named AUTHORS is defined but empty, nobody can write
//
// examples: 
//   $AUTHORS = array('buck','jack');  // only buck and jack bauer can modify the wiki
//   $AUTHORS = array();               // nobody can edit the wiki, mr. nobody can't also :-)
//   //$AUTHORS = array();             // everybody can edit the wiki
//   $FREE4ALL = array('public site'); // in order to enable a page which is editable by everyone, 
                                       // you can define this array which containing a string with the page title
?>

<?php
class ErrorHandler {
    public static function 
reportError($error) {
        print 
'<b>Error:</b> '.$error.'<br>';
    }
}

class 
CodeInterpreter {
    private static 
$instance;
    private 
$wiki;

    private function 
__construct($wiki) {
        
$this->wiki $wiki;
    }

    public static function 
getInstance($wiki) {
        if(!isset(
$instance) || $instance == null) {
            
$instance = new CodeInterpreter($wiki);
        }
        return(
$instance);
    }

    public function 
parseCode($string) {
        
$string $this->resolveInternalLink($string);
        
$string $this->compileImage($string);
        
$string $this->compileExternalLink($string);
        
$string $this->compileExternalCustomLink($string);
        
$string $this->compileMailTo($string);
        
$string $this->compileBoldText($string);
        
$string $this->compileItalicText($string);
        
$string $this->compileUnderlineText($string);
        
$string $this->compileHeader($string);
        
$string $this->compileEnumeration($string);
        return(
$string);
    }

    private function 
resolveInternalLink($string) {
        
preg_match_all('/\[\[.*\]\]/'$string$hits);
        foreach(
$hits[0] as $hit) {
            
$title preg_replace('/\[\[/'''$hit);
            
$title preg_replace('/\]\]/'''$title);
            if(
$this->wiki->getPage($title)->getContent() == '...') { $class 'newpagelink';}
            else {
$class 'link';}
            
$string preg_replace("/\[\[$title\]\]/"
                    
'<a class="'.$class.'" href="?id='.$this->wiki->getPage($title)->getId().'">'.$title.'</a>',$string);
        }
        return(
$string);
    }

    private function 
compileExternalLink($string) {
        
$string=eregi_replace("\[url\]([^\[]+)\[/url\]",
                
"<a class=\"external\" href=\"\\1\" target=\"_blank\">\\1</a>",$string);
        return(
$string);
    }

    private function 
compileExternalCustomLink($string) {
        
$string=eregi_replace('\[url=\\\&quot;','[url="',$string);
        
$string=eregi_replace('\\\&quot;\]','"]',$string);
        
$string=eregi_replace('\[url="([^\"]+)"]([^\[]+)\[/url\]',
                
"<a class=\"external\" href=\"\\1\" target=\"_blank\">\\2</a>",$string);
        return(
$string);
    }

    private function 
compileMailTo($string) {
        
$string eregi_replace("\[mail\]([^\[]+)\[/mail\]","<a href=\"mailto:\\1\">\\1</a>",$string);
        return(
$string);
    }

    private function 
compileImage($string) {
        
$string eregi_replace("\[img\]([^\[]+)\[/img\]","<img src=\"\\1\" border=\"0\">",$string);
        return(
$string);
    }

    private function 
compileBoldText($string) {
        
$string eregi_replace("\[b\]([^\[]+)\[/b\]","<b>\\1</b>",$string);
        return(
$string);
    }

    private function 
compileItalicText($string) {
        
$string eregi_replace("\[i\]([^\[]+)\[/i\]","<i>\\1</i>",$string);
        return(
$string);
    }

    private function 
compileUnderlineText($string) {
        
$string eregi_replace("\[u\]([^\[]+)\[/u\]","<u>\\1</u>",$string);
        return(
$string);
    }

    private function 
compileHeader($string) {
        
$string preg_replace('/[\n]+\!\!([^\ \n].*)[\n]+/e'"'\n\n<p class=\"header2\">'.'$1'.'</p>'"$string);
        
$string preg_replace('/\!([^\ \n].*)[\n]+/e'"'<p class=\"header\">'.'$1'.'</p>'"$string);
        return(
$string);
    }

    private function 
compileEnumeration($string) {
        
$string eregi_replace("\*([^\n]+)\n","<li>\\1</li>"$string);
        
$string eregi_replace("<li>([^\n\n]+)<\/li>","<ul>\\0</ul>"$string);
        return(
$string);
    }

}

class 
Page {
    private 
$id;
    private 
$title;
    private 
$content;
    private 
$wiki;

    public function 
__construct($id$title$content$wiki) {
        
$this->id $id;
        
$this->title $title;
        
$this->content $content;
        
$this->wiki $wiki;
    }

    public function 
getId() { return($this->id); }
    public function 
getTitle() { return($this->title); }
    public function 
getContent() { return($this->content); }
    public function 
getHTMLContent() { 
        return(
nl2br(CodeInterpreter::getInstance($this->wiki)->parseCode($this->content)));
    }
    public function 
setTitle($title) { $this->title htmlspecialchars(str_replace("\r\n""\n"$title)); }
    public function 
setContent($content) { $this->content htmlspecialchars(str_replace("\r\n""\n"$content)); }

}


class 
Wiki {
    private 
$fileName;
    private 
$data;
    private 
$xmlString;
    private 
$pages = array();

    public function 
__construct($fileName) {
        
$this->fileName $fileName;
        
$this->readDataFromFile();
        
$this->extractXMLStringFromData();
        
$this->createPagesFromXML();
    }

    public function 
getPage($pageidentifier) {
        if(
is_integer($pageidentifier)) { // search with id
            
if(!isset($this->pages[$pageidentifier])) {
                
// this feature is dangerous, return null
                //$this->pages[(int) $pageidentifier] = new Page((int)$pageidentifier, 'New Site', '...', $this);
                //$this->saveWikiToFile();
                
return;
            }
            return(
$this->pages[$pageidentifier]);
        } elseif(
is_string($pageidentifier)) { //search with title
            
foreach($this->pages as $page) {
                if(
$page->getTitle() == $pageidentifier) {
                    return(
$page);
                }
            }
            for(
$i 1true$i++) {
                if(!
array_key_exists($i$this->pages)) { 
                    break; 
                }
            }
            
$this->pages[$i] = new Page($i$pageidentifier'...'$this);
            
$this->saveWikiToFile();
            return(
$this->pages[$i]);
        }
    }

    public function 
readDataFromFile() {
        
$this->data "";
        if(
is_file($this->fileName)) {
            
$handle fopen ($this->fileName"r");
            while (!
feof($handle)) {
                
$this->data .= fgets($handle4096);
            }
            
fclose ($handle);
        }
    }

    public function 
findXMLStartPosition() {
        
$i 0;
        while(
$i strlen($this->data)) {
            
$i strpos ($this->data'<<' $i);
            if(
substr($this->data$i+22) == '>>') {
                return(
$i+4);
            }
            
$i++;
        }
    }

    public function 
findXMLStopPosition() {
        
$i strlen($this->data);
        while(
$i >= 0) {
            
$schrumpf substr($this->data0$i);
            if(
substr($schrumpf$i-22) == '>>') {
                if(
substr($schrumpf$i-42) == '<<') { 
                    return(
$i-4);
                } 
            }
            
$i--;
        }
    }

    public function 
extractXMLStringFromData() {
        
$this->xmlString substr($this->data$this->findXMLStartPosition(), 
                
$this->findXMLStopPosition() - $this->findXMLStartPosition());    
    }

    public function 
extractXMLStringFromMemory() {
        
$xmlstr '<!--<<';
        
$xmlstr .= ">>";
        
$xmlstr .= "<pages>\n";
        foreach(
$this->pages as $page) {
            
$xmlstr .= '<page id="'.$page->getId().'" title="'.htmlspecialchars($page->getTitle()).'">'
                
htmlspecialchars($page->getContent())."</page>\n";
        }
        
$xmlstr .= "</pages>\n";
        
$xmlstr .= '<<';
        
$xmlstr .= '>>-->';
        return(
$xmlstr);
    }

    public function 
createPagesFromXML() {
        
$xml = new SimpleXMLElement($this->xmlString);
        foreach(
$xml->page as $page) {
            
$this->pages[(int)$page['id']] = new Page($page['id'], $page['title'], $page$this);
        }
    }

    public function 
saveWikiToFile() {
        
$stringToWrite substr($this->data,0,
                
$this->findXMLStartPosition()-8) . $this->extractXMLStringFromMemory();
        if(
is_writable($_SERVER['SCRIPT_FILENAME'])) {
            
$handle fopen($_SERVER['SCRIPT_FILENAME'], "w+");
            
fwrite($handle$stringToWrite);
            
fclose($handle); 
        } else {
ErrorHandler::reportError($_SERVER['SCRIPT_FILENAME'].' not writable');}
        if(
is_writable(dirname($_SERVER['SCRIPT_FILENAME']).'/history')) {
            
$handle fopen(dirname($_SERVER['SCRIPT_FILENAME']).'/history/'.time().'.php'"w+");
            
fwrite($handle$stringToWrite);
            
fclose($handle); 
        } 
//else {ErrorHandler::reportError(dirname($_SERVER['SCRIPT_FILENAME']).'/history'.' not writable');}
    
}

    public function 
editPage($id$title$content) {
        foreach(
$this->pages as $page) {
            if(
$page->getTitle() == $title && $page->getId() != $id) {
                
ErrorHandler::reportError("this pagetitle is already used by another page!");
                return;
            }
        }
        
$this->pages[$id]->setTitle($title);
        
$this->pages[$id]->setContent($content);
        
$this->saveWikiToFile();
    }
}
?>

<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Yada Yada Yada Wiki</title>
    <style type="text/css">

        body {
            background-color: #f3f3f3; 
            color: black;
            font-style: normal;
            font-size: 12px;
            line-height: 16px;
            font-family: sans-serif, arial;
            margin:0px;
        }
        td {
            color: black;
            font-style: normal;
            font-size: 12px;
            font-family: sans-serif, arial;
        }
        ul {
            list-style-type: disc;
        }
        .footer {
            color: gray;
            clear:left;
            margin-top:1em;
            margin-right:20px;
            text-align:right;
            font-size: 12px;
        }
        .outertable {
            background-color: #f3f3f3; border-width: 0px; border-color: #999999; border-style: solid; 
        }
        .innertable {
            background-color: white; border-width: 1px; border-color: #9f9f9f; border-style: solid; 
        }
        .title { 
            border-bottom: 1px; border-color: #999999; border-style: solid; 
            border-top: none; border-left: none; border-right: none;
            padding-bottom: 5px; font-size: 30px; font-weight:bold;
        }
        .edit { 
            padding: 0px; font-size: 30px; font-weight:bold;
        }
        .niceformelement {
            border: 1px solid gray; width:80px;
        }
        .shyline {
            border-bottom: 1px; border-color: #999999; border-style: dotted; 
            border-top: none; border-left: none; border-right: none;
        }
        a:link { color: blue; text-decoration:none; }
        a:visited { color: blue; text-decoration:none;}
        a:hover { color: blue; text-decoration:none;}
        a:active { color: blue; text-decoration:none;}
        a.newpagelink:link { color: red; text-decoration:none; }
        a.newpagelink:visited { color: red; text-decoration:none;}
        a.newpagelink:hover { color: red; text-decoration:none;}
        a.newpagelink:active { color: red; text-decoration:none;}
        a.external:link { color: blue; text-decoration:underline; }
        a.external:visited { color: blue; text-decoration:underline;}
        a.external:hover { color: blue; text-decoration:underline;}
        a.external:active { color: blue; text-decoration:underline;}
        .header{font-size: 18px; font-weight:bold; margin-bottom: 18px; margin-top: 0px;}
        .header2{font-size: 12px; font-weight:bold; margin-bottom: 12px; margin-top: 0px;}
        
    </style>
</head>
<body>
<?php
/*foreach($_GET as $key => $value) {
    print "GET: $key => $value <br>";
}
foreach($_POST as $key => $value) {
    print "POST: $key => $value <br>";
}*/

if(!isset($_GET['id'])) {$GET_ID 1;} else {$GET_ID $_GET['id'];}
$wiki = new Wiki($_SERVER['SCRIPT_FILENAME']);
if(
$GET_ID <= || $wiki->getPage((int)$GET_ID) == null) {
    
$GET_ID 1;
}
if(
$_POST['edit'] == 'true') {
    
$wiki->editPage($_POST['id'], $_POST['title'], $_POST['content']);
}
if(
$_POST['editmenu'] == 'true') {
    
$wiki->editPage(0$_POST['title'], $_POST['content']);
}
?>

<table width="100%" class="outertable" cellspacing="20px" cellpadding="0px">
    <tr>
        <td class="title" colspan="2">
            <?php print $wiki->getPage((int)$GET_ID)->getTitle();?>
        </td>
    </tr>
    <tr>
        <td valign="top" width="150px">
            <table width="100%" class="innertable" cellspacing="0px" cellpadding="10px">
            <tr>
            <td>
            <?php
                
if($_POST['modifymenu'] == 'true') {
                    print 
'<form method="post">';
                    print 
'<input type="hidden" name="editmenu" value="true">';
                    print 
'<input type="hidden" name="modifymenu" value="false">';
                    print 
'<input type="hidden" name="id" value="'.$wiki->getPage(0)->getId().'">';
                    print 
'<textarea class="text" cols="18" rows="10" name="content" WRAP="PHYSICAL">';
                    print 
stripslashes($wiki->getPage(0)->getContent());
                    print 
'</textarea>';
                    print 
"<br>";
                    print 
'<input type="submit" value="save" class="niceformelement">';
                    print 
"</form>";
                } else {
                    print 
stripslashes($wiki->getPage(0)->getHTMLContent());
                    if(((isset(
$AUTHORS) && in_array(getenv('REMOTE_USER'), $AUTHORS) || !isset($AUTHORS)))
                            || (isset(
$FREE4ALL) && in_array($wiki->getPage((int)$GET_ID)->getTitle(),$FREE4ALL))) 
                    {
                        print 
'<form style="text-align:left" method="post">';
                        print 
'<p class="shyline"></p>';
                        print 
'<input type="hidden" name="modifymenu" value="true"/>';
                        print 
'<input type="submit" value="edit" class="niceformelement"/>';
                        print 
'</form>';
                    }
                }
            
?>
            </td>
            </tr>
            </table>
        </td>
        <td colspan="1" valign="top">
            <table width="100%" class="innertable" cellspacing="0px" cellpadding="10px">
            <tr>
            <td>
            <?php
                
if($_POST['modify'] == 'true') {
                    print 
'<form method="post">';
                    print 
'<input type="hidden" name="edit" value="true">';
                    print 
'<input type="hidden" name="modify" value="false">';
                    print 
'<input type="hidden" name="id" value="'.$wiki->getPage((int)$GET_ID)->getId().'">';
                    print 
'<input type="text" name="title" value="'.$wiki->getPage((int)$GET_ID)->getTitle().'">';
                    print 
"<br>";
                    print 
'<textarea class="text" cols="100" rows="15" name="content" WRAP="PHYSICAL">';
                    print 
stripslashes($wiki->getPage((int)$GET_ID)->getContent());
                    print 
'</textarea>';
                    print 
"<br>";
                    print 
'<input type="submit" value="save" class="niceformelement">';
                    print 
"</form>";
                } else {
                    print 
stripslashes($wiki->getPage((int)$GET_ID)->getHTMLContent());
                    if((isset(
$AUTHORS) && in_array(getenv('REMOTE_USER'), $AUTHORS) || !isset($AUTHORS))) {
                        print 
'<form style="text-align:left;" method="post">';
                        print 
'<p class="shyline"></p>';
                        print 
'<input type="hidden" name="modify" value="true"/>';
                        print 
'<input type="submit" value="edit" class="niceformelement"/>';
                        print 
'</form>';
                    }
                }
            
?>
            </td>
            </tr>
            </table>
        </td>
    </tr>
</table>
<div class="footer">
<!--<a href="<?php print basename($_SERVER['SCRIPT_FILENAME']).'s'?>">Yada Yada Yada Wiki</a> -->
<a href="http://www.pburkhalter.net/yadawiki.php">Yada Yada Yada Wiki 0.0.6</a>
</div>
</body>
</html>

<!--<<>><pages>
<page id="0" title="">[[New Page]]
[[Help]]
</page>
<page id="1" title="New Page">...</page>
<page id="2" title="Help">!This is a Header
!!Images
[img]http://www.rosalux.de/cms/uploads/pics/gnu.png[/img]

!!Links
An internal link to this Wiki: [[New Page]]
(a red link means site is empty, but created)

An internal link to this Wiki: [[Help]]
(a blue link means site is not empty and created)

An external link [url]http://www.pburkhalter.net[/url]
A [url=\&amp;quot;http://www.pburkhalter.net\&amp;quot;]external[/url] link to the same destination
An [url=\&amp;quot;http://www.pburkhalter.net\&amp;quot;][img]http://www.pburkhalter.net/images/external_image_link.png[/img][/url] to the same destination

!!Formating
[b]Bold[/b]
[i]Italic[/i]
[u]Underlined[/u]

!!Enumeration
* banana
* apple
* kiwi

</page>
</pages>
<<>>-->