Wiki.php
<?php

class Wiki
{
    function 
matchWord($word)
    {
        return 
preg_match('^[A-Z]+[a-z]+[A-Za-z0-9]*$'$word);
    }

    function 
formatWord($word)
    {
        
$word preg_replace('/([a-z])([A-Z])/''\1 \2'$word);
        
$word preg_replace('/([a-zA-Z])(\d)/''\1 \2'$word);
        return 
$word;
    }

    function 
process($contents)
    {
        
// First, substitute macros
        
if (preg_match_all('/{([a-z-]+)\s*([^}]*?)}/s'$contents$matches)) {
            list(
$strings$funcs$args) = $matches;
            for (
$i 0$i sizeof($strings); $i++) {
                
$replace Wiki::runMacro($funcs[$i], $args[$i]);
                
$contents str_replace($strings[$i], $replace$contents);
            }
        }
        
// Finally, add Wiki-links
        
if (preg_match_all('#(.*?)\b([A-Z]+[a-z]+[A-Z\d][A-Za-z\d]*)\b(.*?)#s'$contents$matches)) {
            list(, 
$pre_text$nodes$post_text) = $matches;
            
$self $_SERVER['SCRIPT_NAME'];
            
$tmp '';
            for (
$i 0$i sizeof($nodes); $i++) {
                
$spaced Wiki::formatWord($nodes[$i]);
                
$replace "<a href=\"{$self}/{$nodes[$i]}\">$spaced</a>";
                
$tmp .= $pre_text[$i] . $replace $post_text[$i];
            }
            
$contents $tmp;
        }
        return 
nl2br($contents);
    }

    function 
nodeExists($node)
    {
        static 
$cache = array();
        if (isset(
$cache[$node])) {
            return 
$cache[$node];
        }
        global 
$dbh;
        
$id $dbh->getOne('SELECT id FROM nodes WHERE name = ?'$node);
        if (
$id !== null) {
            
$cache[$node] = $id;
        }
        return (bool)
$id;
    }


    function 
runMacro($func$arg)
    {
        global 
$dbh;
        
$ret '';
        switch (
$func) {
            case 
'list':
                
$arg str_replace('?''_'$arg);
                
$arg str_replace('*''%'$arg);
                
$sql "SELECT name FROM nodes WHERE name LIKE '$arg'";
                
// catch errors
                
$dbh->pushErrorHandling(PEAR_ERROR_RETURN);
                
$nodes $dbh->getCol($sql0);
                
$dbh->popErrorHandling();
                if (
is_array($nodes)) {
                    
$ret implode("\n"$nodes);
                }
                break;
            case 
'phpdoc':
                
$url "http://php.net/$arg";
                
$ret "<a href=\"$url\">$arg (php.net)</a>";
                break;
            case 
'pear-listall':
                include_once 
"PEAR/Config.php";
                include_once 
"PEAR/Remote.php";
                
$config = &PEAR_Config::singleton();
                @
$remote =& new PEAR_Remote($config);
                @
$packages $remote->call('package.listAll');
                
$ret implode("\n"array_keys($packages));
                break;
            case 
'recent':
                include_once 
"Date.php";
                
$arg = (int)$arg;
                
$res $dbh->limitQuery("SELECT name, mtime FROM nodes ORDER BY mtime DESC"0$arg);
                
$ret '';
                while (
$res->fetchInto($tmp)) {
                    
$date = new Date($tmp['mtime']);
                    
$ret .= "$tmp[name] " $date->getDate() . "\n";
                }
                
$res->free();
                break;
        }
        return 
$ret;
    }

