Difference between revisions of "Xmlwiki.php"

From Organic Design wiki
Line 19: Line 19:
 
#    - layouts would come with a separate collection of CSS's
 
#    - layouts would come with a separate collection of CSS's
 
#    - CSS's need to themselves be collections of colours, headings etc
 
#    - CSS's need to themselves be collections of colours, headings etc
 
  
 
# LATER:
 
# LATER:

Revision as of 01:25, 31 May 2005

<?php
# xmlWiki - MediaWiki XML Hack
# Nad - 2005-05-18
#
# Output Hook: Transforms output generated by MediaWiki and 
#
# - Adds basic content-management, permissions and publishing to the MediaWiki
# - All articles are XML
# - Impliment by calling this script directly in browser

# FOR NOW:
# - only change rendering, not editing
# - rendering an xwArticle,
#   - compiles php-transform-articles,CSS's & XSLT's from env+doc (the result of each becomes the source of the next)
#   - execute php-transform-articles & XSLT's in order (CSS's are left to the end)
#   - returns html-description with a CSS containing includes to CSS list
#   - PAGE LAYOUT is just a php-transform-article which SURROUNDS the current DOM with raw layout
#     - layouts would come with a separate collection of CSS's
#     - CSS's need to themselves be collections of colours, headings etc

# LATER:
# use XInclude to build large docs from others
# use docBook or DSSSL
# <? is a processing instruction
# eg. <?xml-stylesheet href="person.css" type="text/css"?>  or  <?php...

# ---------------------------------------------------------------------------------------------------------------------- #

# INIT
# - do admin and exit if running directly
# - get wiki/request env
# - get article
# - permissions
# - build env (if action=raw, env is empty but a header is added)
# INPUT
# - validate xml and report error or,
# - process form-input (backslashes etc if necessary)
# OUTPUT
# - trap MediaWiki output
# - extract content and links
# - if view/preview/raw, do transform:
#   - if docType is an xwArticle, see above
#   - replace view/preview with transformed article
# - render output
# - if saving, foreach in publish-list,
#   - do transform but with specified env
#   - publish
# FUNCTION
# - get article as dom
# - process dom-article (pass PT,XSLT list and DOM-article, returns DOM-result)
# - etxract hrefs from text
# - message
# ADMIN
# - enable/disable patch

# ---------------------------------------------------------------------------------------------------------------------- #
# INIT

# If xmlwiki.php requested directly, return admin page
if (eregi("xmlwiki\\.php", $_SERVER['SCRIPT_NAME'])) xwAdminPage();
else {

	# Otherwise set up xmlWiki global environment ready for input and output processing
	$xwArticleCache			= array();
	$xwEditingArticle		= isset($_REQUEST['action'])&&($_REQUEST['action'] == 'edit');
	$xwEditingXML			= isset($_REQUEST['action'])&&($_REQUEST['action'] == 'xwXML');
	$xwViewingArticle		= null; # preview too
	$xwSavingArticle		= isset($_REQUEST['wpSave']);
	$xwSpecialArticle		= null; # do not treat content as xml
	$xwArticleTitle			= $wgTitle->mTextform;
	$xwArticleDOM			= xwGetArticle($xwArticleTitle);		# DOM object of wiki article
	$xwUserName				= $wgUser->mName;
	$xwUserDOM				= xwGetArticle("User:$xwUserName");
	$xwUserGroups			= null;									# Groups this user belongs to (incl. self)

	# Get perms for this article
	$xwReadable				= null;									# True if this article is readable by this user
	$xwWritable				= null;									# True if this article is writeable by this user
	# Get groups this user belongs to from users' special-article
	$xwUserGroups[] = $xwUserName; // This allows users to be specified in permissions-lists in addition to groups

	# Build transform environment (later from prefs, site etc)
	if ($action == 'raw') {
		# Raw article is requested, so env is empty
		$xwEnv = array();
		# TODO: work out what kind of content it is (only if its an xwArticle can this work)
		# header("Content-type: application/pdf");
		# header("Content-Disposition: attachment; filename=downloaded.pdf");
		}
	else {
		# Create default environment (the name of another article)
		$xwEnv = array('defaultTemplate.php');
		}
	
	}

# ---------------------------------------------------------------------------------------------------------------------- #
# INPUT

