Revision history for FileexportAction


Revision [20032]

Last edited on 2008-06-14 17:19:47 by DomBonj [v1.05: fixed XML encoding; PHP5 compatibility; 1.1.6.4 compatibility]
Additions:
- Wikka 1.1.6.2 & 1.1.6.3 & 1.1.6.4
# @version 1.05
function FEpage_data(&$thisone, $tag, &$page_content)
$thisone->SetPage($thisone->LoadPage($tag));
unset ($thisone->config['includes']);
$page_content['raw'] = $thisone->page['body'];
$page = preg_replace('/\{\{\s*fileexport\b(.*?)\}\}/', "[fileexport action, $1]", $thisone->page['body']);
$rendered_body = $thisone->Format($page, 'wakka');
$rendered_body .= FNprint($thisone, 'list', '', $thisone->Href());
function FEhtml(&$thisone, &$pages, &$key_order, $embed_css, $css_path, $remove_links, $save_tag, $save_page, $raw=false)
$header .= ($embed_css ? $stylesheet : '') .'<title>'. $thisone->GetConfigValue('wakka_name') ."</title></head><body>\n";
$file_name = $thisone->GetConfigValue('wakka_name') .'_'. date('Ymd');
$save_includes = $thisone->config['includes'];
FEpage_data($thisone, $tag, $pagedata);
$pagedata['body'] = preg_replace('/'.preg_quote($thisone->GetConfigValue('external_link_tail'),'/').'/', '', $pagedata['body']);
$pagedata['body'] = preg_replace('/'.preg_quote($thisone->GetConfigValue('external_link_tail'),'/').'/', '', $pagedata['body']);
function FExml(&$thisone, &$pages, &$key_order, $remove_links, $save_tag, $save_page)
$file_name = $thisone->GetConfigValue('wakka_name') .'_'. date('Ymd');
$save_includes = $thisone->config['includes'];
FEpage_data($thisone, $tag, $pagedata);
$output .= '<raw_content><![CDATA['. utf8_encode($pagedata['raw']) .".]]></raw_content>\n";
$pagedata['body'] = preg_replace('/'.preg_quote($thisone->GetConfigValue('external_link_tail'),'/').'/', '', $pagedata['body']);
$output .= '<rendered_content>'. utf8_encode(numeric_html_entities($pagedata['body'])) .'</rendered_content>';
$thisone->tag = $save_tag;
$thisone->page = $save_page;
$thisone->config['includes'] = $save_includes;
function numeric_html_entities($string)
$trans_tbl1 = get_html_translation_table(HTML_ENTITIES);
foreach ($trans_tbl1 as $ascii => $html_entity)
$trans_tbl2[$html_entity] = '&#'. ord($ascii) .';';
$trans_tbl3[$ascii] = '&#'. ord($ascii) .';';
// keep XML entities
unset($trans_tbl3['<']);
unset($trans_tbl3['>']);
unset($trans_tbl3['"']);
unset($trans_tbl3['\'']);
unset($trans_tbl3['&']);
$ret = strtr (strtr ($string, $trans_tbl2), $trans_tbl3);
// translate '&' character if not part of a numeric entity
$ret = preg_replace('/&(?!#[x]?[0-9a-f]+;)/i', '&', $ret);
return($ret);
Deletions:
- Wikka 1.1.6.2 & 1.1.6.3
%%(php)<?php
# @version 1.04
function FEpage_data(&$this, $tag, &$page_content)
$this->SetPage($this->LoadPage($tag));
unset ($this->config['includes']);
$page_content['raw'] = $this->page['body'];
$page = preg_replace('/\{\{\s*fileexport\b(.*?)\}\}/', "[fileexport action, $1]", $this->page['body']);
$rendered_body = $this->Format($page, 'wakka');
$rendered_body .= FNprint($this, 'list', '', $this->Href());
function FEhtml(&$this, &$pages, &$key_order, $embed_css, $css_path, $remove_links, $save_tag, $save_page, $raw=false)
$header .= ($embed_css ? $stylesheet : '') .'<title>'. $this->GetConfigValue('wakka_name') ."</title></head><body>\n";
$file_name = $this->GetConfigValue('wakka_name') .'_'. date('Ymd');
$save_includes = $this->config['includes'];
FEpage_data($this, $tag, $pagedata);
$pagedata['body'] = preg_replace('/'.preg_quote($this->GetConfigValue('external_link_tail'),'/').'/', '', $pagedata['body']);
$pagedata['body'] = preg_replace('/'.preg_quote($this->GetConfigValue('external_link_tail'),'/').'/', '', $pagedata['body']);
function FExml(&$this, &$pages, &$key_order, $remove_links, $save_tag, $save_page)
$file_name = $this->GetConfigValue('wakka_name') .'_'. date('Ymd');
$save_includes = $this->config['includes'];
FEpage_data($this, $tag, $pagedata);
$output .= '<raw_content>'. utf8_encode(htmlspecialchars($pagedata['raw'], ENT_COMPAT)) .".</raw_content>\n";
$pagedata['body'] = preg_replace('/'.preg_quote($this->GetConfigValue('external_link_tail'),'/').'/', '', $pagedata['body']);
$output .= '<rendered_content>'. utf8_encode(htmlspecialchars($pagedata['body'], ENT_COMPAT, 'UTF-8')) .'</rendered_content>';
}


Revision [19356]

Edited on 2008-01-28 00:15:25 by DomBonj [Modified links pointing to docs server]

No Differences

Revision [17517]

Edited on 2007-09-26 16:34:22 by DomBonj [typo]
Additions:
- Save the first code block below as ##actions/fileexport.php##
Deletions:
- Save the first code block below as ##action/fileexport.php##


Revision [17047]

Edited on 2007-06-03 05:48:41 by DomBonj [v1.04: added 'raw html' export format]
Deletions:
# @authors DomBonj


Revision [17046]

