Difference between revisions of "Xmlwiki.php"

From Organic Design wiki
Line 129: Line 129:
 
$wgTitle = Title::newFromText('Sorry, the requested article was not readable.');
 
$wgTitle = Title::newFromText('Sorry, the requested article was not readable.');
 
}
 
}
 
 
# ---------------------------------------------------------------------------------------------------------------------- #
 
# INPUT HOOK
 
 
# Parse and process input from forms
 
function xwInputHook() {
 
 
global $xwArticle, $xwArticleXML, $xwArticleTitle, $xwWritable, $_REQUEST;
 
global $xwDebug, $xwSave, $xwEdit, $action, $xwUserName, $wgArticle;
 
if ($xwDebug) xwMessage('xwInputHook()','green');
 
 
# If not writable, change action to view
 
if (!$xwWritable && ($action != 'view')) {
 
xwMessage('Sorry, article not writable, action changed to "view".', 'red');
 
$action = 'view';
 
$xwSave = $xwEdit = false;
 
}
 
 
# Parse POST for XPath inputs
 
# - Form-input-name is "xw:[[@]node]:XPathQuery" which directs the value into xwArticle (if DOM)
 
# - if "node" exists, then a new element (or att if "@node") is created for the value
 
# - hidden-inputs can direct input-handlers into the transform list
 
foreach ($_REQUEST as $k => $v) {
 
if (is_object($xwArticleXML) && preg_match("/^xw:(@?)(\\w*):(.+)$/", $k, $m)) {
 
list(, $att, $node, $xpath) = $m;
 
foreach (xwXPathQuery($xwArticleXML, $xpath) as $result)
 
if ($node) {
 
# create new element/attribute in result-node
 
if ($att) $node = $xwArticleXML->create_attribute($node, $v);
 
else {
 
$node = $xwArticleXML->create_element($node);
 
$node->set_content($v);
 
}
 
$result->append_child($node);
 
}
 
else $result->set_content($v); # node not set, just replace current-result-value
 
}
 
}
 
 
# if it's a pseudo-namespace...
 
if (preg_match('/^(xml)|(sys):/', $xwArticleTitle)) {
 
 
# wpSave should be valid XML to be saved
 
if ($xwSave) {
 
xwDomificate($wpSave);
 
if (!is_object($wpSave)) {
 
xwMessage('A meta-article must be valid XML! changing action to "edit"', 'red');
 
$action='edit';
 
}
 
}
 
 
}
 
 
}
 
 
# ---------------------------------------------------------------------------------------------------------------------- #
 
# OUTPUT HOOK
 
 
# Generate output to send back to client
 
# - if article is not XML, then wiki's parsed content is used
 
function xwOutputHook() {
 
 
global $wgOut, $wgUser, $xwParserHookCalled, $xwSkinHookCalled, $xwDebug;
 
global $xwArticle, $xwArticleXML, $xwArticleTitle, $xwReadable, $xwWritable;
 
global $xwView, $xwPreview, $xwSave, $xwRaw, $xwUserLinks, $xwArticleLinks;
 
if ($xwDebug) xwMessage('xwOutputHook()','green');
 
 
# Generate output page
 
$wgUser->setOption('skin', 'xwskin');
 
$wgOut->output();
 
 
# NOTE - Why not move this into INPUT-HOOK???????? - or maybe not....?
 
# If saving, check the publishing list
 
if ($xwSave) {
 
 
# Check publish-list and process if any
 
if (false) {
 
xwMessage('Publishing...');
 
# Publish each item
 
foreach ($xwArticlePublish as $url) {
 
if ($FH = fopen($url, 'a')) {
 
# ftp example: ftp://user:password@example.com/file.txt
 
fwrite($FH, $xwArticle);
 
fclose($FH);
 
xwMessage("Article published to $url");
 
}
 
else xwMessage("Failed to publish to $url", 'red');
 
}
 
}
 
 
# Check mirror-list and process if any
 
# - allows articles in separate wiki's to be syncronised
 
# - does rudimentary security by sending a salt and response being a hash of the password generated from the salt
 
# - this could be done for login too using ECMA-MD5 on browser
 
if (false) {
 
xwMessage('Mirroring...');
 
}
 
}
 
 
 
# Insert messages into final html and output
 
if ($xwDebug) {
 
if (!$xwParserHookCalled) xwMessage('PARSER-HOOK was not called','green');
 
if (!$xwSkinHookCalled) xwMessage('SKIN-HOOK was not called','green');
 
if (is_object($xwArticleXML)) xwMessage($xwArticleXML->dump_mem(true),'purple');
 
}
 
xwAddMessages();
 
print $xwArticle;
 
}
 
 
# ---------------------------------------------------------------------------------------------------------------------- #
 