# Parse and process input from forms
# - the form can just post changes for xml
function xwProcessInput() {

	global $xwEditingArticle;
	global $xwSavingArticle;
	global $xwReadable;
	global $xwWritable;
	global $xwArticleDOM;

	# If article is being updated,
	if ($xwSavingArticle) {
		global $_POST;
		# If valid xml posted, replace articleDOM
		if ($inputDOM = @domxml_open_mem($_POST["xw.xml"])) $articleDOM = $inputDOM;
		# later: parse POST updating articleDOM
		foreach (preg_grep("/^xw\\.(.+)$/", array_keys($_POST)) as $key) {
			$inputPath = split('.', $key);
			}
		# If description posted, update
		if (isset($_POST["wpTextbox1"])) {
			# write new description to articleDOM
			}
		# Convert articleDOM to text and put into POST data for MediaWiki to process
		$_POST["wpTextbox1"] = $articleDOM->dump_mem(false);
		}

	}

# ---------------------------------------------------------------------------------------------------------------------- #
# OUTPUT

# Generate new output to send back to browser
function xwProcessOutput() {

	global $wgOut;
	
	global $xwEditingArticle;
	global $xwEditingXML;
	global $xwViewingArticle;
	global $xwSavingArticle;
	global $xwSpecialArticle;
	global $xwArticleTitle;
	global $xwArticleDOM;
	global $xwUserName;
	global $xwUserDOM;
	global $xwUserGroups;
	global $xwReadable;
	global $xwWritable;

	$xwTransformedArticle	= null;
	$xwPublishList			= array();
	$xwOutput				= '';

	# First trap Wiki output and extract content and links (should use $ver like Admin Page)
	ob_start();
	$wgOut->output();
	$xwWikiOutput			= ob_get_clean();
	$xwWikiContent			= preg_match('/\<!-- start content -->(.+)<!-- end content -->/sm', $xwWikiOutput, $xwMatch)
							? $xwMatch[1] : '';
	$xwUserLinks			= preg_match('/id="p-personal"(.+?)<\/div>/s', $xwWikiOutput, $xwMatch)
							? xwExtractHrefs($xwMatch[1]) : array();
	$xwArticleLinks			= preg_match('/id="p-cactions"(.+?)<\/div>/s', $xwWikiOutput, $xwMatch)
							? xwExtractHrefs($xwMatch[1]) : array();
	$xwArticleLinks[]		= "<a href=\"./index.php?title=$xwArticleTitle&action=xwXML\">xml</a>";

	# Test output
	?><center><table border cellpadding=0 cellspacing=0><?
	print '<tr><td>'.join(' | ', $xwUserLinks);
	print '<tr><td>'.join(' | ', $xwArticleLinks);
	print '<tr><td>'.htmlentities($xwArticleDOM->dump_mem(true));
	print '<tr><td>'.$xwWikiContent;
	?></table></center><?

	# Transform
	# - This env still needs to apply an outer layout etc
	# - The local-env and the DTD determines transforming/rendering
	# - if DTD says its just text (or special page) render normal
	# - The DTD's need to work outside wiki, so we need to be able to specifiy lang in request

	# eg. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
	#     <!DOCTYPE greeting SYSTEM "hello.dtd">
	
	# - article/input-description/input-xml/input-tree-operation
	# NOTE: we need to handle edit/discuss/history/login/prefs...
	if ($xwEditingXML) {
		# Editing XML, render textarea (later tree)
		$xwOutput .= '\n<textarea name="xw.xml">'.$xwArticleDOM->dump_mem(true).'</textarea>\n';
		}

	if ($xwEditingArticle || $xwSpecialArticle) {
		# If not viewing output wiki content
		$xwOutput .= $wikiContent;
		}
		
	if ($xwViewingArticle) {
		# render article in current context (transform article)
		# - html, ....

		# Apply stylesheets	
		$xwTransformedArticle = null;
		
		# Replace output-buffer content with processed article
		$xwOutput .= $xwTransformedArticle;
		}

	# Publish the article if it has just been updated
	if ($xwSavingArticle) {
		foreach ($xwPublishList as $xwDestination) {
			if ($xwHandle = fopen($xwDestination, 'a')) {
				fwrite($xwHandle, $xwTransformedArticle);
				fclose($xwHandle);
				$xwOutput .= xwMessage("Article published to $cmDestination", 'green');
				} else $xwOutput .= xwMessage("Failed to publish to $cmDestination", 'red');
			}
		}

	# Render output-buffer through page template
	print $xwOutput;
	}

# ---------------------------------------------------------------------------------------------------------------------- #
# FUNCTIONS

