includes/render.php
changeset 832 7152ca0a0ce9
parent 801 eb8b23f11744
child 953 323c4cd1aa37
equal deleted inserted replaced
831:45e887f23282 832:7152ca0a0ce9
    40   
    40   
    41   public static function getPage($page_id, $namespace, $wiki = 1, $smilies = true, $filter_links = true, $redir = true, $render = true)
    41   public static function getPage($page_id, $namespace, $wiki = 1, $smilies = true, $filter_links = true, $redir = true, $render = true)
    42   {
    42   {
    43     global $db, $session, $paths, $template, $plugins; // Common objects
    43     global $db, $session, $paths, $template, $plugins; // Common objects
    44     
    44     
    45     $perms =& $session;
    45     $page = new PageProcessor($page_id, $namespace);
    46     
    46     $text = $page->fetch_text();
    47     if ( $page_id != $paths->page_id || $namespace != $paths->namespace )
    47     
    48     {
    48     if ( !$render )
    49       unset($perms);
    49       return $text;
    50       unset($perms); // PHP <5.1.5 Zend bug
    50     
    51       $perms = $session->fetch_page_acl($page_id, $namespace);
    51     $text = self::render($text, $wiki, $smilies, $filter_links);
    52       if ( !$perms )
    52     return $text;
    53       {
       
    54         $session->init_permissions();
       
    55         $perms = $session->fetch_page_acl($page_id, $namespace);
       
    56       };
       
    57     }
       
    58     
       
    59     if(!$perms->get_permissions('read'))
       
    60       return 'Access denied ('.$paths->nslist[$namespace].$page_id.')';
       
    61     
       
    62     if($namespace != 'Template' && ($wiki == 0 || $render == false))
       
    63     {
       
    64       if(!$perms->get_permissions('view_source'))
       
    65       {
       
    66         return 'Access denied ('.$paths->nslist[$namespace].$page_id.')';
       
    67       }
       
    68     }
       
    69     
       
    70     $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).'\';');
       
    71     if ( !$q )
       
    72     {
       
    73       $db->_die('Method called was: RenderMan::getPage(\''.$page_id.'\', \''.$namespace.'\');.');
       
    74     }
       
    75     if ( $db->numrows() < 1 )
       
    76     {
       
    77       return false;
       
    78     }
       
    79     $row = $db->fetchrow();
       
    80     $db->free_result();
       
    81     
       
    82     $message = $row['page_text'];
       
    83     $chartag = $row['char_tag'];
       
    84     unset($row); // Free some memory
       
    85     
       
    86     if ( preg_match("#^\#redirect \[\[([^\]\r\n\a\t]+?)\]\]#", $message, $m) && $redir && ( !isset($_GET['redirect']) || ( isset($_GET['redirect']) && $_GET['redirect'] != 'no' ) ) )
       
    87     {
       
    88       $old = $paths->cpage;
       
    89       $a = RenderMan::strToPageID($m[1]);
       
    90       $a[0] = str_replace(' ', '_', $a[0]);
       
    91       
       
    92       $pageid = str_replace(' ', '_', $paths->nslist[$a[1]] . $a[0]);
       
    93       $paths->page = $pageid;
       
    94       $paths->cpage = $paths->pages[$pageid];
       
    95       //die('<pre>'.print_r($paths->cpage,true).'</pre>');
       
    96       
       
    97       unset($template);
       
    98       unset($GLOBALS['template']);
       
    99       
       
   100       $GLOBALS['template'] = new template();
       
   101       global $template;
       
   102       
       
   103       $template->template(); // Tear down and rebuild the template parser
       
   104       $template->load_theme($session->theme, $session->style);
       
   105       
       
   106       $data = '<div><small>(Redirected from <a href="'.makeUrlNS($old['namespace'], $old['urlname_nons'], 'redirect=no', true).'">'.$old['name'].'</a>)</small></div>'.RenderMan::getPage($a[0], $a[1], $wiki, $smilies, $filter_links, false /* Enforces a maximum of one redirect */);
       
   107       
       
   108       return $data;
       
   109     }
       
   110     else if(preg_match('#^\#redirect \[\[(.+?)\]\]#', $message, $m) && isset($_GET['redirect']) && $_GET['redirect'] == 'no')
       
   111     {
       
   112       preg_match('#^\#redirect \[\[(.+)\]\]#', $message, $m);
       
   113       $m[1] = str_replace(' ', '_', $m[1]);
       
   114       $message = preg_replace('#\#redirect \[\[(.+)\]\]#', '<nowiki><div class="mdg-infobox"><table border="0" width="100%" cellspacing="0" cellpadding="0"><tr><td valign="top"><img alt="Cute wet-floor icon" src="'.scriptPath.'/images/redirector.png" /></td><td valign="top" style="padding-left: 10px;"><b>This page is a <i>redirector</i>.</b><br />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.<br /><br />To create a redirect page, make the <i>first characters</i> in the page content <tt>#redirect [[Page_ID]]</tt>. For more information, see the Enano <a href="http://enanocms.org/Help:Wiki_formatting">Wiki formatting guide</a>.<br /><br />This page redirects to <a href="'.makeUrl($m[1]).'">'.$paths->pages[$m[1]]['name'].'</a>.</td></tr></table></div><br /><hr style="margin-left: 1em; width: 200px;" /></nowiki>', $message);
       
   115     }
       
   116     $session->disallow_password_grab();
       
   117     return ($render) ? RenderMan::render($message, $wiki, $smilies, $filter_links) : $message;
       
   118   }
    53   }
   119   
    54   
   120   public static function getTemplate($id, $parms)
    55   public static function getTemplate($id, $parms)
   121   {
    56   {
   122     global $db, $session, $paths, $template, $plugins; // Common objects
    57     global $db, $session, $paths, $template, $plugins; // Common objects
   181       {
   116       {
   182         // in practice this should always be true but just to be safe...
   117         // in practice this should always be true but just to be safe...
   183         if ( isset($prefixlist[$match[1]]) )
   118         if ( isset($prefixlist[$match[1]]) )
   184         {
   119         {
   185           $new_id = $paths->nslist[ $prefixlist[$match[1]] ] . sanitize_page_id($match[2]);
   120           $new_id = $paths->nslist[ $prefixlist[$match[1]] ] . sanitize_page_id($match[2]);
   186           if ( !isset($paths->pages[$new_id]) )
   121           if ( !isPage($new_id) )
   187           {
   122           {
   188             return "[[$new_id]]";
   123             return "[[$new_id]]";
   189           }
   124           }
   190           $fetch_ns = $prefixlist[$match[1]];
   125           $fetch_ns = $prefixlist[$match[1]];
   191           $id = sanitize_page_id($match[2]);
   126           $id = sanitize_page_id($match[2]);
   213     }
   148     }
   214     
   149     
   215     return $text;
   150     return $text;
   216   }
   151   }
   217   
   152   
   218   public static function render($text, $wiki = 1, $smilies = true, $filter_links = true)
   153   /**
       
   154    * 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.
       
   155    * @param string Text to render
       
   156    * @param int Render parameters - see constants.php
       
   157    * @return string Rendered text
       
   158    */
       
   159   
       
   160   public static function render($text, $flags = RENDER_WIKI_DEFAULT, $smilies = true)
   219   {
   161   {
   220     global $db, $session, $paths, $template, $plugins; // Common objects
   162     global $db, $session, $paths, $template, $plugins; // Common objects
   221     if($smilies)
   163     
       
   164     if ( !$smilies )
       
   165       $flags |= RENDER_NOSMILIES;
       
   166     
       
   167     if ( $flags & ~RENDER_NOSMILIES )
   222     {
   168     {
   223       $text = RenderMan::smilieyize($text);
   169       $text = RenderMan::smilieyize($text);
   224     }
   170     }
   225     if($wiki == 1)
   171     if ( $flags & RENDER_WIKI_DEFAULT )
   226     {
   172     {
   227       $text = RenderMan::next_gen_wiki_format($text);
   173       $text = RenderMan::next_gen_wiki_format($text, $flags);
   228     }
   174     }
   229     elseif($wiki == 2)
   175     else if ( $flags & RENDER_WIKI_TEMPLATE )
   230     {
   176     {
   231       $text = $template->tplWikiFormat($text);
   177       $text = $template->tplWikiFormat($text);
   232     }
   178     }           
   233     return $text;
   179     return $text;
   234   }
   180   }
   235   
   181   
   236   public static function PlainTextRender($text, $wiki = 1, $smilies = false, $filter_links = true)
   182   private static function next_gen_wiki_format($text, $flags = 0)
   237   {
       
   238     global $db, $session, $paths, $template, $plugins; // Common objects
       
   239     if($smilies)
       
   240     {
       
   241       $text = RenderMan::smilieyize($text);
       
   242     }
       
   243     if($wiki == 1)
       
   244     {
       
   245       $text = RenderMan::next_gen_wiki_format($text, true);
       
   246     }
       
   247     elseif($wiki == 2)
       
   248     {
       
   249       $text = $template->tplWikiFormat($text);
       
   250     }
       
   251     return $text;
       
   252   }
       
   253   
       
   254   public static function next_gen_wiki_format($text, $plaintext = false, $filter_links = true, $do_params = false)
       
   255   {
   183   {
   256     global $db, $session, $paths, $template, $plugins; // Common objects
   184     global $db, $session, $paths, $template, $plugins; // Common objects
   257     global $lang;
   185     global $lang;
   258     
   186     
   259     require_once(ENANO_ROOT.'/includes/wikiformat.php');
   187     require_once(ENANO_ROOT.'/includes/wikiformat.php');
   289     if ( $paths->namespace == 'Template' )
   217     if ( $paths->namespace == 'Template' )
   290     {
   218     {
   291       $text = preg_replace('/<nodisplay>(.*?)<\/nodisplay>/is', '', $text);
   219       $text = preg_replace('/<nodisplay>(.*?)<\/nodisplay>/is', '', $text);
   292     }
   220     }
   293     
   221     
   294     preg_match_all('/<lang (?:code|id)="([a-z0-9_-]+)">([\w\W]+?)<\/lang>/', $text, $langmatch);
   222     if ( !($flags & RENDER_BLOCKONLY) )
   295     foreach ( $langmatch[0] as $i => $match )
   223     {
   296     {
   224       preg_match_all('/<lang (?:code|id)="([a-z0-9_-]+)">([\w\W]+?)<\/lang>/', $text, $langmatch);
   297       if ( $langmatch[1][$i] == $lang->lang_code )
   225       foreach ( $langmatch[0] as $i => $match )
   298       {
   226       {
   299         $text = str_replace_once($match, $langmatch[2][$i], $text);
   227         if ( $langmatch[1][$i] == $lang->lang_code )
   300       }
   228         {
   301       else
   229           $text = str_replace_once($match, $langmatch[2][$i], $text);
   302       {
   230         }
   303         $text = str_replace_once($match, '', $text);
   231         else
   304       }
   232         {
   305     }
   233           $text = str_replace_once($match, '', $text);
   306     
   234         }
   307     $code = $plugins->setHook('render_wikiformat_pre');
   235       }
   308     foreach ( $code as $cmd )
   236     
   309     {
   237       $code = $plugins->setHook('render_wikiformat_pre');
   310       eval($cmd);
   238       foreach ( $code as $cmd )
   311     }
   239       {
       
   240         eval($cmd);
       
   241       }
   312     
   242     
   313     //$template_regex = "/\{\{([^\]]+?)((\n([ ]*?)[A-z0-9]+([ ]*?)=([ ]*?)(.+?))*)\}\}/is";
   243     //$template_regex = "/\{\{([^\]]+?)((\n([ ]*?)[A-z0-9]+([ ]*?)=([ ]*?)(.+?))*)\}\}/is";
   314     $template_regex = "/\{\{(.+)((\n|\|[ ]*([A-z0-9]+)[ ]*=[ ]*(.+))*)\}\}/isU";
   244       $template_regex = "/\{\{(.+)((\n|\|[ ]*([A-z0-9]+)[ ]*=[ ]*(.+))*)\}\}/isU";
   315     $i = 0;
   245       $i = 0;
   316     while ( preg_match($template_regex, $text) )
   246       while ( preg_match($template_regex, $text) )
   317     {
   247       {
   318       $i++;
   248         $i++;
   319       if ( $i == 5 )
   249         if ( $i == 5 )
   320         break;
   250           break;
   321       $text = RenderMan::include_templates($text);
   251         $text = RenderMan::include_templates($text);
   322     }
   252       }
   323     
   253       
   324     $code = $plugins->setHook('render_wikiformat_posttemplates');
   254       $code = $plugins->setHook('render_wikiformat_posttemplates');
   325     foreach ( $code as $cmd )
   255       foreach ( $code as $cmd )
   326     {
   256       {
   327       eval($cmd);
   257         eval($cmd);
   328     }
   258       }
   329     
   259       
   330     if ( !$plaintext )
       
   331     {
       
   332       // Process images
   260       // Process images
   333       $text = RenderMan::process_image_tags($text, $taglist);
   261       $text = RenderMan::process_image_tags($text, $taglist);
   334       $text = RenderMan::process_imgtags_stage2($text, $taglist);
   262       $text = RenderMan::process_imgtags_stage2($text, $taglist);
   335     }
   263     }
   336     
   264     
   337     if($do_params)
       
   338     {
       
   339       preg_match_all('#\(_([0-9]+)_\)#', $text, $matchlist);
       
   340       foreach($matchlist[1] as $m)
       
   341       {
       
   342         $text = str_replace('(_'.$m.'_)', $paths->getParam((int)$m), $text);
       
   343       }
       
   344     }
       
   345     
       
   346     // Before shipping it out to the renderer, replace spaces in between headings and paragraphs:
   265     // Before shipping it out to the renderer, replace spaces in between headings and paragraphs:
   347     $text = preg_replace('/<\/(h[0-9]|div|p)>([\s]+)<(h[0-9]|div|p)( .+?)?>/i', '</\\1><\\3\\4>', $text);
   266     $text = preg_replace('/<\/(h[0-9]|div|p)>([\s]+)<(h[0-9]|div|p)( .+?)?>/i', '</\\1><\\3\\4>', $text);
   348     
   267     
   349     $text = process_tables($text);
   268     $text = process_tables($text);
   350     $text = RenderMan::parse_internal_links($text);
   269     
       
   270     if ( !($flags & RENDER_BLOCKONLY) )
       
   271       $text = RenderMan::parse_internal_links($text);
   351     
   272     
   352     $wiki = Text_Wiki::singleton('Mediawiki');
   273     $wiki = Text_Wiki::singleton('Mediawiki');
   353     if($plaintext)
   274     $wiki->setRenderConf('Xhtml', 'wikilink', 'view_url', contentPath);
   354     {
   275     $wiki->setRenderConf('Xhtml', 'Url', 'css_descr', 'external');
   355       $wiki->setRenderConf('Plain', 'wikilink', 'view_url', contentPath);
   276     if ( $flags & RENDER_BLOCKONLY )
   356       $result = $wiki->transform($text, 'Plain');
   277     {
   357     }
   278       $wiki->disableRule('Freelink');
   358     else
   279       $wiki->disableRule('Url');
   359     {
   280       $wiki->disableRule('Toc');
   360       $wiki->setRenderConf('Xhtml', 'wikilink', 'view_url', contentPath);
   281       $wiki->disableRule('Image');
   361       $wiki->setRenderConf('Xhtml', 'Url', 'css_descr', 'external');
   282     }
   362       $result = $wiki->transform($text, 'Xhtml');
   283     else if ( $flags & RENDER_INLINEONLY )
   363     }
   284     {
       
   285       foreach ( array('code', 'html', 'raw', 'include', 'embed', 'horiz', 'break', 'blockquote', 'list', 'newline', 'paragraph', 'revise', 'tighten') as $rule )
       
   286       {
       
   287         $wiki->disableRule($rule);
       
   288       }
       
   289     }
       
   290     $result = $wiki->transform($text, 'Xhtml');
   364     
   291     
   365     // HTML fixes
   292     // HTML fixes
   366     $result = preg_replace('#<tr>([\s]*?)<\/tr>#is', '', $result);
   293     $result = preg_replace('#<tr>([\s]*?)<\/tr>#is', '', $result);
   367     $result = preg_replace('#<p>([\s]*?)<\/p>#is', '', $result);
   294     $result = preg_replace('#<p>([\s]*?)<\/p>#is', '', $result);
   368     $result = preg_replace('#<br />([\s]*?)<table#is', '<table', $result);
   295     $result = preg_replace('#<br />([\s]*?)<table#is', '<table', $result);
   375     $result = str_replace("</table><br />", "</table>", $result);
   302     $result = str_replace("</table><br />", "</table>", $result);
   376     $result = preg_replace('/<\/table>$/', "</table><br /><br />", $result);
   303     $result = preg_replace('/<\/table>$/', "</table><br /><br />", $result);
   377     $result = str_replace("<p></div></p>", "</div>", $result);
   304     $result = str_replace("<p></div></p>", "</div>", $result);
   378     $result = str_replace("<p></table></p>", "</table>", $result);
   305     $result = str_replace("<p></table></p>", "</table>", $result);
   379     
   306     
   380     $code = $plugins->setHook('render_wikiformat_post');
   307     if ( !($flags & RENDER_BLOCKONLY) )
   381     foreach ( $code as $cmd )
   308     {
   382     {
   309       $code = $plugins->setHook('render_wikiformat_post');
   383       eval($cmd);
   310       foreach ( $code as $cmd )
       
   311       {
       
   312         eval($cmd);
       
   313       }
   384     }
   314     }
   385     
   315     
   386     // Reinsert <nowiki> sections
   316     // Reinsert <nowiki> sections
   387     for($i=0;$i<$nw;$i++)
   317     for($i=0;$i<$nw;$i++)
   388     {
   318     {
   404   public static function wikiFormat($message, $filter_links = true, $do_params = false, $plaintext = false)
   334   public static function wikiFormat($message, $filter_links = true, $do_params = false, $plaintext = false)
   405   {
   335   {
   406     global $db, $session, $paths, $template, $plugins; // Common objects
   336     global $db, $session, $paths, $template, $plugins; // Common objects
   407     
   337     
   408     return RenderMan::next_gen_wiki_format($message, $plaintext, $filter_links, $do_params);
   338     return RenderMan::next_gen_wiki_format($message, $plaintext, $filter_links, $do_params);
   409     
       
   410     $random_id = md5( time() . mt_rand() );
       
   411     
       
   412     // Strip out <nowiki> sections
       
   413     $nw = preg_match_all('#<nowiki>(.*?)<\/nowiki>#is', $message, $nowiki);
       
   414     
       
   415     if(!$plaintext)
       
   416     {
       
   417     
       
   418       //return '<pre>'.print_r($nowiki,true).'</pre>';
       
   419       
       
   420       for($i=0;$i<sizeof($nowiki[1]);$i++)
       
   421       {
       
   422         $message = str_replace('<nowiki>'.$nowiki[1][$i].'</nowiki>', '{NOWIKI:'.$random_id.':'.$i.'}', $message);
       
   423       }
       
   424       
       
   425       $message = preg_replace('/<noinclude>(.*?)<\/noinclude>/is', '\\1', $message);
       
   426       
       
   427       //return '<pre>'.htmlspecialchars($message).'</pre>';
       
   428       
       
   429       $message = RenderMan::process_image_tags($message);
       
   430     
       
   431     }
       
   432     
       
   433     if($do_params)
       
   434     {
       
   435       preg_match_all('#\(_([0-9]+)_\)#', $message, $matchlist);
       
   436       foreach($matchlist[1] as $m)
       
   437       {
       
   438         $message = str_replace('(_'.$m.'_)', $paths->getParam((int)$m), $message);
       
   439       }
       
   440     }
       
   441     
       
   442     $message = RenderMan::include_templates($message);
       
   443     
       
   444     // Reinsert <nowiki> sections
       
   445     for($i=0;$i<$nw;$i++)
       
   446     {
       
   447       $message = str_replace('{NOWIKI:'.$random_id.':'.$i.'}', '<nowiki>'.$nowiki[1][$i].'</nowiki>', $message);
       
   448     }
       
   449     
       
   450     $message = process_tables($message);
       
   451     //if($message2 != $message) return '<pre>'.htmlspecialchars($message2).'</pre>';
       
   452     //$message = str_replace(array('<table>', '</table>'), array('<nowiki><table>', '</table></nowiki>'), $message);
       
   453     
       
   454     $wiki =& Text_Wiki::singleton('Mediawiki');
       
   455     if($plaintext)
       
   456     {
       
   457       $wiki->setRenderConf('Plain', 'wikilink', 'view_url', contentPath);
       
   458       $result = $wiki->transform($message, 'Plain');
       
   459     } else {
       
   460       $wiki->setRenderConf('Xhtml', 'wikilink', 'view_url', contentPath);
       
   461       $wiki->setRenderConf('Xhtml', 'Url', 'css_descr', 'external');
       
   462       $result = $wiki->transform($message, 'Xhtml');
       
   463     }
       
   464     
       
   465     // HTML fixes
       
   466     $result = preg_replace('#<tr>([\s]*?)<\/tr>#is', '', $result);
       
   467     $result = preg_replace('#<p>([\s]*?)<\/p>#is', '', $result);
       
   468     $result = preg_replace('#<br />([\s]*?)<table#is', '<table', $result);
       
   469     $result = str_replace("<pre><code>\n", "<pre><code>", $result);
       
   470     $result = preg_replace("/<p><table([^>]*?)><\/p>/", "<table\\1>", $result);
       
   471     $result = str_replace("<br />\n</td>", "\n</td>", $result);
       
   472     $result = str_replace("<p><tr>", "<tr>", $result);
       
   473     $result = str_replace("<tr><br />", "<tr>", $result);
       
   474     $result = str_replace("</tr><br />", "</tr>", $result);
       
   475     $result = str_replace("</table></p>", "</table>", $result);
       
   476     $result = str_replace("</table><br />", "</table>", $result);
       
   477     $result = preg_replace('/<\/table>$/', "</table><br /><br />", $result);
       
   478     $result = str_replace("<p></div></p>", "</div>", $result);
       
   479     $result = str_replace("<p></table></p>", "</table>", $result);
       
   480     
       
   481     $result = str_replace('<nowiki>',  '&lt;nowiki&gt;',  $result);
       
   482     $result = str_replace('</nowiki>', '&lt;/nowiki&gt;', $result);
       
   483     
       
   484     return $result;
       
   485   }
   339   }
   486   
   340   
   487   public static function destroy_javascript($message, $_php = false)
   341   public static function destroy_javascript($message, $_php = false)
   488   {
   342   {
   489     $message = preg_replace('#<(script|object|applet|embed|iframe|frame|form|input|select)(.*?)>#is', '&lt;\\1\\2&gt;', $message);
   343     $message = preg_replace('#<(script|object|applet|embed|iframe|frame|form|input|select)(.*?)>#is', '&lt;\\1\\2&gt;', $message);
   518     }
   372     }
   519     return $text;
   373     return $text;
   520   }
   374   }
   521   
   375   
   522   /**
   376   /**
       
   377    * Reverse-renders a blob of text (converts it from XHTML back to wikitext) by using parser hints and educated guesses.
       
   378    * @param string XHTML
       
   379    * @return string Wikitext
       
   380    */
       
   381   
       
   382   public static function reverse_render($text)
       
   383   {
       
   384     // convert \r\n to \n
       
   385     $text = str_replace("\r\n", "\n", $text);
       
   386     
       
   387     // Separate certain block level elements onto their own lines. This tidies up the tag
       
   388     // soup that TinyMCE sometimes produces.
       
   389     $block_elements = array('h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'div', 'table', 'ul', 'pre');
       
   390     $block_elements = implode('|', $block_elements);
       
   391     $regex = "#(</(?:$block_elements)>)\n?<($block_elements)(>| .+?>)#i";
       
   392     $text = preg_replace($regex, "$1\n\n<$2$3", $text);
       
   393     
       
   394     $text = self::reverse_process_parser_hints($text);
       
   395     $text = self::reverse_process_headings($text);
       
   396     $text = self::reverse_process_lists($text);
       
   397     $text = self::reverse_process_tables($text);
       
   398     
       
   399     // Lastly, strip out paragraph tags.
       
   400     $text = preg_replace('|^ *<p>(.+?)</p> *$|m', "\\1", $text);
       
   401     
       
   402     return $text;
       
   403   }
       
   404   
       
   405   public static function reverse_process_parser_hints($text)
       
   406   {
       
   407     global $db, $session, $paths, $template, $plugins; // Common objects
       
   408     
       
   409     if ( !preg_match_all('|<!--#([a-z0-9_]+)(?: (.+?))?-->([\w\W]*?)<!--#/\\1-->|s', $text, $matches) )
       
   410       return $text;
       
   411     
       
   412     foreach ( $matches[0] as $i => $match )
       
   413     {
       
   414       $tag =& $matches[1][$i];
       
   415       $attribs =& $matches[2][$i];
       
   416       $inner =& $matches[3][$i];
       
   417       
       
   418       $attribs = self::reverse_process_hint_attribs($attribs);
       
   419       switch($tag)
       
   420       {
       
   421         case 'smiley':
       
   422         case 'internallink':
       
   423         case 'imagelink':
       
   424           if ( isset($attribs['code']) )
       
   425           {
       
   426             $text = str_replace($match, $attribs['code'], $text);
       
   427           }
       
   428           else if ( isset($attribs['src']) )
       
   429           {
       
   430             $text = str_replace($match, $attribs['src'], $text);
       
   431           }
       
   432           break;
       
   433       }
       
   434     }
       
   435     
       
   436     return $text;
       
   437   }
       
   438   
       
   439   public static function reverse_process_hint_attribs($attribs)
       
   440   {
       
   441     $return = array();
       
   442     if ( !preg_match_all('/([a-z0-9_-]+)="([^"]+?)"/', $attribs, $matches) )
       
   443       return array();
       
   444     
       
   445     foreach ( $matches[0] as $i => $match )
       
   446     {
       
   447       $name =& $matches[1][$i];
       
   448       $value =& $matches[2][$i];
       
   449       
       
   450       $value = base64_decode($value);
       
   451       
       
   452       $return[$name] = $value;
       
   453     }
       
   454     
       
   455     return $return;
       
   456   }
       
   457   
       
   458   /**
       
   459    * Escapes a string so that it's safe to use as an attribute in a parser hint.
       
   460    * @param string
       
   461    * @return string
       
   462    */
       
   463   
       
   464   public static function escape_parser_hint_attrib($text)
       
   465   {
       
   466     return base64_encode($text);
       
   467   }
       
   468   
       
   469   public static function reverse_process_headings($text)
       
   470   {
       
   471     if ( !preg_match_all('|^<h([1-6])(?: id="toc[0-9]+")?>(.*?)</h\\1>$|m', $text, $matches) )
       
   472       return $text;
       
   473     
       
   474     foreach ( $matches[0] as $i => $match )
       
   475     {
       
   476       // generate heading tag
       
   477       $heading_size = intval($matches[1][$i]);
       
   478       $eq = '';
       
   479       for ( $j = 0; $j < $heading_size; $j++ )
       
   480         $eq .= '=';
       
   481       
       
   482       $heading =& $matches[2][$i];
       
   483       
       
   484       $tag = "$eq $heading $eq";
       
   485       $text = str_replace($match, $tag, $text);
       
   486     }
       
   487     
       
   488     return $text;
       
   489   }
       
   490   
       
   491   public static function reverse_process_lists($text)
       
   492   {
       
   493     if ( !preg_match('!(</?(?:ul|ol|li)>)!', $text) )
       
   494       return $text;
       
   495     
       
   496     $split = preg_split('!(</?(?:ul|ol|li)>)!', $text, -1, PREG_SPLIT_DELIM_CAPTURE);
       
   497     
       
   498     $stack_height = 0;
       
   499     $current_list = '';
       
   500     $old_current_list = '';
       
   501     $spaces = '';
       
   502     $marker = '*';
       
   503     $list_id = 0;
       
   504     $just_terminated = false;
       
   505     foreach ( $split as $tag )
       
   506     {
       
   507       switch($tag) 
       
   508       {
       
   509         case '<ul>':
       
   510         case '<ol>':
       
   511           $stack_height++;
       
   512           $just_terminated = false;
       
   513           if ( $stack_height > 1 )
       
   514             $spaces .= $marker;
       
   515           
       
   516           $marker = ( $tag == 'ol' ) ? '#' : '*';
       
   517           if ( $stack_height > 1 )
       
   518             $current_list .= "\n";
       
   519           
       
   520           break;
       
   521         case '</ul>':
       
   522         case '</ol>':
       
   523           $stack_height--;
       
   524           $spaces = substr($spaces, 1);
       
   525           
       
   526           if ( $stack_height == 0 )
       
   527           {
       
   528             // rotate
       
   529             $text = str_replace_once("{$old_current_list}{$tag}", trim($current_list), $text);
       
   530             $current_list = '';
       
   531             $old_current_list = '';
       
   532           }
       
   533           $just_terminated = true;
       
   534           break;
       
   535         case '<li>':
       
   536           if ( $stack_height < 1 )
       
   537             break;
       
   538           
       
   539           $current_list .= "{$spaces}{$marker} ";
       
   540           break;
       
   541         case '</li>':
       
   542           if ( $stack_height < 1 )
       
   543             break;
       
   544           
       
   545           if ( !$just_terminated )
       
   546             $current_list .= "\n";
       
   547           
       
   548           $just_terminated = false;
       
   549           break;
       
   550         default:
       
   551           if ( $stack_height > 0 )
       
   552           {
       
   553             $current_list .= trim($tag);
       
   554           }
       
   555           break;
       
   556       }
       
   557       if ( $stack_height > 0 )
       
   558       {
       
   559         $old_current_list .= $tag;
       
   560       }
       
   561     }
       
   562     
       
   563     return $text;
       
   564   }
       
   565   
       
   566   public static function reverse_process_tables($text)
       
   567   {
       
   568     return $text;
       
   569   }
       
   570   
       
   571   /**
   523    * Parses internal links (wikilinks) in a block of text.
   572    * Parses internal links (wikilinks) in a block of text.
   524    * @param string Text to process
   573    * @param string Text to process
   525    * @param string Optional. If included will be used as a template instead of using the default syntax.
   574    * @param string Optional. If included will be used as a template instead of using the default syntax.
   526    * @return string
   575    * @return string
   527    */
   576    */
   565           ));
   614           ));
   566         $link = $parser->run();
   615         $link = $parser->run();
   567       }
   616       }
   568       else
   617       else
   569       {
   618       {
   570         $link = "<a href={$quot}{$url}{$quot}{$exists}>{$inner_text}</a>";
   619         $omatch = self::escape_parser_hint_attrib($match);
       
   620         $link = "<!--#internallink src=\"$omatch\" --><a href={$quot}{$url}{$quot}{$exists}>{$inner_text}</a><!--#/internallink-->";
   571       }
   621       }
   572       
   622       
   573       $text = str_replace($match, $link, $text);
   623       $text = str_replace($match, $link, $text);
   574     }
   624     }
   575     
   625     
   594           ));
   644           ));
   595         $link = $parser->run();
   645         $link = $parser->run();
   596       }
   646       }
   597       else
   647       else
   598       {
   648       {
   599         $link = "<a href={$quot}{$url}{$quot}{$exists}>{$inner_text}</a>";
   649         $omatch = self::escape_parser_hint_attrib($match);
       
   650         $link = "<!--#internallink src=\"$omatch\" --><a href={$quot}{$url}{$quot}{$exists}>{$inner_text}</a><!--#/internallink-->";
   600       }
   651       }
   601       
   652       
   602       $text = str_replace($match, $link, $text);
   653       $text = str_replace($match, $link, $text);
   603     }
   654     }
   604     
   655     
   772     $code = $plugins->setHook('render_sanitize_post');
   823     $code = $plugins->setHook('render_sanitize_post');
   773     foreach ( $code as $cmd )
   824     foreach ( $code as $cmd )
   774     {
   825     {
   775       eval($cmd);
   826       eval($cmd);
   776     }
   827     }
       
   828     
       
   829     // gently apply some reverse-processing to allow Text_Wiki to do magic with TOCs and stuff
       
   830     $text = self::reverse_process_headings($text);
   777     
   831     
   778     // Reinsert <nowiki> sections
   832     // Reinsert <nowiki> sections
   779     for($i=0;$i<$nw;$i++)
   833     for($i=0;$i<$nw;$i++)
   780     {
   834     {
   781       $text = str_replace('{NOWIKI:'.$random_id.':'.$i.'}', '<nowiki>'.$nowiki[1][$i].'</nowiki>', $text);
   835       $text = str_replace('{NOWIKI:'.$random_id.':'.$i.'}', '<nowiki>'.$nowiki[1][$i].'</nowiki>', $text);
   842       ':]'      => 'face-oops.png',
   896       ':]'      => 'face-oops.png',
   843       ':oops:'  => 'face-oops.png',
   897       ':oops:'  => 'face-oops.png',
   844       ':-['     => 'face-embarassed.png',
   898       ':-['     => 'face-embarassed.png',
   845       ':['      => 'face-embarassed.png'
   899       ':['      => 'face-embarassed.png'
   846       );
   900       );
   847     /*
       
   848     $keys = array_keys($smileys);
       
   849     foreach($keys as $k)
       
   850     {
       
   851       $regex1 = '#([\W]+)'.preg_quote($k).'([\s\n\r\.]+)#s';
       
   852       $regex2 = '\\1<img alt="'.$k.'" title="'.$k.'" src="'.scriptPath.'/images/smilies/'.$smileys[$k].'" style="border: 0;" />\\2';
       
   853       $text = preg_replace($regex1, $regex2, $text);
       
   854     }                                                                      
       
   855     */
       
   856     
   901     
   857     // Strip out <nowiki> sections
   902     // Strip out <nowiki> sections
   858     //return '<pre>'.htmlspecialchars($text).'</pre>';
   903     //return '<pre>'.htmlspecialchars($text).'</pre>';
   859     $nw = preg_match_all('#<nowiki>(.*?)<\/nowiki>#is', $text, $nowiki);
   904     $nw = preg_match_all('#<nowiki>(.*?)<\/nowiki>#is', $text, $nowiki);
   860     
   905     
   861     for($i=0;$i<sizeof($nowiki[1]);$i++)
   906     for ( $i = 0; $i < count($nowiki[1]); $i++ )
   862     {
   907     {
   863       $text = str_replace('<nowiki>'.$nowiki[1][$i].'</nowiki>', '{NOWIKI:'.$random_id.':'.$i.'}', $text);
   908       $text = str_replace('<nowiki>' . $nowiki[1][$i] . '</nowiki>', '{NOWIKI:'.$random_id.':'.$i.'}', $text);
   864     }
   909     }
   865     
   910     
   866     $keys = array_keys($smileys);
   911     foreach ( $smileys as $smiley => $smiley_path )
   867     foreach($keys as $k)
   912     {
   868     {
   913       $hex_smiley = hexencode($smiley, '&#x', ';');
   869       $t = hexencode($k, ' ', '');
   914       $pfx = ( $complete_urls ) ? get_server_url() : '';
   870       $t = trim($t);
   915       $text = str_replace(' ' . $smiley,
   871       $t = explode(' ', $t);
   916           ' <!--#smiley code="' . self::escape_parser_hint_attrib($smiley) . '"--><nowiki>
   872       $s = '';
   917            <!-- The above is a reverse-parser hint -->
   873       foreach($t as $b)
   918              <img title="' . $hex_smiley . '" alt="' . $hex_smiley . '" src="' . $pfx . scriptPath . '/images/smilies/' . $smiley_path . '"
   874       {
   919               style="border: 0;" />
   875         $s.='&#x'.$b.';';
   920            </nowiki><!--#/smiley-->', $text);
   876       }
       
   877       $pfx = ( $complete_urls ) ? 'http' . ( isset($_SERVER['HTTPS']) ? 's' : '' ) . '://'.$_SERVER['HTTP_HOST'] : '';
       
   878       $text = str_replace(' '.$k, ' <nowiki><img title="'.$s.'" alt="'.$s.'" src="'.$pfx.scriptPath.'/images/smilies/'.$smileys[$k].'" style="border: 0;" /></nowiki>', $text);
       
   879     }
   921     }
   880     //*/
   922     //*/
   881     
   923     
   882     // Reinsert <nowiki> sections
   924     // Reinsert <nowiki> sections
   883     for($i=0;$i<$nw;$i++)
   925     for ( $i = 0; $i < $nw; $i++ )
   884     {
   926     {
   885       $text = str_replace('{NOWIKI:'.$random_id.':'.$i.'}', '<nowiki>'.$nowiki[1][$i].'</nowiki>', $text);
   927       $text = str_replace('{NOWIKI:'.$random_id.':'.$i.'}', '<nowiki>'.$nowiki[1][$i].'</nowiki>', $text);
   886     }
   928     }
   887     
   929     
   888     return $text;
   930     return $text;
   889   }
   931   }
   890   
       
   891   /*
       
   892    * **** DEPRECATED ****
       
   893    * Replaces some critical characters in a string with MySQL-safe equivalents
       
   894    * @param $text string the text to escape
       
   895    * @return array key 0 is the escaped text, key 1 is the character tag
       
   896    * /
       
   897    
       
   898   public static function escape_page_text($text)
       
   899   {
       
   900     $char_tag = md5(microtime() . mt_rand());
       
   901     $text = str_replace("'",  "{APOS:$char_tag}",  $text);
       
   902     $text = str_replace('"',  "{QUOT:$char_tag}",  $text);
       
   903     $text = str_replace("\\", "{SLASH:$char_tag}", $text);
       
   904     return Array($text, $char_tag);
       
   905   }
       
   906   */
       
   907   
       
   908   /* **** DEPRECATED ****
       
   909    * Reverses the result of RenderMan::escape_page_text().
       
   910    * @param $text string the text to unescape
       
   911    * @param $char_tag string the character tag
       
   912    * @return string
       
   913    * /
       
   914    
       
   915   public static function unescape_page_text($text, $char_tag)
       
   916   {
       
   917     $text = str_replace("{APOS:$char_tag}",  "'",  $text);
       
   918     $text = str_replace("{QUOT:$char_tag}",  '"',  $text);
       
   919     $text = str_replace("{SLASH:$char_tag}", "\\", $text);
       
   920     return $text;
       
   921   }
       
   922   */
       
   923   
   932   
   924   /**
   933   /**
   925    * Generates a summary of the differences between two texts, and formats it as XHTML.
   934    * Generates a summary of the differences between two texts, and formats it as XHTML.
   926    * @param $str1 string the first block of text
   935    * @param $str1 string the first block of text
   927    * @param $str2 string the second block of text
   936    * @param $str2 string the second block of text
  1023               $width = intval($dims[1]);
  1032               $width = intval($dims[1]);
  1024               $height = intval($dims[2]);
  1033               $height = intval($dims[2]);
  1025               break;
  1034               break;
  1026             }
  1035             }
  1027             // not the height, so see if a plugin took this over
  1036             // not the height, so see if a plugin took this over
  1028             // this hook requires plugins to return true if they modified anythin
  1037             // this hook requires plugins to return true if they modified anything
  1029             $code = $plugins->setHook('img_tag_parse_params');
  1038             $code = $plugins->setHook('img_tag_parse_params');
  1030             foreach ( $code as $cmd )
  1039             foreach ( $code as $cmd )
  1031             {
  1040             {
  1032               if ( eval($cmd) )
  1041               if ( eval($cmd) )
  1033                 break 2;
  1042                 break 2;
  1039         }
  1048         }
  1040       }
  1049       }
  1041       
  1050       
  1042       if ( !isPage( $paths->nslist['File'] . $filename ) )
  1051       if ( !isPage( $paths->nslist['File'] . $filename ) )
  1043       {
  1052       {
  1044         $text = str_replace($full_tag, '[[' . makeUrlNS('File', $filename) . ']]', $text);
  1053         $text = str_replace($full_tag, '[[' . $paths->nslist['File'] . $filename . ']]', $text);
  1045         continue;
  1054         continue;
  1046       }
  1055       }
  1047       
  1056       
  1048       if ( $scale_type == 'thumb' )
  1057       if ( $scale_type == 'thumb' )
  1049       {
  1058       {
  1079         eval($cmd);
  1088         eval($cmd);
  1080       }
  1089       }
  1081       
  1090       
  1082       $img_tag .= '/>';
  1091       $img_tag .= '/>';
  1083       
  1092       
  1084       $complete_tag = '';
  1093       $s_full_tag = self::escape_parser_hint_attrib($full_tag);
       
  1094       $complete_tag = '<!--#imagelink src="' . $s_full_tag . '" -->';
  1085       
  1095       
  1086       if ( !empty($scale_type) && !$raw_display )
  1096       if ( !empty($scale_type) && !$raw_display )
  1087       {
  1097       {
  1088         $complete_tag .= '<div class="thumbnail" ';
  1098         $complete_tag .= '<div class="thumbnail" ';
  1089         $clear_text = '';
  1099         $clear_text = '';
  1129         $complete_tag .= '>';
  1139         $complete_tag .= '>';
  1130         $complete_tag .= $img_tag;
  1140         $complete_tag .= $img_tag;
  1131         $complete_tag .= '</a>';
  1141         $complete_tag .= '</a>';
  1132       }
  1142       }
  1133       
  1143       
  1134       $complete_tag .= "\n\n";
  1144       $complete_tag .= "<!--#/imagelink-->";
  1135       $taglist[$i] = $complete_tag;
  1145       $taglist[$i] = $complete_tag;
  1136       
  1146       
       
  1147       /*
  1137       $pos = strpos($text, $full_tag);
  1148       $pos = strpos($text, $full_tag);
  1138       
  1149       
  1139       /*
       
  1140       while(true)
  1150       while(true)
  1141       {
  1151       {
  1142         $check1 = substr($text, $pos, 3);
  1152         $check1 = substr($text, $pos, 3);
  1143         $check2 = substr($text, $pos, 1);
  1153         $check2 = substr($text, $pos, 1);
  1144         if ( $check1 == '<p>' || $pos == 0 || $check2 == "\n" )
  1154         if ( $check1 == '<p>' || $pos == 0 || $check2 == "\n" )