|
|
| Line 1: |
Line 1: |
| | + | <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> |
| | <?php | | <?php |
| − | # xmlWiki - MediaWiki XML Hack
| |
| − | # Nad - 2005-05-18
| |
| | | | |
| − | # INIT HOOK
| + | if (array_key_exists('enable', $_GET)) { |
| − | # INPUT HOOK
| |
| − | # OUTPUT HOOK
| |
| − | # PARSER HOOK
| |
| − | # SKIN HOOK
| |
| − | # ARTICLE FUNCTIONS
| |
| − | # TRANSFORMS
| |
| − | # UTILITY FUNCTIONS
| |
| | | | |
| − | # ---------------------------------------------------------------------------------------------------------------------- # | + | # Apply index.php patches |
| | + | $success = patchFile('../index.php', array( |
| | + | "/^(wfProfileOut\\( *'main-misc-setup' *\\);)$/m", "$1\nrequire_once( './xmlwiki/xmlwiki.php' );", |
| | + | "/^(wfProfileIn\\( *'main-action' *\\);)$/m", "xwInputHook();\n$1", |
| | + | "/(\\\$wgOut->output\\(\\);)/", "xwOutputHook();" |
| | + | )); |
| | | | |
| − | # TODO: | + | # Apply Parser.php patch |
| − | # Security:
| + | if ($success) patchFile('../includes/Parser.php', array( |
| − | # - xml:article - holds article perms, it doesn't have perms of its own (owner, read-groups, write-groups)
| + | "/(function\\s+parse\\s*\\(.+?\\)\\s*\\{.+?OT_HTML;.)(.+?)(\\s*\\\$this->mOutput->setText)/s", |
| − | # - xml:user - r/w by user, not currently used, but for xmlWiki prefs etc
| + | "$1\nif (!xwParserHook(\$text)) {\n$2\n}$3" |
| − | # - sys:user - r/w by admin only, holds users groups and other system info like stats
| + | )); |
| − | # Publish:
| |
| − | # - xml:article - holds article publish-list
| |
| − | # - mirror/wiki-sync
| |
| − | # Transforms:
| |
| − | # - xml:article - now transforms are in here (main article is now like <body>)
| |
| − | # - so we don't do the "its one of ours" thing anymore
| |
| − | # Raw as Default:
| |
| − | # - Need to mod the article-link so it has action=view
| |
| − | | |
| − | # LATER:
| |
| − | # - allow XIncludes to build large docs from others
| |
| − | # - allow docBook and DSSSL content
| |
| − | # - Maybe only use XML transforms and use PHP via PI's
| |
| − | | |
| − | # ---------------------------------------------------------------------------------------------------------------------- #
| |
| − | # INIT HOOK
| |
| − | | |
| − | # Exit if not included from index.php
| |
| − | defined('MEDIAWIKI') or die('xmlwiki.php must be included from MediaWiki\'s index.php!');
| |
| − | | |
| − | # Allows Geshi to be installed by PARSER-HOOK if not installed th usual way already
| |
| − | if (!@is_object($wgGeshiSyntaxSettings)) $wgGeshiSyntaxSettings = false;
| |
| − | | |
| − | # Otherwise set up xmlWiki global environment ready for input and output processing
| |
| − | $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;
| |
| − | $xwArticle = $xwPreview ? $wgRequest->gettext('wpTextbox1') : $wgArticle->getContent(false);
| |
| − | $xwArticleTitle = $wgTitle->getPrefixedURL();
| |
| − | $xwArticleCache = array();
| |
| − | $xwArticleLinks = array();
| |
| − | $xwUserLinks = array();
| |
| − | $xwMessages = array();
| |
| − | $xwMetaArticle = false;
| |
| − | $xwMsgToken = '<!--xwMsg-->';
| |
| − | $xwTemplate = null;
| |
| − | $xwParserHookCalled = false;
| |
| − | $xwSkinHookCalled = false;
| |
| − | | |
| − | | |
| − | # Get associated articles and attempt to Domificate
| |
| − | if ($xwArticleXML = xwArticleContent("xml:$xwArticleTitle")) xwDomificateArticle($xwArticleXML, "xml:$xwArticleTitle");
| |
| − | if ($xwUserXML = xwArticleContent("xml:$xwUserName")) xwDomificateArticle($xwUserXML, "xml:$xwUserName");
| |
| − | if ($xwUserSYS = xwArticleContent("sys:$xwUserName")) xwDomificateArticle($xwUserSYS, "sys:$xwUserName");
| |
| − | | |
| − | # Security
| |
| − | if (ereg('^xml:(.+)$', $xwArticleTitle)) {
| |
| − | $xwMetaArticle = true;
| |
| − | # This is an xml-pseudo-namespace
| |
| − | # - get perms from associated article/user
| |
| − | }
| |
| − | elseif (ereg('^sys:(.+)$', $xwArticleTitle)) {
| |
| − | $xwMetaArticle = true;
| |
| − | # This is an sys-pseudo-namespace
| |
| − | # - only admin can read/write sys:
| |
| − | }
| |
| − | elseif (is_object($xwArticleXML)) {
| |
| − | # Get perms from xml:article
| |
| − | }
| |
| − | else $xwReadable = $xwWritable = true;
| |
| − | | |
| − | # ---------------------------------------------------------------------------------------------------------------------- #
| |
| − | # INPUT HOOK
| |
| − | | |
| − | # Parse and process input from forms
| |
| − | function xwInputHook() {
| |
| − | | |
| − | global $xwArticle, $xwArticleTitle, $xwMetaArticle, $xwReadable, $xwWritable;
| |
| − | global $xwDebug, $xwSave;
| |
| − | if ($xwDebug) xwMessage('xwInputHook()','green');
| |
| − | | |
| − | # If an article-change is being attempted,
| |
| − | if ($xwSave) {
| |
| − | if (!$xwReadable || !$xwWritable) {
| |
| − | # Not writable, change action to view
| |
| − | xwMessage('Cannot access article for writing, changing action to "view"', 'red');
| |
| − | global $action;
| |
| − | $action='view';
| |
| − | }
| |
| − | else {
| |
| − | # Parse POST for xmlWiki form input
| |
| − | global $_REQUEST;
| |
| − | foreach ($_REQUEST as $k => $v) {
| |
| − | | |
| − | if (is_object($xwArticle) && preg_match("/^xw:(@?)(\\w*):(.+)$/", $k, $m)) {
| |
| − | # 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
| |
| − | list(, $att, $node, $xpath) = $m;
| |
| − | foreach (xwXPathQuery($xwArticleXML, $xpath) as $result) {
| |
| − | if ($att && $node) {
| |
| − | # create attribute for value
| |
| − | }
| |
| − | elseif ($node) {
| |
| − | # create element for value
| |
| − | }
| |
| − | else {
| |
| − | # overwrite existing node content
| |
| − | }
| |
| − | }
| |
| − | }
| |
| − | | |
| − | elseif ($xwMetaArticle && ($k == 'wpSave')) {
| |
| − | # if it's a pseudo-namespace, wpSave should be valid XML to be saved
| |
| − | xwDomificate($wpSave);
| |
| − | if (!is_object($wpSave)) {
| |
| − | xwMessage('A meta-article must be valid XML! changing action to "edit"', 'red');
| |
| − | global $action;
| |
| − | $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');
| |
| − | | |
| − | # If readable, get wiki-environment, else clear content
| |
| − | if ($xwReadable) {
| |
| − | $wgUser->setOption('skin', 'xwskin');
| |
| − | $wgOut->output();
| |
| − | }
| |
| − | else {
| |
| − | $xwArticle = '';
| |
| − | xwMessage('Cannot access article for reading!', 'red');
| |
| − | }
| |
| − | | |
| − | # If no write-access, remove edit link
| |
| − | if (!$xwWritable) unset($xwArticleLinks['Edit']);
| |
| − | | |
| − | # NOTE - Why not move this into INPUT-HOOK????????
| |
| − | # 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 && !$xwParserHookCalled) xwMessage('PARSER-HOOK was not called','green');
| |
| − | if ($xwDebug && !$xwSkinHookCalled) xwMessage('SKIN-HOOK was not called','green');
| |
| − | xwTransformAddMessages();
| |
| − | print $xwArticle;
| |
| | } | | } |
| | | | |
| − | # ---------------------------------------------------------------------------------------------------------------------- #
| + | elseif (array_key_exists('disable', $_GET)) { |
| − | # PARSER HOOK
| + | # Replace from backup |
| − | | + | replaceFiles(array('../index.php', '../includes/Parser.php')); |
| − | 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
| |
| − | #xwMessage($text,'purple');
| |
| − | #xwMessage($xwArticle,'purple'); | |
| − | if ((strncmp($text, $xwArticle, 100) == 0) || (strncmp($text, xwArticleContent($xwArticleTitle), 100) == 0)) { | |
| − | | |
| − | if ($xwDebug) xwMessage('- PARSER-HOOK has recognised the article');
| |
| − | | |
| − | # If attempted xml encountered, try to domificate and transform
| |
| − | if (preg_match("/^<\\?xml/i", $text)) {
| |
| − | $transformed = true;
| |
| − | xwDomificateArticle($text, 'ParserHook/text');
| |
| − | xwTransformArticle($text);
| |
| − | }
| |
| − | | |
| − | # 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, $text)) {
| |
| − | xwMessage("- Geshi: This is \"$lang\".");
| |
| − | # Replace tabs with spaces (better than geshi)
| |
| − | $text = preg_replace_callback("/^(.*?)(\\t+)/m", 'xwReplaceTabs', $text);
| |
| − | # Set up a geshi-parser
| |
| − | $geshi = new GeSHi($text, $lang == 'xslt' ? 'xml' : $lang, 'extensions/geshi/geshi');
| |
| − | $geshi->set_header_type(GESHI_HEADER_DIV);
| |
| − | @$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('font-style: italic; color:red',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
| |
| − | $text = preg_replace("/^<div.*?>/", '<div class="xwcode">', $geshi->parse_code());
| |
| − | $transformed = true;
| |
| − | }
| |
| − | elseif ($xwDebug) xwMessage('- Geshi: Not my problem.');
| |
| − | }
| |
| − | }
| |
| − | 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 | + | # Print current state (based on index.php) |
| − | # - Raw requests don't get here
| + | if (filesize('../index.php') == filesize('../index.php.bak')) |
| − | function xwSkinHook(&$tmpl) {
| + | print xwMessage('xmlWiki is currently disabled. [ <a href="./index.php?enable">enable</a> ]', '#003366'); |
| − | | + | else print xwMessage('xmlWiki is currently enabled. [ <a href="./index.php?disable">disable</a> ]', '#003366'); |
| − | 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');
| |
| | | | |
| | + | # Add message to queue |
| | + | function xwMessage($msg, $col = 'blue') { |
| | + | global $xwMessages; |
| | + | return $xwMessages[] = "<center><div class=\"xwMessage\"><font color=\"$col\">$msg</font></div></center>\n"; |
| | } | | } |
| − |
| |
| − | # ---------------------------------------------------------------------------------------------------------------------- #
| |
| − | # ARTICLE FUNCTIONS
| |
| | | | |
| − | # Retreive wiki-article as raw text | + | # Replace a list of files from their backups |
| − | function xwArticleContent($articleTitle) { | + | function replaceFiles($list) { |
| − | # Return with results if already cached | + | foreach ($list as $filename) |
| − | global $xwArticleCache, $xwDebug;
| + | if (!copy("$filename.bak", $filename)) |
| − | if ($xwDebug) xwMessage("xwArticleContent(\"$articleTitle\")",'blue');
| + | print xwMessage("Could not replace \"$filename\" from backup!", '#d00000'); |
| − | 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 patchFile($filename, $rules) { |
| − | function xwArticleType($title, $article) { | + | # Back up file if doesn't already exist |
| − | # Name based matches | + | if (!file_exists("$filename.bak")) { |
| − | if (ereg('\\.php$', $title)) return 'php';
| + | if (!copy($filename, "$filename.bak")) { |
| − | if (ereg('\\.css$', $title)) return 'css'; | + | print xwMessage("Could not back up MediaWiki \"$filename\"!", '#d00000'); |
| − | if (ereg('\\.as$', $title)) return 'actionscript';
| + | exit; |
| − | 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("xwDomificatwArticle(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(); | + | # Replace from backup before enabling |
| − | }
| + | if (!copy("$filename.bak", $filename)) |
| | + | print xwMessage("Could not find \"$filename.bak\"!", '#d00000'); |
| | | | |
| − | # Reduce article to a string if it's a DOM object
| + | # Apply patches in passed list |
| − | # - ie if all xslt's had xml-output-method
| + | $file = join('', file($filename)); |
| − | function xwUndomificateArticle(&$article, $id = '') {
| + | $success = true; |
| − | if (!is_object($article)) return false;
| + | for ($i = 0; $i < count($rules); $i += 2) { |
| − | global $xwDebug;
| + | $match = $rules[$i]; |
| − | | + | $replace = $rules[$i+1]; |
| − | if ($xwDebug) xwMessage("xwUndomificate(DOM,$id)",'blue');
| + | if (preg_match($match, $file)) $file = preg_replace($match, $replace, $file); |
| − | # 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;
| |
| − | }
| |
| − | | |
| − | # 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();
| |
| − | $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 ($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;
| |
| − | }
| |
| − | | |
| − | # Transform an article object
| |
| − | # - Article must be an xmlwiki:* DOM object to be transformable
| |
| − | # - Article is undomificated on exit
| |
| − | # - Article remains unchanged if not DOM
| |
| − | function xwTransformArticle(&$article) {
| |
| − | | |
| − | # Get doc info or exit if not one of ours
| |
| − | if (!is_object($article)) return false;
| |
| − | $aType = $article->doctype();
| |
| − | $aType = $aType->name;
| |
| − | $aRoot = $article->document_element();
| |
| − | #if (!ereg('^xmlwiki:', $aType)) return false; # this must change to meta article
| |
| − | global $xwDebug;
| |
| − | if ($xwDebug) xwMessage("xwTransformArticle(xmlwiki:$aType)",'blue');
| |
| − | | |
| − | # Loop thru transforms applying each
| |
| − | foreach ($aRoot->get_elements_by_tagname('transform') as $tElement) {
| |
| − | $tName = $tElement->get_content();
| |
| − | if (ereg('^(.+)\\(\\)$', $tName, $m)) {
| |
| − | # Transform is "name()" format, try to execute from a local function declaration
| |
| − | # - probably this is not needed soon, as XSLT-PI's may be a better structure
| |
| − | $tName = $m[1];
| |
| − | if ($tResult = @call_user_func("xwTransform_$tName", $article)) $article = $tResult;
| |
| − | else xwMessage("- Unknown transform \"$tName\"!", 'red');
| |
| − | }
| |
| | else { | | else { |
| − | # Transform is not local, get transform-article and apply to current-article-object | + | print xwMessage("Could not match rule".($i/2+1)." for \"$filename\"!", '#d00000'); |
| − | if ($tText = xwArticleContent($tName)) {
| + | $success = false; |
| − | # Get transform type
| |
| − | $tType = xwArticleType($tName, $tText);
| |
| − | if ($tType == 'xslt') xwApplyXSLT($article, $tText, $tName);
| |
| − | elseif ($tType == 'php') {
| |
| − | # php, check perms and execute (trapping errors for reporting - unless fatal)
| |
| − | if ($perms_check_out_ok) {
| |
| − | ob_start();
| |
| − | eval($tText);
| |
| − | xwExtractMessages();
| |
| − | ob_end_clean();
| |
| − | }
| |
| − | }
| |
| − | elseif ($tType == 'css') {
| |
| − | # include CSS ref in content
| |
| − | }
| |
| − | }
| |
| − | else xwMessage("- No such transform-article \"$tName\"!", 'red');
| |
| − | }
| |
| − | }
| |
| − | | |
| − | # If article is still a DOM object, stringify it once and for all
| |
| − | xwUndomificateArticle($article);
| |
| − | return true;
| |
| − | }
| |
| − | | |
| − | # ---------------------------------------------------------------------------------------------------------------------- #
| |
| − | # TRANSFORMS
| |
| − | # - these transforms are only temporarily here - they should be articles
| |
| − | # - we should use DTD's for each kind: document, image, layout, table
| |
| − | | |
| − | # Surrounds the article with HTML structural page-layout containing a ref to xmlwiki.css
| |
| − | # - This is temporary
| |
| − | # - It should return the page as a DOM object to be transformed by xmlwiki.xslt
| |
| − | function xwTransformPageLayout() {
| |
| − | | |
| − | global $xwMsgToken, $xwArticle, $xwTemplate, $xwDebug;
| |
| − | 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" />';
| |
| − | | |
| − | $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
| |
| − | $actions = '<div id="p-cactions" class="portlet"><h5>Views</h5><ul>';
| |
| − | foreach ($data['content_actions'] as $key => $action) {
| |
| − | $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 .= ' <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']) { | + | if ($success) { |
| − | $toolbox .= '<li id="feedlinks">'; | + | if ($success && $handle = fopen($filename, 'w')) { |
| − | foreach ($data['feeds'] as $key => $feed) {
| + | fwrite($handle, $file); |
| − | $toolbox .= '<span id="feed-'.htmlspecialchars($key).'">';
| + | fclose($handle); |
| − | $toolbox .= '<a href="'.htmlspecialchars($feed['href']).'">'.htmlspecialchars($feed['text']).'</a>';
| + | } else print xwMessage("Could not open \"$filename\" for writing!", '#d00000'); |
| − | $toolbox .= ' </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>
| |
| − | ";
| |
| − | }
| |
| − |
| |
| − | # Append messages to content
| |
| − | function xwTransformAddMessages() {
| |
| − | 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);
| |
| − | }
| |
| − | }
| |
| − | | |
| − | function xwTransform_document_xxx() {
| |
| − | # documents are built from parts,
| |
| − | # the parts are a tree in its body
| |
| − | # includes 'edit' link for each (like section, and also like table)
| |
| − | }
| |
| − | | |
| − | # A document object is finalised by transforming it to its body's text | |
| − | function xwTransform_document_render() {
| |
| − | global $xwArticle;
| |
| − | $root = $xwArticle->document_element();
| |
| − | $body = $root->get_elements_by_tagname('body');
| |
| − | if (count($body)) $xwArticle = $body[0]->dump_mem(true);
| |
| − | }
| |
| − | | |
| − | function xwTransform_layout_xxx() {
| |
| − | # for layout container style article
| |
| − | }
| |
| − | | |
| − | function xwTransform_image_xxx() {
| |
| − | # object contains properties for loading and transforming an image
| |
| − | # image needs no body
| |
| − | # Get the global image on which imageTransforms work
| |
| − | global $xwArticleImage;
| |
| − | }
| |
| − | | |
| − | # Converts the in-memory-working image into article content
| |
| − | function xwTransform_image_render() {
| |
| − | global $xwArticle, $xwArticleTitle, $xwArticleImage, $xwRaw;
| |
| − | if ($xwRaw) {
| |
| − | # render article directly if 'raw' request
| |
| − | imagePng($xwArticleImage);
| |
| − | # Clear article or it will render as xml
| |
| − | $xwArticle = '';
| |
| − | # set header to image
| |
| − | header("Content-type: image/png");
| |
| − | }
| |
| − | | |
| − | else {
| |
| − | # the raw image is not being requested, render image in-page with info instead
| |
| − | $xwArticle = "<img src=\"$xwArticleTitle?action=raw\" alt=\"$xwArticleTitle\"/>";
| |
| | } | | } |
| − | }
| |
| − |
| |
| − | # A table object is an interface to a database table
| |
| − | # - this can't be implimented fully until the 'edit' hook is done
| |
| − | # - the query result is a list in document body, so any normal document transforms can follow it
| |
| − | function xwTransform_table_xxx() {
| |
| − | # - view lists the table/result with links to edit each (like a normal composition-doc)
| |
| − | # - also form for create/edit/edlete
| |
| − | # - result rows are in document body (just like a content-tree in a document would be)
| |
| − |
| |
| − | # NODE-LIKE-DB
| |
| − |
| |
| − | # - if all tables have GUID for pri-key,
| |
| − | # - and all have time/duration (or cycle?),
| |
| − | # - and we have master list of cols-to-table
| |
| − | # - then we could create a meta-query (resulting in pri-key-list of all matches)
| |
| | | | |
| | + | return $success; |
| | } | | } |
| | | | |
| − | # Transform the body content to a xtml/javascript tree
| |
| − | function xwTransform_tree() {
| |
| − | # import php-tree-component
| |
| − | }
| |
| − |
| |
| − | # ---------------------------------------------------------------------------------------------------------------------- #
| |
| − | # UTILITY FUNCTIONS
| |
| − |
| |
| − | # Return a list of the hrefs found in the passed content
| |
| − | function xwExtractHrefs($content) {
| |
| − | preg_match_all('/(<a.+?>(.+)<\/a>)/', $content, $m);
| |
| − | $hrefs = array();
| |
| − | for ($i = 0; $i < count($m[0]); $i++) $hrefs[$m[2][$i]] = $m[1][$i];
| |
| − | return $hrefs;
| |
| − | }
| |
| − |
| |
| − | # 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;
| |
| − | }
| |
| − |
| |
| − | # Compare two strings - for some reason PHP's one isn't working for me...?
| |
| − | function xwStrCmp($a,$b) {
| |
| − | $i = -1;
| |
| − | while (($i < 100) && (substr($a,$i,1) == substr($b,$i,1))) $i++;
| |
| − | return $i == 100;
| |
| − | }
| |
| − |
| |
| − | function xwDomificateWiki() {
| |
| − | global $xwTemplate;
| |
| − | #$doc = domxml_new_doc("1.0");
| |
| − | #$root = $doc->add_root("xmkwiki");
| |
| − | #$head = $root->new_child("head", "");
| |
| − | #$head->new_child("title", "untitiled");
| |
| − | #htmlentities($doc->dump_mem());
| |
| − | }
| |
| − |
| |
| | ?> | | ?> |
| | + | <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> |