# PARSER HOOK
 
 
function xwParserHook(&$text) {
 
 
global $xwRaw, $xwParserHookCalled, $xwDebug, $xwArticleTitle, $xwArticle;
 
if ($xwDebug) xwMessage('xwParserHook(TEXT)','green');
 
$xwParserHookCalled = true;
 
$transformed = false;
 
 
# If this text-fragment is our article, apply transforms
 
if ((strncmp($text, $xwArticle, 100) == 0) || (strncmp($text, xwArticleContent($xwArticleTitle), 100) == 0)) {
 
if ($xwDebug) xwMessage("PARSER-HOOK: \"$xwArticleTitle\" text-fragment recognised and intercepted.");
 
$xwArticle = $text; # needed because xwTransform works on global article
 
# If attempted xml encountered, try to domificate and transform
 
if (preg_match("/^<\\?xml/i", $xwArticle)) {
 
$transformed = true;
 
xwDomificateArticle($xwArticle, 'ParserHook/text');
 
xwTransformArticle();
 
}
 
# If not a 'raw' request, try some Geshi on
 
if (!$xwRaw) {
 
global $wgGeshiSyntaxSettings;
 
if (!is_object($wgGeshiSyntaxSettings)) require_once('extensions/geshi/geshi.php');
 
if ($lang = xwArticleType($xwArticleTitle, $xwArticle)) {
 
if ($xwDebug) xwMessage("Geshi: This is \"$lang\".");
 
# Replace tabs with spaces (better than geshi)
 
$xwArticle = preg_replace_callback("/^(.*?)(\\t+)/m", 'xwReplaceTabs', $xwArticle);
 
# Set up a geshi-parser
 
$geshi = new GeSHi($xwArticle, $lang == 'xslt' ? 'xml' : $lang, 'extensions/geshi/geshi');
 
$geshi->set_header_type(GESHI_HEADER_DIV);
 
#$geshi->enable_line_numbers(GESHI_NORMAL_LINE_NUMBERS);
 
#@$geshi->set_line_style('color:#aaaaaa');
 
#@$geshi->set_code_style('color:black');
 
@$geshi->set_keyword_group_style(1, 'color:blue', true);
 
@$geshi->set_keyword_group_style(2, 'color:blue', true);
 
@$geshi->set_keyword_group_style(3, 'color:blue', true);
 
@$geshi->set_comments_style(1,'font-style: italic; color:#d00000;',true);
 
@$geshi->set_comments_style(2,'font-style: italic; color:#d00000;',true);
 
@$geshi->set_comments_style(3,'font-style: italic; color:#d00000;',true);
 
@$geshi->set_escape_characters_style('color:red',true);
 
@$geshi->set_brackets_style('color:black',true);
 
@$geshi->set_strings_style('color:#008080',true);
 
@$geshi->set_numbers_style('color:black',true);
 
@$geshi->set_methods_style('color:black',true);
 
@$geshi->set_symbols_style('color:black',true);
 
@$geshi->set_regexps_style('color:green',true);
 
# Do the parse
 
$xwArticle = preg_replace("/^<div.*?>/", '<div class="xwcode">', $geshi->parse_code());
 
$transformed = true;
 
}
 
elseif ($xwDebug) xwMessage('Geshi: Not my problem.');
 
}
 
$text = $xwArticle;
 
}
 
elseif ($xwDebug) xwMessage('Parsing other content');
 
 
# Return this back to wiki-parser so it can do wiki-markup if it wasn't one of ours
 
return $transformed;
 
}
 
 
# Converts tabs to spaces better than geshi
 
function xwReplaceTabs($m) { return $m[1].str_repeat(' ',strlen($m[2])*4-strlen($m[1])%4); }
 
 
# ---------------------------------------------------------------------------------------------------------------------- #
 
# SKIN HOOK
 
 
# If attempted xml encountered, try to domificate and transform
 