    function 
displayEditor(&$tpl$node)
    {
        
$tpl->loadTemplatefile('edit.tpl');
        if (
$node != '__new__') {
            
$contents Wiki::getNodeContents($node);
        }
        if (
$contents === null) {
            
// new node
            
$tpl->setVariable("NewOrEdit""New");
            
$nodename "new node";
            if (
$node == '__new__') {
                
$node "";
            }
            
$new true;
        } else {
            
$tpl->setVariable("NewOrEdit""Edit");
            
$nodename Wiki::formatWord($node);
            
$new false;
        }
        
$tpl->setVariable("NodeName"$nodename);
        
$tpl->setVariable("PageTitle""PEAR Wiki Editor: $nodename");
        
$form = &Wiki::buildEditForm($node$new);
        
$tpl->setVariable("EditForm"$form->toHtml());
        
$tpl->show();
    }

    function 
displayNode(&$tpl$node)
    {
        if (
$node == 'RootNode') {
            
// hack to display a default Root node
            
$contents Wiki::getNodeContents($node);
            if (
$contents === null) {
                
$contents '(Empty Root Node)';
            }
        }
        
$nodename Wiki::formatWord($node);
        if (empty(
$contents)) {
            
$contents Wiki::getNodeContents($node);
        }
        if (
$contents === null) {
            
$tpl->loadTemplatefile('404.tpl');
        } else {
            
$tpl->loadTemplatefile('node.tpl');
            
$tpl->setVariable('Contents'Wiki::process($contents));
        }
        
$tpl->setVariable('User'$GLOBALS['a']->getUsername());
        
$tpl->setVariable('Self'$_SERVER['SCRIPT_NAME']);
        
$tpl->setVariable('Version'PEAR_WIKI_VERSION);
        
$tpl->setVariable('Node'$node);
        
$tpl->setVariable('NodeName'$nodename);
        
$tpl->setVariable('PageTitle'"PEAR Wiki: $nodename");
        
$tpl->show();
    }

    function 
getNodeContents($node)
    {
        global 
$dbh;
        if (empty(
$dbh)) {
            return 
null;
        }
        return 
$dbh->getOne('SELECT content FROM nodes WHERE name = ?',
                            array(
$node));
    }

    function &
buildEditForm($node$new)
    {
        include_once 
'HTML/QuickForm.php';
        
$form =& new HTML_QuickForm('editForm''POST');
        
$form->clearAllTemplates();
        
$constants['node'] = $node;
        
$defaults['contents'] = Wiki::getNodeContents($node);
        
$form->setConstants($constants);
        
$form->setDefaults($defaults);
        
$form->addData('<table border="0" cellpadding="0" cellspacing="2" bgcolor="#eeeeee">');
        
$form->addData('<tr><td colspan="2" align="left">Node:');
        if (
$new) {
            
$form->addElement('text''node'null'size="60"');
            
$form->addRule('node''Must have a node name''required'null'client');
        } else {
            
$form->addElement('hidden''node'$node);
            
$form->addData("<tt>$node</tt>");
        }
        
$form->addData('</td></tr><tr><td align="center" colspan="2">');
        
$form->addElement('textarea''contents'null'cols="60" rows="20" wrap="virtual"');
        
$form->addData('</td></tr><tr><td align="center" colspan="2">');
        
$form->addElement('submit''mode''submit');
        
$form->addData('</td></tr></table>');
        return 
$form;
    }

    function 
storeNode($node$contents)
    {
        global 
$dbh$logger$a;
        
$now time();
        
$sql 'UPDATE nodes SET content = ?, mtime = ? WHERE name = ?';
        
$dbh->query($sql, array($contents$now$node));
        if (
$dbh->affectedRows() == 0) {
            
$sql 'INSERT INTO nodes VALUES(?,?,?,?)';
            
$id $dbh->nextId('nodes');
            
$ret $dbh->query($sql, array($node$id$contents$now));
            
$logger->log($a->getUsername() . " added $node");
        } else {
            
$logger->log($a->getUsername() . " modified $node");
        }
        return 
$ret;
    }

    function 
deleteNode($node)
    {
        global 
$dbh$logger$a;
        
$sql 'DELETE FROM nodes WHERE name = ?';
        
$logger->log($a->getUsername() . " deleted $node");
        return 
$dbh->query($sql, array($node));
    }
}

?>