Edited on 2007-06-03 05:47:25 by DomBonj [v1.04: added 'raw html' export format]
Additions:
# @authors DomBonj
# @version 0.97
# @input Parameters = [type=('html'|'rawhtml'|'xml')] [sort=('tag'|'type'|'time')] [scope=('PageTag'|'m'|'o'|'p')] [opts=['e']['r']] [cats='Category1','Category2'..]
if (!defined('FE_ERROR_USAGE')) define ('FE_ERROR_USAGE', "fileexport [type=\"html|rawhtml|xml\"] [scope=\"PageTag|m|o|p\"] [opts=\"[e][r]\"] [sort=\"tag|time|title\"] [cats=\"<i>category list</i>\"]");
if (!defined('FE_ERROR_MISSING_PAGE')) define ('FE_ERROR_MISSING_PAGE', 'Can not export: page \'%s\' does not exist');
|| (isset($vars['type']) && (!preg_match("/^(html|rawhtml|xml)$/i", $vars['type'])))
else if ( isset($vars['scope']) && preg_match("/^[A-ZÄÖÜ]+[a-zßäöü]+[A-Z0-9ÄÖÜ][A-Za-z0-9ÄÖÜßäöü]*$/", $vars['scope']) && !$this->ExistsPage($vars['scope']) )
$output .= FEerror(sprintf(FE_ERROR_MISSING_PAGE, $vars['scope']));
# @version 1.04
function FEhtml(&$this, &$pages, &$key_order, $embed_css, $css_path, $remove_links, $save_tag, $save_page, $raw=false)
if (!$raw)
{ // preserve intra-wiki links
$pagedata['body'] = '<a name="'. $pages[$tag]['i'] .'"></a>'. preg_replace($pat, $rep, $pagedata['body']);
{ // remove all intra-wiki links for raw HTML
$pat = '/<\s*a[^>]+href=([\'\"])'. preg_quote('http://'.$root_url, '/') .'\?wakka=.+?[^>].*?\>(.*?)<\/a>/';
$pagedata['body'] = preg_replace($pat, "$2", $pagedata['body']);
else if ($raw)
{ // remove links tail
if (!$raw)
$output = $header .'<div class="page"><h2>'. FE_TABLE_OF_CONTENTS. '</h2><ul>'. $toc .'</ul><hr />'. $output . '</div></body></html>';
else
{ // remove last ruler from raw HTML
$output = preg_replace('/\<hr \/\>$/', '', $output);
}
|| (isset($_GET['type']) && (!preg_match("/^(html|rawhtml|xml)$/i", $_GET['type'])))
if (!isset($_GET['type']) || ($_GET['type'] == 'html') || ($_GET['type'] == 'rawhtml'))
$raw_html = ($_GET['type'] == 'rawhtml');
FEhtml($this, $pages, $key_order, $embed_css, $css_path, $remove_links, $save_tag, $save_page, $raw_html);
Deletions:
# @version 0.96
# @input Parameters = [type=('html'|'xml')] [sort=('tag'|'type'|'time')] [scope=('PageTag'|'m'|'o'|'p')] [opts=['e']['r']] [cats='Category1','Category2'..]
if (!defined('FE_ERROR_USAGE')) define ('FE_ERROR_USAGE', "fileexport [type=\"html|xml\"] [scope=\"PageTag|m|o|p\"] [opts=\"[e][r]\"] [sort=\"tag|time|title\"] [cats=\"<i>category list</i>\"]");
|| (isset($vars['type']) && (!preg_match("/^(html|xml)$/i", $vars['type'])))
# @version 1.03
if (!defined('FE_ERROR_MISSING_LIBRARY')) define ('FE_ERROR_MISSING_LIBRARY', 'Could not find the \'pclzip\' library, check installation instructions');
function FEhtml(&$this, &$pages, &$key_order, $embed_css, $css_path, $remove_links, $save_tag, $save_page)
// preserve intra-wiki links
$pagedata['body'] = '<a name="'. $pages[$tag]['i'] .'"></a>'. preg_replace($pat, $rep, $pagedata['body']);
$output = $header .'<div class="page"><h2>'. FE_TABLE_OF_CONTENTS. '</h2><ul>'. $toc .'</ul><hr />'. $output;
echo '</div></body></html>';
|| (isset($_GET['type']) && (!preg_match("/^(html|xml)$/i", $_GET['type'])))
if (!isset($_GET['type']) || $_GET['type'] == 'html')
FEhtml($this, $pages, $key_order, $embed_css, $css_path, $remove_links, $save_tag, $save_page);


Revision [16627]

Edited on 2007-05-22 17:03:57 by DomBonj [v1.03: added 'scope' parameter, XML export of structured data items, 1.1.6.3 compatibility]
Additions:
$query .= '&scope='. (isset($vars['scope']) ? $vars['scope'] : 'm');
Deletions:
$query = '&scope='. (isset($vars['scope']) ? $vars['scope'] : 'm');


Revision [16624]

Edited on 2007-05-22 16:35:32 by DomBonj [v1.03: added 'scope' parameter, XML export of structured data items, 1.1.6.3 compatibility]
Additions:
- Wikka 1.1.6.2 & 1.1.6.3
%%(php)<?php
# @version 0.96
# @input Parameters = [type=('html'|'xml')] [sort=('tag'|'type'|'time')] [scope=('PageTag'|'m'|'o'|'p')] [opts=['e']['r']] [cats='Category1','Category2'..]
if (!defined('FE_ERROR_USAGE')) define ('FE_ERROR_USAGE', "fileexport [type=\"html|xml\"] [scope=\"PageTag|m|o|p\"] [opts=\"[e][r]\"] [sort=\"tag|time|title\"] [cats=\"<i>category list</i>\"]");
return ('<em class="error">'. $msg .'</em><br />');
$output = '';
if ( (isset($vars['opts']) && (!preg_match("/^[er]{1,4}$/i", $vars['opts'])))
|| (isset($vars['scope']) && (!preg_match("/^([oO]|[pP]|[mM]|[A-ZÄÖÜ]+[a-zßäöü]+[A-Z0-9ÄÖÜ][A-Za-z0-9ÄÖÜßäöü]*)$/", $vars['scope'])))
$query = '&type='. $type;
$query = '&scope='. (isset($vars['scope']) ? $vars['scope'] : 'm');
$query .= '&cats=';
%%(php)<?php
# @version 1.03
if (!defined('FE_TABLE_OF_CONTENTS')) define ('FE_TABLE_OF_CONTENTS', 'Table of contents');
if (!defined('FE_ERROR_REQUEST_STRING')) define ('FE_ERROR_REQUEST_STRING', 'Illegal request string, unable to export');
if (!defined('FE_ERROR_ARCHIVE_BUILD')) define ('FE_ERROR_ARCHIVE_BUILD', 'Error building the archive file, unable to export');
if (!defined('FE_ERROR_MISSING_LIBRARY')) define ('FE_ERROR_MISSING_LIBRARY', 'Could not find the \'pclzip\' library, check installation instructions');
function FEerror($msg)
return ('<em class="error">'. $msg .'</em><br />');
function FEpage_data(&$this, $tag, &$page_content)
// add page footer from FootnoteAction
function FEhtml(&$this, &$pages, &$key_order, $embed_css, $css_path, $remove_links, $save_tag, $save_page)
$root_url = $_SERVER['SERVER_NAME'] . $_SERVER['PHP_SELF'];
$header = "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>\n".
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1' />\n";
if ($fcss = fopen($css_path, 'r'))
if (!($stylesheet = file_get_contents($css_path)))
$stylesheet = '';
else
$stylesheet = "<style type='text/css'>$stylesheet\n</style>";
$stylesheet = '';
$header .= ($embed_css ? $stylesheet : '') .'<title>'. $this->GetConfigValue('wakka_name') ."</title></head><body>\n";
$toc = '';
$file_name = $this->GetConfigValue('wakka_name') .'_'. date('Ymd');
foreach ($pages as $tag => $mypage)
{ // prepare mapping table for translation of intra-wiki links
$pat[] = '/'. preg_quote('http://'.$root_url, '/') .'\?wakka='. $tag .'([^\w^Ä^Ö^Ü^ß^ä^ö^ü])/';
$rep[] = '#'. $mypage['i'] .'$1';
$save_includes = $this->config['includes'];
foreach ($key_order as $tag => $val)
$pagedata = array();
FEpage_data($this, $tag, $pagedata);
$toc .= '<li><a href="#'. $pages[$tag]['i'] .'">'. $pages[$tag]['title'] ."</a></li>\n";
// preserve intra-wiki links
$pagedata['body'] = '<a name="'. $pages[$tag]['i'] .'"></a>'. preg_replace($pat, $rep, $pagedata['body']);
// relabel footnotes from FootnoteAction
$pagedata['body'] = preg_replace("/href=\'\#(\d+)\#fn(\d+)/", "href='#fn$1_$2", $pagedata['body']);
$pagedata['body'] = preg_replace("/id=\'fn(\d+)/", "id='fn". $pages[$tag]['i']. "_$1", $pagedata['body']);
$pagedata['body'] = preg_replace("/href=\'\#(\d+)\#fnback(\d+)/", "href='#fnback$1_$2", $pagedata['body']);
$pagedata['body'] = preg_replace("/id=\'fnback(\d+)/", "id='fnback". $pages[$tag]['i']. "_$1", $pagedata['body']);
// if requested, remove external links including tail
if ($remove_links)
{
$pagedata['body'] = preg_replace("/<\s*a[^>]+href=([\'\"])[^#][^>]*?\>(.*?)<\/a>/", "$2", $pagedata['body']);
$pagedata['body'] = preg_replace('/'.preg_quote($this->GetConfigValue('external_link_tail'),'/').'/', '', $pagedata['body']);
$output .= $pagedata['body'] ."<hr />\n";
$output = $header .'<div class="page"><h2>'. FE_TABLE_OF_CONTENTS. '</h2><ul>'. $toc .'</ul><hr />'. $output;
// restore original values
$this->tag = $save_tag;
$this->page = $save_page;
$this->config['includes'] = $save_includes;
header('Content-Disposition: attachment; filename='. $file_name .'.html');
header('Content-Type: text/html; charset=ISO-8859-1');
header('Expires: 0');
header('Pragma: no-cache');
print $output;
echo '</div></body></html>';
exit();
function FExml(&$this, &$pages, &$key_order, $remove_links, $save_tag, $save_page)
$file_name = $this->GetConfigValue('wakka_name') .'_'. date('Ymd');
$output = '<?xml version="1.0" encoding="UTF-8" standalone="yes" ?><wikka>';
$save_includes = $this->config['includes'];
foreach ($key_order as $tag => $val)
$mytab = $pages[$tag];
$output .= '<page tag="'. $tag .'" lastchange="'. strftime('%Y-%m-%dT%H:%M:%S', strtotime($mytab['lastchange'])) .'"><owner>'. $mytab['owner'] .'</owner>';
foreach (explode (' ', $mytab['cats']) as $mycat)
if ($mycat)
$output .= '<category>'. $mycat. '</category>';
$output .= '<title>'. utf8_encode(htmlspecialchars($mytab['title'], ENT_COMPAT, 'UTF-8')) ."</title>\n";
$pagedata = array();
FEpage_data($this, $tag, $pagedata);
$output .= '<raw_content>'. utf8_encode(htmlspecialchars($pagedata['raw'], ENT_COMPAT)) .".</raw_content>\n";
if ($remove_links)
{ // if requested, remove external links including tail
$pagedata['body'] = preg_replace("/<\s*a[^>]+href=([\'\"])[^#][^>]*?\>(.*?)<\/a>/", "$2", $pagedata['body']);
$pagedata['body'] = preg_replace('/'.preg_quote($this->GetConfigValue('external_link_tail'),'/').'/', '', $pagedata['body']);
$output .= '<rendered_content>'. utf8_encode(htmlspecialchars($pagedata['body'], ENT_COMPAT, 'UTF-8')) .'</rendered_content>';
if (preg_match_all('/\{\{structdata(.+?)\}\}/', $pagedata['raw'], $matches))
{ // extract structured data items and add them to XML
foreach ($matches[1] as $mym)
$structdatatype = '';
$params = array();
if (preg_match('/type=\"(.*?)\"[ \t]*.*?data=\"(.*?)\"/', $mym, $matches2))
{
$structdatatype = $matches2[1];
preg_match_all('/(\w+?)\=\'(.*?)\'/', $matches2[2], $matches3);
}
else if (preg_match('/data=\"(.*?)\"[ \t]*.*?type=\"(.*?)\"/', $mym, $matches2))
{
$structdatatype = $matches2[2];
preg_match_all('/(\w+?)\=\'(.*?)\'/', $matches2[1], $matches3);
}
for ($i=0; $i < count($matches3[1]); $i++)
{
$params[strtolower($matches3[1][$i])] = $matches3[2][$i];
}
if ($structdatatype)
{
$output .= '<structdataitem type="'. $structdatatype. '">';
foreach ($params as $myparam => $myval)
{
$output .= '<'. $myparam .'>'. utf8_encode(htmlspecialchars($myval, ENT_COMPAT)) .'</'. $myparam .'>';
}
$output .= "</structdataitem>\n";
}
$output .= "</page>\n";
$output .= '</wikka>';
// restore original values
$this->tag = $save_tag;
$this->page = $save_page;
$this->config['includes'] = $save_includes;
header('Content-Disposition: attachment; filename='. $file_name .'.xml');
header('Content-Type: text/xml; charset=UTF-8');
header('Expires: 0');
header('Pragma: no-cache');
print $output;
exit();
if ((isset($_GET['emb']) && (!preg_match("/^[YN]$/i", $_GET['emb'])))
|| (isset($_GET['scope']) && (!preg_match("/^([oO]|[pP]|[mM]|[A-ZÄÖÜ]+[a-zßäöü]+[A-Z0-9ÄÖÜ][A-Za-z0-9ÄÖÜßäöü]*)$/", $_GET['scope'])))
$css_path = 'css' .DIRECTORY_SEPARATOR. $this->GetConfigValue('stylesheet');
if ('m' == strtolower($_GET['scope']))
$query .= ' AND (owner = \''. $this->GetUserName() .'\')';
else if ('o' == strtolower($_GET['scope']))
$query .= ' AND (owner <> \'(Public)\')';
else if ('p' == strtolower($_GET['scope']))
{ // placeholder
$query .= '';
else
{ // a single page is exported
$query .= ' AND (tag = \''. $_GET['scope'] .'\')';
$query .= ' AND (body REGEXP \'Category[A-Z0-9ÄÖÜ][A-Za-z0-9ÄÖÜßäöü]*[[:>:]]\')';
{ // this page is to be exported: pretend your are this page
$pages[$row['tag']]['title'] = trim($this->PageTitle());
FEhtml($this, $pages, $key_order, $embed_css, $css_path, $remove_links, $save_tag, $save_page);
FExml($this, $pages, $key_order, $remove_links, $save_tag, $save_page);
$xml .= '<?xml-stylesheet href="' . $this->GetConfigValue('base_url') .'/css/xml.css" type="text/css"?' .">\n";
Deletions:
- Wikka 1.1.6.2
%%(php)<?php
# @version 0.95
# @input Parameters = [type=('html'|'xml')] [sort=('tag'|'type'|'title')] [opts=['e']['o']['p']['r']] [cats='Category1','Category2'..]
if (!defined('FE_ERROR_USAGE')) define ('FE_ERROR_USAGE', "fileexport [type=\"html|xml\"] [opts=\"[e][o][p][r]\"] [sort=\"tag|time|title\"] [cats=\"<i>category list</i>\"]");
return ("<em class='error'>$msg</em><br />");
$output = "";
if ( (isset($vars['opts']) && (!preg_match("/^[eopr]{1,4}$/i", $vars['opts'])))
$query = "&type=". $type;
$query .= "&own=". (preg_match("/[o]/i", $vars['opts']) ? 'n' : 'y');
$query .= "&sys=". (preg_match("/[p]/i", $vars['opts']) ? 'y' : 'n');
$query .= "&cats=";
%%(php)<?php
# @version 0.99
if (!defined('FE_TABLE_OF_CONTENTS')) define ('FE_TABLE_OF_CONTENTS', "Table of contents");
if (!defined('FE_ERROR_REQUEST_STRING')) define ('FE_ERROR_REQUEST_STRING', "Illegal request string, unable to export");
if (!defined('FE_ERROR_ARCHIVE_BUILD')) define ('FE_ERROR_ARCHIVE_BUILD', "Error building the archive file, unable to export");
return ("<em class='error'>$msg</em><br />");
function FEpage_data (&$this, $tag, &$page_content)
// page footer from FootnoteAction
function FEhtml (&$this, &$pages, &$key_order, $embed_css, $css_path, $remove_links, $save_tag, $save_page)
{
$root_url = $_SERVER['SERVER_NAME'].$_SERVER['PHP_SELF'];
$header = "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>\n".
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1' />\n";
if ($fcss = fopen($css_path, 'r'))
{
if (!($stylesheet = file_get_contents($css_path)))
{
$stylesheet = '';
}
else
{
$stylesheet = "<style type='text/css'>$stylesheet\n</style>";
}
}
else
{
$stylesheet = '';
}
$header .= ($embed_css ? $stylesheet : '') .'<title>'. $this->GetConfigValue('wakka_name') ."</title></head><body>\n";
$toc = '';
$file_name = $this->GetConfigValue('wakka_name') .'_'. date('Ymd');
foreach ($pages as $tag => $mypage)
{
// prepare mapping table for translation of intra-wiki links
$pat[] = '/'. preg_quote('http://'.$root_url, '/') .'\?wakka='. $tag .'([^\w\.\/]?)/';
$rep[] = '#'. $mypage['i'] .'$1';
}
$save_includes = $this->config['includes'];
foreach ($key_order as $tag => $val)
{
$pagedata = array();
FEpage_data($this, $tag, $pagedata);
$toc .= "<li><a href='#{$pages[$tag]['i']}'>". $pages[$tag]['title'] ."</a></li>\n";
// preserve intra-wiki links
$pagedata['body'] = "<a name='". $pages[$tag]['i'] ."'></a>". preg_replace($pat, $rep, $pagedata['body']);
// relabel footnotes from FootnoteAction
$pagedata['body'] = preg_replace("/href=\'\#(\d+)\#fn(\d+)/", "href='#fn$1_$2", $pagedata['body']);
$pagedata['body'] = preg_replace("/id=\'fn(\d+)/", "id='fn". $pages[$tag]['i']. "_$1", $pagedata['body']);
$pagedata['body'] = preg_replace("/href=\'\#(\d+)\#fnback(\d+)/", "href='#fnback$1_$2", $pagedata['body']);
$pagedata['body'] = preg_replace("/id=\'fnback(\d+)/", "id='fnback". $pages[$tag]['i']. "_$1", $pagedata['body']);
// if requested, remove external links including tail
if ($remove_links)
{
$pagedata['body'] = preg_replace("/<\s*a[^>]+href=([\'\"])[^#][^>]*?\>(.*?)<\/a>/", "$2", $pagedata['body']);
$pagedata['body'] = preg_replace('/'.preg_quote($this->GetConfigValue('external_link_tail'),'/').'/', '', $pagedata['body']);
}
$output .= $pagedata['body'] ."<hr />\n";
}
$output = $header ."<div class='page'><h2>". FE_TABLE_OF_CONTENTS. '</h2><ul>'. $toc .'</ul><hr />'. $output;
// restore original values
$this->tag = $save_tag;
$this->page = $save_page;
$this->config['includes'] = $save_includes;
header('Content-Disposition: attachment; filename='. $file_name .'html');
header('Content-Type: text/html; charset=ISO-8859-1');
header('Expires: 0');
header('Pragma: no-cache');
print $output;
echo '</div></body></html>';
exit();
function FExml (&$this, &$pages, &$key_order, $remove_links, $save_tag, $save_page)
{
$file_name = $this->GetConfigValue('wakka_name') .'_'. date('Ymd');
$output = '<?xml version="1.0" encoding="UTF-8" standalone="yes" ?><wikka>';
$save_includes = $this->config['includes'];
foreach ($key_order as $tag => $val)
{
$mytab = $pages[$tag];
$output .= '<page tag="'. $tag .'" lastchange="'. strftime('%Y-%m-%dT%H:%M:%S', strtotime($mytab['lastchange'])) .'"><owner>'. $mytab['owner'] .'</owner>';
foreach (explode (' ', $mytab['cats']) as $mycat)
{
if ($mycat)
{
$output .= '<category>'. $mycat. '</category>';
}
}
$output .= '<title>'. utf8_encode(htmlspecialchars($mytab['title'], ENT_COMPAT, 'UTF-8')) .'</title>\n';
$pagedata = array();
FEpage_data($this, $tag, $pagedata);
$output .= '<raw_content>'. utf8_encode(htmlspecialchars($pagedata['raw'], ENT_COMPAT)) .".</raw_content>\n";
// if requested, remove external links including tail
if ($remove_links)
{
$pagedata['body'] = preg_replace("/<\s*a[^>]+href=([\'\"])[^#][^>]*?\>(.*?)<\/a>/", "$2", $pagedata['body']);
$pagedata['body'] = preg_replace('/'.preg_quote($this->GetConfigValue('external_link_tail'),'/').'/', '', $pagedata['body']);
}
$output .= '<rendered_content>'.utf8_encode(htmlspecialchars($pagedata['body'], ENT_COMPAT, 'UTF-8')).".</rendered_content>";
$output .= "</page>\n";
}
$output .= '</wikka>';
// restore original values
$this->tag = $save_tag;
$this->page = $save_page;
$this->config['includes'] = $save_includes;
header('Content-Disposition: attachment; filename='. $file_name .'xml');
header('Content-Type: text/xml; charset=UTF-8');
header('Expires: 0');
header('Pragma: no-cache');
print $output;
exit();
if ((isset($_GET['own']) && !(preg_match("/^[YN]$/i", $_GET['own'])))
|| (isset($_GET['emb']) && (!preg_match("/^[YN]$/i", $_GET['emb'])))
|| (isset($_GET['sys']) && (!preg_match("/^[YN]$/i", $_GET['sys'])))
$css_path = 'css/'. $this->GetConfigValue('stylesheet');
if ('y' == strtolower($_GET['own']))
$query .= " AND (owner = '".$this->GetUserName()."')";
if ('y' != strtolower($_GET['sys']))
$query .= " AND (owner <> '(Public)')";
$query .= " AND (body REGEXP 'Category[A-Z0-9ÄÖÜ][A-Za-z0-9ÄÖÜßäöü]*[[:>:]]')";
// this page is to be exported: pretend your are this page
$pages[$row['tag']]['title'] = $this->PageTitle();
FEhtml ($this, $pages, $key_order, $embed_css, $css_path, $remove_links, $save_tag, $save_page);
FExml ($this, $pages, $key_order, $remove_links, $save_tag, $save_page);
$xml .= '<?xml-stylesheet href="' . $this->GetConfigValue("base_url") .'/css/xml.css" type="text/css"?' .">\n";


Revision [16468]

Edited on 2007-04-22 09:24:41 by DomBonj [v0.99: reduced memory usage; added 'e' and 'r' options; support for Footnote action; coding standard]
Additions:
# Displays a link to download a selection of the wiki content in various formats
# @version 0.95
# @input Parameters = [type=('html'|'xml')] [sort=('tag'|'type'|'title')] [opts=['e']['o']['p']['r']] [cats='Category1','Category2'..]
// i18n strings
if (!defined('FE_ERROR_REQUEST_FORMAT')) define ('FE_ERROR_REQUEST_FORMAT', 'Incorrect parameter; usage: %s');
if (!defined('FE_ERROR_USAGE')) define ('FE_ERROR_USAGE', "fileexport [type=\"html|xml\"] [opts=\"[e][o][p][r]\"] [sort=\"tag|time|title\"] [cats=\"<i>category list</i>\"]");
function FEerror ($msg)
{
return ("<em class='error'>$msg</em><br />");
$output = "";
if (isset($vars['cats']))
$categories = preg_split("/\s*,\s*/i", $vars['cats']);
if ( (isset($vars['opts']) && (!preg_match("/^[eopr]{1,4}$/i", $vars['opts'])))
|| (isset($vars['type']) && (!preg_match("/^(html|xml)$/i", $vars['type'])))
|| (isset($vars['sort']) && (!preg_match("/^(time|tag|title)$/i", $vars['sort']))))
$output .= FEerror(sprintf(FE_ERROR_REQUEST_FORMAT, FE_ERROR_USAGE));
else
$query = "&type=". $type;
$query .= "&emb=". (preg_match("/[e]/i", $vars['opts']) ? 'y' : 'n');
$query .= "&rlnk=". (preg_match("/[r]/i", $vars['opts']) ? 'y' : 'n');

if ($categories)
{
foreach ($categories as $lacat)
{
// sanitize categories
if (preg_match("/^(Category[A-Z0-9ÄÖÜ][A-Za-z0-9ÄÖÜßäöü]*)\s*$/", $lacat, $matches))
{
if ($first)
{
$query .= $matches[1];
$first = false;
else
{
$query .= '_'. $lacat;
}
$output .= '<a href="'. $this->Href('fileexport.xml'.$query, $this->tag, '') .'" title="'. FE_DOWNLOAD_LINK_TITLE. '">'. sprintf(FE_DOWNLOAD_LINK_TEXT, strtoupper($type)). '</a>';
# Exports part of the wiki content in various formats
# @name fileexport.xml
# @version 0.99
# @uses Wakka::PageTitle()
// i18n strings
if (!defined('FE_ERROR_REQUEST_STRING')) define ('FE_ERROR_REQUEST_STRING', "Illegal request string, unable to export");
if (!defined('FE_ERROR_ARCHIVE_BUILD')) define ('FE_ERROR_ARCHIVE_BUILD', "Error building the archive file, unable to export");
function FEerror ($msg)
{
return ("<em class='error'>$msg</em><br />");

function FEpage_data (&$this, $tag, &$page_content)
{
// pretend your are this page
$this->SetPage($this->LoadPage($tag));
unset ($this->config['includes']);
$page_content['raw'] = $this->page['body'];
// prevent recursive calling
$page = preg_replace('/\{\{\s*fileexport\b(.*?)\}\}/', "[fileexport action, $1]", $this->page['body']);
$rendered_body = $this->Format($page, 'wakka');
// page footer from FootnoteAction
if (function_exists('FNprint'))
{
$rendered_body .= FNprint($this, 'list', '', $this->Href());
$page_content['body'] = $rendered_body;

function FEhtml (&$this, &$pages, &$key_order, $embed_css, $css_path, $remove_links, $save_tag, $save_page)
{
$root_url = $_SERVER['SERVER_NAME'].$_SERVER['PHP_SELF'];
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1' />\n";
if ($fcss = fopen($css_path, 'r'))
{
if (!($stylesheet = file_get_contents($css_path)))
{
$stylesheet = '';
else
{
$stylesheet = "<style type='text/css'>$stylesheet\n</style>";
else
{
$stylesheet = '';
$header .= ($embed_css ? $stylesheet : '') .'<title>'. $this->GetConfigValue('wakka_name') ."</title></head><body>\n";
$toc = '';
$file_name = $this->GetConfigValue('wakka_name') .'_'. date('Ymd');
foreach ($pages as $tag => $mypage)
{
// prepare mapping table for translation of intra-wiki links
$pat[] = '/'. preg_quote('http://'.$root_url, '/') .'\?wakka='. $tag .'([^\w\.\/]?)/';
$rep[] = '#'. $mypage['i'] .'$1';
$save_includes = $this->config['includes'];
foreach ($key_order as $tag => $val)
{
$pagedata = array();
FEpage_data($this, $tag, $pagedata);
$toc .= "<li><a href='#{$pages[$tag]['i']}'>". $pages[$tag]['title'] ."</a></li>\n";
// preserve intra-wiki links
$pagedata['body'] = "<a name='". $pages[$tag]['i'] ."'></a>". preg_replace($pat, $rep, $pagedata['body']);
// relabel footnotes from FootnoteAction
$pagedata['body'] = preg_replace("/href=\'\#(\d+)\#fn(\d+)/", "href='#fn$1_$2", $pagedata['body']);
$pagedata['body'] = preg_replace("/id=\'fn(\d+)/", "id='fn". $pages[$tag]['i']. "_$1", $pagedata['body']);
$pagedata['body'] = preg_replace("/href=\'\#(\d+)\#fnback(\d+)/", "href='#fnback$1_$2", $pagedata['body']);
$pagedata['body'] = preg_replace("/id=\'fnback(\d+)/", "id='fnback". $pages[$tag]['i']. "_$1", $pagedata['body']);
// if requested, remove external links including tail
if ($remove_links)
{
$pagedata['body'] = preg_replace("/<\s*a[^>]+href=([\'\"])[^#][^>]*?\>(.*?)<\/a>/", "$2", $pagedata['body']);
$pagedata['body'] = preg_replace('/'.preg_quote($this->GetConfigValue('external_link_tail'),'/').'/', '', $pagedata['body']);
$output .= $pagedata['body'] ."<hr />\n";
$output = $header ."<div class='page'><h2>". FE_TABLE_OF_CONTENTS. '</h2><ul>'. $toc .'</ul><hr />'. $output;
// restore original values
$this->tag = $save_tag;
$this->page = $save_page;
$this->config['includes'] = $save_includes;
header('Content-Disposition: attachment; filename='. $file_name .'html');
echo '</div></body></html>';
function FExml (&$this, &$pages, &$key_order, $remove_links, $save_tag, $save_page)
{
$file_name = $this->GetConfigValue('wakka_name') .'_'. date('Ymd');
$save_includes = $this->config['includes'];
foreach ($key_order as $tag => $val)
{
$output .= '<page tag="'. $tag .'" lastchange="'. strftime('%Y-%m-%dT%H:%M:%S', strtotime($mytab['lastchange'])) .'"><owner>'. $mytab['owner'] .'</owner>';
foreach (explode (' ', $mytab['cats']) as $mycat)
{
if ($mycat)
{
$output .= '<category>'. $mycat. '</category>';
}
$output .= '<title>'. utf8_encode(htmlspecialchars($mytab['title'], ENT_COMPAT, 'UTF-8')) .'</title>\n';
$pagedata = array();
FEpage_data($this, $tag, $pagedata);
$output .= '<raw_content>'. utf8_encode(htmlspecialchars($pagedata['raw'], ENT_COMPAT)) .".</raw_content>\n";
// if requested, remove external links including tail
if ($remove_links)
{
$pagedata['body'] = preg_replace("/<\s*a[^>]+href=([\'\"])[^#][^>]*?\>(.*?)<\/a>/", "$2", $pagedata['body']);
$pagedata['body'] = preg_replace('/'.preg_quote($this->GetConfigValue('external_link_tail'),'/').'/', '', $pagedata['body']);
$output .= '<rendered_content>'.utf8_encode(htmlspecialchars($pagedata['body'], ENT_COMPAT, 'UTF-8')).".</rendered_content>";
$output .= '</wikka>';
// restore original values
$this->tag = $save_tag;
$this->page = $save_page;
$this->config['includes'] = $save_includes;
header('Content-Disposition: attachment; filename='. $file_name .'xml');
$pages = array();
$error_msg = '';
if (isset($_GET['cats']))
$categories = preg_split("/_/i", $_GET['cats']);
if ((isset($_GET['own']) && !(preg_match("/^[YN]$/i", $_GET['own'])))
|| (isset($_GET['emb']) && (!preg_match("/^[YN]$/i", $_GET['emb'])))
|| (isset($_GET['rlnk']) && (!preg_match("/^[YN]$/i", $_GET['rlnk'])))
|| (isset($_GET['sys']) && (!preg_match("/^[YN]$/i", $_GET['sys'])))
|| (isset($_GET['type']) && (!preg_match("/^(html|xml)$/i", $_GET['type'])))
|| (isset($_GET['sort']) && (!preg_match("/^(time|tag|title)$/i", $_GET['sort']))))
{
$error_msg .= FEerror(FE_ERROR_REQUEST_STRING);
else
$embed_css = ('y' == strtolower($_GET['emb']));
$remove_links = ('y' == strtolower($_GET['rlnk']));
$css_path = 'css/'. $this->GetConfigValue('stylesheet');
$query = 'SELECT * FROM '. $this->config['table_prefix']. 'pages WHERE ((latest = \'Y\')';
if ('y' == strtolower($_GET['own']))
{
{
if ($categories[0])
{
$query .= " AND (body REGEXP 'Category[A-Z0-9ÄÖÜ][A-Za-z0-9ÄÖÜßäöü]*[[:>:]]')";
$query .= ')';
foreach ($rows as $row)
{
if ($categories[0])
{
$match = false;
foreach ($categories as $mycat)
{
if (preg_match("/\b$mycat\b/i", $row['body']))
{
else
{
$match = true;
// sanitize categories
preg_match_all("/\b(Category[A-Z0-9ÄÖÜ][A-Za-z0-9ÄÖÜßäöü]*)\b/", $row['body'], $matches);
{
if ($match && $this->HasAccess('read', $row['tag']))
{
// fill the 'pages' associative array
$pages[$row['tag']]['cats'] = implode (' ', array_unique($itscats));
$pages[$row['tag']]['title'] = $this->PageTitle();
if (isset($_GET['sort']))
{
if ($_GET['sort'] == 'time')
{
$field = 'ts'; $fn = 'arsort';
else if ($_GET['sort'] == 'title')
{
$field = 'title'; $fn= 'asort';
if (!$field)
{
$field = 'tag'; $fn = 'asort';
$key_order = array();
foreach ($pages as $tag => $mytab)
{
$key_order[$tag] = ($field == 'tag') ? strtolower($tag) : strtolower($mytab[$field]);
$fn($key_order);

if (!isset($_GET['type']) || $_GET['type'] == 'html')
{
FEhtml ($this, $pages, $key_order, $embed_css, $css_path, $remove_links, $save_tag, $save_page);
else if ($_GET['type'] == 'xml')
{
FExml ($this, $pages, $key_order, $remove_links, $save_tag, $save_page);
if ($error_msg)
header('Content-type: text/xml');
$xml = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n";
$xml .= '<?xml-stylesheet href="' . $this->GetConfigValue("base_url") .'/css/xml.css" type="text/css"?' .">\n";
$xml .= '<item><title>Error message</title>';
$xml .= '<description>'. $error_msg. '</description></item>';
print $xml;
Deletions:
# Displays a link to download a selection of the wiki content as a single HTML or XML file
# @version 0.9
# @input Parameters = [html=('html'|'xml')] [sort=('tag'|'type'|'cnt')] [opts=['o']['p']] [cats='Category1','Category2'..]
function FEerror ($msg) {
return ("<em class='error'>$msg</em><br />");
$output = "";
if (isset($vars['cats'])) $categories = preg_split("/\s*,\s*/i", $vars['cats']);
if ( (isset($vars['opts']) && (!preg_match("/^[op]{1,2}$/i", $vars['opts'])))
|| (isset($vars['type']) && (!preg_match("/^(html|xml)$/i", $vars['type'])))
|| (isset($vars['sort']) && (!preg_match("/^(time|tag|title)$/i", $vars['sort']))))
$output .= FEerror("Usage: fileexport [own=\"Y|N\"] [sys=\"Y|N\"] [sort=\"tag|time|title\"] [cats=\"<i>category list</i>\"]");
else {
$query = "&type=$type";
if ($categories) {
foreach ($categories as $lacat) {
// sanitize categories
if (preg_match("/^(Category[A-Z0-9ÄÖÜ][A-Za-z0-9ÄÖÜßäöü]*)\s*$/", $lacat, $matches)) {
if ($first) {
$query .= $matches[1];
$first = false;
else $query .= "_".$lacat;
$output .= '<a href="'. $this->Href('fileexport.xml'.$query, $this->tag, ''). '" title="'.FE_DOWNLOAD_LINK_TITLE.'">'. sprintf(FE_DOWNLOAD_LINK_TEXT, strtoupper($type)). '</a>';
# Exports part of the wiki content as a single HTML or XML file
# @version 0.91
// i18n
function FEerror ($msg) {
return ("<em class='error'>$msg</em><br />");
function FEhtml ($this, $pages, $csspath="", $keyorder, $title="") {
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1' />\n<style type='text/css'>";
if ($fcss = fopen($csspath, 'r')) {
if (!($stylesheet = file_get_contents($csspath)))
$stylesheet = "";
} else $stylesheet = "";
$header .= $stylesheet."\n</style><title>".$this->GetConfigValue("wakka_name")."</title></head><body>\n";
$toc = "";
$filename = $this->GetConfigValue("wakka_name")."_".date("Ymd");
foreach ($keyorder as $tag => $val) {
$toc .= "<li><a href='#{$pages[$tag]['i']}'>{$pages[$tag]['title']}</a></li>\n";
$output .= $pages[$tag]['body']."<hr />\n";
$output = "$header<div class='page'><h2>".FE_TABLE_OF_CONTENTS."</h2><ul>$toc</ul><hr />$output</div></body></html>";
header("Content-disposition: attachment; filename=$filename.html");
// header('Cache-Control: private');
function FExml ($this, $pages, $keyorder, $title="") {
$filename = $this->GetConfigValue("wakka_name")."_".date("Ymd");
foreach ($keyorder as $tag => $val) {
$output .= "<page tag=\"{$tag}\" lastchange=\"".strftime("%Y-%m-%dT%H:%M:%S", strtotime($mytab['lastchange']))."\"><owner>{$mytab['owner']}</owner>";
foreach (explode (' ', $mytab['cats']) as $mycat) {
if ($mycat) $output .= "<category>$mycat</category>";
$output .= "<title>".utf8_encode(htmlspecialchars($mytab['title'], ENT_COMPAT, "UTF-8"))."</title>\n";
$output .= "<raw_content>".utf8_encode(htmlspecialchars($mytab['raw'], ENT_COMPAT, "UTF-8")).".</raw_content>\n";
$output .= "<rendered_content>".utf8_encode(htmlspecialchars($mytab['body'], ENT_COMPAT, "UTF-8")).".</rendered_content>";
$output .= "</wikka>";
header("Content-disposition: attachment; filename=$filename.xml");
$pages = array();
$error_msg = "";
if (isset($_GET['cats'])) $categories = preg_split("/_/i", $_GET['cats']);
if ((isset($_GET['own']) && !(preg_match("/^[YN]$/i", $_GET['own'])))
|| (isset($_GET['sys']) && (!preg_match("/^[YN]$/i", $_GET['sys'])))
|| (isset($_GET['type']) && (!preg_match("/^(html|xml)$/i", $_GET['type'])))
|| (isset($_GET['sort']) && (!preg_match("/^(time|tag|title)$/i", $_GET['sort']))))
$error_msg .= FEerror("illegal request string, unable to export");
else {
$csspath = "css/".$this->GetConfigValue("stylesheet");
$root_url = $_SERVER['SERVER_NAME'].$_SERVER['PHP_SELF'];
$query = "SELECT * FROM ".$this->config['table_prefix']."pages WHERE ((latest = 'Y')";
if ('y' == strtolower($_GET['own']))
$query .= ")";
foreach ($rows as $row) {
if ($categories[0]) {
$match = false;
foreach ($categories as $mycat) {
if (preg_match("/$mycat/i", $row['body'])) {
} else {
$match = true;
// sanitize categories
preg_match_all("/(Category[A-Z0-9ÄÖÜ][A-Za-z0-9ÄÖÜßäöü]*)\b/", $row['body'], $matches);
if ($match && $this->HasAccess("read", $row['tag'])) {
// prevent recursive calling
$page = preg_replace('/\{\{\s*fileexport\b(.*?)\}\}/', "[fileexport action, $1]", $this->page['body']);
// fill 'pages' associative array
$pages[$row['tag']]['raw'] = $this->page['body'];
$pages[$row['tag']]['cats'] = implode (' ', $itscats);
$pages[$row['tag']]['body'] = "<a name='$pagecnt'></a>".$this->Format($page, 'wakka');
// set title for Table of Contents
$title = "";
if (preg_match('/^(={2,6})([^=\n]+)\1/', $this->page['body'], $matches)) {
$title = $matches[2];
$formatting_tags = array("**", "//", "__", "##", "''", "++", "#%", "@@", "\"\"");
$title = str_replace($formatting_tags, "", $title);
$title = strip_tags($this->Format($title));
$pages[$row['tag']]['title'] = ($title) ? $title : $this->page['tag'];
foreach ($pages as $tag => $mytab) {
// prepare mapping table for translation of intra-wiki links
$pat[] = "/".preg_quote('http://'.$root_url, '/')."\?wakka=".$tag."([^\w\.\/])/";
$rep[] = "#".$pages[$tag]['i']."$1";
foreach ($pages as $tag => $mytab) {
// preserve intra-wiki links
$pages[$tag]['body'] = preg_replace($pat, $rep, $mytab['body']);
// restore original values
$this->tag = $save_tag;
$this->page = $save_page;
if (isset($_GET['sort'])) {
if ($_GET['sort'] == 'time') { $field = 'ts'; $fn = 'arsort'; }
else if ($_GET['sort'] == 'title') { $field = 'title'; $fn= 'asort'; }
if (!$field) { $field = 'tag'; $fn = 'asort'; }
$keyorder = array();
foreach ($pages as $tag => $mytab) {
$keyorder[$tag] = ($field == 'tag') ? strtolower($tag) : strtolower($mytab[$field]);
$fn($keyorder);
if (!isset($_GET['type']) || $_GET['type']=='html')
FEhtml ($this, $pages, $csspath, $keyorder);
else if ($_GET['type']=='xml')
FExml ($this, $pages, $keyorder);
if ($error_msg) {
header("Content-type: text/xml");
$xml = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n";
$xml .= '<?xml-stylesheet href="' . $this->GetConfigValue("base_url") .'/css/xml.css" type="text/css"?' .">\n";
$xml .= '<item><title>Error message</title>';
$xml .= '<description>'. $error_msg. '</description></item>';
print $xml;


Revision [16229]

Edited on 2007-02-27 17:23:06 by DomBonj [v0.91: changed XML format]
Additions:
# @version 0.91
$output .= "<page tag=\"{$tag}\" lastchange=\"".strftime("%Y-%m-%dT%H:%M:%S", strtotime($mytab['lastchange']))."\"><owner>{$mytab['owner']}</owner>";
Deletions:
$output .= "<page><tag>{$tag}</tag>\n<owner>{$mytab['owner']}</owner><lastchange>{$mytab['lastchange']}</lastchange>\n";


Revision [16176]

Edited on 2007-02-21 16:53:16 by DomBonj [v0.90: first upload]
Additions:
- Documentation: FileexportActionInfo
Deletions:
- Documentation: FileexportActionInfo.


Revision [16175]

Edited on 2007-02-21 16:52:54 by DomBonj [v0.90:typo]
Additions:
- Documentation: FileexportActionInfo.
Deletions:
- Documentation: FileexportActionInfo


Revision [16174]

Edited on 2007-02-21 16:51:53 by DomBonj [typo]
Additions:
<<##handlers/page/fileexport.xml.php##<<
Deletions:
<<##handlers/page/filexport.xml.php##<<


Revision [16173]

The oldest known version of this page was created on 2007-02-21 16:51:15 by DomBonj [typo]
Valid XHTML :: Valid CSS: :: Powered by WikkaWiki