# Retreive XML wiki-article and return as a DOM object
# - DOM articles are cached in $xwArticleCache for reuse in recursive processing
function xwGetArticle($articleTitle) {
	# Return with results if already cached
	global $xwArticleCache;
	if (isset($xwArticleCache[$articleTitle])) return $xwArticleCache[$articleTitle];
	# Get wiki article content (XML)
	$articleXML = new Article(Title::newFromText($articleTitle));
	$articleXML = $articleXML->getContent(false);
	# Convert to DOM object
	if (!$articleDOM = @domxml_open_mem($articleXML)) $articleDOM = domxml_new_doc("1.0");
	return $xwArticleCache[$articleTitle] = $articleDOM;
	}

# Return a list of the hrefs found in the passed content
function xwExtractHrefs($content) {
	preg_match_all('/(<a.+?<\/a>)/', $content, $match);
	return $match[1];
	}

# Render a xmlWiki system message
function xwMessage($msg, $col) {
	return "\n<table width=100% border=0><tr><td align=center>
	<table width=50% border bordercolor=#bbbbbb borderwidth=1 bgcolor=#999999><tr><td align=center>
	<font face=arial size=2 color=$col><b>$msg</b></font>
	</table></table>\n";
	}

# ---------------------------------------------------------------------------------------------------------------------- #
# ADMIN
function xwAdminPage() {

	?><html><head><title>xmlWiki Admin Page</title></head><body bgcolor=#cccccc>
	<table border=0 width=100% cellpadding=0 cellspacing=0>
	<tr><td align=center><table border=0 width=30%>
	<tr><td align=center>
	<a href="./index.php/xmlWiki"><img src="./xmlwiki.jpg" border=0 alt="xmlWiki"></a>
	<tr><td align=center bgcolor=#003366>
	<b><font size=5 color=white face=helvetica>xmlWiki Admin Page</font></b>
	</table></table><br><br><br><br><?

	# back up index.php if doesn't already exist
	if (!file_exists('./index.bak')) {
		if (!copy('./index.bak', './index.php')) {
			print xwMessage('Could not back up index.php!', '#d00000');
			exit;
			}
		}
	if (array_key_exists('enable', $_GET)) {
		# Replace from backup before enabling
		if (!copy('./index.bak', './index.php'))
			print xwMessage('Could not copy index.bak over index.php', '#d00000');
		require_once('./Version.php');
		$ver = $wgSoftwareRevision;
		# Matches for patch-points/MediaWiki versions
		$requireMatch['1002'] = "/^wfProfileOut\\( *'main-misc-setup' *\\);$/m";
		$inputMatch['1002'] = "/^wfProfileIn\\( *'main-action' *\\);$/m";
		$outputMatch['1002'] = "/\\\$wgOut->output\\(\\);/m";
		# Apply patches
		if (preg_match($requireMatch[$ver], $file = join('', file('./index.php')))
		&&  preg_match($inputMatch[$ver], $file)
		&&  preg_match($outputMatch[$ver], $file)) {
			$file = preg_replace($requireMatch[$ver], "wfProfileOut( 'main-misc-setup' );\nrequire_once( './xmlwiki.php' );", $file);
			$file = preg_replace($inputMatch[$ver], "xwProcessInput();\nwfProfileIn( 'main-action' );", $file);
			$file = preg_replace($outputMatch[$ver], "xwProcessOutput();", $file);
			if ($handle = fopen('./index.php', 'w')) {
				fwrite($handle, $file);
				fclose($handle);
				} else	print xwMessage('Could not open index.php for writing!', '#d00000');
			} else		print xwMessage('Could not match content of index.php script!', '#d00000');
		}
	elseif (array_key_exists('disable', $_GET)) {
		# Replace from backup
		if (!copy('./index.bak', './index.php'))
			print xwMessage('Could not copy index.bak over index.php', '#d00000');
		}
	# Print current state
	if (filesize('./index.php') == filesize('./index.bak'))
			print xwMessage('xmlWiki is currently disabled. [ <a href="./xmlwiki.php?enable">enable</a> ]', '#003366');
	else	print xwMessage('xmlWiki is currently enabled. [ <a href="./xmlwiki.php?disable">disable</a> ]', '#003366');
	

	?><br><br><br><table border=0 width=100% cellpadding=0 cellspacing=0>
	<tr><td align=center colspan=3><table border=0 width=50%>
	<td align=right valign=top><a href="http://w3c.org/"><img src="./xhtml.jpg" alt="XHTML1.0" border=0 /></a>
	<td align=right valign=top><a href="http://www.php.net/"><img src="./php.jpg" alt="PHP" border=0 /></a>
	<td align=right valign=top><a href="http://www.mediawiki.org/"><img src="./mediawiki.jpg" alt="MediaWiki" border=0 /></a>
	</table></table><br><br></body></html><?
	}

?>