diff -r 45e887f23282 -r 7152ca0a0ce9 includes/render.php
--- a/includes/render.php Mon Feb 16 16:04:54 2009 -0500
+++ b/includes/render.php Mon Feb 16 16:17:25 2009 -0500
@@ -42,79 +42,14 @@
{
global $db, $session, $paths, $template, $plugins; // Common objects
- $perms =& $session;
-
- if ( $page_id != $paths->page_id || $namespace != $paths->namespace )
- {
- unset($perms);
- unset($perms); // PHP <5.1.5 Zend bug
- $perms = $session->fetch_page_acl($page_id, $namespace);
- if ( !$perms )
- {
- $session->init_permissions();
- $perms = $session->fetch_page_acl($page_id, $namespace);
- };
- }
-
- if(!$perms->get_permissions('read'))
- return 'Access denied ('.$paths->nslist[$namespace].$page_id.')';
-
- if($namespace != 'Template' && ($wiki == 0 || $render == false))
- {
- if(!$perms->get_permissions('view_source'))
- {
- return 'Access denied ('.$paths->nslist[$namespace].$page_id.')';
- }
- }
-
- $q = $db->sql_query('SELECT page_text,char_tag FROM '.table_prefix.'page_text WHERE page_id=\''.$db->escape($page_id).'\' AND namespace=\''.$db->escape($namespace).'\';');
- if ( !$q )
- {
- $db->_die('Method called was: RenderMan::getPage(\''.$page_id.'\', \''.$namespace.'\');.');
- }
- if ( $db->numrows() < 1 )
- {
- return false;
- }
- $row = $db->fetchrow();
- $db->free_result();
+ $page = new PageProcessor($page_id, $namespace);
+ $text = $page->fetch_text();
- $message = $row['page_text'];
- $chartag = $row['char_tag'];
- unset($row); // Free some memory
+ if ( !$render )
+ return $text;
- if ( preg_match("#^\#redirect \[\[([^\]\r\n\a\t]+?)\]\]#", $message, $m) && $redir && ( !isset($_GET['redirect']) || ( isset($_GET['redirect']) && $_GET['redirect'] != 'no' ) ) )
- {
- $old = $paths->cpage;
- $a = RenderMan::strToPageID($m[1]);
- $a[0] = str_replace(' ', '_', $a[0]);
-
- $pageid = str_replace(' ', '_', $paths->nslist[$a[1]] . $a[0]);
- $paths->page = $pageid;
- $paths->cpage = $paths->pages[$pageid];
- //die('
'.print_r($paths->cpage,true).'
');
-
- unset($template);
- unset($GLOBALS['template']);
-
- $GLOBALS['template'] = new template();
- global $template;
-
- $template->template(); // Tear down and rebuild the template parser
- $template->load_theme($session->theme, $session->style);
-
- $data = ''.RenderMan::getPage($a[0], $a[1], $wiki, $smilies, $filter_links, false /* Enforces a maximum of one redirect */);
-
- return $data;
- }
- else if(preg_match('#^\#redirect \[\[(.+?)\]\]#', $message, $m) && isset($_GET['redirect']) && $_GET['redirect'] == 'no')
- {
- preg_match('#^\#redirect \[\[(.+)\]\]#', $message, $m);
- $m[1] = str_replace(' ', '_', $m[1]);
- $message = preg_replace('#\#redirect \[\[(.+)\]\]#', ' | This page is a redirector. This means that this page will not show its own content by default. Instead it will display the contents of the page it redirects to.
To create a redirect page, make the first characters in the page content #redirect [[Page_ID]]. For more information, see the Enano Wiki formatting guide.
This page redirects to '.$paths->pages[$m[1]]['name'].'. |
', $message);
- }
- $session->disallow_password_grab();
- return ($render) ? RenderMan::render($message, $wiki, $smilies, $filter_links) : $message;
+ $text = self::render($text, $wiki, $smilies, $filter_links);
+ return $text;
}
public static function getTemplate($id, $parms)
@@ -183,7 +118,7 @@
if ( isset($prefixlist[$match[1]]) )
{
$new_id = $paths->nslist[ $prefixlist[$match[1]] ] . sanitize_page_id($match[2]);
- if ( !isset($paths->pages[$new_id]) )
+ if ( !isPage($new_id) )
{
return "[[$new_id]]";
}
@@ -215,43 +150,36 @@
return $text;
}
- public static function render($text, $wiki = 1, $smilies = true, $filter_links = true)
+ /**
+ * Renders a glob of text. Note that this is PHP-safe, so if returned text (or rather, "?>" . $returned) has PHP it can be eval'ed.
+ * @param string Text to render
+ * @param int Render parameters - see constants.php
+ * @return string Rendered text
+ */
+
+ public static function render($text, $flags = RENDER_WIKI_DEFAULT, $smilies = true)
{
global $db, $session, $paths, $template, $plugins; // Common objects
- if($smilies)
+
+ if ( !$smilies )
+ $flags |= RENDER_NOSMILIES;
+
+ if ( $flags & ~RENDER_NOSMILIES )
{
$text = RenderMan::smilieyize($text);
}
- if($wiki == 1)
+ if ( $flags & RENDER_WIKI_DEFAULT )
{
- $text = RenderMan::next_gen_wiki_format($text);
+ $text = RenderMan::next_gen_wiki_format($text, $flags);
}
- elseif($wiki == 2)
+ else if ( $flags & RENDER_WIKI_TEMPLATE )
{
$text = $template->tplWikiFormat($text);
- }
+ }
return $text;
}
- public static function PlainTextRender($text, $wiki = 1, $smilies = false, $filter_links = true)
- {
- global $db, $session, $paths, $template, $plugins; // Common objects
- if($smilies)
- {
- $text = RenderMan::smilieyize($text);
- }
- if($wiki == 1)
- {
- $text = RenderMan::next_gen_wiki_format($text, true);
- }
- elseif($wiki == 2)
- {
- $text = $template->tplWikiFormat($text);
- }
- return $text;
- }
-
- public static function next_gen_wiki_format($text, $plaintext = false, $filter_links = true, $do_params = false)
+ private static function next_gen_wiki_format($text, $flags = 0)
{
global $db, $session, $paths, $template, $plugins; // Common objects
global $lang;
@@ -291,76 +219,75 @@
$text = preg_replace('/(.*?)<\/nodisplay>/is', '', $text);
}
- preg_match_all('/([\w\W]+?)<\/lang>/', $text, $langmatch);
- foreach ( $langmatch[0] as $i => $match )
+ if ( !($flags & RENDER_BLOCKONLY) )
{
- if ( $langmatch[1][$i] == $lang->lang_code )
- {
- $text = str_replace_once($match, $langmatch[2][$i], $text);
- }
- else
+ preg_match_all('/([\w\W]+?)<\/lang>/', $text, $langmatch);
+ foreach ( $langmatch[0] as $i => $match )
{
- $text = str_replace_once($match, '', $text);
+ if ( $langmatch[1][$i] == $lang->lang_code )
+ {
+ $text = str_replace_once($match, $langmatch[2][$i], $text);
+ }
+ else
+ {
+ $text = str_replace_once($match, '', $text);
+ }
}
- }
- $code = $plugins->setHook('render_wikiformat_pre');
- foreach ( $code as $cmd )
- {
- eval($cmd);
- }
+ $code = $plugins->setHook('render_wikiformat_pre');
+ foreach ( $code as $cmd )
+ {
+ eval($cmd);
+ }
//$template_regex = "/\{\{([^\]]+?)((\n([ ]*?)[A-z0-9]+([ ]*?)=([ ]*?)(.+?))*)\}\}/is";
- $template_regex = "/\{\{(.+)((\n|\|[ ]*([A-z0-9]+)[ ]*=[ ]*(.+))*)\}\}/isU";
- $i = 0;
- while ( preg_match($template_regex, $text) )
- {
- $i++;
- if ( $i == 5 )
- break;
- $text = RenderMan::include_templates($text);
- }
-
- $code = $plugins->setHook('render_wikiformat_posttemplates');
- foreach ( $code as $cmd )
- {
- eval($cmd);
- }
-
- if ( !$plaintext )
- {
+ $template_regex = "/\{\{(.+)((\n|\|[ ]*([A-z0-9]+)[ ]*=[ ]*(.+))*)\}\}/isU";
+ $i = 0;
+ while ( preg_match($template_regex, $text) )
+ {
+ $i++;
+ if ( $i == 5 )
+ break;
+ $text = RenderMan::include_templates($text);
+ }
+
+ $code = $plugins->setHook('render_wikiformat_posttemplates');
+ foreach ( $code as $cmd )
+ {
+ eval($cmd);
+ }
+
// Process images
$text = RenderMan::process_image_tags($text, $taglist);
$text = RenderMan::process_imgtags_stage2($text, $taglist);
}
- if($do_params)
- {
- preg_match_all('#\(_([0-9]+)_\)#', $text, $matchlist);
- foreach($matchlist[1] as $m)
- {
- $text = str_replace('(_'.$m.'_)', $paths->getParam((int)$m), $text);
- }
- }
-
// Before shipping it out to the renderer, replace spaces in between headings and paragraphs:
$text = preg_replace('/<\/(h[0-9]|div|p)>([\s]+)<(h[0-9]|div|p)( .+?)?>/i', '\\1><\\3\\4>', $text);
$text = process_tables($text);
- $text = RenderMan::parse_internal_links($text);
+
+ if ( !($flags & RENDER_BLOCKONLY) )
+ $text = RenderMan::parse_internal_links($text);
$wiki = Text_Wiki::singleton('Mediawiki');
- if($plaintext)
+ $wiki->setRenderConf('Xhtml', 'wikilink', 'view_url', contentPath);
+ $wiki->setRenderConf('Xhtml', 'Url', 'css_descr', 'external');
+ if ( $flags & RENDER_BLOCKONLY )
{
- $wiki->setRenderConf('Plain', 'wikilink', 'view_url', contentPath);
- $result = $wiki->transform($text, 'Plain');
+ $wiki->disableRule('Freelink');
+ $wiki->disableRule('Url');
+ $wiki->disableRule('Toc');
+ $wiki->disableRule('Image');
}
- else
+ else if ( $flags & RENDER_INLINEONLY )
{
- $wiki->setRenderConf('Xhtml', 'wikilink', 'view_url', contentPath);
- $wiki->setRenderConf('Xhtml', 'Url', 'css_descr', 'external');
- $result = $wiki->transform($text, 'Xhtml');
+ foreach ( array('code', 'html', 'raw', 'include', 'embed', 'horiz', 'break', 'blockquote', 'list', 'newline', 'paragraph', 'revise', 'tighten') as $rule )
+ {
+ $wiki->disableRule($rule);
+ }
}
+ $result = $wiki->transform($text, 'Xhtml');
// HTML fixes
$result = preg_replace('#([\s]*?)<\/tr>#is', '', $result);
@@ -377,10 +304,13 @@
$result = str_replace("", "", $result);
$result = str_replace("", "", $result);
- $code = $plugins->setHook('render_wikiformat_post');
- foreach ( $code as $cmd )
+ if ( !($flags & RENDER_BLOCKONLY) )
{
- eval($cmd);
+ $code = $plugins->setHook('render_wikiformat_post');
+ foreach ( $code as $cmd )
+ {
+ eval($cmd);
+ }
}
// Reinsert sections
@@ -406,82 +336,6 @@
global $db, $session, $paths, $template, $plugins; // Common objects
return RenderMan::next_gen_wiki_format($message, $plaintext, $filter_links, $do_params);
-
- $random_id = md5( time() . mt_rand() );
-
- // Strip out sections
- $nw = preg_match_all('#(.*?)<\/nowiki>#is', $message, $nowiki);
-
- if(!$plaintext)
- {
-
- //return ''.print_r($nowiki,true).'
';
-
- for($i=0;$i'.$nowiki[1][$i].'', '{NOWIKI:'.$random_id.':'.$i.'}', $message);
- }
-
- $message = preg_replace('/(.*?)<\/noinclude>/is', '\\1', $message);
-
- //return ''.htmlspecialchars($message).'
';
-
- $message = RenderMan::process_image_tags($message);
-
- }
-
- if($do_params)
- {
- preg_match_all('#\(_([0-9]+)_\)#', $message, $matchlist);
- foreach($matchlist[1] as $m)
- {
- $message = str_replace('(_'.$m.'_)', $paths->getParam((int)$m), $message);
- }
- }
-
- $message = RenderMan::include_templates($message);
-
- // Reinsert sections
- for($i=0;$i<$nw;$i++)
- {
- $message = str_replace('{NOWIKI:'.$random_id.':'.$i.'}', ''.$nowiki[1][$i].'', $message);
- }
-
- $message = process_tables($message);
- //if($message2 != $message) return ''.htmlspecialchars($message2).'
';
- //$message = str_replace(array(''), array(''), $message);
-
- $wiki =& Text_Wiki::singleton('Mediawiki');
- if($plaintext)
- {
- $wiki->setRenderConf('Plain', 'wikilink', 'view_url', contentPath);
- $result = $wiki->transform($message, 'Plain');
- } else {
- $wiki->setRenderConf('Xhtml', 'wikilink', 'view_url', contentPath);
- $wiki->setRenderConf('Xhtml', 'Url', 'css_descr', 'external');
- $result = $wiki->transform($message, 'Xhtml');
- }
-
- // HTML fixes
- $result = preg_replace('#([\s]*?)<\/tr>#is', '', $result);
- $result = preg_replace('#([\s]*?)<\/p>#is', '', $result);
- $result = preg_replace('#
([\s]*?)
\n", "", $result);
- $result = preg_replace("/]*?)><\/p>/", "", $result);
- $result = str_replace("
\n", "\n", $result);
- $result = str_replace("", "
", $result);
- $result = str_replace("
", "|
", $result);
- $result = str_replace("
", "", $result);
- $result = str_replace("
", "
", $result);
- $result = str_replace("
", "", $result);
- $result = preg_replace('/<\/table>$/', "
", $result);
- $result = str_replace("", "", $result);
- $result = str_replace("", "", $result);
-
- $result = str_replace('', '<nowiki>', $result);
- $result = str_replace('', '</nowiki>', $result);
-
- return $result;
}
public static function destroy_javascript($message, $_php = false)
@@ -520,6 +374,201 @@
}
/**
+ * Reverse-renders a blob of text (converts it from XHTML back to wikitext) by using parser hints and educated guesses.
+ * @param string XHTML
+ * @return string Wikitext
+ */
+
+ public static function reverse_render($text)
+ {
+ // convert \r\n to \n
+ $text = str_replace("\r\n", "\n", $text);
+
+ // Separate certain block level elements onto their own lines. This tidies up the tag
+ // soup that TinyMCE sometimes produces.
+ $block_elements = array('h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'div', 'table', 'ul', 'pre');
+ $block_elements = implode('|', $block_elements);
+ $regex = "#((?:$block_elements)>)\n?<($block_elements)(>| .+?>)#i";
+ $text = preg_replace($regex, "$1\n\n<$2$3", $text);
+
+ $text = self::reverse_process_parser_hints($text);
+ $text = self::reverse_process_headings($text);
+ $text = self::reverse_process_lists($text);
+ $text = self::reverse_process_tables($text);
+
+ // Lastly, strip out paragraph tags.
+ $text = preg_replace('|^ *(.+?)
*$|m', "\\1", $text);
+
+ return $text;
+ }
+
+ public static function reverse_process_parser_hints($text)
+ {
+ global $db, $session, $paths, $template, $plugins; // Common objects
+
+ if ( !preg_match_all('|([\w\W]*?)|s', $text, $matches) )
+ return $text;
+
+ foreach ( $matches[0] as $i => $match )
+ {
+ $tag =& $matches[1][$i];
+ $attribs =& $matches[2][$i];
+ $inner =& $matches[3][$i];
+
+ $attribs = self::reverse_process_hint_attribs($attribs);
+ switch($tag)
+ {
+ case 'smiley':
+ case 'internallink':
+ case 'imagelink':
+ if ( isset($attribs['code']) )
+ {
+ $text = str_replace($match, $attribs['code'], $text);
+ }
+ else if ( isset($attribs['src']) )
+ {
+ $text = str_replace($match, $attribs['src'], $text);
+ }
+ break;
+ }
+ }
+
+ return $text;
+ }
+
+ public static function reverse_process_hint_attribs($attribs)
+ {
+ $return = array();
+ if ( !preg_match_all('/([a-z0-9_-]+)="([^"]+?)"/', $attribs, $matches) )
+ return array();
+
+ foreach ( $matches[0] as $i => $match )
+ {
+ $name =& $matches[1][$i];
+ $value =& $matches[2][$i];
+
+ $value = base64_decode($value);
+
+ $return[$name] = $value;
+ }
+
+ return $return;
+ }
+
+ /**
+ * Escapes a string so that it's safe to use as an attribute in a parser hint.
+ * @param string
+ * @return string
+ */
+
+ public static function escape_parser_hint_attrib($text)
+ {
+ return base64_encode($text);
+ }
+
+ public static function reverse_process_headings($text)
+ {
+ if ( !preg_match_all('|^(.*?)$|m', $text, $matches) )
+ return $text;
+
+ foreach ( $matches[0] as $i => $match )
+ {
+ // generate heading tag
+ $heading_size = intval($matches[1][$i]);
+ $eq = '';
+ for ( $j = 0; $j < $heading_size; $j++ )
+ $eq .= '=';
+
+ $heading =& $matches[2][$i];
+
+ $tag = "$eq $heading $eq";
+ $text = str_replace($match, $tag, $text);
+ }
+
+ return $text;
+ }
+
+ public static function reverse_process_lists($text)
+ {
+ if ( !preg_match('!(?(?:ul|ol|li)>)!', $text) )
+ return $text;
+
+ $split = preg_split('!(?(?:ul|ol|li)>)!', $text, -1, PREG_SPLIT_DELIM_CAPTURE);
+
+ $stack_height = 0;
+ $current_list = '';
+ $old_current_list = '';
+ $spaces = '';
+ $marker = '*';
+ $list_id = 0;
+ $just_terminated = false;
+ foreach ( $split as $tag )
+ {
+ switch($tag)
+ {
+ case '':
+ case '':
+ $stack_height++;
+ $just_terminated = false;
+ if ( $stack_height > 1 )
+ $spaces .= $marker;
+
+ $marker = ( $tag == 'ol' ) ? '#' : '*';
+ if ( $stack_height > 1 )
+ $current_list .= "\n";
+
+ break;
+ case '
':
+ case '':
+ $stack_height--;
+ $spaces = substr($spaces, 1);
+
+ if ( $stack_height == 0 )
+ {
+ // rotate
+ $text = str_replace_once("{$old_current_list}{$tag}", trim($current_list), $text);
+ $current_list = '';
+ $old_current_list = '';
+ }
+ $just_terminated = true;
+ break;
+ case '':
+ if ( $stack_height < 1 )
+ break;
+
+ $current_list .= "{$spaces}{$marker} ";
+ break;
+ case '':
+ if ( $stack_height < 1 )
+ break;
+
+ if ( !$just_terminated )
+ $current_list .= "\n";
+
+ $just_terminated = false;
+ break;
+ default:
+ if ( $stack_height > 0 )
+ {
+ $current_list .= trim($tag);
+ }
+ break;
+ }
+ if ( $stack_height > 0 )
+ {
+ $old_current_list .= $tag;
+ }
+ }
+
+ return $text;
+ }
+
+ public static function reverse_process_tables($text)
+ {
+ return $text;
+ }
+
+ /**
* Parses internal links (wikilinks) in a block of text.
* @param string Text to process
* @param string Optional. If included will be used as a template instead of using the default syntax.
@@ -567,7 +616,8 @@
}
else
{
- $link = "{$inner_text}";
+ $omatch = self::escape_parser_hint_attrib($match);
+ $link = "{$inner_text}";
}
$text = str_replace($match, $link, $text);
@@ -596,7 +646,8 @@
}
else
{
- $link = "{$inner_text}";
+ $omatch = self::escape_parser_hint_attrib($match);
+ $link = "{$inner_text}";
}
$text = str_replace($match, $link, $text);
@@ -775,6 +826,9 @@
eval($cmd);
}
+ // gently apply some reverse-processing to allow Text_Wiki to do magic with TOCs and stuff
+ $text = self::reverse_process_headings($text);
+
// Reinsert sections
for($i=0;$i<$nw;$i++)
{
@@ -844,43 +898,31 @@
':-[' => 'face-embarassed.png',
':[' => 'face-embarassed.png'
);
- /*
- $keys = array_keys($smileys);
- foreach($keys as $k)
- {
- $regex1 = '#([\W]+)'.preg_quote($k).'([\s\n\r\.]+)#s';
- $regex2 = '\\1\\2';
- $text = preg_replace($regex1, $regex2, $text);
- }
- */
// Strip out sections
//return ''.htmlspecialchars($text).'
';
$nw = preg_match_all('#(.*?)<\/nowiki>#is', $text, $nowiki);
- for($i=0;$i'.$nowiki[1][$i].'', '{NOWIKI:'.$random_id.':'.$i.'}', $text);
+ $text = str_replace('' . $nowiki[1][$i] . '', '{NOWIKI:'.$random_id.':'.$i.'}', $text);
}
- $keys = array_keys($smileys);
- foreach($keys as $k)
+ foreach ( $smileys as $smiley => $smiley_path )
{
- $t = hexencode($k, ' ', '');
- $t = trim($t);
- $t = explode(' ', $t);
- $s = '';
- foreach($t as $b)
- {
- $s.=''.$b.';';
- }
- $pfx = ( $complete_urls ) ? 'http' . ( isset($_SERVER['HTTPS']) ? 's' : '' ) . '://'.$_SERVER['HTTP_HOST'] : '';
- $text = str_replace(' '.$k, ' ', $text);
+ $hex_smiley = hexencode($smiley, '', ';');
+ $pfx = ( $complete_urls ) ? get_server_url() : '';
+ $text = str_replace(' ' . $smiley,
+ '
+
+
+ ', $text);
}
//*/
// Reinsert sections
- for($i=0;$i<$nw;$i++)
+ for ( $i = 0; $i < $nw; $i++ )
{
$text = str_replace('{NOWIKI:'.$random_id.':'.$i.'}', ''.$nowiki[1][$i].'', $text);
}
@@ -888,39 +930,6 @@
return $text;
}
- /*
- * **** DEPRECATED ****
- * Replaces some critical characters in a string with MySQL-safe equivalents
- * @param $text string the text to escape
- * @return array key 0 is the escaped text, key 1 is the character tag
- * /
-
- public static function escape_page_text($text)
- {
- $char_tag = md5(microtime() . mt_rand());
- $text = str_replace("'", "{APOS:$char_tag}", $text);
- $text = str_replace('"', "{QUOT:$char_tag}", $text);
- $text = str_replace("\\", "{SLASH:$char_tag}", $text);
- return Array($text, $char_tag);
- }
- */
-
- /* **** DEPRECATED ****
- * Reverses the result of RenderMan::escape_page_text().
- * @param $text string the text to unescape
- * @param $char_tag string the character tag
- * @return string
- * /
-
- public static function unescape_page_text($text, $char_tag)
- {
- $text = str_replace("{APOS:$char_tag}", "'", $text);
- $text = str_replace("{QUOT:$char_tag}", '"', $text);
- $text = str_replace("{SLASH:$char_tag}", "\\", $text);
- return $text;
- }
- */
-
/**
* Generates a summary of the differences between two texts, and formats it as XHTML.
* @param $str1 string the first block of text
@@ -1025,7 +1034,7 @@
break;
}
// not the height, so see if a plugin took this over
- // this hook requires plugins to return true if they modified anythin
+ // this hook requires plugins to return true if they modified anything
$code = $plugins->setHook('img_tag_parse_params');
foreach ( $code as $cmd )
{
@@ -1041,7 +1050,7 @@
if ( !isPage( $paths->nslist['File'] . $filename ) )
{
- $text = str_replace($full_tag, '[[' . makeUrlNS('File', $filename) . ']]', $text);
+ $text = str_replace($full_tag, '[[' . $paths->nslist['File'] . $filename . ']]', $text);
continue;
}
@@ -1081,7 +1090,8 @@
$img_tag .= '/>';
- $complete_tag = '';
+ $s_full_tag = self::escape_parser_hint_attrib($full_tag);
+ $complete_tag = '';
if ( !empty($scale_type) && !$raw_display )
{
@@ -1131,12 +1141,12 @@
$complete_tag .= '';
}
- $complete_tag .= "\n\n";
+ $complete_tag .= "";
$taglist[$i] = $complete_tag;
+ /*
$pos = strpos($text, $full_tag);
- /*
while(true)
{
$check1 = substr($text, $pos, 3);