# - Raw requests don't get here
 
function xwSkinHook(&$tmpl) {
 
 
global $xwArticle, $xwTemplate, $xwDebug, $xwSkinHookCalled;
 
if ($xwDebug) xwMessage('xwSkinHook(TEMPLATE)','green');
 
$xwSkinHookCalled = true;
 
$xwTemplate = $tmpl;
 
$xwArticle = $xwTemplate->data['bodytext'];
 
#$xslt = xwArticleContent('xmlwiki.xslt');
 
 
# Do xmlWiki page-layout transform
 
 
xwTransformPageLayout(); # should be: xwApplyXSLT($xwArticle, $xslt, 'xmlwiki.xslt');
 
 
}
 
 
# ---------------------------------------------------------------------------------------------------------------------- #
 
# ARTICLE FUNCTIONS
 
 
# Retreive wiki-article as raw text
 
function xwArticleContent($articleTitle) {
 
# Return with results if already cached
 
global $xwArticleCache, $xwDebug;
 
if ($xwDebug) xwMessage("xwArticleContent(\"$articleTitle\")",'blue');
 
if (isset($xwArticleCache[$articleTitle])) return $xwArticleCache[$articleTitle];
 
# Get wiki article content (or use global if no article passed)
 
# - using getContentWithoutUsingSoManyDamnGlobals() because getContent() fucks up nested-article-reads
 
if ($article = new Article(Title::newFromText($articleTitle)))
 
$article = $article->getContentWithoutUsingSoManyDamnGlobals();
 
if ($article == '(There is currently no text in this page)') return false;
 
if ($articleTitle) $xwArticleCache[$articleTitle] = $article;
 
return $article;
 
}
 
 
# Decide kind of article from content and title
 
function xwArticleType($title, $article) {
 
# Name based matches
 
if (ereg('\\.php$', $title)) return 'php';
 
if (ereg('\\.css$', $title)) return 'css';
 
if (ereg('\\.as$', $title)) return 'actionscript';
 
if (ereg('\\.py$', $title)) return 'python';
 
if (ereg('\\.java$', $title)) return 'java';
 
if (ereg('\\.((cpp)|(h))$', $title)) return 'cpp';
 
if (ereg('\\.js$', $title)) return 'javascript';
 
if (ereg('\\.css$', $title)) return 'css';
 
# Content based matches
 
if (preg_match("/^<\\?xml.+?\\?>\\s*<xsl:stylesheet/i", $article)) return 'xslt';
 
if (ereg('^<\\?xml', $article)) return 'xml';
 
if (ereg('^<\\?html', $article)) return 'html4strict';
 
if (ereg('^#![/a-zA-Z0-9]+\\/perl', $article)) return 'perl';
 
if (ereg('^#![/a-zA-Z0-9]+sh', $article)) return 'bash';
 
}
 
 
# Convert passed article to a DOM object
 
# - Article is unchanged if not valid XML
 
function xwDomificateArticle(&$article, $id = '') {
 
global $xwDebug;
 
if ($xwDebug) xwMessage("xwDomificateArticle(XML,$id)",'blue');
 
ob_start();
 
if ($dom = domxml_open_mem($article)) $article = $dom;
 
else {
 
# Could not convert, extract error messages from output
 
xwMessage("Failed :-(", 'red');
 
xwExtractMessages();
 
}
 
ob_end_clean();
 
}
 
 
# Reduce article to a string if it's a DOM object
 
# - ie if all xslt's had xml-output-method
 
function xwUndomificateArticle(&$article, $id = '') {
 
if (!is_object($article)) return false;
 
global $xwDebug;
 
if ($xwDebug) xwMessage("xwUndomificate(DOM,$id)",'blue');
 
# TODO:
 
# Validate, report errors
 
# xwApplyXSLT($article, $xslt) if xml referrs one
 
# Convert DOM back to XML if still an object
 
if (is_object($article)) $article = $article->dump_mem(true);
 
return true;
 
}
 
 
# Transform an article object
 
# - Article is undomificated on exit
 
# - Article remains unchanged if not DOM
 
