Difference between revisions of "Xmlwiki.php"

From Organic Design wiki
Line 238: Line 238:
 
xwAddMessages();
 
xwAddMessages();
 
print $xwArticle;
 
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');
 +
 
}
 
}

Revision as of 22:07, 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.'); }


  1. ---------------------------------------------------------------------------------------------------------------------- #
  2. INPUT HOOK
  1. 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'; } }

}

}

  1. ---------------------------------------------------------------------------------------------------------------------- #
  2. OUTPUT HOOK
  1. Generate output to send back to client
  2. - 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; }

  1. ---------------------------------------------------------------------------------------------------------------------- #
  2. 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.*?>/", '

', $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; }

  1. Converts tabs to spaces better than geshi

function xwReplaceTabs($m) { return $m[1].str_repeat(' ',strlen($m[2])*4-strlen($m[1])%4); }

  1. ---------------------------------------------------------------------------------------------------------------------- #
  2. SKIN HOOK
  1. If attempted xml encountered, try to domificate and transform
  2. - 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');

}