includes/render.php
changeset 1 fe660c52c48f
child 16 64e0d3d4cf14
equal deleted inserted replaced
0:902822492a68 1:fe660c52c48f
       
     1 <?php
       
     2 /*
       
     3  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
       
     4  * Version 1.0 (Banshee)
       
     5  * render.php - handles fetching pages and parsing them into HTML
       
     6  * Copyright (C) 2006-2007 Dan Fuhry
       
     7  *
       
     8  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
       
     9  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
       
    10  *
       
    11  * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
       
    12  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
       
    13  */
       
    14  
       
    15 class RenderMan {
       
    16   
       
    17   function strToPageID($string)
       
    18   {
       
    19     global $db, $session, $paths, $template, $plugins; // Common objects
       
    20     $k = array_keys($paths->nslist);
       
    21     for($i=0;$i<sizeof($paths->nslist);$i++)
       
    22     {
       
    23       $ln = strlen($paths->nslist[$k[$i]]);
       
    24       if(substr($string, 0, $ln) == $paths->nslist[$k[$i]])
       
    25       {
       
    26         $ns = $k[$i];
       
    27         $pg = substr($string, strlen($paths->nslist[$ns]), strlen($string));
       
    28       }
       
    29     }
       
    30     return Array($pg, $ns);
       
    31   }
       
    32   
       
    33   function getPage($page_id, $namespace, $wiki = 1, $smilies = true, $filter_links = true, $redir = true, $render = true)
       
    34   {
       
    35     global $db, $session, $paths, $template, $plugins; // Common objects
       
    36     dc_here('render: page requested<br />ID/namespace: '."$page_id, $namespace<br />Wiki mode: $wiki<br />Smilies: ".(string)$smilies."<br />Allow redirects: ".(string)$redir);
       
    37     
       
    38     $perms =& $session;
       
    39     
       
    40     if ( $page_id != $paths->cpage['urlname_nons'] || $namespace != $paths->namespace )
       
    41     {
       
    42       unset($perms);
       
    43       unset($perms); // PHP <5.1.5 Zend bug
       
    44       $perms = $session->fetch_page_acl($page_id, $namespace);
       
    45     }
       
    46     
       
    47     if(!$perms->get_permissions('read'))
       
    48       return 'Access denied ('.$paths->nslist[$namespace].$page_id.')';
       
    49     
       
    50     if($wiki == 0 || $render == false)
       
    51     {
       
    52       if(!$perms->get_permissions('view_source'))
       
    53       {
       
    54         return 'Access denied ('.$paths->nslist[$namespace].$page_id.')';
       
    55       }
       
    56     }
       
    57     
       
    58     $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).'\';');
       
    59     if ( !$q )
       
    60     {
       
    61       $db->_die('Method called was: RenderMan::getPage(\''.$page_id.'\', \''.$namespace.'\');.');
       
    62     }
       
    63     if ( $db->numrows() < 1 )
       
    64     {
       
    65       return false;
       
    66     }
       
    67     $row = $db->fetchrow();
       
    68     $db->free_result();
       
    69     
       
    70     $message = $row['page_text'];
       
    71     $chartag = $row['char_tag'];
       
    72     unset($row); // Free some memory
       
    73     
       
    74     if ( preg_match('#^\#redirect \[\[(.+?)\]\]#', $message, $m) && $redir && !isset($_GET['redirect']) || ( isset($_GET['redirect']) && $_GET['redirect'] != 'no' ) )
       
    75     {
       
    76       dc_here('render: looks like a redirect page to me...');
       
    77       $old = $paths->cpage;
       
    78       $a = RenderMan::strToPageID($m[1]);
       
    79       $a[0] = str_replace(' ', '_', $a[0]);
       
    80       
       
    81       $pageid = str_replace(' ', '_', $paths->nslist[$a[1]] . $a[0]);
       
    82       $paths->page = $pageid;
       
    83       $paths->cpage = $paths->pages[$pageid];
       
    84       //die('<pre>'.print_r($paths->cpage,true).'</pre>');
       
    85       
       
    86       dc_here('render: wreckin\' $template, and reloading the theme vars to match the new page<br />This might get messy!');
       
    87       
       
    88       unset($template);
       
    89       unset($GLOBALS['template']);
       
    90       
       
    91       $GLOBALS['template'] = new template();
       
    92       global $template;
       
    93       
       
    94       $template->template(); // Tear down and rebuild the template parser
       
    95       $template->load_theme($session->theme, $session->style);
       
    96       
       
    97       $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 */);
       
    98       
       
    99       return $data;
       
   100     }
       
   101     else if(preg_match('#^\#redirect \[\[(.+?)\]\]#', $message, $m) && isset($_GET['redirect']) && $_GET['redirect'] == 'no')
       
   102     {
       
   103       dc_here('render: looks like a redirect page to me...');
       
   104       dc_here('render: skipping redirect as requested on URI');
       
   105       preg_match('#^\#redirect \[\[(.+)\]\]#', $message, $m);
       
   106       $m[1] = str_replace(' ', '_', $m[1]);
       
   107       $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);
       
   108     }
       
   109     $session->disallow_password_grab();
       
   110     dc_here('render: alright, got the text, formatting...');
       
   111     return ($render) ? RenderMan::render($message, $wiki, $smilies, $filter_links) : $message;
       
   112   }
       
   113   
       
   114   function getTemplate($id, $parms)
       
   115   {
       
   116     global $db, $session, $paths, $template, $plugins; // Common objects
       
   117     dc_here('render: template requested: '.$id);
       
   118     if(!isset($paths->pages[$paths->nslist['Template'].$id])) 
       
   119     {
       
   120       return '[['.$paths->nslist['Template'].$id.']]';
       
   121     }
       
   122     if(isset($paths->template_cache[$id]))
       
   123     {
       
   124       $text = $paths->template_cache[$id];
       
   125     }
       
   126     else
       
   127     {
       
   128       $text = RenderMan::getPage($id, 'Template', 0, true, true, 0);
       
   129       $paths->template_cache[$id] = $text;
       
   130     }
       
   131     
       
   132     $text = preg_replace('/<noinclude>(.*?)<\/noinclude>/is', '', $text);
       
   133     $text = preg_replace('/<nodisplay>(.*?)<\/nodisplay>/is', '\\1', $text);
       
   134     
       
   135     preg_match_all('#\(_([0-9]+)_\)#', $text, $matchlist);
       
   136     
       
   137     foreach($matchlist[1] as $m)
       
   138     {
       
   139       if(isset($parms[((int)$m)+1])) 
       
   140       {
       
   141         $p = $parms[((int)$m)+1];
       
   142       }
       
   143       else
       
   144       {
       
   145         $p = '<b>Notice:</b> RenderMan::getTemplate(): Parameter '.$m.' is not set';
       
   146       }
       
   147       $text = str_replace('(_'.$m.'_)', $p, $text);
       
   148     }
       
   149     $text = RenderMan::include_templates($text);
       
   150     return $text;
       
   151   }
       
   152   
       
   153   function fetch_template_text($id)
       
   154   {
       
   155     global $db, $session, $paths, $template, $plugins; // Common objects
       
   156     dc_here('render: template raw data requested: '.$id);
       
   157     if(!isset($paths->pages[$paths->nslist['Template'].$id])) 
       
   158     {
       
   159       return '[['.$paths->nslist['Template'].$id.']]';
       
   160     }
       
   161     if(isset($paths->template_cache[$id]))
       
   162     {
       
   163       $text = $paths->template_cache[$id];
       
   164     }
       
   165     else
       
   166     {
       
   167       $text = RenderMan::getPage($id, 'Template', 0, false, false, false, false);
       
   168       $paths->template_cache[$id] = $text;
       
   169     }
       
   170     
       
   171     if ( is_string($text) )
       
   172     {
       
   173       $text = preg_replace('/<noinclude>(.*?)<\/noinclude>/is', '', $text);
       
   174       $text = preg_replace('/<nodisplay>(.*?)<\/nodisplay>/is', '\\1', $text);
       
   175     }
       
   176     
       
   177     return $text;
       
   178   }
       
   179   
       
   180   function render($text, $wiki = 1, $smilies = true, $filter_links = true)
       
   181   {
       
   182     global $db, $session, $paths, $template, $plugins; // Common objects
       
   183     if($smilies)
       
   184     {
       
   185       $text = RenderMan::smilieyize($text);
       
   186     }
       
   187     if($wiki == 1)
       
   188     {
       
   189       $text = RenderMan::next_gen_wiki_format($text);
       
   190     }
       
   191     elseif($wiki == 2)
       
   192     {
       
   193       $text = $template->tplWikiFormat($text);
       
   194     }
       
   195     return $text;
       
   196   }
       
   197   
       
   198   function PlainTextRender($text, $wiki = 1, $smilies = false, $filter_links = true)
       
   199   {
       
   200     global $db, $session, $paths, $template, $plugins; // Common objects
       
   201     if($smilies)
       
   202     {
       
   203       $text = RenderMan::smilieyize($text);
       
   204     }
       
   205     if($wiki == 1)
       
   206     {
       
   207       $text = RenderMan::next_gen_wiki_format($text, true);
       
   208     }
       
   209     elseif($wiki == 2)
       
   210     {
       
   211       $text = $template->tplWikiFormat($text);
       
   212     }
       
   213     return $text;
       
   214   }
       
   215   
       
   216   function next_gen_wiki_format($text, $plaintext = false, $filter_links = true, $do_params = false)
       
   217   {
       
   218     global $db, $session, $paths, $template, $plugins; // Common objects
       
   219     $random_id = md5( time() . mt_rand() );
       
   220     
       
   221     // Strip out <nowiki> sections and PHP code
       
   222     
       
   223     $php = preg_match_all('#<\?php(.*?)\?>#is', $text, $phpsec);
       
   224     
       
   225     for($i=0;$i<sizeof($phpsec[1]);$i++)
       
   226     {
       
   227       $text = str_replace('<?php'.$phpsec[1][$i].'?>', '{PHP:'.$random_id.':'.$i.'}', $text);
       
   228     }
       
   229     
       
   230     $nw = preg_match_all('#<nowiki>(.*?)<\/nowiki>#is', $text, $nowiki);
       
   231     
       
   232     for($i=0;$i<sizeof($nowiki[1]);$i++)
       
   233     {
       
   234       $text = str_replace('<nowiki>'.$nowiki[1][$i].'</nowiki>', '{NOWIKI:'.$random_id.':'.$i.'}', $text);
       
   235     }
       
   236     
       
   237     $text = preg_replace('/<noinclude>(.*?)<\/noinclude>/is', '\\1', $text);
       
   238     if ( $paths->namespace == 'Template' )
       
   239     {
       
   240       $text = preg_replace('/<nodisplay>(.*?)<\/nodisplay>/is', '', $text);
       
   241     }
       
   242     
       
   243     if ( !$plaintext )
       
   244     {
       
   245       // Process images
       
   246       
       
   247       $j = preg_match_all('#\[\[:'.$paths->nslist['File'].'([\w\s0-9_\(\)!@%\^\+\|\.-]+?)\|([0-9]+)\|([0-9]+)\]\]#is', $text, $matchlist);
       
   248       $matches = Array();
       
   249       $matches['images']  =& $matchlist[1];
       
   250       $matches['widths']  =& $matchlist[2];
       
   251       $matches['heights'] =& $matchlist[3];
       
   252       for($i=0;$i<sizeof($matchlist[1]);$i++)
       
   253       {
       
   254         if(isPage($paths->nslist['File'].$matches['images'][$i])) $text = str_replace('[[:'.$paths->nslist['File'].$matches['images'][$i].'|'.$matches['widths'][$i].'|'.$matches['heights'][$i].']]',
       
   255           '<nowiki><a href="'.makeUrlNS('File', $matches['images'][$i]).'"><img alt="'.$matches['images'][$i].'" style="border: 0" src="'.makeUrlNS('Special', 'DownloadFile/'.$matches['images'][$i], 'preview&amp;width='.$matches['widths'][$i].'&amp;height='.$matches['heights'][$i]).'" /></a></nowiki>',
       
   256           $text);
       
   257       }
       
   258       
       
   259       $j = preg_match_all('#\[\[:'.$paths->nslist['File'].'([\w\s0-9_\(\)!@%\^\+\|\.-]+?)\]\]#is', $text, $matchlist);
       
   260       $matches = Array();
       
   261       $matches['images'] = $matchlist[1];
       
   262       for($i=0;$i<sizeof($matchlist[1]);$i++)
       
   263       {
       
   264         if(isPage($paths->nslist['File'].$matches['images'][$i])) $text = str_replace('[[:'.$paths->nslist['File'].$matches['images'][$i].']]',
       
   265           '<nowiki><a href="'.makeUrlNS('File', $matches['images'][$i]).'"><img alt="'.$matches['images'][$i].'" style="border: 0" src="'.makeUrlNS('Special', 'DownloadFile/'.$matches['images'][$i]).'" /></a></nowiki>',
       
   266           $text);
       
   267       }
       
   268       
       
   269     }
       
   270     
       
   271     if($do_params)
       
   272     {
       
   273       preg_match_all('#\(_([0-9]+)_\)#', $text, $matchlist);
       
   274       foreach($matchlist[1] as $m)
       
   275       {
       
   276         $text = str_replace('(_'.$m.'_)', $paths->getParam((int)$m), $text);
       
   277       }
       
   278     }
       
   279     
       
   280     $text = RenderMan::include_templates($text);
       
   281     
       
   282     $text = process_tables($text);
       
   283     
       
   284     $wiki =& Text_Wiki::singleton('Mediawiki');
       
   285     if($plaintext)
       
   286     {
       
   287       $wiki->setRenderConf('Plain', 'wikilink', 'view_url', contentPath);
       
   288       $result = $wiki->transform($text, 'Plain');
       
   289     }
       
   290     else
       
   291     {
       
   292       $wiki->setRenderConf('Xhtml', 'wikilink', 'view_url', contentPath);
       
   293       $wiki->setRenderConf('Xhtml', 'Url', 'css_descr', 'external');
       
   294       $result = $wiki->transform($text, 'Xhtml');
       
   295     }
       
   296     
       
   297     // Reinsert <nowiki> sections
       
   298     for($i=0;$i<$nw;$i++)
       
   299     {
       
   300       $result = str_replace('{NOWIKI:'.$random_id.':'.$i.'}', $nowiki[1][$i], $result);
       
   301     }
       
   302     
       
   303     // Reinsert PHP
       
   304     for($i=0;$i<$php;$i++)
       
   305     {
       
   306       $result = str_replace('{PHP:'.$random_id.':'.$i.'}', '<?php'.$phpsec[1][$i].'?>', $result);
       
   307     }
       
   308     
       
   309     return $result;
       
   310     
       
   311   }
       
   312   
       
   313   function wikiFormat($message, $filter_links = true, $do_params = false, $plaintext = false) {
       
   314     global $db, $session, $paths, $template, $plugins; // Common objects
       
   315     
       
   316     return RenderMan::next_gen_wiki_format($message, $plaintext, $filter_links, $do_params);
       
   317     
       
   318     $random_id = md5( time() . mt_rand() );
       
   319     
       
   320     // Strip out <nowiki> sections
       
   321     $nw = preg_match_all('#<nowiki>(.*?)<\/nowiki>#is', $message, $nowiki);
       
   322     
       
   323     if(!$plaintext)
       
   324     {
       
   325     
       
   326       //return '<pre>'.print_r($nowiki,true).'</pre>';
       
   327       
       
   328       for($i=0;$i<sizeof($nowiki[1]);$i++)
       
   329       {
       
   330         $message = str_replace('<nowiki>'.$nowiki[1][$i].'</nowiki>', '{NOWIKI:'.$random_id.':'.$i.'}', $message);
       
   331       }
       
   332       
       
   333       $message = preg_replace('/<noinclude>(.*?)<\/noinclude>/is', '\\1', $message);
       
   334       
       
   335       //return '<pre>'.htmlspecialchars($message).'</pre>';
       
   336       
       
   337       $j = preg_match_all('#\[\[:'.$paths->nslist['File'].'([\w\s0-9_\(\)!@%\^\+\|\.-]+?)\|([0-9]+)\|([0-9]+)\]\]#is', $message, $matchlist);
       
   338       $matches = Array();
       
   339       $matches['images'] = $matchlist[1];
       
   340       $matches['widths'] = $matchlist[2];
       
   341       $matches['heights'] = $matchlist[3];
       
   342       for($i=0;$i<sizeof($matchlist[1]);$i++)
       
   343       {
       
   344         if(isPage($paths->nslist['File'].$matches['images'][$i])) $message = str_replace('[[:'.$paths->nslist['File'].$matches['images'][$i].'|'.$matches['widths'][$i].'|'.$matches['heights'][$i].']]',
       
   345           '<nowiki><a href="'.makeUrlNS('File', $matches['images'][$i]).'"><img alt="'.$matches['images'][$i].'" style="border: 0" src="'.makeUrlNS('Special', 'DownloadFile/'.$matches['images'][$i], 'preview&amp;width='.$matches['widths'][$i].'&amp;height='.$matches['heights'][$i]).'" /></a></nowiki>',
       
   346           $message);
       
   347       }
       
   348       
       
   349       $j = preg_match_all('#\[\[:'.$paths->nslist['File'].'([\w\s0-9_\(\)!@%\^\+\|\.-]+?)\]\]#is', $message, $matchlist);
       
   350       $matches = Array();
       
   351       $matches['images'] = $matchlist[1];
       
   352       for($i=0;$i<sizeof($matchlist[1]);$i++)
       
   353       {
       
   354         if(isPage($paths->nslist['File'].$matches['images'][$i])) $message = str_replace('[[:'.$paths->nslist['File'].$matches['images'][$i].']]',
       
   355           '<nowiki><a href="'.makeUrlNS('File', $matches['images'][$i]).'"><img alt="'.$matches['images'][$i].'" style="border: 0" src="'.makeUrlNS('Special', 'DownloadFile/'.$matches['images'][$i]).'" /></a></nowiki>',
       
   356           $message);
       
   357       }
       
   358     
       
   359     }
       
   360     
       
   361     if($do_params)
       
   362     {
       
   363       preg_match_all('#\(_([0-9]+)_\)#', $message, $matchlist);
       
   364       foreach($matchlist[1] as $m)
       
   365       {
       
   366         $message = str_replace('(_'.$m.'_)', $paths->getParam((int)$m), $message);
       
   367       }
       
   368     }
       
   369     
       
   370     $message = RenderMan::include_templates($message);
       
   371     
       
   372     // Reinsert <nowiki> sections
       
   373     for($i=0;$i<$nw;$i++)
       
   374     {
       
   375       $message = str_replace('{NOWIKI:'.$random_id.':'.$i.'}', '<nowiki>'.$nowiki[1][$i].'</nowiki>', $message);
       
   376     }
       
   377     
       
   378     $message = process_tables($message);
       
   379     //if($message2 != $message) return '<pre>'.htmlspecialchars($message2).'</pre>';
       
   380     //$message = str_replace(array('<table>', '</table>'), array('<nowiki><table>', '</table></nowiki>'), $message);
       
   381     
       
   382     $wiki =& Text_Wiki::singleton('Mediawiki');
       
   383     if($plaintext)
       
   384     {
       
   385       $wiki->setRenderConf('Plain', 'wikilink', 'view_url', contentPath);
       
   386       $result = $wiki->transform($message, 'Plain');
       
   387     } else {
       
   388       $wiki->setRenderConf('Xhtml', 'wikilink', 'view_url', contentPath);
       
   389       $wiki->setRenderConf('Xhtml', 'Url', 'css_descr', 'external');
       
   390       $result = $wiki->transform($message, 'Xhtml');
       
   391     }
       
   392     
       
   393     // HTML fixes
       
   394     $result = preg_replace('#<tr>([\s]*?)<\/tr>#is', '', $result);
       
   395     $result = preg_replace('#<p>([\s]*?)<\/p>#is', '', $result);
       
   396     $result = preg_replace('#<br />([\s]*?)<table#is', '<table', $result);
       
   397     $result = str_replace("<pre><code>\n", "<pre><code>", $result);
       
   398     $result = preg_replace("/<p><table([^>]*?)><\/p>/", "<table\\1>", $result);
       
   399     $result = str_replace("<br />\n</td>", "\n</td>", $result);
       
   400     $result = str_replace("<p><tr>", "<tr>", $result);
       
   401     $result = str_replace("<tr><br />", "<tr>", $result);
       
   402     $result = str_replace("</tr><br />", "</tr>", $result);
       
   403     $result = str_replace("</table></p>", "</table>", $result);
       
   404     $result = str_replace("</table><br />", "</table>", $result);
       
   405     $result = preg_replace('/<\/table>$/', "</table><br /><br />", $result);
       
   406     
       
   407     $result = str_replace('<nowiki>',  '&lt;nowiki&gt;',  $result);
       
   408     $result = str_replace('</nowiki>', '&lt;/nowiki&gt;', $result);
       
   409     
       
   410     return $result;
       
   411   }
       
   412   
       
   413   function destroy_javascript($message, $_php = false)
       
   414   {
       
   415     $message = preg_replace('#<(script|object|applet|embed|iframe|frame|form|input|select)(.*?)>#is', '&lt;\\1\\2&gt;', $message);
       
   416     $message = preg_replace('#</(script|object|applet|embed|iframe|frame|form|input|select)(.*?)>#is', '&lt;/\\1\\2&gt;', $message);
       
   417     $message = preg_replace('#(javascript|script|activex|chrome|about|applet):#is', '\\1&#058;', $message);
       
   418     if ( $_php )
       
   419     {
       
   420       // Left in only for compatibility
       
   421       $message = preg_replace('#&lt;(.*?)>#is', '<\\1>', $message);
       
   422       $message = preg_replace('#<(.*?)&gt;#is', '<\\1>', $message);
       
   423       $message = preg_replace('#<(\?|\?php|%)(.*?)(\?|%)>#is', '&lt;\\1\\2\\3&gt;', $message);
       
   424       // strip <a href="foo" onclick="bar();">-type attacks
       
   425       $message = preg_replace('#<([a-zA-Z:\-]+) (.*?)on([A-Za-z]*)=(.*?)>#is', '&lt;\\1\\2on\\3=\\4&gt;', $message);
       
   426     }
       
   427     return $message;
       
   428   }
       
   429   
       
   430   function strip_php($message)
       
   431   {
       
   432     return RenderMan::destroy_javascript($message, true);
       
   433   }
       
   434   
       
   435   function sanitize_html($text)
       
   436   {
       
   437     $text = htmlspecialchars($text);
       
   438     $allowed_tags = Array('b', 'i', 'u', 'pre', 'code', 'tt', 'br', 'p', 'nowiki', '!--([^.]+)--');
       
   439     foreach($allowed_tags as $t)
       
   440     {
       
   441       $text = preg_replace('#&lt;'.$t.'&gt;(.*?)&lt;/'.$t.'&gt;#is', '<'.$t.'>\\1</'.$t.'>', $text);
       
   442       $text = preg_replace('#&lt;'.$t.' /&gt;#is', '<'.$t.' />', $text);
       
   443       $text = preg_replace('#&lt;'.$t.'&gt;#is', '<'.$t.'>', $text);
       
   444     }
       
   445     return $text;
       
   446   }
       
   447   
       
   448   /* *
       
   449    * Replaces template inclusions with the templates
       
   450    * @param string $message The text to format
       
   451    * @return string
       
   452    * /
       
   453    
       
   454   function old_include_templates($message)
       
   455   {
       
   456     $random_id = md5( time() . mt_rand() );
       
   457     preg_match_all('#\{\{(.+?)\}\}#s', $message, $matchlist);
       
   458     foreach($matchlist[1] as $m)
       
   459     {
       
   460       $mn = $m;
       
   461       // Strip out wikilinks and re-add them after the explosion (because of the "|")
       
   462       preg_match_all('#\[\[(.+?)\]\]#i', $m, $linklist);
       
   463       //echo '<pre>'.print_r($linklist, true).'</pre>';
       
   464       for($i=0;$i<sizeof($linklist[1]);$i++)
       
   465       {
       
   466         $mn = str_replace('[['.$linklist[1][$i].']]', '{WIKILINK:'.$random_id.':'.$i.'}', $mn);
       
   467       }
       
   468       
       
   469       $ar = explode('|', $mn);
       
   470       
       
   471       for($j=0;$j<sizeof($ar);$j++)
       
   472       {
       
   473         for($i=0;$i<sizeof($linklist[1]);$i++)
       
   474         {
       
   475           $ar[$j] = str_replace('{WIKILINK:'.$random_id.':'.$i.'}', '[['.$linklist[1][$i].']]', $ar[$j]);
       
   476         }
       
   477       }
       
   478       
       
   479       $tp = $ar[0];
       
   480       unset($ar[0]);
       
   481       $tp = str_replace(' ', '_', $tp);
       
   482       $message = str_replace('{{'.$m.'}}', RenderMan::getTemplate($tp, $ar), $message);
       
   483     }
       
   484     return $message;
       
   485   }
       
   486   */
       
   487   
       
   488   /**
       
   489    * Parses a partial template tag in wikitext, and return an array with the parameters.
       
   490    * @param string The portion of the template tag that contains the parameters. Example:
       
   491    * <code>
       
   492    * foo = lorem ipsum
       
   493    * bar = dolor sit amet
       
   494    * </code>
       
   495    * @return array Example:
       
   496    * [foo] => lorem ipsum
       
   497    * [bar] => dolor sit amet
       
   498    */
       
   499   
       
   500   function parse_template_vars($input)
       
   501   {
       
   502     $input = explode("\n", trim( $input ));
       
   503     $parms = Array();
       
   504     $current_line = '';
       
   505     $current_parm = '';
       
   506     foreach ( $input as $num => $line )
       
   507     {
       
   508       if ( preg_match('/^([ ]*?)([A-z0-9_]+?)([ ]*?)=([ ]*?)(.+?)$/i', $line, $matches) )
       
   509       {
       
   510         $parm =& $matches[2];
       
   511         $text =& $matches[5];
       
   512         if ( $parm == $current_parm )
       
   513         {
       
   514           $current_line .= $text;
       
   515         }
       
   516         else
       
   517         {
       
   518           // New parameter
       
   519           if ( $current_parm != '' )
       
   520             $parms[$current_parm] = $current_line;
       
   521           $current_line = $text;
       
   522           $current_parm = $parm;
       
   523         }
       
   524       }
       
   525       else if ( $num == 0 )
       
   526       {
       
   527         // Syntax error
       
   528         return false;
       
   529       }
       
   530       else
       
   531       {
       
   532         $current_line .= "\n$line";
       
   533       }
       
   534     }
       
   535     if ( !empty($current_parm) && !empty($current_line) )
       
   536     {
       
   537       $parms[$current_parm] = $current_line;
       
   538     }
       
   539     return $parms;
       
   540   }
       
   541   
       
   542   /**
       
   543    * Processes all template tags within a block of wikitext.
       
   544    * @param string The text to process
       
   545    * @return string Formatted text
       
   546    * @example
       
   547    * <code>
       
   548    $text = '{{Template
       
   549      parm1 = Foo
       
   550      parm2 = Bar
       
   551      }}';
       
   552    $text = include_templates($text);
       
   553    * </code>
       
   554    */
       
   555   
       
   556   function include_templates($text)
       
   557   {
       
   558     global $db, $session, $paths, $template, $plugins; // Common objects
       
   559     $template_regex = "/\{\{([A-z0-9_-]+?)((\n([ ]*?)[A-z0-9]+([ ]*?)=([ ]*?)(.+?))*)\}\}/is";
       
   560     if ( $count = preg_match_all($template_regex, $text, $matches) )
       
   561     {
       
   562       for ( $i = 0; $i < $count; $i++ )
       
   563       {
       
   564         $parmsection = trim($matches[2][$i]);
       
   565         if ( !empty($parmsection) )
       
   566         {
       
   567           $parms = RenderMan::parse_template_vars($parmsection);
       
   568           foreach ( $parms as $j => $parm )
       
   569           {
       
   570             $parms[$j] = $parm;
       
   571           }
       
   572         }
       
   573         else
       
   574         {
       
   575           $parms = Array();
       
   576         }
       
   577         if ( $tpl_code = RenderMan::fetch_template_text($matches[1][$i]) )
       
   578         {
       
   579           $parser = $template->makeParserText($tpl_code);
       
   580           $parser->assign_vars($parms);
       
   581           $text = str_replace($matches[0][$i], $parser->run(), $text);
       
   582         }
       
   583       }
       
   584     }
       
   585     return $text;
       
   586   }
       
   587   
       
   588   /**
       
   589    * Preprocesses an HTML text string prior to being sent to MySQL.
       
   590    * @param string $text
       
   591    * @param bool $strip_all_php - if true, strips all PHP regardless of user permissions. Else, strips PHP only if user level < USER_LEVEL_ADMIN.
       
   592    */
       
   593   function preprocess_text($text, $strip_all_php = true, $sqlescape = true)
       
   594   {
       
   595     global $db, $session, $paths, $template, $plugins; // Common objects
       
   596     $random_id = md5( time() . mt_rand() );
       
   597     
       
   598     $can_do_php = ( $session->get_permissions('php_in_pages') && !$strip_all_php );
       
   599     
       
   600     $text = sanitize_html($text, ( !$can_do_php ));
       
   601     
       
   602     if ( !$can_do_php )
       
   603     {
       
   604       // If we can't do PHP, we can't do Javascript either.
       
   605       $text = RenderMan::destroy_javascript($text);
       
   606     }
       
   607     
       
   608     // Strip out <nowiki> sections and PHP code
       
   609     
       
   610     $php = preg_match_all('#(<|&lt;)\?php(.*?)\?(>|&gt;)#is', $text, $phpsec);
       
   611     
       
   612     //die('<pre>'.htmlspecialchars(print_r($phpsec, true))."\n".htmlspecialchars(print_r($text, true)).'</pre>');
       
   613     
       
   614     for($i=0;$i<sizeof($phpsec[1]);$i++)
       
   615     {
       
   616       $text = str_replace($phpsec[0][$i], '{PHP:'.$random_id.':'.$i.'}', $text);
       
   617     }
       
   618     
       
   619     $nw = preg_match_all('#<nowiki>(.*?)<\/nowiki>#is', $text, $nowiki);
       
   620     
       
   621     for($i=0;$i<sizeof($nowiki[1]);$i++)
       
   622     {
       
   623       $text = str_replace('<nowiki>'.$nowiki[1][$i].'</nowiki>', '{NOWIKI:'.$random_id.':'.$i.'}', $text);
       
   624     }
       
   625     
       
   626     $text = str_replace('~~~~~', date('G:i, j F Y (T)'), $text);
       
   627     $text = str_replace('~~~~', "[[User:$session->username|$session->username]] ".date('G:i, j F Y (T)'), $text);
       
   628     $text = str_replace('~~~', "[[User:$session->username|$session->username]] ", $text);
       
   629     
       
   630     // Reinsert <nowiki> sections
       
   631     for($i=0;$i<$nw;$i++)
       
   632     {
       
   633       $text = str_replace('{NOWIKI:'.$random_id.':'.$i.'}', '<nowiki>'.$nowiki[1][$i].'</nowiki>', $text);
       
   634     }
       
   635     // Reinsert PHP
       
   636     for($i=0;$i<$php;$i++)
       
   637     {
       
   638       $phsec = ''.$phpsec[1][$i].'?php'.$phpsec[2][$i].'?'.$phpsec[3][$i].'';
       
   639       if ( $strip_all_php )
       
   640         $phsec = htmlspecialchars($phsec);
       
   641       $text = str_replace('{PHP:'.$random_id.':'.$i.'}', $phsec, $text);
       
   642     }
       
   643     
       
   644     $text = ( $sqlescape ) ? $db->escape($text) : $text;
       
   645     
       
   646     return $text;
       
   647   }
       
   648   
       
   649   function smilieyize($text, $complete_urls = false)
       
   650   {
       
   651     
       
   652     $random_id = md5( time() . mt_rand() );
       
   653     
       
   654     // Smileys array - eventually this will be fetched from the database by
       
   655     // RenderMan::initSmileys during initialization, but it will all be hardcoded for beta 2
       
   656     
       
   657     $smileys = Array(
       
   658       'O:-)'    => 'face-angel.png',
       
   659       'O:)'     => 'face-angel.png',
       
   660       'O=)'     => 'face-angel.png',
       
   661       ':-)'     => 'face-smile.png',
       
   662       ':)'      => 'face-smile.png',
       
   663       '=)'      => 'face-smile-big.png',
       
   664       ':-('     => 'face-sad.png',
       
   665       ':('      => 'face-sad.png',
       
   666       ';('      => 'face-sad.png',
       
   667       ':-O'     => 'face-surprise.png',
       
   668       ';-)'     => 'face-wink.png',
       
   669       ';)'      => 'face-wink.png',
       
   670       '8-)'     => 'face-glasses.png',
       
   671       '8)'      => 'face-glasses.png',
       
   672       ':-D'     => 'face-grin.png',
       
   673       ':D'      => 'face-grin.png',
       
   674       '=D'      => 'face-grin.png',
       
   675       ':-*'     => 'face-kiss.png',
       
   676       ':*'      => 'face-kiss.png',
       
   677       '=*'      => 'face-kiss.png',
       
   678       ':\'('    => 'face-crying.png',
       
   679       ':-|'     => 'face-plain.png',
       
   680       ':-\\'    => 'face-plain.png',
       
   681       ':-/'     => 'face-plain.png',
       
   682       ':joke:'  => 'face-plain.png',
       
   683       ']:-&gt;' => 'face-devil-grin.png',
       
   684       ':kiss:'  => 'face-kiss.png',
       
   685       ':-P'     => 'face-tongue-out.png',
       
   686       ':P'      => 'face-tongue-out.png',
       
   687       ':-p'     => 'face-tongue-out.png',
       
   688       ':p'      => 'face-tongue-out.png',
       
   689       ':-X'     => 'face-sick.png',
       
   690       ':X'      => 'face-sick.png',
       
   691       ':sick:'  => 'face-sick.png',
       
   692       ':-]'     => 'face-oops.png',
       
   693       ':]'      => 'face-oops.png',
       
   694       ':oops:'  => 'face-oops.png',
       
   695       ':-['     => 'face-embarassed.png',
       
   696       ':['      => 'face-embarassed.png'
       
   697       );
       
   698     /*
       
   699     $keys = array_keys($smileys);
       
   700     foreach($keys as $k)
       
   701     {
       
   702       $regex1 = '#([\W]+)'.preg_quote($k).'([\s\n\r\.]+)#s';
       
   703       $regex2 = '\\1<img alt="'.$k.'" title="'.$k.'" src="'.scriptPath.'/images/smilies/'.$smileys[$k].'" style="border: 0;" />\\2';
       
   704       $text = preg_replace($regex1, $regex2, $text);
       
   705     }                                                                      
       
   706     */
       
   707     
       
   708     // Strip out <nowiki> sections
       
   709     //return '<pre>'.htmlspecialchars($text).'</pre>';
       
   710     $nw = preg_match_all('#<nowiki>(.*?)<\/nowiki>#is', $text, $nowiki);
       
   711     
       
   712     for($i=0;$i<sizeof($nowiki[1]);$i++)
       
   713     {
       
   714       $text = str_replace('<nowiki>'.$nowiki[1][$i].'</nowiki>', '{NOWIKI:'.$random_id.':'.$i.'}', $text);
       
   715     }
       
   716     
       
   717     $keys = array_keys($smileys);
       
   718     foreach($keys as $k)
       
   719     {
       
   720       $t = str_hex($k);
       
   721       $t = explode(' ', $t);
       
   722       $s = '';
       
   723       foreach($t as $b)
       
   724       {
       
   725         $s.='&#x'.$b.';';
       
   726       }
       
   727       $pfx = ( $complete_urls ) ? 'http' . ( isset($_SERVER['HTTPS']) ? 's' : '' ) . '://'.$_SERVER['HTTP_HOST'] : '';
       
   728       $text = str_replace(' '.$k, ' <nowiki><img title="'.$s.'" alt="'.$s.'" src="'.$pfx.scriptPath.'/images/smilies/'.$smileys[$k].'" style="border: 0;" /></nowiki>', $text);
       
   729     }
       
   730     //*/
       
   731     
       
   732     // Reinsert <nowiki> sections
       
   733     for($i=0;$i<$nw;$i++)
       
   734     {
       
   735       $text = str_replace('{NOWIKI:'.$random_id.':'.$i.'}', '<nowiki>'.$nowiki[1][$i].'</nowiki>', $text);
       
   736     }
       
   737     
       
   738     return $text;
       
   739   }
       
   740   
       
   741   /*
       
   742    * **** DEPRECATED ****
       
   743    * Replaces some critical characters in a string with MySQL-safe equivalents
       
   744    * @param $text string the text to escape
       
   745    * @return array key 0 is the escaped text, key 1 is the character tag
       
   746    * /
       
   747    
       
   748   function escape_page_text($text)
       
   749   {
       
   750     $char_tag = md5(microtime() . mt_rand());
       
   751     $text = str_replace("'",  "{APOS:$char_tag}",  $text);
       
   752     $text = str_replace('"',  "{QUOT:$char_tag}",  $text);
       
   753     $text = str_replace("\\", "{SLASH:$char_tag}", $text);
       
   754     return Array($text, $char_tag);
       
   755   }
       
   756   */
       
   757   
       
   758   /* **** DEPRECATED ****
       
   759    * Reverses the result of RenderMan::escape_page_text().
       
   760    * @param $text string the text to unescape
       
   761    * @param $char_tag string the character tag
       
   762    * @return string
       
   763    * /
       
   764    
       
   765   function unescape_page_text($text, $char_tag)
       
   766   {
       
   767     $text = str_replace("{APOS:$char_tag}",  "'",  $text);
       
   768     $text = str_replace("{QUOT:$char_tag}",  '"',  $text);
       
   769     $text = str_replace("{SLASH:$char_tag}", "\\", $text);
       
   770     return $text;
       
   771   }
       
   772   */
       
   773   
       
   774   /**
       
   775    * Generates a summary of the differences between two texts, and formats it as XHTML.
       
   776    * @param $str1 string the first block of text
       
   777    * @param $str2 string the second block of text
       
   778    * @return string
       
   779    */
       
   780   function diff($str1, $str2)
       
   781   {
       
   782     global $db, $session, $paths, $template, $plugins; // Common objects
       
   783     $str1 = explode("\n", $str1);
       
   784     $str2 = explode("\n", $str2);
       
   785     $diff = new Diff($str1, $str2);
       
   786     $renderer = new TableDiffFormatter();
       
   787     return '<table class="diff">'.$renderer->format($diff).'</table>';
       
   788   }
       
   789   
       
   790 }
       
   791  
       
   792 ?>