function xwTransformArticle() {
 
global $xwDebug, $xwArticle, $xwArticleXML, $xwArticleTitle;
 
# xml:article must be an object...
 
if (is_object($xwArticleXML)) {
 
$docType = $xwArticleXML->doctype();
 
# ...and must be xmlwiki:* doctype
 
if (ereg('^xmlwiki:', $docType->name)) {
 
$root = $xwArticle->document_element();
 
if ($xwDebug) xwMessage("xwTransformArticle()",'blue');
 
# Loop thru transforms applying each
 
foreach ($root->get_elements_by_tagname('transform') as $tElement) {
 
$tName = $tElement->get_content();
 
# Transform is not local, get transform-article and apply to current-article-object
 
if ($tText = xwArticleContent($tName)) {
 
# Get transform type
 
$tType = xwArticleType($tName, $tText);
 
if ($tType == 'xslt') xwApplyXSLT($xwArticle, $tText, $tName);
 
elseif ($tType == 'php') {
 
# TODO: php, check perms and execute (trapping errors for reporting - unless fatal)
 
if ($perms_check_out_ok = true) {
 
ob_start();
 
eval("?>$tText<?");
 
xwExtractMessages();
 
ob_end_clean();
 
}
 
}
 
elseif ($tType == 'css') xwMessage("CSS's from transform-list aren't applied yet :-(", 'red');
 
}
 
else xwMessage("No such transform-article \"$tName\"!", 'red');
 
}
 
}
 
else xwMessage("Could not transform: xml:article must be doctype:xmlwiki!",'red');
 
}
 
else xwMessage("xwTransformArticle(NON-OBJECT)",'red');
 
# If article is still a DOM object, stringify it once and for all
 
if (is_object($xwArticle)) xwUndomificateArticle($xwArticle, $xwArticleTitle);
 
return true;
 
}
 
 
# Apply XSLT to article-dom
 
# - if output-method is html, article will get stringified
 
function xwApplyXSLT(&$article, &$xslt, $id = '') {
 
global $xwDebug;
 
if ($xwDebug) xwMessage("xwApplyXSLT(DOM,$id)",'blue');
 
ob_start();
 
if ($tObject = domxml_xslt_stylesheet($xslt)) {
 
$tResult = $tObject->process($article);
 
# If output-method is html, use XSLT's dump_mem to create an html-string
 
if (preg_match('/<xsl:output +?method *= *"html"/i', $xslt))
 
$tResult = $tObject->result_dump_mem($tResult);
 
}
 
xwExtractMessages();
 
ob_end_clean();
 
if (isset($tResult)) $article = $tResult; else return false;
 
return true;
 
}
 
 
# Return result set of an XPath query on passed DOM-object
 
function xwXPathQuery(&$dom, $query) {
 
global $xwDebug;
 
if ($xwDebug) xwMessage("xwXPathQuery(DOM,\"$query\")",'blue');
 
ob_start();
 
$context = $dom->xpath_new_context();
 
if ($xpath = $context->xpath_eval($query)) $result = $xpath->nodeset;
 
else {
 
xwMessage('Query Failed! :-(', 'red');
 
$result = array();
 
}
 
xwExtractMessages();
 
ob_end_clean();
 
return $result;
 
}
 
 
# Surrounds the article with HTML structural page-layout containing a ref to xmlwiki.css
 
# - TEMP: see skin-hook
 
