includes/render.php
changeset 1227 bdac73ed481e
parent 1216 4125e19d3b27
child 1230 31d226269d2f
equal deleted inserted replaced
1226:de56132c008d 1227:bdac73ed481e
    11  * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
    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.
    12  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
    13  */
    13  */
    14  
    14  
    15 class RenderMan {
    15 class RenderMan {
    16   
    16 	
    17   public static function strToPageID($string)
    17 	public static function strToPageID($string)
    18   {
    18 	{
    19     global $db, $session, $paths, $template, $plugins; // Common objects
    19 		global $db, $session, $paths, $template, $plugins; // Common objects
    20     $k = array_keys($paths->nslist);
    20 		$k = array_keys($paths->nslist);
    21     $proj_alt = 'Project:';
    21 		$proj_alt = 'Project:';
    22     if ( substr($string, 0, (strlen($proj_alt))) == $proj_alt )
    22 		if ( substr($string, 0, (strlen($proj_alt))) == $proj_alt )
    23     {
    23 		{
    24       $ns = 'Project';
    24 			$ns = 'Project';
    25       $pg = substr($string, strlen($proj_alt), strlen($string));
    25 			$pg = substr($string, strlen($proj_alt), strlen($string));
    26       return Array($pg, $ns);
    26 			return Array($pg, $ns);
    27     }
    27 		}
    28     for($i=0;$i<sizeof($paths->nslist);$i++)
    28 		for($i=0;$i<sizeof($paths->nslist);$i++)
    29     {
    29 		{
    30       $ln = strlen($paths->nslist[$k[$i]]);
    30 			$ln = strlen($paths->nslist[$k[$i]]);
    31       if(substr($string, 0, $ln) == $paths->nslist[$k[$i]])
    31 			if(substr($string, 0, $ln) == $paths->nslist[$k[$i]])
    32       {
    32 			{
    33         $ns = $k[$i];
    33 				$ns = $k[$i];
    34         $pg = substr($string, strlen($paths->nslist[$ns]), strlen($string));
    34 				$pg = substr($string, strlen($paths->nslist[$ns]), strlen($string));
    35       }
    35 			}
    36     }
    36 		}
    37     return Array($pg, $ns);
    37 		return Array($pg, $ns);
    38   }
    38 	}
    39   
    39 	
    40   public static function getPage($page_id, $namespace, $wiki = 1, $smilies = true, $filter_links = true, $redir = true, $render = true)
    40 	public static function getPage($page_id, $namespace, $wiki = 1, $smilies = true, $filter_links = true, $redir = true, $render = true)
    41   {
    41 	{
    42     global $db, $session, $paths, $template, $plugins; // Common objects
    42 		global $db, $session, $paths, $template, $plugins; // Common objects
    43     
    43 		
    44     $page = new PageProcessor($page_id, $namespace);
    44 		$page = new PageProcessor($page_id, $namespace);
    45     $text = $page->fetch_text();
    45 		$text = $page->fetch_text();
    46     
    46 		
    47     if ( !$render )
    47 		if ( !$render )
    48       return $text;
    48 			return $text;
    49     
    49 		
    50     $text = self::render($text, $wiki, $smilies, $filter_links);
    50 		$text = self::render($text, $wiki, $smilies, $filter_links);
    51     return $text;
    51 		return $text;
    52   }
    52 	}
    53   
    53 	
    54   public static function getTemplate($id, $parms)
    54 	public static function getTemplate($id, $parms)
    55   {
    55 	{
    56     global $db, $session, $paths, $template, $plugins; // Common objects
    56 		global $db, $session, $paths, $template, $plugins; // Common objects
    57     if ( !isPage($paths->get_pathskey($id, 'Template')) ) 
    57 		if ( !isPage($paths->get_pathskey($id, 'Template')) ) 
    58     {
    58 		{
    59       return '[['.$paths->nslist['Template'].$id.']]';
    59 			return '[['.$paths->nslist['Template'].$id.']]';
    60     }
    60 		}
    61     if(isset($paths->template_cache[$id]))
    61 		if(isset($paths->template_cache[$id]))
    62     {
    62 		{
    63       $text = $paths->template_cache[$id];
    63 			$text = $paths->template_cache[$id];
    64     }
    64 		}
    65     else
    65 		else
    66     {
    66 		{
    67       $page = new PageProcessor($id, 'Template');
    67 			$page = new PageProcessor($id, 'Template');
    68       $text = $page->fetch_text();
    68 			$text = $page->fetch_text();
    69       $paths->template_cache[$id] = $text;
    69 			$paths->template_cache[$id] = $text;
    70     }
    70 		}
    71     
    71 		
    72     $text = preg_replace('/<noinclude>(.*?)<\/noinclude>/is', '', $text);
    72 		$text = preg_replace('/<noinclude>(.*?)<\/noinclude>/is', '', $text);
    73     $text = preg_replace('/<nodisplay>(.*?)<\/nodisplay>/is', '\\1', $text);
    73 		$text = preg_replace('/<nodisplay>(.*?)<\/nodisplay>/is', '\\1', $text);
    74     
    74 		
    75     preg_match_all('#\(_([0-9]+)_\)#', $text, $matchlist);
    75 		preg_match_all('#\(_([0-9]+)_\)#', $text, $matchlist);
    76     
    76 		
    77     foreach($matchlist[1] as $m)
    77 		foreach($matchlist[1] as $m)
    78     {
    78 		{
    79       if(isset($parms[((int)$m)+1])) 
    79 			if(isset($parms[((int)$m)+1])) 
    80       {
    80 			{
    81         $p = $parms[((int)$m)+1];
    81 				$p = $parms[((int)$m)+1];
    82       }
    82 			}
    83       else
    83 			else
    84       {
    84 			{
    85         $p = '<b>Notice:</b> RenderMan::getTemplate(): Parameter '.$m.' is not set';
    85 				$p = '<b>Notice:</b> RenderMan::getTemplate(): Parameter '.$m.' is not set';
    86       }
    86 			}
    87       $text = str_replace('(_'.$m.'_)', $p, $text);
    87 			$text = str_replace('(_'.$m.'_)', $p, $text);
    88       $text = str_replace('{{' . ( $m + 1 ) . '}}', $p, $text);
    88 			$text = str_replace('{{' . ( $m + 1 ) . '}}', $p, $text);
    89     }
    89 		}
    90     $text = RenderMan::include_templates($text);
    90 		$text = RenderMan::include_templates($text);
    91     return $text;
    91 		return $text;
    92   }
    92 	}
    93   
    93 	
    94   public static function fetch_template_text($id)
    94 	public static function fetch_template_text($id)
    95   {
    95 	{
    96     global $db, $session, $paths, $template, $plugins; // Common objects
    96 		global $db, $session, $paths, $template, $plugins; // Common objects
    97     $fetch_ns = 'Template';
    97 		$fetch_ns = 'Template';
    98     if ( !isPage($paths->get_pathskey($id, 'Template')) ) 
    98 		if ( !isPage($paths->get_pathskey($id, 'Template')) ) 
    99     {
    99 		{
   100       // Transclusion of another page
   100 			// Transclusion of another page
   101       // 1.1.5: Now You, Too, Can Be A Template, Even If You're Just A Plain Old Article! (TM)
   101 			// 1.1.5: Now You, Too, Can Be A Template, Even If You're Just A Plain Old Article! (TM)
   102       $nssep = substr($paths->nslist['Special'], -1);
   102 			$nssep = substr($paths->nslist['Special'], -1);
   103       $nslist = $paths->nslist;
   103 			$nslist = $paths->nslist;
   104       foreach ( $nslist as &$ns )
   104 			foreach ( $nslist as &$ns )
   105       {
   105 			{
   106         if ( $ns == '' )
   106 				if ( $ns == '' )
   107           $ns = $nssep;
   107 					$ns = $nssep;
   108       }
   108 			}
   109       $prefixlist = array_flip($nslist);
   109 			$prefixlist = array_flip($nslist);
   110       foreach ( $nslist as &$ns )
   110 			foreach ( $nslist as &$ns )
   111       {
   111 			{
   112         $ns = preg_quote($ns);
   112 				$ns = preg_quote($ns);
   113       }
   113 			}
   114       $nslist = implode('|', $nslist);
   114 			$nslist = implode('|', $nslist);
   115       if ( preg_match("/^($nslist)(.*?)$/", $id, $match) )
   115 			if ( preg_match("/^($nslist)(.*?)$/", $id, $match) )
   116       {
   116 			{
   117         // 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...
   118         if ( isset($prefixlist[$match[1]]) )
   118 				if ( isset($prefixlist[$match[1]]) )
   119         {
   119 				{
   120           $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]);
   121           if ( !isPage($new_id) )
   121 					if ( !isPage($new_id) )
   122           {
   122 					{
   123             return "[[$new_id]]";
   123 						return "[[$new_id]]";
   124           }
   124 					}
   125           $fetch_ns = $prefixlist[$match[1]];
   125 					$fetch_ns = $prefixlist[$match[1]];
   126           $id = sanitize_page_id($match[2]);
   126 					$id = sanitize_page_id($match[2]);
   127         }
   127 				}
   128       }
   128 			}
   129       else
   129 			else
   130       {
   130 			{
   131         return '[['.$paths->nslist['Template'].$id.']]';
   131 				return '[['.$paths->nslist['Template'].$id.']]';
   132       }
   132 			}
   133     }
   133 		}
   134     if(isset($paths->template_cache[$id]))
   134 		if(isset($paths->template_cache[$id]))
   135     {
   135 		{
   136       $text = $paths->template_cache[$id];
   136 			$text = $paths->template_cache[$id];
   137     }
   137 		}
   138     else
   138 		else
   139     {
   139 		{
   140       $text = RenderMan::getPage($id, $fetch_ns, 0, false, false, false, false);
   140 			$text = RenderMan::getPage($id, $fetch_ns, 0, false, false, false, false);
   141       $paths->template_cache[$id] = $text;
   141 			$paths->template_cache[$id] = $text;
   142     }
   142 		}
   143     
   143 		
   144     if ( is_string($text) )
   144 		if ( is_string($text) )
   145     {
   145 		{
   146       $text = preg_replace('/<noinclude>(.*?)<\/noinclude>/is', '', $text);
   146 			$text = preg_replace('/<noinclude>(.*?)<\/noinclude>/is', '', $text);
   147       $text = preg_replace('/<nodisplay>(.*?)<\/nodisplay>/is', '\\1', $text);
   147 			$text = preg_replace('/<nodisplay>(.*?)<\/nodisplay>/is', '\\1', $text);
   148     }
   148 		}
   149     
   149 		
   150     return $text;
   150 		return $text;
   151   }
   151 	}
   152   
   152 	
   153   /**
   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.
   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
   155  	* @param string Text to render
   156    * @param int Render parameters - see constants.php
   156  	* @param int Render parameters - see constants.php
   157    * @return string Rendered text
   157  	* @return string Rendered text
   158    */
   158  	*/
   159   
   159 	
   160   public static function render($text, $flags = RENDER_WIKI_DEFAULT, $smilies = true)
   160 	public static function render($text, $flags = RENDER_WIKI_DEFAULT, $smilies = true)
   161   {
   161 	{
   162     global $db, $session, $paths, $template, $plugins; // Common objects
   162 		global $db, $session, $paths, $template, $plugins; // Common objects
   163     
   163 		
   164     if ( !$smilies )
   164 		if ( !$smilies )
   165       $flags |= RENDER_NOSMILIES;
   165 			$flags |= RENDER_NOSMILIES;
   166     
   166 		
   167     if ( !($flags & RENDER_NOSMILIES) )
   167 		if ( !($flags & RENDER_NOSMILIES) )
   168     {
   168 		{
   169       $text = RenderMan::smilieyize($text);
   169 			$text = RenderMan::smilieyize($text);
   170     }
   170 		}
   171     if ( $flags & RENDER_WIKI_DEFAULT )
   171 		if ( $flags & RENDER_WIKI_DEFAULT )
   172     {
   172 		{
   173       $text = RenderMan::next_gen_wiki_format($text, $flags);
   173 			$text = RenderMan::next_gen_wiki_format($text, $flags);
   174     }
   174 		}
   175     else if ( $flags & RENDER_WIKI_TEMPLATE )
   175 		else if ( $flags & RENDER_WIKI_TEMPLATE )
   176     {
   176 		{
   177       $text = $template->tplWikiFormat($text);
   177 			$text = $template->tplWikiFormat($text);
   178     }           
   178 		}           
   179     return $text;
   179 		return $text;
   180   }
   180 	}
   181   
   181 	
   182   private static function next_gen_wiki_format($text, $flags = 0)
   182 	private static function next_gen_wiki_format($text, $flags = 0)
   183   {
   183 	{
   184     global $db, $session, $paths, $template, $plugins; // Common objects
   184 		global $db, $session, $paths, $template, $plugins; // Common objects
   185     global $lang;
   185 		global $lang;
   186     
   186 		
   187     profiler_log("RenderMan: starting wikitext render");
   187 		profiler_log("RenderMan: starting wikitext render");
   188     require_once( ENANO_ROOT . '/includes/wikiformat.php' );
   188 		require_once( ENANO_ROOT . '/includes/wikiformat.php' );
   189     require_once( ENANO_ROOT . '/includes/wikiengine/TagSanitizer.php' );
   189 		require_once( ENANO_ROOT . '/includes/wikiengine/TagSanitizer.php' );
   190     require_once( ENANO_ROOT . '/includes/wikiengine/Tables.php' );
   190 		require_once( ENANO_ROOT . '/includes/wikiengine/Tables.php' );
   191     
   191 		
   192     // this is still needed by parser plugins
   192 		// this is still needed by parser plugins
   193     $random_id = md5( time() . mt_rand() );
   193 		$random_id = md5( time() . mt_rand() );
   194     
   194 		
   195     // Strip out <nowiki> sections
   195 		// Strip out <nowiki> sections
   196     self::nowiki_strip($text, $nowiki_stripped);
   196 		self::nowiki_strip($text, $nowiki_stripped);
   197     
   197 		
   198     // Run early parsing plugins
   198 		// Run early parsing plugins
   199     $code = $plugins->setHook('render_wikiformat_veryearly');
   199 		$code = $plugins->setHook('render_wikiformat_veryearly');
   200     foreach ( $code as $cmd )
   200 		foreach ( $code as $cmd )
   201     {
   201 		{
   202       eval($cmd);
   202 			eval($cmd);
   203     }
   203 		}
   204     
   204 		
   205     // Strip out embedded PHP
   205 		// Strip out embedded PHP
   206     self::php_strip($text, $php_stripped);
   206 		self::php_strip($text, $php_stripped);
   207     
   207 		
   208     // Convert newlines for the parser
   208 		// Convert newlines for the parser
   209     $text = str_replace("\r\n", "\n", $text);
   209 		$text = str_replace("\r\n", "\n", $text);
   210     
   210 		
   211     // Perform render through the engine
   211 		// Perform render through the engine
   212     $carpenter = new Carpenter();
   212 		$carpenter = new Carpenter();
   213     $carpenter->flags = $flags;
   213 		$carpenter->flags = $flags;
   214     $carpenter->hook(array(__CLASS__, 'hook_pre'), PO_AFTER, 'lang');
   214 		$carpenter->hook(array(__CLASS__, 'hook_pre'), PO_AFTER, 'lang');
   215     $carpenter->hook(array(__CLASS__, 'hook_posttemplates'), PO_AFTER, 'templates');
   215 		$carpenter->hook(array(__CLASS__, 'hook_posttemplates'), PO_AFTER, 'templates');
   216     if ( $flags & RENDER_WIKI_TEMPLATE )
   216 		if ( $flags & RENDER_WIKI_TEMPLATE )
   217     {
   217 		{
   218       // FIXME: Where is noinclude/nodisplay being processed in the pipeline? (Seems to be processed, but not here)
   218 			// FIXME: Where is noinclude/nodisplay being processed in the pipeline? (Seems to be processed, but not here)
   219     }
   219 		}
   220     
   220 		
   221     //
   221 		//
   222     // Set rules for the rendering process
   222 		// Set rules for the rendering process
   223     //
   223 		//
   224     
   224 		
   225     if ( $flags & RENDER_BLOCK && !($flags & RENDER_INLINE) )
   225 		if ( $flags & RENDER_BLOCK && !($flags & RENDER_INLINE) )
   226     {
   226 		{
   227       // block only
   227 			// block only
   228       $carpenter->disable_all_rules();
   228 			$carpenter->disable_all_rules();
   229       foreach ( array('blockquote', 'tables', 'heading', 'hr', 'multilist', 'bold', 'italic', 'underline', 'paragraph', 'blockquotepost') as $rule )
   229 			foreach ( array('blockquote', 'tables', 'heading', 'hr', 'multilist', 'bold', 'italic', 'underline', 'paragraph', 'blockquotepost') as $rule )
   230       {
   230 			{
   231         $carpenter->enable_rule($rule);
   231 				$carpenter->enable_rule($rule);
   232       }
   232 			}
   233       
   233 			
   234       $code = $plugins->setHook('render_block_only');
   234 			$code = $plugins->setHook('render_block_only');
   235       foreach ( $code as $cmd )
   235 			foreach ( $code as $cmd )
   236       {
   236 			{
   237         eval($cmd);
   237 				eval($cmd);
   238       }
   238 			}
   239     }
   239 		}
   240     else if ( $flags & RENDER_INLINE && !($flags & RENDER_BLOCK) )
   240 		else if ( $flags & RENDER_INLINE && !($flags & RENDER_BLOCK) )
   241     {
   241 		{
   242       // inline only
   242 			// inline only
   243       $carpenter->disable_all_rules();
   243 			$carpenter->disable_all_rules();
   244       foreach ( array('bold', 'italic', 'underline', 'externalwithtext', 'externalnotext', 'image', 'internallink') as $rule )
   244 			foreach ( array('bold', 'italic', 'underline', 'externalwithtext', 'externalnotext', 'image', 'internallink') as $rule )
   245       {
   245 			{
   246         $carpenter->enable_rule($rule);
   246 				$carpenter->enable_rule($rule);
   247       }
   247 			}
   248       
   248 			
   249       $code = $plugins->setHook('render_inline_only');
   249 			$code = $plugins->setHook('render_inline_only');
   250       foreach ( $code as $cmd )
   250 			foreach ( $code as $cmd )
   251       {
   251 			{
   252         eval($cmd);
   252 				eval($cmd);
   253       }
   253 			}
   254     }
   254 		}
   255     else
   255 		else
   256     {
   256 		{
   257       // full render
   257 			// full render
   258       $code = $plugins->setHook('render_full');
   258 			$code = $plugins->setHook('render_full');
   259       foreach ( $code as $cmd )
   259 			foreach ( $code as $cmd )
   260       {
   260 			{
   261         eval($cmd);
   261 				eval($cmd);
   262       }
   262 			}
   263     }
   263 		}
   264     $text = $carpenter->render($text);
   264 		$text = $carpenter->render($text);
   265     
   265 		
   266     // For plugin compat
   266 		// For plugin compat
   267     $result =& $text;
   267 		$result =& $text;
   268     
   268 		
   269     // Post processing hook
   269 		// Post processing hook
   270     $code = $plugins->setHook('render_wikiformat_post');
   270 		$code = $plugins->setHook('render_wikiformat_post');
   271     foreach ( $code as $cmd )
   271 		foreach ( $code as $cmd )
   272     {
   272 		{
   273       eval($cmd);
   273 			eval($cmd);
   274     }
   274 		}
   275     
   275 		
   276     // Add PHP and nowiki back in
   276 		// Add PHP and nowiki back in
   277     self::nowiki_unstrip($text, $nowiki_stripped);
   277 		self::nowiki_unstrip($text, $nowiki_stripped);
   278     self::php_unstrip($text, $php_stripped);
   278 		self::php_unstrip($text, $php_stripped);
   279     
   279 		
   280     profiler_log("RenderMan: finished wikitext render");
   280 		profiler_log("RenderMan: finished wikitext render");
   281     
   281 		
   282     return $text;
   282 		return $text;
   283   }
   283 	}
   284   
   284 	
   285   public static function hook_pre($text)
   285 	public static function hook_pre($text)
   286   {
   286 	{
   287     global $db, $session, $paths, $template, $plugins; // Common objects
   287 		global $db, $session, $paths, $template, $plugins; // Common objects
   288     
   288 		
   289     $code = $plugins->setHook('render_wikiformat_pre');
   289 		$code = $plugins->setHook('render_wikiformat_pre');
   290     foreach ( $code as $cmd )
   290 		foreach ( $code as $cmd )
   291     {
   291 		{
   292       eval($cmd);
   292 			eval($cmd);
   293     }
   293 		}
   294     
   294 		
   295     return $text;
   295 		return $text;
   296   }
   296 	}
   297   
   297 	
   298   public static function hook_posttemplates($text)
   298 	public static function hook_posttemplates($text)
   299   {
   299 	{
   300     global $db, $session, $paths, $template, $plugins; // Common objects
   300 		global $db, $session, $paths, $template, $plugins; // Common objects
   301     
   301 		
   302     $code = $plugins->setHook('render_wikiformat_posttemplates');
   302 		$code = $plugins->setHook('render_wikiformat_posttemplates');
   303     foreach ( $code as $cmd )
   303 		foreach ( $code as $cmd )
   304     {
   304 		{
   305       eval($cmd);
   305 			eval($cmd);
   306     }
   306 		}
   307     
   307 		
   308     return $text;
   308 		return $text;
   309   }
   309 	}
   310   
   310 	
   311   /**
   311 	/**
   312    * Strip out <nowiki> tags (to bypass parsing on them)
   312  	* Strip out <nowiki> tags (to bypass parsing on them)
   313    * @access private
   313  	* @access private
   314    */
   314  	*/
   315   
   315 	
   316   private static function nowiki_strip(&$text, &$stripdata)
   316 	private static function nowiki_strip(&$text, &$stripdata)
   317   {
   317 	{
   318     self::tag_strip('nowiki', $text, $stripdata);
   318 		self::tag_strip('nowiki', $text, $stripdata);
   319   }
   319 	}
   320   
   320 	
   321   /**
   321 	/**
   322    * Restore stripped <nowiki> tags.
   322  	* Restore stripped <nowiki> tags.
   323    * @access private
   323  	* @access private
   324    */
   324  	*/
   325   
   325 	
   326   public static function nowiki_unstrip(&$text, &$stripdata)
   326 	public static function nowiki_unstrip(&$text, &$stripdata)
   327   {
   327 	{
   328     self::tag_unstrip('nowiki', $text, $stripdata);
   328 		self::tag_unstrip('nowiki', $text, $stripdata);
   329   }
   329 	}
   330   
   330 	
   331   /**
   331 	/**
   332    * Strip out an arbitrary HTML tag.
   332  	* Strip out an arbitrary HTML tag.
   333    * @access private
   333  	* @access private
   334    */
   334  	*/
   335   
   335 	
   336   public static function tag_strip($tag, &$text, &$stripdata)
   336 	public static function tag_strip($tag, &$text, &$stripdata)
   337   {
   337 	{
   338     $random_id = md5( time() . mt_rand() );
   338 		$random_id = md5( time() . mt_rand() );
   339     
   339 		
   340     preg_match_all("#<$tag>(.*?)</$tag>#is", $text, $blocks);
   340 		preg_match_all("#<$tag>(.*?)</$tag>#is", $text, $blocks);
   341     
   341 		
   342     foreach ( $blocks[0] as $i => $match )
   342 		foreach ( $blocks[0] as $i => $match )
   343     {
   343 		{
   344       $text = str_replace($match, "{{$tag}:{$random_id}:{$i}}", $text);
   344 			$text = str_replace($match, "{{$tag}:{$random_id}:{$i}}", $text);
   345     }
   345 		}
   346     
   346 		
   347     $stripdata = array(
   347 		$stripdata = array(
   348         'random_id' => $random_id,
   348 				'random_id' => $random_id,
   349         'blocks' => $blocks[1]
   349 				'blocks' => $blocks[1]
   350       );
   350 			);
   351   }
   351 	}
   352   
   352 	
   353   /**
   353 	/**
   354    * Strip out an arbitrary HTML tag, pushing on to the existing list of stripped data.
   354  	* Strip out an arbitrary HTML tag, pushing on to the existing list of stripped data.
   355    * @access private
   355  	* @access private
   356    */
   356  	*/
   357   
   357 	
   358   public static function tag_strip_push($tag, &$text, &$stripdata)
   358 	public static function tag_strip_push($tag, &$text, &$stripdata)
   359   {
   359 	{
   360     if ( !is_array($stripdata) )
   360 		if ( !is_array($stripdata) )
   361     {
   361 		{
   362       $stripdata = array(
   362 			$stripdata = array(
   363           'random_id' => md5( time() . mt_rand() ),
   363 					'random_id' => md5( time() . mt_rand() ),
   364           'blocks' => array()
   364 					'blocks' => array()
   365         );
   365 				);
   366     }
   366 		}
   367     $random_id =& $stripdata['random_id'];
   367 		$random_id =& $stripdata['random_id'];
   368     
   368 		
   369     preg_match_all("#<$tag>(.*?)</$tag>#is", $text, $blocks);
   369 		preg_match_all("#<$tag>(.*?)</$tag>#is", $text, $blocks);
   370     
   370 		
   371     foreach ( $blocks[0] as $i => $match )
   371 		foreach ( $blocks[0] as $i => $match )
   372     {
   372 		{
   373       $j = count($stripdata['blocks']);
   373 			$j = count($stripdata['blocks']);
   374       $stripdata['blocks'][] = $blocks[1][$i];
   374 			$stripdata['blocks'][] = $blocks[1][$i];
   375       $text = str_replace($match, "{{$tag}:{$random_id}:{$j}}", $text);
   375 			$text = str_replace($match, "{{$tag}:{$random_id}:{$j}}", $text);
   376     }
   376 		}
   377   }
   377 	}
   378   
   378 	
   379   /**
   379 	/**
   380    * Restore stripped <nowiki> tags.
   380  	* Restore stripped <nowiki> tags.
   381    * @access private
   381  	* @access private
   382    */
   382  	*/
   383   
   383 	
   384   public static function tag_unstrip($tag, &$text, &$stripdata, $keep = false)
   384 	public static function tag_unstrip($tag, &$text, &$stripdata, $keep = false)
   385   {
   385 	{
   386     $random_id = $stripdata['random_id'];
   386 		$random_id = $stripdata['random_id'];
   387     
   387 		
   388     foreach ( $stripdata['blocks'] as $i => $block )
   388 		foreach ( $stripdata['blocks'] as $i => $block )
   389     {
   389 		{
   390       $block = $keep ? "<$tag>$block</$tag>" : $block;
   390 			$block = $keep ? "<$tag>$block</$tag>" : $block;
   391       $text = str_replace("{{$tag}:{$random_id}:{$i}}", $block, $text);
   391 			$text = str_replace("{{$tag}:{$random_id}:{$i}}", $block, $text);
   392     }
   392 		}
   393     
   393 		
   394     $stripdata = array();
   394 		$stripdata = array();
   395   }
   395 	}
   396   
   396 	
   397   /**
   397 	/**
   398    * Strip out PHP code (to prevent it from being sent through the parser). Private because it does not do what you think it does. (The method you are looking for is strip_php.)
   398  	* Strip out PHP code (to prevent it from being sent through the parser). Private because it does not do what you think it does. (The method you are looking for is strip_php.)
   399    * @access private
   399  	* @access private
   400    */
   400  	*/
   401   
   401 	
   402   private static function php_strip(&$text, &$stripdata)
   402 	private static function php_strip(&$text, &$stripdata)
   403   {
   403 	{
   404     $random_id = md5( time() . mt_rand() );
   404 		$random_id = md5( time() . mt_rand() );
   405     
   405 		
   406     preg_match_all('#<\?(?:php)?[\s=].+?\?>#is', $text, $blocks);
   406 		preg_match_all('#<\?(?:php)?[\s=].+?\?>#is', $text, $blocks);
   407     
   407 		
   408     foreach ( $blocks[0] as $i => $match )
   408 		foreach ( $blocks[0] as $i => $match )
   409     {
   409 		{
   410       $text = str_replace($match, "{PHP:$random_id:$i}", $text);
   410 			$text = str_replace($match, "{PHP:$random_id:$i}", $text);
   411     }
   411 		}
   412     
   412 		
   413     $stripdata = array(
   413 		$stripdata = array(
   414         'random_id' => $random_id,
   414 				'random_id' => $random_id,
   415         'blocks' => $blocks[0]
   415 				'blocks' => $blocks[0]
   416       );
   416 			);
   417   }
   417 	}
   418   
   418 	
   419   /**
   419 	/**
   420    * Restore stripped PHP code
   420  	* Restore stripped PHP code
   421    * @access private
   421  	* @access private
   422    */
   422  	*/
   423   
   423 	
   424   private static function php_unstrip(&$text, &$stripdata)
   424 	private static function php_unstrip(&$text, &$stripdata)
   425   {
   425 	{
   426     $random_id = $stripdata['random_id'];
   426 		$random_id = $stripdata['random_id'];
   427     
   427 		
   428     foreach ( $stripdata['blocks'] as $i => $block )
   428 		foreach ( $stripdata['blocks'] as $i => $block )
   429     {
   429 		{
   430       $text = str_replace("{PHP:$random_id:$i}", $block, $text);
   430 			$text = str_replace("{PHP:$random_id:$i}", $block, $text);
   431     }
   431 		}
   432     
   432 		
   433     $stripdata = array();
   433 		$stripdata = array();
   434   }
   434 	}
   435   
   435 	
   436   /**
   436 	/**
   437    * Deprecated.
   437  	* Deprecated.
   438    */
   438  	*/
   439   
   439 	
   440   public static function wikiFormat($message, $filter_links = true, $do_params = false, $plaintext = false)
   440 	public static function wikiFormat($message, $filter_links = true, $do_params = false, $plaintext = false)
   441   {
   441 	{
   442     global $db, $session, $paths, $template, $plugins; // Common objects
   442 		global $db, $session, $paths, $template, $plugins; // Common objects
   443     
   443 		
   444     return RenderMan::next_gen_wiki_format($message, $plaintext, $filter_links, $do_params);
   444 		return RenderMan::next_gen_wiki_format($message, $plaintext, $filter_links, $do_params);
   445   }
   445 	}
   446   
   446 	
   447   public static function destroy_javascript($message, $_php = false)
   447 	public static function destroy_javascript($message, $_php = false)
   448   {
   448 	{
   449     $message = preg_replace('#<(script|object|applet|embed|iframe|frame|form|input|select)(.*?)>#is', '&lt;\\1\\2&gt;', $message);
   449 		$message = preg_replace('#<(script|object|applet|embed|iframe|frame|form|input|select)(.*?)>#is', '&lt;\\1\\2&gt;', $message);
   450     $message = preg_replace('#</(script|object|applet|embed|iframe|frame|form|input|select)(.*?)>#is', '&lt;/\\1\\2&gt;', $message);
   450 		$message = preg_replace('#</(script|object|applet|embed|iframe|frame|form|input|select)(.*?)>#is', '&lt;/\\1\\2&gt;', $message);
   451     $message = preg_replace('#(javascript|script|activex|chrome|about|applet):#is', '\\1&#058;', $message);
   451 		$message = preg_replace('#(javascript|script|activex|chrome|about|applet):#is', '\\1&#058;', $message);
   452     if ( $_php )
   452 		if ( $_php )
   453     {
   453 		{
   454       // Left in only for compatibility
   454 			// Left in only for compatibility
   455       $message = preg_replace('#&lt;(.*?)>#is', '<\\1>', $message);
   455 			$message = preg_replace('#&lt;(.*?)>#is', '<\\1>', $message);
   456       $message = preg_replace('#<(.*?)&gt;#is', '<\\1>', $message);
   456 			$message = preg_replace('#<(.*?)&gt;#is', '<\\1>', $message);
   457       $message = preg_replace('#<(\?|\?php|%)(.*?)(\?|%)>#is', '&lt;\\1\\2\\3&gt;', $message);
   457 			$message = preg_replace('#<(\?|\?php|%)(.*?)(\?|%)>#is', '&lt;\\1\\2\\3&gt;', $message);
   458       // strip <a href="foo" onclick="bar();">-type attacks
   458 			// strip <a href="foo" onclick="bar();">-type attacks
   459       $message = preg_replace('#<([a-zA-Z:\-]+) (.*?)on([A-Za-z]*)=(.*?)>#is', '&lt;\\1\\2on\\3=\\4&gt;', $message);
   459 			$message = preg_replace('#<([a-zA-Z:\-]+) (.*?)on([A-Za-z]*)=(.*?)>#is', '&lt;\\1\\2on\\3=\\4&gt;', $message);
   460     }
   460 		}
   461     return $message;
   461 		return $message;
   462   }
   462 	}
   463   
   463 	
   464   public static function strip_php($message)
   464 	public static function strip_php($message)
   465   {
   465 	{
   466     return RenderMan::destroy_javascript($message, true);
   466 		return RenderMan::destroy_javascript($message, true);
   467   }
   467 	}
   468   
   468 	
   469   public static function sanitize_html($text)
   469 	public static function sanitize_html($text)
   470   {
   470 	{
   471     $text = htmlspecialchars($text);
   471 		$text = htmlspecialchars($text);
   472     $allowed_tags = Array('b', 'i', 'u', 'pre', 'code', 'tt', 'br', 'p', 'nowiki', '!--([\w\W]+)--');
   472 		$allowed_tags = Array('b', 'i', 'u', 'pre', 'code', 'tt', 'br', 'p', 'nowiki', '!--([\w\W]+)--');
   473     foreach($allowed_tags as $t)
   473 		foreach($allowed_tags as $t)
   474     {
   474 		{
   475       $text = preg_replace('#&lt;'.$t.'&gt;(.*?)&lt;/'.$t.'&gt;#is', '<'.$t.'>\\1</'.$t.'>', $text);
   475 			$text = preg_replace('#&lt;'.$t.'&gt;(.*?)&lt;/'.$t.'&gt;#is', '<'.$t.'>\\1</'.$t.'>', $text);
   476       $text = preg_replace('#&lt;'.$t.' /&gt;#is', '<'.$t.' />', $text);
   476 			$text = preg_replace('#&lt;'.$t.' /&gt;#is', '<'.$t.' />', $text);
   477       $text = preg_replace('#&lt;'.$t.'&gt;#is', '<'.$t.'>', $text);
   477 			$text = preg_replace('#&lt;'.$t.'&gt;#is', '<'.$t.'>', $text);
   478     }
   478 		}
   479     return $text;
   479 		return $text;
   480   }
   480 	}
   481   
   481 	
   482   /**
   482 	/**
   483    * Reverse-renders a blob of text (converts it from XHTML back to wikitext) by using parser hints and educated guesses.
   483  	* Reverse-renders a blob of text (converts it from XHTML back to wikitext) by using parser hints and educated guesses.
   484    * @param string XHTML
   484  	* @param string XHTML
   485    * @return string Wikitext
   485  	* @return string Wikitext
   486    */
   486  	*/
   487   
   487 	
   488   public static function reverse_render($text)
   488 	public static function reverse_render($text)
   489   {
   489 	{
   490     // convert \r\n to \n
   490 		// convert \r\n to \n
   491     $text = str_replace("\r\n", "\n", $text);
   491 		$text = str_replace("\r\n", "\n", $text);
   492     
   492 		
   493     // Separate certain block level elements onto their own lines. This tidies up the tag
   493 		// Separate certain block level elements onto their own lines. This tidies up the tag
   494     // soup that TinyMCE sometimes produces.
   494 		// soup that TinyMCE sometimes produces.
   495     $block_elements = array('h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'div', 'table', 'ul', 'pre');
   495 		$block_elements = array('h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'div', 'table', 'ul', 'pre');
   496     $block_elements = implode('|', $block_elements);
   496 		$block_elements = implode('|', $block_elements);
   497     $regex = "#(</(?:$block_elements)>)\n?<($block_elements)(>| .+?>)#i";
   497 		$regex = "#(</(?:$block_elements)>)\n?<($block_elements)(>| .+?>)#i";
   498     $text = preg_replace($regex, "$1\n\n<$2$3", $text);
   498 		$text = preg_replace($regex, "$1\n\n<$2$3", $text);
   499     
   499 		
   500     $text = self::reverse_process_parser_hints($text);
   500 		$text = self::reverse_process_parser_hints($text);
   501     $text = self::reverse_process_headings($text);
   501 		$text = self::reverse_process_headings($text);
   502     $text = self::reverse_process_lists($text);
   502 		$text = self::reverse_process_lists($text);
   503     $text = self::reverse_process_tables($text);
   503 		$text = self::reverse_process_tables($text);
   504     
   504 		
   505     // Lastly, strip out paragraph tags.
   505 		// Lastly, strip out paragraph tags.
   506     $text = preg_replace('|^ *<p>(.+?)</p> *$|m', "\\1", $text);
   506 		$text = preg_replace('|^ *<p>(.+?)</p> *$|m', "\\1", $text);
   507     
   507 		
   508     return $text;
   508 		return $text;
   509   }
   509 	}
   510   
   510 	
   511   public static function reverse_process_parser_hints($text)
   511 	public static function reverse_process_parser_hints($text)
   512   {
   512 	{
   513     global $db, $session, $paths, $template, $plugins; // Common objects
   513 		global $db, $session, $paths, $template, $plugins; // Common objects
   514     
   514 		
   515     if ( !preg_match_all('|<!--#([a-z0-9_]+)(?: (.+?))?-->([\w\W]*?)<!--#/\\1-->|s', $text, $matches) )
   515 		if ( !preg_match_all('|<!--#([a-z0-9_]+)(?: (.+?))?-->([\w\W]*?)<!--#/\\1-->|s', $text, $matches) )
   516       return $text;
   516 			return $text;
   517     
   517 		
   518     foreach ( $matches[0] as $i => $match )
   518 		foreach ( $matches[0] as $i => $match )
   519     {
   519 		{
   520       $tag =& $matches[1][$i];
   520 			$tag =& $matches[1][$i];
   521       $attribs =& $matches[2][$i];
   521 			$attribs =& $matches[2][$i];
   522       $inner =& $matches[3][$i];
   522 			$inner =& $matches[3][$i];
   523       
   523 			
   524       $attribs = self::reverse_process_hint_attribs($attribs);
   524 			$attribs = self::reverse_process_hint_attribs($attribs);
   525       switch($tag)
   525 			switch($tag)
   526       {
   526 			{
   527         case 'smiley':
   527 				case 'smiley':
   528         case 'internallink':
   528 				case 'internallink':
   529         case 'imagelink':
   529 				case 'imagelink':
   530           if ( isset($attribs['code']) )
   530 					if ( isset($attribs['code']) )
   531           {
   531 					{
   532             $text = str_replace($match, $attribs['code'], $text);
   532 						$text = str_replace($match, $attribs['code'], $text);
   533           }
   533 					}
   534           else if ( isset($attribs['src']) )
   534 					else if ( isset($attribs['src']) )
   535           {
   535 					{
   536             $text = str_replace($match, $attribs['src'], $text);
   536 						$text = str_replace($match, $attribs['src'], $text);
   537           }
   537 					}
   538           break;
   538 					break;
   539       }
   539 			}
   540     }
   540 		}
   541     
   541 		
   542     return $text;
   542 		return $text;
   543   }
   543 	}
   544   
   544 	
   545   public static function reverse_process_hint_attribs($attribs)
   545 	public static function reverse_process_hint_attribs($attribs)
   546   {
   546 	{
   547     $return = array();
   547 		$return = array();
   548     if ( !preg_match_all('/([a-z0-9_-]+)="([^"]+?)"/', $attribs, $matches) )
   548 		if ( !preg_match_all('/([a-z0-9_-]+)="([^"]+?)"/', $attribs, $matches) )
   549       return array();
   549 			return array();
   550     
   550 		
   551     foreach ( $matches[0] as $i => $match )
   551 		foreach ( $matches[0] as $i => $match )
   552     {
   552 		{
   553       $name =& $matches[1][$i];
   553 			$name =& $matches[1][$i];
   554       $value =& $matches[2][$i];
   554 			$value =& $matches[2][$i];
   555       
   555 			
   556       $value = base64_decode($value);
   556 			$value = base64_decode($value);
   557       
   557 			
   558       $return[$name] = $value;
   558 			$return[$name] = $value;
   559     }
   559 		}
   560     
   560 		
   561     return $return;
   561 		return $return;
   562   }
   562 	}
   563   
   563 	
   564   /**
   564 	/**
   565    * Escapes a string so that it's safe to use as an attribute in a parser hint.
   565  	* Escapes a string so that it's safe to use as an attribute in a parser hint.
   566    * @param string
   566  	* @param string
   567    * @return string
   567  	* @return string
   568    */
   568  	*/
   569   
   569 	
   570   public static function escape_parser_hint_attrib($text)
   570 	public static function escape_parser_hint_attrib($text)
   571   {
   571 	{
   572     return base64_encode($text);
   572 		return base64_encode($text);
   573   }
   573 	}
   574   
   574 	
   575   public static function reverse_process_headings($text)
   575 	public static function reverse_process_headings($text)
   576   {
   576 	{
   577     if ( !preg_match_all('|^<h([1-6])(?: id="toc[0-9]+")?>(.*?)</h\\1>$|m', $text, $matches) )
   577 		if ( !preg_match_all('|^<h([1-6])(?: id="toc[0-9]+")?>(.*?)</h\\1>$|m', $text, $matches) )
   578       return $text;
   578 			return $text;
   579     
   579 		
   580     foreach ( $matches[0] as $i => $match )
   580 		foreach ( $matches[0] as $i => $match )
   581     {
   581 		{
   582       // generate heading tag
   582 			// generate heading tag
   583       $heading_size = intval($matches[1][$i]);
   583 			$heading_size = intval($matches[1][$i]);
   584       $eq = '';
   584 			$eq = '';
   585       for ( $j = 0; $j < $heading_size; $j++ )
   585 			for ( $j = 0; $j < $heading_size; $j++ )
   586         $eq .= '=';
   586 				$eq .= '=';
   587       
   587 			
   588       $heading =& $matches[2][$i];
   588 			$heading =& $matches[2][$i];
   589       
   589 			
   590       $tag = "$eq $heading $eq";
   590 			$tag = "$eq $heading $eq";
   591       $text = str_replace($match, $tag, $text);
   591 			$text = str_replace($match, $tag, $text);
   592     }
   592 		}
   593     
   593 		
   594     return $text;
   594 		return $text;
   595   }
   595 	}
   596   
   596 	
   597   public static function reverse_process_lists($text)
   597 	public static function reverse_process_lists($text)
   598   {
   598 	{
   599     if ( !preg_match('!(</?(?:ul|ol|li)>)!', $text) )
   599 		if ( !preg_match('!(</?(?:ul|ol|li)>)!', $text) )
   600       return $text;
   600 			return $text;
   601     
   601 		
   602     $split = preg_split('!(</?(?:ul|ol|li)>)!', $text, -1, PREG_SPLIT_DELIM_CAPTURE);
   602 		$split = preg_split('!(</?(?:ul|ol|li)>)!', $text, -1, PREG_SPLIT_DELIM_CAPTURE);
   603     
   603 		
   604     $stack_height = 0;
   604 		$stack_height = 0;
   605     $current_list = '';
   605 		$current_list = '';
   606     $old_current_list = '';
   606 		$old_current_list = '';
   607     $spaces = '';
   607 		$spaces = '';
   608     $marker = '*';
   608 		$marker = '*';
   609     $list_id = 0;
   609 		$list_id = 0;
   610     $just_terminated = false;
   610 		$just_terminated = false;
   611     foreach ( $split as $tag )
   611 		foreach ( $split as $tag )
   612     {
   612 		{
   613       switch($tag) 
   613 			switch($tag) 
   614       {
   614 			{
   615         case '<ul>':
   615 				case '<ul>':
   616         case '<ol>':
   616 				case '<ol>':
   617           $stack_height++;
   617 					$stack_height++;
   618           $just_terminated = false;
   618 					$just_terminated = false;
   619           if ( $stack_height > 1 )
   619 					if ( $stack_height > 1 )
   620             $spaces .= $marker;
   620 						$spaces .= $marker;
   621           
   621 					
   622           $marker = ( $tag == 'ol' ) ? '#' : '*';
   622 					$marker = ( $tag == 'ol' ) ? '#' : '*';
   623           if ( $stack_height > 1 )
   623 					if ( $stack_height > 1 )
   624             $current_list .= "\n";
   624 						$current_list .= "\n";
   625           
   625 					
   626           break;
   626 					break;
   627         case '</ul>':
   627 				case '</ul>':
   628         case '</ol>':
   628 				case '</ol>':
   629           $stack_height--;
   629 					$stack_height--;
   630           $spaces = substr($spaces, 1);
   630 					$spaces = substr($spaces, 1);
   631           
   631 					
   632           if ( $stack_height == 0 )
   632 					if ( $stack_height == 0 )
   633           {
   633 					{
   634             // rotate
   634 						// rotate
   635             $text = str_replace_once("{$old_current_list}{$tag}", trim($current_list), $text);
   635 						$text = str_replace_once("{$old_current_list}{$tag}", trim($current_list), $text);
   636             $current_list = '';
   636 						$current_list = '';
   637             $old_current_list = '';
   637 						$old_current_list = '';
   638           }
   638 					}
   639           $just_terminated = true;
   639 					$just_terminated = true;
   640           break;
   640 					break;
   641         case '<li>':
   641 				case '<li>':
   642           if ( $stack_height < 1 )
   642 					if ( $stack_height < 1 )
   643             break;
   643 						break;
   644           
   644 					
   645           $current_list .= "{$spaces}{$marker} ";
   645 					$current_list .= "{$spaces}{$marker} ";
   646           break;
   646 					break;
   647         case '</li>':
   647 				case '</li>':
   648           if ( $stack_height < 1 )
   648 					if ( $stack_height < 1 )
   649             break;
   649 						break;
   650           
   650 					
   651           if ( !$just_terminated )
   651 					if ( !$just_terminated )
   652             $current_list .= "\n";
   652 						$current_list .= "\n";
   653           
   653 					
   654           $just_terminated = false;
   654 					$just_terminated = false;
   655           break;
   655 					break;
   656         default:
   656 				default:
   657           if ( $stack_height > 0 )
   657 					if ( $stack_height > 0 )
   658           {
   658 					{
   659             $current_list .= trim($tag);
   659 						$current_list .= trim($tag);
   660           }
   660 					}
   661           break;
   661 					break;
   662       }
   662 			}
   663       if ( $stack_height > 0 )
   663 			if ( $stack_height > 0 )
   664       {
   664 			{
   665         $old_current_list .= $tag;
   665 				$old_current_list .= $tag;
   666       }
   666 			}
   667     }
   667 		}
   668     
   668 		
   669     return $text;
   669 		return $text;
   670   }
   670 	}
   671   
   671 	
   672   public static function reverse_process_tables($text)
   672 	public static function reverse_process_tables($text)
   673   {
   673 	{
   674     return $text;
   674 		return $text;
   675   }
   675 	}
   676   
   676 	
   677   /**
   677 	/**
   678    * Parses internal links (wikilinks) in a block of text.
   678  	* Parses internal links (wikilinks) in a block of text.
   679    * @param string Text to process
   679  	* @param string Text to process
   680    * @param string Optional. If included will be used as a template instead of using the default syntax.
   680  	* @param string Optional. If included will be used as a template instead of using the default syntax.
   681    * @param bool If false, does not add wikilink-nonexistent or check for exsistence of pages. Can reduce DB queries; defualts to true.
   681  	* @param bool If false, does not add wikilink-nonexistent or check for exsistence of pages. Can reduce DB queries; defualts to true.
   682    * @param string Page ID. If specified, class="currentpage" will be added to links if they match the given page ID and namespace
   682  	* @param string Page ID. If specified, class="currentpage" will be added to links if they match the given page ID and namespace
   683    * @param string Namespace. If specified, class="currentpage" will be added to links if they match the given page ID and namespace
   683  	* @param string Namespace. If specified, class="currentpage" will be added to links if they match the given page ID and namespace
   684    * @return string
   684  	* @return string
   685    */
   685  	*/
   686   
   686 	
   687   public static function parse_internal_links($text, $tplcode = false, $do_exist_check = true, $match_page_id = false, $match_namespace = false)
   687 	public static function parse_internal_links($text, $tplcode = false, $do_exist_check = true, $match_page_id = false, $match_namespace = false)
   688   {
   688 	{
   689     global $db, $session, $paths, $template, $plugins; // Common objects
   689 		global $db, $session, $paths, $template, $plugins; // Common objects
   690   
   690 	
   691     $parser = is_string($tplcode) ? $template->makeParserText($tplcode) : false;
   691 		$parser = is_string($tplcode) ? $template->makeParserText($tplcode) : false;
   692     
   692 		
   693     // allow blank urlname?
   693 		// allow blank urlname?
   694     $repeater = have_blank_urlname_page() ? '*' : '+';
   694 		$repeater = have_blank_urlname_page() ? '*' : '+';
   695     
   695 		
   696     // stage 1 - links with alternate text
   696 		// stage 1 - links with alternate text
   697     preg_match_all('/\[\[([^\[\]<>\{\}\|]' . $repeater . ')\|(.+?)\]\]/', $text, $matches);
   697 		preg_match_all('/\[\[([^\[\]<>\{\}\|]' . $repeater . ')\|(.+?)\]\]/', $text, $matches);
   698     foreach ( $matches[0] as $i => $match )
   698 		foreach ( $matches[0] as $i => $match )
   699     {
   699 		{
   700       list($page_id, $namespace) = RenderMan::strToPageID($matches[1][$i]);
   700 			list($page_id, $namespace) = RenderMan::strToPageID($matches[1][$i]);
   701       $link = self::generate_internal_link($namespace, $page_id, $matches[2][$i], $match, $parser, $do_exist_check, $match_page_id, $match_namespace);
   701 			$link = self::generate_internal_link($namespace, $page_id, $matches[2][$i], $match, $parser, $do_exist_check, $match_page_id, $match_namespace);
   702       $text = str_replace($match, $link, $text);
   702 			$text = str_replace($match, $link, $text);
   703     }
   703 		}
   704     
   704 		
   705     // stage 2 - links with no alternate text
   705 		// stage 2 - links with no alternate text
   706     preg_match_all('/\[\[([^\[\]<>\{\}\|]' . $repeater . ')\]\]/', $text, $matches);
   706 		preg_match_all('/\[\[([^\[\]<>\{\}\|]' . $repeater . ')\]\]/', $text, $matches);
   707     foreach ( $matches[0] as $i => $match )
   707 		foreach ( $matches[0] as $i => $match )
   708     {
   708 		{
   709       list($page_id, $namespace) = RenderMan::strToPageID($matches[1][$i]);
   709 			list($page_id, $namespace) = RenderMan::strToPageID($matches[1][$i]);
   710       $pid_clean = $paths->nslist[$namespace] . sanitize_page_id($page_id);
   710 			$pid_clean = $paths->nslist[$namespace] . sanitize_page_id($page_id);
   711       $inner_text = ( isPage($pid_clean) ) ? htmlspecialchars(get_page_title($pid_clean)) : htmlspecialchars($matches[1][$i]);
   711 			$inner_text = ( isPage($pid_clean) ) ? htmlspecialchars(get_page_title($pid_clean)) : htmlspecialchars($matches[1][$i]);
   712       
   712 			
   713       $link = self::generate_internal_link($namespace, $page_id, $inner_text, $match, $parser, $do_exist_check, $match_page_id, $match_namespace);
   713 			$link = self::generate_internal_link($namespace, $page_id, $inner_text, $match, $parser, $do_exist_check, $match_page_id, $match_namespace);
   714       
   714 			
   715       $text = str_replace($match, $link, $text);
   715 			$text = str_replace($match, $link, $text);
   716     }
   716 		}
   717     
   717 		
   718     return $text;
   718 		return $text;
   719   }
   719 	}
   720   
   720 	
   721   /**
   721 	/**
   722    * Internal link generation function
   722  	* Internal link generation function
   723    * @access private
   723  	* @access private
   724    * @return string HTML
   724  	* @return string HTML
   725    */
   725  	*/
   726   
   726 	
   727   private static function generate_internal_link($namespace, $page_id, $inner_text, $match, $parser = false, $do_exist_check = true, $match_page_id = false, $match_namespace = false)
   727 	private static function generate_internal_link($namespace, $page_id, $inner_text, $match, $parser = false, $do_exist_check = true, $match_page_id = false, $match_namespace = false)
   728   {
   728 	{
   729     global $db, $session, $paths, $template, $plugins; // Common objects
   729 		global $db, $session, $paths, $template, $plugins; // Common objects
   730     
   730 		
   731     if ( ($pos = strrpos($page_id, '#')) !== false )
   731 		if ( ($pos = strrpos($page_id, '#')) !== false )
   732     {
   732 		{
   733       $hash = substr($page_id, $pos);
   733 			$hash = substr($page_id, $pos);
   734       $page_id = substr($page_id, 0, $pos);
   734 			$page_id = substr($page_id, 0, $pos);
   735     }
   735 		}
   736     else
   736 		else
   737     {
   737 		{
   738       $hash = '';
   738 			$hash = '';
   739     }
   739 		}
   740     
   740 		
   741     if ( $namespace == 'Admin' )
   741 		if ( $namespace == 'Admin' )
   742     {
   742 		{
   743       // No linking directly to Admin pages!
   743 			// No linking directly to Admin pages!
   744       $get = 'module=' . $paths->nslist[$namespace] . sanitize_page_id($page_id);
   744 			$get = 'module=' . $paths->nslist[$namespace] . sanitize_page_id($page_id);
   745       $pid_clean = $paths->nslist['Special'] . 'Administration';
   745 			$pid_clean = $paths->nslist['Special'] . 'Administration';
   746       $onclick = ' onclick="ajaxLoginNavTo(\'Special\', \'Administration\', USER_LEVEL_ADMIN, \'' . addslashes($get) . '\'); return false;"';
   746 			$onclick = ' onclick="ajaxLoginNavTo(\'Special\', \'Administration\', USER_LEVEL_ADMIN, \'' . addslashes($get) . '\'); return false;"';
   747     }
   747 		}
   748     else
   748 		else
   749     {
   749 		{
   750       $get = false;
   750 			$get = false;
   751       $onclick = '';
   751 			$onclick = '';
   752       $pid_clean = $paths->nslist[$namespace] . sanitize_page_id($page_id);
   752 			$pid_clean = $paths->nslist[$namespace] . sanitize_page_id($page_id);
   753     }
   753 		}
   754     
   754 		
   755     $url = makeUrl($pid_clean, $get, true) . $hash;
   755 		$url = makeUrl($pid_clean, $get, true) . $hash;
   756     $quot = '"';
   756 		$quot = '"';
   757     $exists = ( ($do_exist_check && isPage($pid_clean)) || !$do_exist_check ) ? '' : ' class="wikilink-nonexistent"';
   757 		$exists = ( ($do_exist_check && isPage($pid_clean)) || !$do_exist_check ) ? '' : ' class="wikilink-nonexistent"';
   758     
   758 		
   759     if ( $match_page_id && $match_namespace && $pid_clean === $paths->get_pathskey($match_page_id, $match_namespace) )
   759 		if ( $match_page_id && $match_namespace && $pid_clean === $paths->get_pathskey($match_page_id, $match_namespace) )
   760       $exists .= ' class="currentpage"';
   760 			$exists .= ' class="currentpage"';
   761     
   761 		
   762     if ( $parser )
   762 		if ( $parser )
   763     {
   763 		{
   764       $parser->assign_vars(array(
   764 			$parser->assign_vars(array(
   765           'HREF' => $url,
   765 					'HREF' => $url,
   766           'FLAGS' => $exists,
   766 					'FLAGS' => $exists,
   767           'TEXT' => $inner_text
   767 					'TEXT' => $inner_text
   768         ));
   768 				));
   769       $link = $parser->run();
   769 			$link = $parser->run();
   770     }
   770 		}
   771     else
   771 		else
   772     {
   772 		{
   773       $omatch = self::escape_parser_hint_attrib($match);
   773 			$omatch = self::escape_parser_hint_attrib($match);
   774       $link = "<!--#internallink src=\"$omatch\" --><a{$onclick} href={$quot}{$url}{$quot}{$exists}>{$inner_text}</a><!--#/internallink-->";
   774 			$link = "<!--#internallink src=\"$omatch\" --><a{$onclick} href={$quot}{$url}{$quot}{$exists}>{$inner_text}</a><!--#/internallink-->";
   775     }
   775 		}
   776     
   776 		
   777     return $link;
   777 		return $link;
   778   }
   778 	}
   779   
   779 	
   780   /**
   780 	/**
   781    * Parses a partial template tag in wikitext, and return an array with the parameters.
   781  	* Parses a partial template tag in wikitext, and return an array with the parameters.
   782    * @param string The portion of the template tag that contains the parameters.
   782  	* @param string The portion of the template tag that contains the parameters.
   783    * @example
   783  	* @example
   784    * <code>
   784  	* <code>
   785    foo = lorem ipsum
   785  	foo = lorem ipsum
   786    bar = dolor sit amet
   786  	bar = dolor sit amet
   787    * </code>
   787  	* </code>
   788    * @return array Example:
   788  	* @return array Example:
   789    * [foo] => lorem ipsum
   789  	* [foo] => lorem ipsum
   790    * [bar] => dolor sit amet
   790  	* [bar] => dolor sit amet
   791    */
   791  	*/
   792   
   792 	
   793   public static function parse_template_vars($input, $newlinemode = true)
   793 	public static function parse_template_vars($input, $newlinemode = true)
   794   {
   794 	{
   795     $parms = array();
   795 		$parms = array();
   796     $input = trim($input);
   796 		$input = trim($input);
   797     if ( $newlinemode )
   797 		if ( $newlinemode )
   798     {
   798 		{
   799       // we're going by newlines.
   799 			// we're going by newlines.
   800       // split by parameter, then parse each one individually
   800 			// split by parameter, then parse each one individually
   801       $input = explode("\n", str_replace("\r", '', $input));
   801 			$input = explode("\n", str_replace("\r", '', $input));
   802       $lastparam = '';
   802 			$lastparam = '';
   803       $i = 0;
   803 			$i = 0;
   804       foreach ( $input as $line )
   804 			foreach ( $input as $line )
   805       {
   805 			{
   806         if ( preg_match('/^ *\|? *([A-z0-9_]+) *= *(.+)$/', $line, $match) )
   806 				if ( preg_match('/^ *\|? *([A-z0-9_]+) *= *(.+)$/', $line, $match) )
   807         {
   807 				{
   808           // new parameter, named
   808 					// new parameter, named
   809           $parms[ $match[1] ] = $match[2];
   809 					$parms[ $match[1] ] = $match[2];
   810           $lastparam = $match[1];
   810 					$lastparam = $match[1];
   811         }
   811 				}
   812         else if ( preg_match('/^ *\| *(.+)$/', $line, $match) || $lastparam === '' )
   812 				else if ( preg_match('/^ *\| *(.+)$/', $line, $match) || $lastparam === '' )
   813         {
   813 				{
   814           $parms[ $i ] = $match[1];
   814 					$parms[ $i ] = $match[1];
   815           $lastparam = $i;
   815 					$lastparam = $i;
   816           $i++;
   816 					$i++;
   817         }
   817 				}
   818         else
   818 				else
   819         {
   819 				{
   820           $parms[ $lastparam ] .= "\n$line";
   820 					$parms[ $lastparam ] .= "\n$line";
   821         }
   821 				}
   822       }
   822 			}
   823     }
   823 		}
   824     else
   824 		else
   825     {
   825 		{
   826       $result = preg_match_all('/
   826 			$result = preg_match_all('/
   827                                  (?:^|[ ]*)\|         # start of parameter - string start or series of spaces
   827  																(?:^|[ ]*)\|         # start of parameter - string start or series of spaces
   828                                  [ ]*
   828  																[ ]*
   829                                  (?:
   829  																(?:
   830                                    ([A-z0-9_]+)       # variable name
   830  																	([A-z0-9_]+)       # variable name
   831                                    [ ]* = [ ]*        # assignment
   831  																	[ ]* = [ ]*        # assignment
   832                                  )?                   # name section is optional - if the parameter name is not given, a numerical index is assigned
   832  																)?                   # name section is optional - if the parameter name is not given, a numerical index is assigned
   833                                  ([^\|]+|.+?\n[ ]*\|) # value
   833  																([^\|]+|.+?\n[ ]*\|) # value
   834                                /x', trim($input), $matches);
   834  															/x', trim($input), $matches);
   835       if ( $result )
   835 			if ( $result )
   836       {
   836 			{
   837         $pi = 0;
   837 				$pi = 0;
   838         for ( $i = 0; $i < count($matches[0]); $i++ )
   838 				for ( $i = 0; $i < count($matches[0]); $i++ )
   839         {
   839 				{
   840           $matches[1][$i] = trim($matches[1][$i]);
   840 					$matches[1][$i] = trim($matches[1][$i]);
   841           $parmname = !empty($matches[1][$i]) ? $matches[1][$i] : strval(++$pi);
   841 					$parmname = !empty($matches[1][$i]) ? $matches[1][$i] : strval(++$pi);
   842           $parms[ $parmname ] = $matches[2][$i];
   842 					$parms[ $parmname ] = $matches[2][$i];
   843         }
   843 				}
   844       }
   844 			}
   845     }
   845 		}
   846     // die('<pre>' . print_r($parms, true) . '</pre>');
   846 		// die('<pre>' . print_r($parms, true) . '</pre>');
   847     return $parms;
   847 		return $parms;
   848   }
   848 	}
   849   
   849 	
   850   /**
   850 	/**
   851    * Processes all template tags within a block of wikitext.
   851  	* Processes all template tags within a block of wikitext.
   852    * Updated in 1.0.2 to also parse template tags in the format of {{Foo |a = b |b = c |c = therefore, a}}
   852  	* Updated in 1.0.2 to also parse template tags in the format of {{Foo |a = b |b = c |c = therefore, a}}
   853    * @param string The text to process
   853  	* @param string The text to process
   854    * @return string Formatted text
   854  	* @return string Formatted text
   855    * @example
   855  	* @example
   856    * <code>
   856  	* <code>
   857    $text = '{{Template
   857  	$text = '{{Template
   858        | parm1 = Foo
   858  			| parm1 = Foo
   859        | parm2 = Bar
   859  			| parm2 = Bar
   860      }}';
   860  		}}';
   861    $text = RenderMan::include_templates($text);
   861  	$text = RenderMan::include_templates($text);
   862    * </code>
   862  	* </code>
   863    */
   863  	*/
   864   
   864 	
   865   public static function include_templates($text)
   865 	public static function include_templates($text)
   866   {
   866 	{
   867     global $db, $session, $paths, $template, $plugins; // Common objects
   867 		global $db, $session, $paths, $template, $plugins; // Common objects
   868     // $template_regex = "/\{\{([^\]]+?)((\n([ ]*?)[A-z0-9]+([ ]*?)=([ ]*?)(.+?))*)\}\}/is";
   868 		// $template_regex = "/\{\{([^\]]+?)((\n([ ]*?)[A-z0-9]+([ ]*?)=([ ]*?)(.+?))*)\}\}/is";
   869     // matches:
   869 		// matches:
   870     //  1 - template name
   870 		//  1 - template name
   871     //  2 - parameter section
   871 		//  2 - parameter section
   872     $template_regex = "/
   872 		$template_regex = "/
   873                          \{\{                     # opening
   873  												\{\{                     # opening
   874                            ([^\n\t\a\r]+)         # template name
   874  													([^\n\t\a\r]+)         # template name
   875                            ((?:(?:[\s]+\|?)[ ]*(?:[A-z0-9_]+)[ ]*=[ ]*?(?:.+))*) # parameters
   875  													((?:(?:[\s]+\|?)[ ]*(?:[A-z0-9_]+)[ ]*=[ ]*?(?:.+))*) # parameters
   876                          \}\}                     # closing
   876  												\}\}                     # closing
   877                        /isxU";
   877  											/isxU";
   878     if ( $count = preg_match_all($template_regex, $text, $matches) )
   878 		if ( $count = preg_match_all($template_regex, $text, $matches) )
   879     {
   879 		{
   880       // die('<pre>' . print_r($matches, true) . '</pre>');
   880 			// die('<pre>' . print_r($matches, true) . '</pre>');
   881       for ( $i = 0; $i < $count; $i++ )
   881 			for ( $i = 0; $i < $count; $i++ )
   882       {
   882 			{
   883         $matches[1][$i] = sanitize_page_id($matches[1][$i]);
   883 				$matches[1][$i] = sanitize_page_id($matches[1][$i]);
   884         $newlinemode = ( substr($matches[2][$i], 0, 1) == "\n" );
   884 				$newlinemode = ( substr($matches[2][$i], 0, 1) == "\n" );
   885         $parmsection = trim($matches[2][$i]);
   885 				$parmsection = trim($matches[2][$i]);
   886         if ( !empty($parmsection) )
   886 				if ( !empty($parmsection) )
   887         {
   887 				{
   888           $parms = RenderMan::parse_template_vars($parmsection, $newlinemode);
   888 					$parms = RenderMan::parse_template_vars($parmsection, $newlinemode);
   889           if ( !is_array($parms) )
   889 					if ( !is_array($parms) )
   890             // Syntax error
   890 						// Syntax error
   891             $parms = array();
   891 						$parms = array();
   892         }
   892 				}
   893         else
   893 				else
   894         {
   894 				{
   895           $parms = Array();
   895 					$parms = Array();
   896         }
   896 				}
   897         if ( $tpl_code = RenderMan::fetch_template_text($matches[1][$i]) )
   897 				if ( $tpl_code = RenderMan::fetch_template_text($matches[1][$i]) )
   898         {
   898 				{
   899           // Intelligent paragraphs.
   899 					// Intelligent paragraphs.
   900           // If:
   900 					// If:
   901           //   * A line is fully wrapped in a <p> tag
   901 					//   * A line is fully wrapped in a <p> tag
   902           //   * The line contains a variable
   902 					//   * The line contains a variable
   903           //   * The variable contains newlines
   903 					//   * The variable contains newlines
   904           // Then:
   904 					// Then:
   905           //   * Drop the <p> tag, replace it fully paragraph-ized by newlines
   905 					//   * Drop the <p> tag, replace it fully paragraph-ized by newlines
   906           
   906 					
   907           if ( preg_match_all('/^( *)<p(\s.+)?>(.*?\{([A-z0-9]+)\}.*?)<\/p> *$/m', $tpl_code, $paramatch) )
   907 					if ( preg_match_all('/^( *)<p(\s.+)?>(.*?\{([A-z0-9]+)\}.*?)<\/p> *$/m', $tpl_code, $paramatch) )
   908           {
   908 					{
   909             $parser = new Carpenter();
   909 						$parser = new Carpenter();
   910             $parser->exclusive_rule('paragraph');
   910 						$parser->exclusive_rule('paragraph');
   911             
   911 						
   912             foreach ( $paramatch[0] as $j => $match )
   912 						foreach ( $paramatch[0] as $j => $match )
   913             {
   913 						{
   914               // $line is trimmed (the <p> is gone)
   914 							// $line is trimmed (the <p> is gone)
   915               $spacing =& $paramatch[1][$i];
   915 							$spacing =& $paramatch[1][$i];
   916               $para_attrs =& $paramatch[2][$j];
   916 							$para_attrs =& $paramatch[2][$j];
   917               $para_attrs = str_replace(array('$', '\\'), array('\$', '\\\\'), $para_attrs);
   917 							$para_attrs = str_replace(array('$', '\\'), array('\$', '\\\\'), $para_attrs);
   918               $line =& $paramatch[3][$j];
   918 							$line =& $paramatch[3][$j];
   919               $varname =& $paramatch[4][$j];
   919 							$varname =& $paramatch[4][$j];
   920               if ( isset($parms[$varname]) && strstr($parms[$varname], "\n") )
   920 							if ( isset($parms[$varname]) && strstr($parms[$varname], "\n") )
   921               {
   921 							{
   922                 $newline = str_replace('{' . $varname . '}', $parms[$varname], $line);
   922 								$newline = str_replace('{' . $varname . '}', $parms[$varname], $line);
   923                 $paraized = $parser->render($newline);
   923 								$paraized = $parser->render($newline);
   924                 $paraized = preg_replace('/^<p>/m', "$spacing<p{$para_attrs}>", $paraized);
   924 								$paraized = preg_replace('/^<p>/m', "$spacing<p{$para_attrs}>", $paraized);
   925                 $paraized = $spacing . trim($paraized);
   925 								$paraized = $spacing . trim($paraized);
   926                 $tpl_code = str_replace_once($match, $paraized, $tpl_code);
   926 								$tpl_code = str_replace_once($match, $paraized, $tpl_code);
   927               }
   927 							}
   928             }
   928 						}
   929           }
   929 					}
   930           
   930 					
   931           $parser = $template->makeParserText($tpl_code);
   931 					$parser = $template->makeParserText($tpl_code);
   932           $parser->assign_vars($parms);
   932 					$parser->assign_vars($parms);
   933           $text = str_replace($matches[0][$i], $parser->run(), $text);
   933 					$text = str_replace($matches[0][$i], $parser->run(), $text);
   934         }
   934 				}
   935       }
   935 			}
   936     }
   936 		}
   937     return $text;
   937 		return $text;
   938   }
   938 	}
   939   
   939 	
   940   /**
   940 	/**
   941    * Preprocesses an HTML text string prior to being sent to MySQL.
   941  	* Preprocesses an HTML text string prior to being sent to MySQL.
   942    * @param string $text
   942  	* @param string $text
   943    * @param bool $strip_all_php - if true, strips all PHP regardless of user permissions. Else, strips PHP only if user level < USER_LEVEL_ADMIN. Defaults to true.
   943  	* @param bool $strip_all_php - if true, strips all PHP regardless of user permissions. Else, strips PHP only if user level < USER_LEVEL_ADMIN. Defaults to true.
   944    * @param bool $sqlescape - if true, sends text through $db->escape(). Otherwise returns unescaped text. Defaults to true.
   944  	* @param bool $sqlescape - if true, sends text through $db->escape(). Otherwise returns unescaped text. Defaults to true.
   945    * @param bool $reduceheadings - if true, finds HTML headings and replaces them with wikitext. Else, does not touch headings. Defaults to true.
   945  	* @param bool $reduceheadings - if true, finds HTML headings and replaces them with wikitext. Else, does not touch headings. Defaults to true.
   946    * @param Session_ACLPageInfo Optional permissions instance to check against, $session is used if not provided
   946  	* @param Session_ACLPageInfo Optional permissions instance to check against, $session is used if not provided
   947    */
   947  	*/
   948   public static function preprocess_text($text, $strip_all_php = true, $sqlescape = true, $reduceheadings = true, $perms = false)
   948 	public static function preprocess_text($text, $strip_all_php = true, $sqlescape = true, $reduceheadings = true, $perms = false)
   949   {
   949 	{
   950     global $db, $session, $paths, $template, $plugins; // Common objects
   950 		global $db, $session, $paths, $template, $plugins; // Common objects
   951     $random_id = md5( time() . mt_rand() );
   951 		$random_id = md5( time() . mt_rand() );
   952     
   952 		
   953     $code = $plugins->setHook('render_sanitize_pre');
   953 		$code = $plugins->setHook('render_sanitize_pre');
   954     foreach ( $code as $cmd )
   954 		foreach ( $code as $cmd )
   955     {
   955 		{
   956       eval($cmd);
   956 			eval($cmd);
   957     }
   957 		}
   958     
   958 		
   959     if ( !is_object($perms) )
   959 		if ( !is_object($perms) )
   960     {
   960 		{
   961       $namespace = $paths->namespace;
   961 			$namespace = $paths->namespace;
   962       $perms =& $session;
   962 			$perms =& $session;
   963     }
   963 		}
   964     else
   964 		else
   965     {
   965 		{
   966       $namespace = $perms->namespace;
   966 			$namespace = $perms->namespace;
   967     }
   967 		}
   968     
   968 		
   969     $can_do_php = ( !$strip_all_php && $perms->get_permissions('php_in_pages') );
   969 		$can_do_php = ( !$strip_all_php && $perms->get_permissions('php_in_pages') );
   970     $can_do_html = $session->check_acl_scope('html_in_pages', $namespace) && $perms->get_permissions('html_in_pages');
   970 		$can_do_html = $session->check_acl_scope('html_in_pages', $namespace) && $perms->get_permissions('html_in_pages');
   971     
   971 		
   972     if ( $can_do_html && !$can_do_php )
   972 		if ( $can_do_html && !$can_do_php )
   973     {
   973 		{
   974       $text = preg_replace('#<(\?|\?php|%)(.*?)(\?|%)>#is', '&lt;\\1\\2\\3&gt;', $text);
   974 			$text = preg_replace('#<(\?|\?php|%)(.*?)(\?|%)>#is', '&lt;\\1\\2\\3&gt;', $text);
   975     }
   975 		}
   976     else if ( !$can_do_html && !$can_do_php )
   976 		else if ( !$can_do_html && !$can_do_php )
   977     {
   977 		{
   978       $text = sanitize_html($text, true);
   978 			$text = sanitize_html($text, true);
   979       // If we can't do PHP, we can't do Javascript either.
   979 			// If we can't do PHP, we can't do Javascript either.
   980       $text = RenderMan::destroy_javascript($text);
   980 			$text = RenderMan::destroy_javascript($text);
   981     }
   981 		}
   982     
   982 		
   983     // Strip out <nowiki> sections and PHP code
   983 		// Strip out <nowiki> sections and PHP code
   984     
   984 		
   985     $php = preg_match_all('#(<|&lt;)\?php(.*?)\?(>|&gt;)#is', $text, $phpsec);
   985 		$php = preg_match_all('#(<|&lt;)\?php(.*?)\?(>|&gt;)#is', $text, $phpsec);
   986     
   986 		
   987     //die('<pre>'.htmlspecialchars(print_r($phpsec, true))."\n".htmlspecialchars(print_r($text, true)).'</pre>');
   987 		//die('<pre>'.htmlspecialchars(print_r($phpsec, true))."\n".htmlspecialchars(print_r($text, true)).'</pre>');
   988     
   988 		
   989     for($i=0;$i<sizeof($phpsec[1]);$i++)
   989 		for($i=0;$i<sizeof($phpsec[1]);$i++)
   990     {
   990 		{
   991       $text = str_replace($phpsec[0][$i], '{PHP:'.$random_id.':'.$i.'}', $text);
   991 			$text = str_replace($phpsec[0][$i], '{PHP:'.$random_id.':'.$i.'}', $text);
   992     }
   992 		}
   993     
   993 		
   994     $nw = preg_match_all('#<nowiki>(.*?)<\/nowiki>#is', $text, $nowiki);
   994 		$nw = preg_match_all('#<nowiki>(.*?)<\/nowiki>#is', $text, $nowiki);
   995     
   995 		
   996     for($i=0;$i<sizeof($nowiki[1]);$i++)
   996 		for($i=0;$i<sizeof($nowiki[1]);$i++)
   997     {
   997 		{
   998       $text = str_replace('<nowiki>'.$nowiki[1][$i].'</nowiki>', '{NOWIKI:'.$random_id.':'.$i.'}', $text);
   998 			$text = str_replace('<nowiki>'.$nowiki[1][$i].'</nowiki>', '{NOWIKI:'.$random_id.':'.$i.'}', $text);
   999     }
   999 		}
  1000     
  1000 		
  1001     $text = str_replace('~~~~~', enano_date('G:i, j F Y (T)'), $text);
  1001 		$text = str_replace('~~~~~', enano_date('G:i, j F Y (T)'), $text);
  1002     $text = str_replace('~~~~', "[[User:$session->username|$session->username]] ".enano_date('G:i, j F Y (T)'), $text);
  1002 		$text = str_replace('~~~~', "[[User:$session->username|$session->username]] ".enano_date('G:i, j F Y (T)'), $text);
  1003     $text = str_replace('~~~', "[[User:$session->username|$session->username]] ", $text);
  1003 		$text = str_replace('~~~', "[[User:$session->username|$session->username]] ", $text);
  1004     
  1004 		
  1005     $code = $plugins->setHook('render_sanitize_post');
  1005 		$code = $plugins->setHook('render_sanitize_post');
  1006     foreach ( $code as $cmd )
  1006 		foreach ( $code as $cmd )
  1007     {
  1007 		{
  1008       eval($cmd);
  1008 			eval($cmd);
  1009     }
  1009 		}
  1010     
  1010 		
  1011     // gently apply some reverse-processing to allow the parser to do magic with TOCs and stuff
  1011 		// gently apply some reverse-processing to allow the parser to do magic with TOCs and stuff
  1012     if ( $reduceheadings )
  1012 		if ( $reduceheadings )
  1013       $text = self::reverse_process_headings($text);
  1013 			$text = self::reverse_process_headings($text);
  1014     
  1014 		
  1015     // Reinsert <nowiki> sections
  1015 		// Reinsert <nowiki> sections
  1016     for($i=0;$i<$nw;$i++)
  1016 		for($i=0;$i<$nw;$i++)
  1017     {
  1017 		{
  1018       $text = str_replace('{NOWIKI:'.$random_id.':'.$i.'}', '<nowiki>'.$nowiki[1][$i].'</nowiki>', $text);
  1018 			$text = str_replace('{NOWIKI:'.$random_id.':'.$i.'}', '<nowiki>'.$nowiki[1][$i].'</nowiki>', $text);
  1019     }
  1019 		}
  1020     // Reinsert PHP
  1020 		// Reinsert PHP
  1021     for($i=0;$i<$php;$i++)
  1021 		for($i=0;$i<$php;$i++)
  1022     {
  1022 		{
  1023       $phsec = ''.$phpsec[1][$i].'?php'.$phpsec[2][$i].'?'.$phpsec[3][$i].'';
  1023 			$phsec = ''.$phpsec[1][$i].'?php'.$phpsec[2][$i].'?'.$phpsec[3][$i].'';
  1024       if ( $strip_all_php )
  1024 			if ( $strip_all_php )
  1025         $phsec = htmlspecialchars($phsec);
  1025 				$phsec = htmlspecialchars($phsec);
  1026       $text = str_replace('{PHP:'.$random_id.':'.$i.'}', $phsec, $text);
  1026 			$text = str_replace('{PHP:'.$random_id.':'.$i.'}', $phsec, $text);
  1027     }
  1027 		}
  1028     
  1028 		
  1029     $text = ( $sqlescape ) ? $db->escape($text) : $text;
  1029 		$text = ( $sqlescape ) ? $db->escape($text) : $text;
  1030     
  1030 		
  1031     return $text;
  1031 		return $text;
  1032   }
  1032 	}
  1033   
  1033 	
  1034   public static function smilieyize($text, $complete_urls = false)
  1034 	public static function smilieyize($text, $complete_urls = false)
  1035   {
  1035 	{
  1036     
  1036 		
  1037     $random_id = md5( time() . mt_rand() );
  1037 		$random_id = md5( time() . mt_rand() );
  1038     
  1038 		
  1039     // Smileys array - eventually this will be fetched from the database by
  1039 		// Smileys array - eventually this will be fetched from the database by
  1040     // RenderMan::initSmileys during initialization, but it will all be hardcoded for beta 2
  1040 		// RenderMan::initSmileys during initialization, but it will all be hardcoded for beta 2
  1041     
  1041 		
  1042     $smileys = Array(
  1042 		$smileys = Array(
  1043       'O:-)'    => 'face-angel.png',
  1043 			'O:-)'    => 'face-angel.png',
  1044       'O:)'     => 'face-angel.png',
  1044 			'O:)'     => 'face-angel.png',
  1045       'O=)'     => 'face-angel.png',
  1045 			'O=)'     => 'face-angel.png',
  1046       ':-)'     => 'face-smile.png',
  1046 			':-)'     => 'face-smile.png',
  1047       ':)'      => 'face-smile.png',
  1047 			':)'      => 'face-smile.png',
  1048       '=)'      => 'face-smile-big.png',
  1048 			'=)'      => 'face-smile-big.png',
  1049       ':-('     => 'face-sad.png',
  1049 			':-('     => 'face-sad.png',
  1050       ':('      => 'face-sad.png',
  1050 			':('      => 'face-sad.png',
  1051       ';('      => 'face-sad.png',
  1051 			';('      => 'face-sad.png',
  1052       ':-O'     => 'face-surprise.png',
  1052 			':-O'     => 'face-surprise.png',
  1053       ';-)'     => 'face-wink.png',
  1053 			';-)'     => 'face-wink.png',
  1054       ';)'      => 'face-wink.png',
  1054 			';)'      => 'face-wink.png',
  1055       '8-)'     => 'face-glasses.png',
  1055 			'8-)'     => 'face-glasses.png',
  1056       '8)'      => 'face-glasses.png',
  1056 			'8)'      => 'face-glasses.png',
  1057       ':-D'     => 'face-grin.png',
  1057 			':-D'     => 'face-grin.png',
  1058       ':D'      => 'face-grin.png',
  1058 			':D'      => 'face-grin.png',
  1059       '=D'      => 'face-grin.png',
  1059 			'=D'      => 'face-grin.png',
  1060       ':-*'     => 'face-kiss.png',
  1060 			':-*'     => 'face-kiss.png',
  1061       ':*'      => 'face-kiss.png',
  1061 			':*'      => 'face-kiss.png',
  1062       '=*'      => 'face-kiss.png',
  1062 			'=*'      => 'face-kiss.png',
  1063       ':\'('    => 'face-crying.png',
  1063 			':\'('    => 'face-crying.png',
  1064       ':-|'     => 'face-plain.png',
  1064 			':-|'     => 'face-plain.png',
  1065       ':-\\'    => 'face-plain.png',
  1065 			':-\\'    => 'face-plain.png',
  1066       ':-/'     => 'face-plain.png',
  1066 			':-/'     => 'face-plain.png',
  1067       ':joke:'  => 'face-plain.png',
  1067 			':joke:'  => 'face-plain.png',
  1068       ']:-&gt;' => 'face-devil-grin.png',
  1068 			']:-&gt;' => 'face-devil-grin.png',
  1069       ']:->'    => 'face-devil-grin.png',
  1069 			']:->'    => 'face-devil-grin.png',
  1070       ':kiss:'  => 'face-kiss.png',
  1070 			':kiss:'  => 'face-kiss.png',
  1071       ':-P'     => 'face-tongue-out.png',
  1071 			':-P'     => 'face-tongue-out.png',
  1072       ':P'      => 'face-tongue-out.png',
  1072 			':P'      => 'face-tongue-out.png',
  1073       ':-p'     => 'face-tongue-out.png',
  1073 			':-p'     => 'face-tongue-out.png',
  1074       ':p'      => 'face-tongue-out.png',
  1074 			':p'      => 'face-tongue-out.png',
  1075       ':-X'     => 'face-sick.png',
  1075 			':-X'     => 'face-sick.png',
  1076       ':X'      => 'face-sick.png',
  1076 			':X'      => 'face-sick.png',
  1077       ':sick:'  => 'face-sick.png',
  1077 			':sick:'  => 'face-sick.png',
  1078       ':-]'     => 'face-oops.png',
  1078 			':-]'     => 'face-oops.png',
  1079       ':]'      => 'face-oops.png',
  1079 			':]'      => 'face-oops.png',
  1080       ':oops:'  => 'face-oops.png',
  1080 			':oops:'  => 'face-oops.png',
  1081       ':-['     => 'face-embarassed.png',
  1081 			':-['     => 'face-embarassed.png',
  1082       ':['      => 'face-embarassed.png'
  1082 			':['      => 'face-embarassed.png'
  1083       );
  1083 			);
  1084     
  1084 		
  1085     // Strip out <nowiki> sections
  1085 		// Strip out <nowiki> sections
  1086     //return '<pre>'.htmlspecialchars($text).'</pre>';
  1086 		//return '<pre>'.htmlspecialchars($text).'</pre>';
  1087     $nw = preg_match_all('#<nowiki>(.*?)<\/nowiki>#is', $text, $nowiki);
  1087 		$nw = preg_match_all('#<nowiki>(.*?)<\/nowiki>#is', $text, $nowiki);
  1088     
  1088 		
  1089     for ( $i = 0; $i < count($nowiki[1]); $i++ )
  1089 		for ( $i = 0; $i < count($nowiki[1]); $i++ )
  1090     {
  1090 		{
  1091       $text = str_replace('<nowiki>' . $nowiki[1][$i] . '</nowiki>', '{NOWIKI:'.$random_id.':'.$i.'}', $text);
  1091 			$text = str_replace('<nowiki>' . $nowiki[1][$i] . '</nowiki>', '{NOWIKI:'.$random_id.':'.$i.'}', $text);
  1092     }
  1092 		}
  1093     
  1093 		
  1094     foreach ( $smileys as $smiley => $smiley_path )
  1094 		foreach ( $smileys as $smiley => $smiley_path )
  1095     {
  1095 		{
  1096       $hex_smiley = hexencode($smiley, '&#x', ';');
  1096 			$hex_smiley = hexencode($smiley, '&#x', ';');
  1097       $pfx = ( $complete_urls ) ? get_server_url() : '';
  1097 			$pfx = ( $complete_urls ) ? get_server_url() : '';
  1098       $text = str_replace(' ' . $smiley,
  1098 			$text = str_replace(' ' . $smiley,
  1099           ' <!--#smiley code="' . self::escape_parser_hint_attrib($smiley) . '"--><nowiki>
  1099 					' <!--#smiley code="' . self::escape_parser_hint_attrib($smiley) . '"--><nowiki>
  1100            <!-- The above is a reverse-parser hint -->
  1100  					<!-- The above is a reverse-parser hint -->
  1101              <img title="' . $hex_smiley . '" alt="' . $hex_smiley . '" src="' . $pfx . scriptPath . '/images/smilies/' . $smiley_path . '"
  1101  						<img title="' . $hex_smiley . '" alt="' . $hex_smiley . '" src="' . $pfx . scriptPath . '/images/smilies/' . $smiley_path . '"
  1102               style="border: 0;" />
  1102 							style="border: 0;" />
  1103            </nowiki><!--#/smiley-->', $text);
  1103  					</nowiki><!--#/smiley-->', $text);
  1104     }
  1104 		}
  1105     //*/
  1105 		//*/
  1106     
  1106 		
  1107     // Reinsert <nowiki> sections
  1107 		// Reinsert <nowiki> sections
  1108     for ( $i = 0; $i < $nw; $i++ )
  1108 		for ( $i = 0; $i < $nw; $i++ )
  1109     {
  1109 		{
  1110       $text = str_replace('{NOWIKI:'.$random_id.':'.$i.'}', '<nowiki>'.$nowiki[1][$i].'</nowiki>', $text);
  1110 			$text = str_replace('{NOWIKI:'.$random_id.':'.$i.'}', '<nowiki>'.$nowiki[1][$i].'</nowiki>', $text);
  1111     }
  1111 		}
  1112     
  1112 		
  1113     return $text;
  1113 		return $text;
  1114   }
  1114 	}
  1115   
  1115 	
  1116   /**
  1116 	/**
  1117    * Generates a summary of the differences between two texts, and formats it as XHTML.
  1117  	* Generates a summary of the differences between two texts, and formats it as XHTML.
  1118    * @param $str1 string the first block of text
  1118  	* @param $str1 string the first block of text
  1119    * @param $str2 string the second block of text
  1119  	* @param $str2 string the second block of text
  1120    * @return string
  1120  	* @return string
  1121    */
  1121  	*/
  1122   public static function diff($str1, $str2)
  1122 	public static function diff($str1, $str2)
  1123   {
  1123 	{
  1124     global $db, $session, $paths, $template, $plugins; // Common objects
  1124 		global $db, $session, $paths, $template, $plugins; // Common objects
  1125     require_once(ENANO_ROOT.'/includes/diff.php');
  1125 		require_once(ENANO_ROOT.'/includes/diff.php');
  1126     $str1 = explode("\n", $str1);
  1126 		$str1 = explode("\n", $str1);
  1127     $str2 = explode("\n", $str2);
  1127 		$str2 = explode("\n", $str2);
  1128     $diff = new Diff($str1, $str2);
  1128 		$diff = new Diff($str1, $str2);
  1129     $renderer = new TableDiffFormatter();
  1129 		$renderer = new TableDiffFormatter();
  1130     return '<table class="diff">'.$renderer->format($diff).'</table>';
  1130 		return '<table class="diff">'.$renderer->format($diff).'</table>';
  1131   }
  1131 	}
  1132   
  1132 	
  1133   /**
  1133 	/**
  1134    * Changes wikitext image tags to HTML.
  1134  	* Changes wikitext image tags to HTML.
  1135    * @param string The wikitext to process
  1135  	* @param string The wikitext to process
  1136    * @param array Will be overwritten with the list of HTML tags (the system uses tokens for TextWiki compatibility)
  1136  	* @param array Will be overwritten with the list of HTML tags (the system uses tokens for TextWiki compatibility)
  1137    * @return string
  1137  	* @return string
  1138    */
  1138  	*/
  1139   
  1139 	
  1140   public static function process_image_tags($text, &$taglist)
  1140 	public static function process_image_tags($text, &$taglist)
  1141   {
  1141 	{
  1142     global $db, $session, $paths, $template, $plugins; // Common objects
  1142 		global $db, $session, $paths, $template, $plugins; // Common objects
  1143     
  1143 		
  1144     $s_delim = "\xFF";
  1144 		$s_delim = "\xFF";
  1145     $f_delim = "\xFF";
  1145 		$f_delim = "\xFF";
  1146     $taglist = array();
  1146 		$taglist = array();
  1147     
  1147 		
  1148     // Wicked huh?
  1148 		// Wicked huh?
  1149     $ns_file = str_replace('/', '\\/', preg_quote($paths->nslist['File']));
  1149 		$ns_file = str_replace('/', '\\/', preg_quote($paths->nslist['File']));
  1150     $regex = '/
  1150 		$regex = '/
  1151            \[\[                                                                  # starting delimiter 
  1151  					\[\[                                                                  # starting delimiter 
  1152            :' . $ns_file . '([\w\s0-9_\(\)!@%\^\+\|\.-]+?\.(?:png|gif|jpg|jpeg)) # image filename
  1152  					:' . $ns_file . '([\w\s0-9_\(\)!@%\^\+\|\.-]+?\.(?:png|gif|jpg|jpeg)) # image filename
  1153            (?:(?:\|(?:.+?))*)                                                    # parameters
  1153  					(?:(?:\|(?:.+?))*)                                                    # parameters
  1154            \]\]                                                                  # ending delimiter
  1154  					\]\]                                                                  # ending delimiter
  1155            /ix';
  1155  					/ix';
  1156     
  1156 		
  1157     preg_match_all($regex, $text, $matches);
  1157 		preg_match_all($regex, $text, $matches);
  1158     
  1158 		
  1159     foreach ( $matches[0] as $i => $match )
  1159 		foreach ( $matches[0] as $i => $match )
  1160     {
  1160 		{
  1161       
  1161 			
  1162       $full_tag   =& $matches[0][$i];
  1162 			$full_tag   =& $matches[0][$i];
  1163       $filename   =& $matches[1][$i];
  1163 			$filename   =& $matches[1][$i];
  1164       
  1164 			
  1165       // apply recursion (hack? @todo could this be done with (?R) in PCRE?)
  1165 			// apply recursion (hack? @todo could this be done with (?R) in PCRE?)
  1166       $tag_pos = strpos($text, $full_tag);
  1166 			$tag_pos = strpos($text, $full_tag);
  1167       $tag_end_pos = $tag_pos + strlen($full_tag);
  1167 			$tag_end_pos = $tag_pos + strlen($full_tag);
  1168       while ( get_char_count($full_tag, ']') < get_char_count($full_tag, '[') && $tag_end_pos < strlen($text) )
  1168 			while ( get_char_count($full_tag, ']') < get_char_count($full_tag, '[') && $tag_end_pos < strlen($text) )
  1169       {
  1169 			{
  1170         $full_tag .= substr($text, $tag_end_pos, 1);
  1170 				$full_tag .= substr($text, $tag_end_pos, 1);
  1171         $tag_end_pos++;
  1171 				$tag_end_pos++;
  1172       }
  1172 			}
  1173       if ( $tag_end_pos > strlen($text) )
  1173 			if ( $tag_end_pos > strlen($text) )
  1174       {
  1174 			{
  1175         // discard tag, not closed fully
  1175 				// discard tag, not closed fully
  1176         continue;
  1176 				continue;
  1177       }
  1177 			}
  1178       
  1178 			
  1179       // init the various image parameters
  1179 			// init the various image parameters
  1180       $width = null;
  1180 			$width = null;
  1181       $height = null;
  1181 			$height = null;
  1182       $scale_type = null;
  1182 			$scale_type = null;
  1183       $raw_display = false;
  1183 			$raw_display = false;
  1184       $clear = null;
  1184 			$clear = null;
  1185       $caption = null;
  1185 			$caption = null;
  1186       
  1186 			
  1187       // trim tag and parse particles
  1187 			// trim tag and parse particles
  1188       $tag_trim = rtrim(ltrim($full_tag, '['), ']');
  1188 			$tag_trim = rtrim(ltrim($full_tag, '['), ']');
  1189       // trim off the filename from the start of the tag
  1189 			// trim off the filename from the start of the tag
  1190       $filepart_len = 1 + strlen($paths->nslist['File']) + strlen($filename) + 1;
  1190 			$filepart_len = 1 + strlen($paths->nslist['File']) + strlen($filename) + 1;
  1191       $tag_trim = substr($tag_trim, $filepart_len);
  1191 			$tag_trim = substr($tag_trim, $filepart_len);
  1192       // explode and we should have parameters
  1192 			// explode and we should have parameters
  1193       $tag_parts = explode('|', $tag_trim);
  1193 			$tag_parts = explode('|', $tag_trim);
  1194       
  1194 			
  1195       // for each of the parameters, see if it matches a known option. If so, apply it;
  1195 			// for each of the parameters, see if it matches a known option. If so, apply it;
  1196       // otherwise, see if a plugin reserved that parameter and if not treat it as the caption
  1196 			// otherwise, see if a plugin reserved that parameter and if not treat it as the caption
  1197       foreach ( $tag_parts as $param )
  1197 			foreach ( $tag_parts as $param )
  1198       {
  1198 			{
  1199         switch($param)
  1199 				switch($param)
  1200         {
  1200 				{
  1201           case 'left':
  1201 					case 'left':
  1202           case 'right':
  1202 					case 'right':
  1203             $clear = $param;
  1203 						$clear = $param;
  1204             break;
  1204 						break;
  1205           case 'thumb':
  1205 					case 'thumb':
  1206             $scale_type = 'thumb';
  1206 						$scale_type = 'thumb';
  1207             break;
  1207 						break;
  1208           case 'raw':
  1208 					case 'raw':
  1209             $raw_display = true;
  1209 						$raw_display = true;
  1210             break;
  1210 						break;
  1211           default:
  1211 					default:
  1212             // height specification
  1212 						// height specification
  1213             if ( preg_match('/^([0-9]+)x([0-9]+)$/', $param, $dims) )
  1213 						if ( preg_match('/^([0-9]+)x([0-9]+)$/', $param, $dims) )
  1214             {
  1214 						{
  1215               $width = intval($dims[1]);
  1215 							$width = intval($dims[1]);
  1216               $height = intval($dims[2]);
  1216 							$height = intval($dims[2]);
  1217               break;
  1217 							break;
  1218             }
  1218 						}
  1219             // not the height, so see if a plugin took this over
  1219 						// not the height, so see if a plugin took this over
  1220             // this hook requires plugins to return true if they modified anything
  1220 						// this hook requires plugins to return true if they modified anything
  1221             $code = $plugins->setHook('img_tag_parse_params');
  1221 						$code = $plugins->setHook('img_tag_parse_params');
  1222             foreach ( $code as $cmd )
  1222 						foreach ( $code as $cmd )
  1223             {
  1223 						{
  1224               if ( eval($cmd) )
  1224 							if ( eval($cmd) )
  1225                 break 2;
  1225 								break 2;
  1226             }
  1226 						}
  1227             // we would have broken out by now if a plugin properly handled this,
  1227 						// we would have broken out by now if a plugin properly handled this,
  1228             // so just set the caption now.
  1228 						// so just set the caption now.
  1229             $caption = $param;
  1229 						$caption = $param;
  1230             break;
  1230 						break;
  1231         }
  1231 				}
  1232       }
  1232 			}
  1233       
  1233 			
  1234       if ( !isPage( $paths->nslist['File'] . $filename ) )
  1234 			if ( !isPage( $paths->nslist['File'] . $filename ) )
  1235       {
  1235 			{
  1236         $text = str_replace($full_tag, '[[' . $paths->nslist['File'] . $filename . ']]', $text);
  1236 				$text = str_replace($full_tag, '[[' . $paths->nslist['File'] . $filename . ']]', $text);
  1237         continue;
  1237 				continue;
  1238       }
  1238 			}
  1239       
  1239 			
  1240       if ( $scale_type == 'thumb' )
  1240 			if ( $scale_type == 'thumb' )
  1241       {
  1241 			{
  1242         $r_width  = 225;
  1242 				$r_width  = 225;
  1243         $r_height = 225;
  1243 				$r_height = 225;
  1244         
  1244 				
  1245         $url = makeUrlNS('Special', 'DownloadFile/' . $filename, 'preview&width=' . $r_width . '&height=' . $r_height, true);
  1245 				$url = makeUrlNS('Special', 'DownloadFile/' . $filename, 'preview&width=' . $r_width . '&height=' . $r_height, true);
  1246       }
  1246 			}
  1247       else if ( !empty($width) && !empty($height) )
  1247 			else if ( !empty($width) && !empty($height) )
  1248       {
  1248 			{
  1249         $r_width = $width;
  1249 				$r_width = $width;
  1250         $r_height = $height;
  1250 				$r_height = $height;
  1251         
  1251 				
  1252         $url = makeUrlNS('Special', 'DownloadFile/' . $filename, 'preview&width=' . $r_width . '&height=' . $r_height, true);
  1252 				$url = makeUrlNS('Special', 'DownloadFile/' . $filename, 'preview&width=' . $r_width . '&height=' . $r_height, true);
  1253       }
  1253 			}
  1254       else
  1254 			else
  1255       {
  1255 			{
  1256         $url = makeUrlNS('Special', 'DownloadFile/' . $filename);
  1256 				$url = makeUrlNS('Special', 'DownloadFile/' . $filename);
  1257       }
  1257 			}
  1258       
  1258 			
  1259       $img_tag = '<img src="' . $url . '" ';
  1259 			$img_tag = '<img src="' . $url . '" ';
  1260       
  1260 			
  1261       // if ( isset($r_width) && isset($r_height) && $scale_type != '|thumb' )
  1261 			// if ( isset($r_width) && isset($r_height) && $scale_type != '|thumb' )
  1262       // {
  1262 			// {
  1263       //   $img_tag .= 'width="' . $r_width . '" height="' . $r_height . '" ';
  1263 			//   $img_tag .= 'width="' . $r_width . '" height="' . $r_height . '" ';
  1264       // }
  1264 			// }
  1265       
  1265 			
  1266       $img_tag .= 'style="border-width: 0px; /* background-color: white; */" ';
  1266 			$img_tag .= 'style="border-width: 0px; /* background-color: white; */" ';
  1267       
  1267 			
  1268       $code = $plugins->setHook('img_tag_parse_img');
  1268 			$code = $plugins->setHook('img_tag_parse_img');
  1269       foreach ( $code as $cmd )
  1269 			foreach ( $code as $cmd )
  1270       {
  1270 			{
  1271         eval($cmd);
  1271 				eval($cmd);
  1272       }
  1272 			}
  1273       
  1273 			
  1274       $img_tag .= '/>';
  1274 			$img_tag .= '/>';
  1275       
  1275 			
  1276       $s_full_tag = self::escape_parser_hint_attrib($full_tag);
  1276 			$s_full_tag = self::escape_parser_hint_attrib($full_tag);
  1277       $complete_tag = '<!--#imagelink src="' . $s_full_tag . '" -->';
  1277 			$complete_tag = '<!--#imagelink src="' . $s_full_tag . '" -->';
  1278       
  1278 			
  1279       if ( !empty($scale_type) && !$raw_display )
  1279 			if ( !empty($scale_type) && !$raw_display )
  1280       {
  1280 			{
  1281         $complete_tag .= '<div class="thumbnail" ';
  1281 				$complete_tag .= '<div class="thumbnail" ';
  1282         $clear_text = '';
  1282 				$clear_text = '';
  1283         if ( !empty($clear) )
  1283 				if ( !empty($clear) )
  1284         {
  1284 				{
  1285           $side = ( $clear == 'left' ) ? 'left' : 'right';
  1285 					$side = ( $clear == 'left' ) ? 'left' : 'right';
  1286           $opposite = ( $clear == 'left' ) ? 'right' : 'left';
  1286 					$opposite = ( $clear == 'left' ) ? 'right' : 'left';
  1287           $clear_text .= "float: $side; margin-$opposite: 20px; width: {$r_width}px;";
  1287 					$clear_text .= "float: $side; margin-$opposite: 20px; width: {$r_width}px;";
  1288           $complete_tag .= 'style="' . $clear_text . '" ';
  1288 					$complete_tag .= 'style="' . $clear_text . '" ';
  1289         }
  1289 				}
  1290         $complete_tag .= '>';
  1290 				$complete_tag .= '>';
  1291         
  1291 				
  1292         $complete_tag .= '<a href="' . makeUrlNS('File', $filename) . '" style="display: block;">';
  1292 				$complete_tag .= '<a href="' . makeUrlNS('File', $filename) . '" style="display: block;">';
  1293         $complete_tag .= $img_tag;
  1293 				$complete_tag .= $img_tag;
  1294         $complete_tag .= '</a>';
  1294 				$complete_tag .= '</a>';
  1295         
  1295 				
  1296         $mag_button = '<a href="' . makeUrlNS('File', $filename) . '" style="display: block; float: right; clear: right; margin: 0 0 10px 10px;"><img alt="[ + ]" src="' . scriptPath . '/images/thumbnail.png" style="border-width: 0px;" /></a>';
  1296 				$mag_button = '<a href="' . makeUrlNS('File', $filename) . '" style="display: block; float: right; clear: right; margin: 0 0 10px 10px;"><img alt="[ + ]" src="' . scriptPath . '/images/thumbnail.png" style="border-width: 0px;" /></a>';
  1297       
  1297 			
  1298         if ( !empty($caption) )
  1298 				if ( !empty($caption) )
  1299         {
  1299 				{
  1300           $complete_tag .= $mag_button . $caption;
  1300 					$complete_tag .= $mag_button . $caption;
  1301         }
  1301 				}
  1302         
  1302 				
  1303         $complete_tag .= '</div>';
  1303 				$complete_tag .= '</div>';
  1304       }
  1304 			}
  1305       else if ( $raw_display )
  1305 			else if ( $raw_display )
  1306       {
  1306 			{
  1307         $complete_tag .= "$img_tag";
  1307 				$complete_tag .= "$img_tag";
  1308         $taglist[$i] = $complete_tag;
  1308 				$taglist[$i] = $complete_tag;
  1309         
  1309 				
  1310         $repl = "{$s_delim}e_img_{$i}{$f_delim}";
  1310 				$repl = "{$s_delim}e_img_{$i}{$f_delim}";
  1311         $text = str_replace($full_tag, $repl, $text);
  1311 				$text = str_replace($full_tag, $repl, $text);
  1312         continue;
  1312 				continue;
  1313       }
  1313 			}
  1314       else
  1314 			else
  1315       {
  1315 			{
  1316         $complete_tag .= '<a href="' . makeUrlNS('File', $filename) . '" style="display: block;"';
  1316 				$complete_tag .= '<a href="' . makeUrlNS('File', $filename) . '" style="display: block;"';
  1317         $code = $plugins->setHook('img_tag_parse_link');
  1317 				$code = $plugins->setHook('img_tag_parse_link');
  1318         foreach ( $code as $cmd )
  1318 				foreach ( $code as $cmd )
  1319         {
  1319 				{
  1320           eval($cmd);
  1320 					eval($cmd);
  1321         }
  1321 				}
  1322         $complete_tag .= '>';
  1322 				$complete_tag .= '>';
  1323         $complete_tag .= $img_tag;
  1323 				$complete_tag .= $img_tag;
  1324         $complete_tag .= '</a>';
  1324 				$complete_tag .= '</a>';
  1325       }
  1325 			}
  1326       
  1326 			
  1327       $complete_tag .= "<!--#/imagelink-->";
  1327 			$complete_tag .= "<!--#/imagelink-->";
  1328       $taglist[$i] = $complete_tag;
  1328 			$taglist[$i] = $complete_tag;
  1329       
  1329 			
  1330       /*
  1330 			/*
  1331       $pos = strpos($text, $full_tag);
  1331 			$pos = strpos($text, $full_tag);
  1332       
  1332 			
  1333       while(true)
  1333 			while(true)
  1334       {
  1334 			{
  1335         $check1 = substr($text, $pos, 3);
  1335 				$check1 = substr($text, $pos, 3);
  1336         $check2 = substr($text, $pos, 1);
  1336 				$check2 = substr($text, $pos, 1);
  1337         if ( $check1 == '<p>' || $pos == 0 || $check2 == "\n" )
  1337 				if ( $check1 == '<p>' || $pos == 0 || $check2 == "\n" )
  1338         {
  1338 				{
  1339           // die('found at pos '.$pos);
  1339 					// die('found at pos '.$pos);
  1340           break;
  1340 					break;
  1341         }
  1341 				}
  1342         $pos--;
  1342 				$pos--;
  1343       }
  1343 			}
  1344       */
  1344 			*/
  1345       
  1345 			
  1346       /*
  1346 			/*
  1347       $repl = "{$s_delim}e_img_{$i}{$f_delim}";
  1347 			$repl = "{$s_delim}e_img_{$i}{$f_delim}";
  1348       $text = substr($text, 0, $pos) . $repl . substr($text, $pos);
  1348 			$text = substr($text, 0, $pos) . $repl . substr($text, $pos);
  1349       
  1349 			
  1350       $text = str_replace($full_tag, '', $text);
  1350 			$text = str_replace($full_tag, '', $text);
  1351       */
  1351 			*/
  1352       $text = str_replace_once($full_tag, $complete_tag, $text);
  1352 			$text = str_replace_once($full_tag, $complete_tag, $text);
  1353       
  1353 			
  1354       unset($full_tag, $filename, $scale_type, $width, $height, $clear, $caption, $r_width, $r_height);
  1354 			unset($full_tag, $filename, $scale_type, $width, $height, $clear, $caption, $r_width, $r_height);
  1355       
  1355 			
  1356     }
  1356 		}
  1357     
  1357 		
  1358     // if ( count($matches[0]) > 0 )
  1358 		// if ( count($matches[0]) > 0 )
  1359     //   die('<pre>' . htmlspecialchars($text) . '</pre>');
  1359 		//   die('<pre>' . htmlspecialchars($text) . '</pre>');
  1360     
  1360 		
  1361     return $text;
  1361 		return $text;
  1362   }
  1362 	}
  1363   
  1363 	
  1364   /**
  1364 	/**
  1365    * Finalizes processing of image tags.
  1365  	* Finalizes processing of image tags.
  1366    * @param string The preprocessed text
  1366  	* @param string The preprocessed text
  1367    * @param array The list of image tags created by RenderMan::process_image_tags()
  1367  	* @param array The list of image tags created by RenderMan::process_image_tags()
  1368    */
  1368  	*/
  1369    
  1369  	
  1370   public static function process_imgtags_stage2($text, $taglist)
  1370 	public static function process_imgtags_stage2($text, $taglist)
  1371   {
  1371 	{
  1372     $s_delim = "\xFF";
  1372 		$s_delim = "\xFF";
  1373     $f_delim = "\xFF";
  1373 		$f_delim = "\xFF";
  1374     foreach ( $taglist as $i => $tag )
  1374 		foreach ( $taglist as $i => $tag )
  1375     {
  1375 		{
  1376       $repl = "{$s_delim}e_img_{$i}{$f_delim}";
  1376 			$repl = "{$s_delim}e_img_{$i}{$f_delim}";
  1377       $text = str_replace($repl, $tag, $text);
  1377 			$text = str_replace($repl, $tag, $text);
  1378     }               
  1378 		}               
  1379     return $text;
  1379 		return $text;
  1380   }
  1380 	}
  1381   
  1381 	
  1382 }
  1382 }
  1383  
  1383  
  1384 ?>
  1384 ?>