function xwTransformPageLayout() {
 
 
global $xwMsgToken, $xwArticle, $xwTemplate, $xwDebug, $xwWritable;
 
if ($xwDebug) xwMessage("xwTransformPageLayout()",'blue');
 
$tmpl = &$xwTemplate;
 
$data = &$tmpl->data;
 
$doctype = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ';
 
$doctype .= '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">';
 
$html = '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="';
 
$html .= htmlspecialchars($data['lang']).'" lang="'.htmlspecialchars($data['lang']).'" dir="';
 
$html .= htmlspecialchars($data['dir']).'">';
 
 
# Head
 
$head = '<head><meta http-equiv="Content-Type" content="'.htmlspecialchars($data['mimetype']);
 
$head .= '; charset='.htmlspecialchars($data['charset']).'" />'.$data['headlinks'];
 
$head .= '<link rel="stylesheet" type="text/css" href="/wiki/index.php?title=xmlwiki.css&action=raw&gen=css" />';
 
 
$head .= '<title>'.htmlspecialchars($data['pagetitle']).'</title>';
 
$head .= '</head>';
 
 
# Body opening tag
 
$body = '<body ';
 
if ($data['body_ondblclick']) $body .= 'ondblclick="'.htmlspecialchars($data['body_ondblclick']).'" ';
 
if ($data['nsclass']) $body .= 'class="'.htmlspecialchars($data['nsclass']).'"';
 
$body .= '>';
 
 
# Content
 
$content = '<div id="column-content">';
 
$content .= '<div id="content"><a name="top" id="contentTop"></a>';
 
if ($data['sitenotice']) $content .= '<div id="siteNotice">'.$data['sitenotice'].'</div>';
 
$content .= '<h1 class="firstHeading">'.htmlspecialchars($data['title']).'</h1>';
 
$content .= '<div id="bodyContent">';
 
$content .= '<h3 id="siteSub">'.htmlspecialchars($tmpl->translator->translate('tagline')).'</h3>';
 
$content .= '<div id="contentSub">'.$data['subtitle'].'</div>';
 
if ($data['undelete']) $content .= '<div id="contentSub">'.$data['undelete'].'</div>';
 
if ($data['newtalk']) $content .= '<div class="usermessage">'.$data['newtalk'].'</div>';
 
$content .= "<!-- start content -->$xwArticle"; # <---- Actual article content inserted here
 
if ($data['catlinks']) $content .= '<div id="catlinks">'.$data['catlinks'].'</div>';
 
$content .= '<!-- end content --><div class="visualClear"></div>';
 
$content .= '</div></div></div>';
 
 
# Action-links (remove edit link if not writable)
 
$actions = '<div id="p-cactions" class="portlet"><h5>Views</h5><ul>';
 
foreach ($data['content_actions'] as $key => $action) {
 
#if ($key == '
 
#if (!(ereg('action=edit$', $action['href'])&&!$xwWritable)) {
 
$actions .= '<li id="ca-'.htmlspecialchars($key).'"';
 
if ($action['class']) $actions .= ' class="'.htmlspecialchars($action['class']).'"';
 
$href = '<a href="'.htmlspecialchars($action['href']).'">'.htmlspecialchars($action['text']).'</a>';
 
$actions .= ">$href</li>";
 
# }
 
}
 
$actions .= '</ul></div>';
 
 
# Personal-links
 
$personal = '<div class="portlet" id="p-personal">';
 
$personal .= '<h5>'.htmlspecialchars($tmpl->translator->translate('personaltools')).'</h5>';
 
$personal .= '<div class="pBody"><ul>';
 
foreach ($data['personal_urls'] as $key => $item) {
 
$personal .= '<li id="pt-'.htmlspecialchars($key).'">';
 
$href = '<a href="'.htmlspecialchars($item['href']).'"';
 
if (!empty($item['class'])) $href .= 'class="'.htmlspecialchars($item['class']).'"';
 
$href .= '>'.htmlspecialchars($item['text']).'</a>';
 
$personal .= "$href</li>";
 
}
 
$personal .= "</ul></div></div>";
 
 
# Logo
 
$logo = '<div class="portlet" id="p-logo">';
 
$logo .= '<a style="background-image: url('.htmlspecialchars($data['logopath']).');" ';
 
$logo .= 'href="'.htmlspecialchars($data['nav_urls']['mainpage']['href']).'" ';
 
$logo .= 'title="'.htmlspecialchars($tmpl->translator->translate('mainpage')).'"></a></div>';
 
$logo .= '<script type="text/javascript"> if (window.isMSIE55) fixalpha(); </script>';
 
 
# Navigation
 
$nav = '<div class="portlet" id="p-nav">';
 
$nav .= '<h5>'.htmlspecialchars($tmpl->translator->translate('navigation')).'</h5>';
 
$nav .= '<div class="pBody"><ul>';
 
foreach ($data['navigation_urls'] as $navlink) {
 
$nav .= '<li id="'.htmlspecialchars($navlink['id']).'">';
 
$nav .= '<a href="'.htmlspecialchars($navlink['href']).'">'.htmlspecialchars($navlink['text']).'</a>';
 
$nav .= '</li>';
 
}
 
$nav .= '</ul></div></div>';
 
 
# Search
 
$search = '<div id="p-search" class="portlet">';
 
$search .= '<h5><label for="searchInput">'.htmlspecialchars($tmpl->translator->translate('search')).'</label></h5>';
 
$search .= '<div class="pBody">';
 
$search .= '<form name="searchform" action="'.htmlspecialchars($data['searchaction']).'" id="searchform">';
 
$search .= '<input id="searchInput" name="search" type="text"';
 
if ($tmpl->haveMsg('accesskey-search')) $search .= ' accesskey="';
 
$search .= htmlspecialchars($tmpl->translator->translate('accesskey-search')).'"';
 
if (isset($data['search'])) $search .= ' value="'.htmlspecialchars($data['search']).'"';
 
$search .= ' />';
 
$search .= '<input type="submit" name="go" class="searchButton" id="searchGoButton" value="';
 
$search .= htmlspecialchars($tmpl->translator->translate('go')).'" />';
 
$search .= '&nbsp;<input type="submit" name="fulltext" class="searchButton" value="';
 
$search .= htmlspecialchars($tmpl->translator->translate('search')).'" />';
 
$search .= '</form></div></div>';
 
 
# Toolbox
 
$toolbox = '<div class="portlet" id="p-tb">';
 
$toolbox .= '<h5>'.htmlspecialchars($tmpl->translator->translate('toolbox')).'</h5>';
 
$toolbox .= '<div class="pBody"><ul>';
 
if ($data['notspecialpage']) {
 
foreach (array('whatlinkshere', 'recentchangeslinked') as $special ) {
 
$href = '<a href="'.htmlspecialchars($data['nav_urls'][$special]['href']).'">';
 
$href .= htmlspecialchars($tmpl->translator->translate($special)).'</a>';
 
$toolbox .= "<li id=\"t-'$special'\">$href</li>";
 
}
 
}
 
if ($data['feeds']) {
 
$toolbox .= '<li id="feedlinks">';
 
foreach ($data['feeds'] as $key => $feed) {
 
$toolbox .= '<span id="feed-'.htmlspecialchars($key).'">';
 
$toolbox .= '<a href="'.htmlspecialchars($feed['href']).'">'.htmlspecialchars($feed['text']).'</a>';
 
$toolbox .= '&nbsp;</span>';
 
}
 
$toolbox .= '</li>';
 
}
 
foreach (array('contributions', 'emailuser', 'upload', 'specialpages') as $special ) {
 
if ($data['nav_urls'][$special]) {
 
$href = '<a href="'.htmlspecialchars($data['nav_urls'][$special]['href']).'">';
 
$href .= htmlspecialchars($tmpl->translator->translate($special)).'</a>';
 
$toolbox .= "<li id=\"t-$special\">$href</li>";
 
}
 
}
 
$toolbox .= '</ul></div></div>';
 
 
# Language
 
$language = '';
 
if ($data['language_urls']) {
 
$language .= '<div id="p-lang" class="portlet">';
 
$language .= '<h5>'.htmlspecialchars($tmpl->translator->translate('otherlanguages')).'</h5>';
 
$language .= '<div class="pBody"><ul>';
 
foreach ($data['language_urls'] as $langlink) {
 
$href = '<a href="'.htmlspecialchars($langlink['href']).'">'.$langlink['text'].'</a>';
 
$language .= "<li>$href</li>";
 
}
 
$language .= '</ul></div></div>';
 
}
 
 
# Footer
 
$footer = '<div id="footer"><ul id="f-list">';
 
if ($data['lastmod']) $footer .= '<li id="f-lastmod">'.$data['lastmod'].'</li>';
 
if ($data['viewcount']) $footer .= '<li id="f-viewcount">'.$data['viewcount'].'</li>';
 
if ($data['credits']) $footer .= '<li id="f-credits">'.$data['credits'].'</li>';
 
if ($data['copyright']) $footer .= '<li id="f-copyright">'.$data['copyright'].'</li>';
 
if ($data['about']) $footer .= '<li id="f-about">'.$data['about'].'</li>';
 
if ($data['disclaimer']) $footer .= '<li id="f-disclaimer">'.$data['disclaimer'].'</li>';
 
$footer .= '</ul></div>';
 
 
# Return assembled parts
 
$xwArticle = " $doctype
 
$html
 
$head
 
$body
 
<table border=\"0\" cellpadding=\"10\" cellspacing=\"1\">
 
<tr>
 
<td valign=\"top\" bgcolor=\"#cccccc\">
 
<img src=\"/wiki/xmlwiki.jpg\" />
 
$search
 
$nav
 
$toolbox
 
</td>
 
<td width=\"100%\" valign=\"top\" bgcolor=\"#cccccc\">
 
$personal$actions$xwMsgToken$content
 
</td>
 
</tr>
 
<td colspan=\"2\" bgcolor=\"#cccccc\">$footer</td>
 
<tr>
 
</table>
 
</body>
 
</html>
 
";
 
}
 
 
# ---------------------------------------------------------------------------------------------------------------------- #
 
# UTILITY FUNCTIONS
 
 
# Append messages to content
 
function xwAddMessages() {
 
global $xwArticle, $xwMessages, $xwMsgToken;
 
if (count($xwMessages)) {
 
$msg = '<div class="portlet" id="p-xwmessages"><h5>There are Messages</h5></div>';
 
$msg .= '<div class="xwmessage"><ul><li>'.join("</li><li>", $xwMessages).'</li></ul></div>';
 
$xwArticle = ereg_replace($xwMsgToken, $msg, $xwArticle);
 
}
 
}
 
 
# Extract error-messages from captured output and put in proper message-queue
 
function xwExtractMessages() {
 
$err = preg_replace("/<.+?>/", "", ob_get_contents());
 
$err = preg_replace('/ in .+? on line.+?[0-9]+/', '', $err);
 
$err = preg_replace('/Warning.+?\\(\\): /', '', $err);
 
foreach (split("\n", $err) as $msg) if ($msg) xwMessage("$msg", 'red');
 
}
 
 
# Add message to queue
 
function xwMessage($msg, $col = '#000080') {
 
global $xwMessages;
 
$msg = htmlentities($msg);
 
return $xwMessages[] = "<font color=\"$col\">$msg</font>";
 
}
 
 
# Print list of passed object's methods and properties
 
function xwCheckoutObject($obj) {
 
if (is_object($obj)) {
 
print strtoupper("<br>$obj properties:<br>");
 
foreach (get_object_vars($obj) as $k=>$v) print htmlentities("$k => $v")."<br>";
 
print strtoupper("<br>$obj methods:<br>");
 
foreach (get_class_methods($obj) as $k=>$v) print "$v<br>";
 
}
 
if (is_array($obj)) {
 
print strtoupper("<br>Array content:<br>");
 
foreach ($obj as $k=>$v) print "$k => $v<br>";
 
}
 
die;
 
}
 
 
?>
 

Revision as of 22:06, 18 June 2005

<?php

  1. xmlWiki - MediaWiki XML Hack
  2. Nad - 2005-05-18

$xwDebug=1;

  1. INIT
  2. SECURITY
  3. INPUT HOOK
  4. OUTPUT HOOK
  5. PARSER HOOK
  6. SKIN HOOK
  7. ARTICLE FUNCTIONS
  8. UTILITY FUNCTIONS
  1. ---------------------------------------------------------------------------------------------------------------------- #
  1. TODO:
  2. - Undomificate: validation, xslt
  3. - Transform: check perms on php-execution
  4. Publish:
  5. - xml:article - holds article publish-list
  6. - mirror/wiki-sync
  7. Transforms:
  8. - xml:article - now transforms are in here (main article is now like <body>)
  9. - so we don't do the "its one of ours" thing anymore
  1. LATER:
  2. - allow XIncludes to build large docs from others
  3. - allow docBook and DSSSL content
  4. - Maybe only use XML transforms and use PHP via PI's
  1. ---------------------------------------------------------------------------------------------------------------------- #
  2. INIT
  1. Exit if not included from index.php

defined('MEDIAWIKI') or die('xmlwiki.php must be included from MediaWiki\'s index.php!');

  1. Allows Geshi to be installed by PARSER-HOOK if not installed th usual way already

if (!@is_object($wgGeshiSyntaxSettings)) $wgGeshiSyntaxSettings = false;

  1. Otherwise set up xmlWiki global environment ready for input and output processing

$xwMessages = array(); $xwEdit = isset($_REQUEST['action']) && ($_REQUEST['action'] == 'edit'); $xwView = (!isset($_REQUEST['action']) || (isset($_REQUEST['action']) && ($_REQUEST['action'] == 'view'))); $xwRaw = isset($_REQUEST['action']) && ($_REQUEST['action'] == 'raw'); $xwPreview = isset($_REQUEST['wpPreview']); $xwSave = isset($_REQUEST['wpSave']); $xwUserName = $wgUser->mName; $xwUserGroups = array(strtolower($xwUserName), 'anyone', 'everyone', 'nobody', 'world'); $xwArticleReadableBy = array('anyone'); $xwArticleWritableBy = array('anyone'); $xwArticle = $xwPreview ? $wgRequest->gettext('wpTextbox1') : $wgArticle->getContent(false); $xwArticleTitle = $wgTitle->getPrefixedURL(); $xwArticleCache = array(); $xwArticleLinks = array(); $xwUserLinks = array(); $xwMetaArticle = false; $xwMsgToken = ; $xwTemplate = null; $xwParserHookCalled = false; $xwSkinHookCalled = false;

  1. ---------------------------------------------------------------------------------------------------------------------- #
  2. SECURITY
  1. Not currently used: R/W by user, for xmlWiki prefs etc

if ($xwUserXML = xwArticleContent(strtolower("xml:$xwUserName"))) xwDomificateArticle($xwUserXML, "xml:$xwUserName");

  1. R/W by admin only, holds users groups and other system info like stats
  2. - no sys:user means "anyone" in group "everyone" as far as perms goes

if ($xwUserSYS = xwArticleContent(strtolower("sys:$xwUserName"))) xwDomificateArticle($xwUserSYS, "sys:$xwUserName");

  1. If sys:user exists, get users' group-list

if (is_object($xwUserSYS)) { $xwRoot = $xwUserSYS->document_element(); if (count($xwList = $xwRoot->get_elements_by_tagname('groups'))) $xwUserGroups = array_merge($xwUserGroups, split(',', strtolower($xwList[0]->get_content()))); }

  1. - Security info is: owner, read-groups, write-groups (default values are "world")
  2. - Users and groups are interchangeable
  3. - Default user is "anyone", default group is "everyone"

if (ereg('^xml:(.+)$', $xwArticleTitle)) { # This is an xml-pseudo-namespace # - its perms apply to its 'parent' and to itself aswell $xwXML = $xwArticle; xwDomificateArticle($xwXML, $xwArticleTitle); if (is_object($xwXML)) { $xwRoot = $xwXML->document_element(); if (count($xwList = $xwRoot->get_elements_by_tagname('read'))) $xwArticleReadableBy = split(',', strtolower($xwList[0]->get_content())); if (count($xwList = $xwRoot->get_elements_by_tagname('write'))) $xwArticleWritableBy = split(',', strtolower($xwList[0]->get_content())); } } elseif (ereg('^sys:(.+)$', $xwArticleTitle)) { # This is a sys-pseudo-namespace # - only admin can read/write sys: $xwArticleReadableBy = $articleWritableBy = array('admin'); } else { # This is a normal article, get xml:article if ($xwArticleXML = xwArticleContent(strtolower("xml:$xwArticleTitle"))) xwDomificateArticle($xwArticleXML, "xml:$xwArticleTitle"); if (is_object($xwArticleXML)) { $xwRoot = $xwArticleXML->document_element(); if (count($xwList = $xwRoot->get_elements_by_tagname('read'))) $xwArticleReadableBy = split(',', $xwList = strtolower($xwList[0]->get_content())); if (count($xwList = $xwRoot->get_elements_by_tagname('write'))) $xwArticleWritableBy = split(',', $xwList = strtolower($xwList[0]->get_content())); } }

  1. Set perms for this request

$xwReadable = 0 < count(array_intersect($xwArticleReadableBy, $xwUserGroups)); $xwWritable = 0 < count(array_intersect($xwArticleWritableBy, $xwUserGroups)); if ($xwDebug) { xwMessage('Groups: '.join(', ', $xwUserGroups)); xwMessage("Readable ($xwReadable): ".join(', ', $xwArticleReadableBy)); xwMessage("Writable ($xwWritable): ".join(', ', $xwArticleWritableBy)); }

  1. Divert to access-denied article if not readable

if (!$xwReadable) { xwMessage('no'); $action = 'view'; $xwSave = $xwEdit = false; $wgTitle = Title::newFromText('Sorry, the requested article was not readable.'); }