PageRenderTime 89ms CodeModel.GetById 50ms app.highlight 20ms RepoModel.GetById 0ms app.codeStats 2ms

/shared/codes.php

https://github.com/altatof/altashop
PHP | 4537 lines | 2349 code | 800 blank | 1388 comment | 419 complexity | f92ed821b33a69f7ff4014c9e52ef3da MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1<?php
   2/**
   3 * Transform some text containing UBB-like code sequences.
   4 *
   5 * @todo CDATA for proxy http://javascript.about.com/library/blxhtml.htm
   6 * @todo &#91;files] - most recent files, in a compact list
   7 * @todo &#91;files=section:&lt;id>] - files attached in the given section
   8 * @todo &#91;links] - most recent links, in a compact list
   9 * @todo &#91;links=section:&lt;id>] - links attached in the given section
  10 * @todo for [read, add hits aside
  11 * @todo add a code to link images with clickable maps
  12 * @todo replace marquee with our own customizable scroller
  13 * @todo WiKi rendering for lists
  14 *
  15 * This module uses the Skin class for the actual rendering.
  16 *
  17 * Basic codes, demonstrated into [link]codes/basic.php[/link]:
  18 * - **...** - wiki bold text
  19 * - &#91;b]...[/b] - bold text
  20 * - //...// - italics
  21 * - &#91;i]...[/i] - italics
  22 * - __...__ - underlined
  23 * - &#91;u]...[/u] - underlined
  24 * - ##...## - monospace
  25 * - &#91;code]...[/code] - a short sample of fixed-size text (e.g. a file name)
  26 * - &#91;color]...[/color] - change font color
  27 * - &#91;tiny]...[/tiny] - tiny size
  28 * - &#91;small]...[/small] - small size
  29 * - &#91;big]...[/big] - big size
  30 * - &#91;huge]...[/huge] - huge size
  31 * - &#91;subscript]...[/subscript] - subscript
  32 * - &#91;superscript]...[/superscript] - superscript
  33 * - ++...++ - inserted
  34 * - &#91;inserted]...[/inserted] - inserted
  35 * - --...-- - deleted
  36 * - &#91;deleted]...[/deleted] - deleted
  37 * - &#91;flag]...[/flag] - draw attention
  38 * - &#91;lang=xy]...[/lang] - show some text only on matching language
  39 * - &#91;style=sans-serif]...[/style] - use a sans-serif font
  40 * - &#91;style=serif]...[/style] - use a serif font
  41 * - &#91;style=cursive]...[/style] - mimic hand writing
  42 * - &#91;style=comic]...[/style] - make it funny
  43 * - &#91;style=fantasy]...[/style] - guess what will appear
  44 * - &#91;style=my_style]...[/style] - translated to &lt;span class="my_style"&gt;...&lt;/span&gt;
  45 *
  46 * @see codes/basic.php
  47 *
  48 * Block codes, demonstrated in [link]codes/blocks.php[/link]:
  49 * - &#91;indent]...[/indent] - shift text to the right
  50 * - &#91;center]...[/center] - some centered text
  51 * - &#91;right]...[/right] - some right-aligned text
  52 * - &#91;decorated]...[/decorated] - some pretty paragraphs
  53 * - &#91;caution]...[/caution] - a warning paragraph
  54 * - &#91;note]...[/note] - a noticeable paragraph
  55 * - &#91;php]...[/php] - a snippet of php
  56 * - &#91;snippet]...[/snippet] - a snippet of fixed font data
  57 * - &#91;quote]...[/quote] - a block of quoted text
  58 * - &#91;folded]...[/folded] - click to view its content, or to fold it away
  59 * - &#91;folded=foo bar]...[/folded] - with title 'foo bar'
  60 * - &#91;unfolded]...[/unfolded] - click to fold
  61 * - &#91;unfolded=foo bar]...[/unfolded] - with title 'foo bar'
  62 * - &#91;sidebar]...[/sidebar] - a nice box aside
  63 * - &#91;sidebar=foo bar]...[/sidebar] - with title 'foo bar'
  64 * - &#91;scroller]...[/scroller] - some scrolling text
  65 *
  66 * @see codes/blocks.php
  67 *
  68 * List codes, demonstrated in [link]codes/lists.php[/link]:
  69 * - &#91;*] - for simple lists
  70 * - &#91;list]...[/list] - bulleted list
  71 * - &#91;list=1]...[/list] - numbered list, use numbers
  72 * - &#91;list=a]...[/list] - numbered list, use letters
  73 * - &#91;list=A]...[/list] - numbered list, use capital letters
  74 * - &#91;list=i]...[/list] - numbered list, use roman numbers
  75 * - &#91;list=I]...[/list] - numbered list, use upper case roman numbers
  76 *
  77 * @see codes/lists.php
  78 *
  79 * Codes for links, demonstrated in [link]codes/links.php[/link]:
  80 * - &lt;url&gt; - &lt;a href="url">url&lt;/a> or &lt;a href="url" class="external">url&lt;/a>
  81 * - &#91;link]&lt;url&gt;[/link] - &lt;a href="url">url&lt;/a> or &lt;a href="url" class="external">url&lt;/a>
  82 * - &#91;&lt;label&gt;|&lt;url&gt;] - &lt;a href="url">label&lt;/a> or &lt;a href="url" class="external">label&lt;/a>
  83 * - &#91;link=&lt;label&gt;]&lt;url&gt;[/link] - &lt;a href="url">label&lt;/a> or &lt;a href="url" class="external">label&lt;/a>
  84 * - &#91;url]&lt;url&gt;[/url] - deprecated by &#91;link]
  85 * - &#91;url=&lt;url&gt;]&lt;label&gt;[/url] - deprecated by &#91;link]
  86 * - &#91;button=&lt;label&gt;|&lt;url&gt;] - build simple buttons with css
  87 * - &#91;click=&lt;label&gt;|&lt;url&gt;] - a button that counts clicks
  88 * - &#91;clicks=&lt;url&gt;] - lists people who have clicked
  89 * - &lt;address&gt; - &lt;a href="mailto:address" class="email">address&lt;/a>
  90 * - &#91;email]&lt;address&gt;[/email] - &lt;a href="mailto:address" class="email">address&lt;/a>
  91 * - &#91;email=&lt;name&gt;]&lt;address&gt;[/email] - &lt;a href="mailto:address" class="email">name&lt;/a>
  92 * - &#91;go=&lt;name&gt;, &lt;label&gt;] - trigger the selector on 'name'
  93 * - &#91;&#91;&lt;name&gt;, &lt;label&gt;]] - Wiki selector
  94 * - &#91;article=&lt;id>] - use article title as link label
  95 * - &#91;article=&lt;id>, foo bar] - with label 'foo bar'
  96 * - &#91;article.description=&lt;id>] - insert article description
  97 * - &#91;form=&lt;id>] - use form title as link label
  98 * - &#91;form=&lt;id>, foo bar] - with label 'foo bar'
  99 * - &#91;next=&lt;id>] - shortcut to next article
 100 * - &#91;next=&lt;id>, foo bar] - with label 'foo bar'
 101 * - &#91;previous=&lt;id>] - shortcut to previous article
 102 * - &#91;previous=&lt;id>, foo bar] - with label 'foo bar'
 103 * - &#91;random] - pick up one page randomly
 104 * - &#91;random=&lt;section:id>] - one page in this section
 105 * - &#91;section=&lt;id>] - use section title as link label
 106 * - &#91;section=&lt;id>, foo bar] - with label 'foo bar'
 107 * - &#91;category=&lt;id>] - use category title as link label
 108 * - &#91;category=&lt;id>, foo bar] - with label 'foo bar'
 109 * - &#91;category.description=&lt;id>] - insert category description
 110 * - &#91;decision=&lt;id>] - use decision id in link label
 111 * - &#91;decision=&lt;id>, foo bar] - with label 'foo bar'
 112 * - &#91;user=&lt;id>] - use nick name as link label
 113 * - &#91;user=&lt;id>, foo bar] - with label 'foo bar'
 114 * - &#91;server=&lt;id>] - use server title as link label
 115 * - &#91;server=&lt;id>, foo bar] - with label 'foo bar'
 116 * - &#91;file=&lt;id>] - use file title as link label
 117 * - &#91;file=&lt;id>, foo bar] - with label 'foo bar'
 118 * - &#91;download=&lt;id>] - a link to download a file
 119 * - &#91;download=&lt;id>, foo bar] - with label 'foo bar'
 120 * - &#91;comment=&lt;id>] - use comment id in link label
 121 * - &#91;comment=&lt;id>, foo bar] - with label 'foo bar'
 122 * - &#91;script]&lt;path/script.php&gt;[/script] - to the phpDoc page for script 'path/script.php'
 123 * - &#91;search] - a search form
 124 * - &#91;search=&lt;word&gt;] - hit Enter to search for 'word'
 125 * - &#91;action=&lt;id>] - use action title as link label
 126 * - &#91;action=&lt;id>, foo bar] - with label 'foo bar'
 127 * - &#91;wikipedia=&lt;keyword] - search Wikipedia
 128 * - &#91;wikipedia=&lt;keyword, foo bar] - search Wikipedia, with label 'foo bar'
 129 *
 130 * @see codes/links.php
 131 *
 132 * Titles and questions, demonstrated in [link]codes/titles.php[/link]:
 133 * - &#91;toc] - table of contents
 134 * - ==...== - a level 1 headline
 135 * - &#91;title]...[/title] - a level 1 headline, put in the table of contents
 136 * - ===...=== - a level 2 headline
 137 * - &#91;subtitle]...[/subtitle] - a level 2 headline
 138 * - &#91;header1]...[/header1] - a level 1 headline
 139 * - &#91;header2]...[/header2] - a level 2 headline
 140 * - &#91;header3]...[/header3] - a level 3 headline
 141 * - &#91;header4]...[/header4] - a level 4 headline
 142 * - &#91;header5]...[/header5] - a level 5 headline
 143 * - &#91;toq] - the table of questions for this page
 144 * - &#91;question]...[/question] - a question-title
 145 * - &#91;question] - a simple question
 146 * - &#91;answer] - some answer in a FAQ
 147 *
 148 * @see codes/titles.php
 149 *
 150 * Tables, demonstrated in [link]codes/tables.php[/link]:
 151 * - &#91;table]...[/table] - one simple table
 152 * - &#91;table=grid]...[/table] - add a grid
 153 * - &#91;table].[body].[/table] - a table with headers
 154 * - &#91;csv]...[/csv] - import some data from Excel
 155 * - &#91;csv=;]...[/csv] - import some data from Excel
 156 * - &#91;table.json] - format a table as json
 157 *
 158 * @see codes/tables.php
 159 *
 160 * Live codes, demonstrated in [link]codes/live.php[/link]:
 161 * - &#91;sections] - site map
 162 * - &#91;sections=section:&lt;id>] - sub-sections
 163 * - &#91;sections=self] - sections assigned to current surfer
 164 * - &#91;sections=user:&lt;id>] - sections assigned to given user
 165 * - &#91;categories] - category tree
 166 * - &#91;categories=category:&lt;id>] - sub-categories
 167 * - &#91;categories=self] - categories assigned to current surfer
 168 * - &#91;categories=user:&lt;id>] - categories assigned to given user
 169 * - &#91;published] - most recent published pages, in a compact list
 170 * - &#91;published=section:&lt;id>] - articles published most recently in the given section
 171 * - &#91;published=category:&lt;id>] - articles published most recently in the given category
 172 * - &#91;published=user:&lt;id>] - articles published most recently created by given user
 173 * - &#91;published.decorated=self, 20] - 20 most recent pages from current surfer, as a decorated list
 174 * - &#91;updated] - most recent updated pages, in a compact list
 175 * - &#91;updated=section:&lt;id>] - articles updated most recently in the given section
 176 * - &#91;updated=category:&lt;id>] - articles updated most recently in the given category
 177 * - &#91;updated=user:&lt;id>] - articles updated most recently created by given user
 178 * - &#91;updated.simple=self, 12] - articles updated most recently created by current surfer, as a simple list
 179 * - &#91;read] - most read articles, in a compact list
 180 * - &#91;read=section:&lt;id>] - articles of fame in the given section
 181 * - &#91;read=self] - personal hits
 182 * - &#91;read=user:&lt;id>] - personal hits
 183 * - &#91;voted] - most voted articles, in a compact list
 184 * - &#91;voted=section:&lt;id>] - articles of fame in the given section
 185 * - &#91;voted=self] - personal hits
 186 * - &#91;voted=user:&lt;id>] - personal hits
 187 * - &#91;collections] - list available collections
 188 * - &#91;users=present] - list of users present on site
 189 *
 190 * @see codes/live.php
 191 *
 192 * Widgets, demonstrated in [link]codes/widgets.php[/link]:
 193 * - &#91;newsfeed=url] - integrate a newsfeed dynamically
 194 * - &#91;newsfeed.embed=url] - integrate a newsfeed dynamically
 195 * - &#91;twitter=id] - twitter updates of one person
 196 * - &#91;tsearch=token] - twitter search on a given topic
 197 * - &#91;iframe=&lt;width&gt;, &lt;height&gt;]&lt;url&gt;[/iframe] - include some external page
 198 * - &#91;freemind] - a Freemind map of site content
 199 * - &#91;freemind=section:&lt;id>] - a Freemind map of a section and its content
 200 * - &#91;freemind=section:&lt;id>, width, height] - a Freemind map of a section and its content
 201 * - &#91;cloud] - the tags used at this site
 202 * - &#91;cloud=12] - maximum count of tags used at this site
 203 * - &#91;calendar] - events for this month
 204 * - &#91;calendar=section:&lt;id>] - dates in one section
 205 * - &#91;locations=all] - newest locations
 206 * - &#91;locations=users] - map user locations on Google maps
 207 * - &#91;location=latitude, longitude, label] - to build a dynamic map
 208 *
 209 * @see codes/widgets.php
 210 *
 211 * Miscellaneous codes, demonstrated in [link]codes/misc.php[/link]:
 212 * - &#91;chart]...[/chart] - draw a dynamic chart
 213 * - &#91;hint=&lt;help popup]...[/hint] - &lt;acronym tite="help popup">...&lt;/acronym>
 214 * - &#91;nl] - new line
 215 * - ----... - line break
 216 * - &#91;---] or &#91;___] - horizontal rule
 217 * - &#91;new] - something new
 218 * - &#91;popular] - people love it
 219 * - &#91;be] - country flag
 220 * - &#91;ca] - country flag
 221 * - &#91;ch] - country flag
 222 * - &#91;de] - country flag
 223 * - &#91;en] - country flag
 224 * - &#91;es] - country flag
 225 * - &#91;fr] - country flag
 226 * - &#91;gb] - country flag
 227 * - &#91;gr] - country flag
 228 * - &#91;it] - country flag
 229 * - &#91;pt] - country flag
 230 * - &#91;us] - country flag
 231 *
 232 * @see codes/misc.php
 233 *
 234 * In-line elements:
 235 * - &#91;embed=&lt;id>, &lt;width>, &lt;height>, &lt;flashparams>] - embed a multimedia file
 236 * - &#91;embed=&lt;id>, window] - render a multimedia file in a separate window
 237 * - &#91;freemind=&lt;id>] - a Freemind map out of given file
 238 * - &#91;sound=&lt;id>] - play a sound
 239 * - &#91;image=&lt;id>] - an inline image
 240 * - &#91;image=&lt;id>,left] - a left-aligned image
 241 * - &#91;image=&lt;id>,center] - a centered image
 242 * - &#91;image=&lt;id>,right] - a right-aligned image
 243 * - &#91;image]src[/image]
 244 * - &#91;image=&lt;alt>]src[/image]
 245 * - &#91;images=&lt;id1>, &lt;id2>, ...] - a stack of images
 246 * - &#91;img]src[/img] (deprecated)
 247 * - &#91;img=&lt;alt>]src[/img] (deprecated)
 248 * - &#91;table=&lt;id>] - an inline table
 249 * - &#91;location=&lt;id>] - embed a map
 250 * - &#91;location=&lt;id>, foo bar] - with label 'foo bar'
 251 * - &#91;clear] - to introduce breaks after floating elements
 252 *
 253 * @link http://www.estvideo.com/dew/index/2005/02/16/370-player-flash-mp3-leger-comme-une-plume the dewplayer page
 254 *
 255 * Other codes:
 256 * - &#91;menu=label]url[/menu] -> one of the main menu command
 257 * - &#91;submenu=label]url[/submenu]	-> one of the second-level menu commands
 258 * - &#91;escape]...[/escape]
 259 * - &#91;anonymous]...[/anonymous] 	-> for non-logged people only
 260 * - &#91;restricted]...[/restricted]		-> for logged members only
 261 * - &#91;hidden]...[/hidden]		-> for associates only
 262 * - &#91;parameter=name]	-> value of one attribute of the global context
 263 *
 264 *
 265 * This script attempts to fight bbCode code injections by filtering strings to be used
 266 * as [code]src[/code] or as [code]href[/code] attributes (Thank you Mordread).
 267 *
 268 * @author Bernard Paques
 269 * @author Mordread Wallas
 270 * @author GnapZ
 271 * @author Alain Lesage (Lasares)
 272 * @tester Viviane Zaniroli
 273 * @tester Agnes
 274 * @tester Pat
 275 * @tester Guillaume Perez
 276 * @tester Fw_crocodile
 277 * @tester Christian Piercot
 278 * @tester Christian Loubechine
 279 * @reference
 280 * @license http://www.gnu.org/copyleft/lesser.txt GNU Lesser General Public License
 281 */
 282Class Codes {
 283
 284	/**
 285	 * beautify some text for final rendering
 286	 *
 287	 * This function is used to transform some text before sending it back to the browser.
 288	 * It actually performs following analysis:
 289	 * - implicit formatting
 290	 * - formatting codes
 291	 * - smileys
 292	 *
 293	 * If the keyword [escape][formatted][/escape] appears at the first line of text,
 294	 * or if options have the keyword ##formatted##, no implicit formatting is performed.
 295	 *
 296	 * If the keyword [escape][hardcoded][/escape] appears at the first line of text,
 297	 * or if options have the keyword ##hardcoded##, the only transformation is is new lines to breaks.
 298	 *
 299	 * If options feature the keyword ##compact##, then YACS codes that may
 300	 * generate big objects are removed, such as [escape][table]...[/table][/escape]
 301	 * and [escape][location][/escape].
 302	 *
 303	 * @param string the text to beautify
 304	 * @param string the set of options that apply to this text
 305	 * @return the beautified text
 306	 *
 307	 * @see articles/view.php
 308	 */
 309	function &beautify($text, $options='') {
 310		global $context;
 311
 312		// save CPU cycles
 313		$text = trim($text);
 314		if(!$text)
 315			return $text;
 316
 317		//
 318		// looking for compact content
 319		//
 320		if(preg_match('/\bcompact\b/i', $options))
 321			$text = preg_replace(array('/\[table.+?\/table\]/', '/\[location.+?\]/'), '', $text);
 322
 323		//
 324		// implicit formatting
 325		//
 326
 327		// new lines will have to be checked
 328		$new_lines = 'proceed';
 329
 330		// text is already formatted
 331		if(!strncmp($text, '[formatted]', 11)) {
 332			$new_lines = 'none';
 333			$text = substr($text, 11);
 334
 335		// text is already formatted (through options)
 336		} elseif(preg_match('/\bformatted\b/i', $options))
 337			$new_lines = 'none';
 338
 339		// newlines are hard coded
 340		elseif(!strncmp($text, '[hardcoded]', 11)) {
 341			$new_lines = 'hardcoded';
 342			$text = substr($text, 11);
 343
 344		// newlines are hard coded (through options)
 345		} elseif(preg_match('/\bhardcoded\b/i', $options))
 346			$new_lines = 'hardcoded';
 347
 348		// implicit formatting
 349		else
 350			$text =& Codes::beautify_implied($text, 'text');
 351
 352		//
 353		// translate codes
 354		//
 355
 356		// render codes
 357		$text =& Codes::render($text);
 358
 359		// render smileys after codes, else it will break escaped strings
 360		if(is_callable(array('Smileys', 'render_smileys')))
 361			$text =& Smileys::render_smileys($text);
 362
 363		// relocate images
 364		$text = str_replace('"skins/', '"'.$context['path_to_root'].'skins/', $text);
 365
 366		//
 367		// adjust end of lines
 368		//
 369
 370		// newlines are hard coded
 371		if($new_lines == 'hardcoded')
 372			$text = nl2br($text);
 373
 374		// implicit formatting
 375		elseif($new_lines == 'proceed')
 376			$text =& Codes::beautify_implied($text, 'newlines');
 377
 378		return $text;
 379	}
 380
 381	/**
 382	 * beautify some text in the extra panel
 383	 *
 384	 * @param string the text to beautify
 385	 * @return the beautified text
 386	 *
 387	 * @see articles/view.php
 388	 */
 389	function &beautify_extra($text) {
 390		global $context;
 391
 392		$search = array();
 393		$replace = array();
 394
 395		// [box.extra=title]...[/box]
 396		$search[] = '/\[box\.(extra)=([^\]]+?)\](.*?)\[\/box\]/ise';
 397		$replace[] = "Skin::build_box(stripslashes('$2'), stripslashes('$3'), '$1')";
 398
 399		// [box.navigation=title]...[/box]
 400		$search[] = '/\[box\.(navigation)=([^\]]+?)\](.*?)\[\/box\]/ise';
 401		$replace[] = "Skin::build_box(stripslashes('$2'), stripslashes('$3'), '$1')";
 402
 403		// process all codes
 404		$text = preg_replace($search, $replace, $text);
 405
 406		// regular rendering
 407		$text =& Codes::beautify($text);
 408
 409		return $text;
 410
 411	}
 412
 413	/**
 414	 * render some basic formatting
 415	 *
 416	 * - suppress multiple newlines
 417	 * - render empty lines
 418	 * - render simple bulleted lines
 419	 * - make URL clickable (http://..., www.foo.bar, foo.bar@foo.com)
 420	 *
 421	 * Now this function looks for the keyword &#91;escape] in order
 422	 * to avoid for formatting pre-formatted areas.
 423	 *
 424	 * For example, if you type:
 425	 * [snippet]
 426	 * hello
 427	 * world
 428	 *
 429	 * how are
 430	 * you doing?
 431	 *
 432	 * - my first item
 433	 * - my second item
 434	 *
 435	 * > quoted from
 436	 * > a previous message
 437	 * [/snippet]
 438	 *
 439	 * This will be rendered visually in the browser as:
 440	 * [snippet]
 441	 * hello world
 442	 *
 443	 * how are you doing?
 444	 *
 445	 * - my first item
 446	 * - my second item
 447	 *
 448	 * > quoted from
 449	 * > a previous message
 450	 * [/snippet]
 451	 *
 452	 * @param string the text to transform
 453	 * @param sring either 'text' or 'newlines'
 454	 * @return the modified string
 455	 */
 456	function &beautify_implied($text, $variant='text') {
 457
 458		// streamline newlines, even if this has been done elsewhere
 459		$text = str_replace(array("\r\n", "\r"), "\n", $text);
 460
 461		// only change end of lines
 462		if($variant == 'newlines') {
 463
 464			// formatting patterns
 465			$search = array(
 466				"|<br\s*/>\n+|i",		/* don't insert additional \n after <br /> */
 467				"|\n\n+|i"				/* force an html space between paragraphs */
 468				);
 469
 470			$replace = array(
 471				BR,
 472				BR.BR
 473				);
 474
 475		// change everything, except new lines
 476		} else {
 477
 478			// formatting patterns
 479			$search = array(
 480				"|</h1>\n+|i",			/* strip \n after title */
 481				"|</h2>\n+|i",
 482				"|</h3>\n+|i",
 483				"|</h4>\n+|i",
 484				'/http:\/\/www\.youtube\.com\/watch\?v=([a-zA-Z0-9]+)/i', // YouTube link
 485				"#^([a-z]+?)://([a-z0-9_\-\.\~\/@&;:=%$\?]+)#ie", /* make URL clickable */
 486				"#([\n\t ])([a-z]+?)://([a-z0-9_\-\.\~\/@&;:=%$\?]+)#ie", /* make URL clickable */
 487				"#([\n\t \(])www\.([a-z0-9\-]+)\.([a-z0-9_\-\.\~]+)((?:/[^,< \r\n\)]*)?)#ie",	/* web server */
 488				"/^\<p\>(-|\*)\s+(.+)\<\/p\>$/im", /* lists hard-coded with -, *, �, or � -- no space ahead */
 489				"/^(-|\*)\s+(.+)$/m", /* lists hard-coded with -, *, �, or � -- no space ahead */
 490				"/\n[ \t]*(From|To|cc|bcc|Subject|Date):(\s*)/i",	/* common message headers */
 491				"|\n[ \t]*>(\s*)|i",		/* quoted by > */
 492				"|\n[ \t]*\|(\s*)|i",		/* quoted by | */
 493				"#([\n\t ])(mailto:|)([a-z0-9_\-\.\~]+?)@([a-z0-9_\-\.\~]+\.[a-z0-9_\-\.\~]+)([\n\t ]*)#ie" /* mail address*/
 494				);
 495
 496			$replace = array(
 497				"</h1>",
 498				"</h2>",
 499				"</h3>",
 500				"</h4>",
 501				'<iframe class="youtube-player" type="text/html" width="445" height="364" src="http://www.youtube.com/embed/$1" frameborder="0"></iframe>', // YouTube link
 502				"Skin::build_link('$1://$2', '$1://$2')",
 503				"'$1'.Skin::build_link('$2://$3', '$2://$3')",
 504				"'$1'.Skin::build_link('http://www.$2.$3$4', 'www.$2.$3$4')",
 505				"<ul><li>$2</li></ul>",
 506				"<ul><li>$2</li></ul>",
 507				BR."$1:$2",
 508				BR.">$1",
 509				BR."|$1",
 510				"'$1'.Skin::build_link('mailto:$3@$4', '$3@$4', 'email').'$5'"
 511				);
 512		}
 513
 514		// preserve escaped areas
 515		$text = str_replace(array('[escape]', '[/escape]', '[list]', '[/list]', '[php]', '[/php]', '[snippet]', '[/snippet]'),
 516			array('<escape>', '</escape>', '<list>', '</list>', '<php>', '</php>', '<snippet>', '</snippet>'), $text);
 517
 518		// locate pre-formatted areas
 519		$areas = preg_split('/<(code|escape|list|php|snippet|pre)>(.*?)<\/\1>/is', trim($text), -1, PREG_SPLIT_DELIM_CAPTURE);
 520
 521		// format only adequate areas
 522		$index = 0;
 523		$formatted = '';
 524		$inside = FALSE;
 525		$target = '';
 526		foreach($areas as $area) {
 527
 528			switch($index%3) {
 529			case 0: // area to be formatted
 530
 531				// do not rewrite tags
 532				$items = preg_split('/<(.+?)>/is', $area, -1, PREG_SPLIT_DELIM_CAPTURE);
 533				$where = 0;
 534				foreach($items as $item) {
 535
 536					switch($where%2) {
 537
 538					case 0: // outside a tag
 539						if($inside)
 540							$target .= $item;
 541						else
 542							$formatted .= preg_replace($search, $replace, $item);
 543						break;
 544
 545					case 1: // inside a tag
 546
 547						// inside or outside a link
 548						if($inside && !strncmp($item, '/a', 2)) {
 549							$formatted .= preg_replace($search, $replace, $target).'<'.$item.'>';
 550							$target = '';
 551							$inside = FALSE;
 552						} elseif($inside)
 553							$target .= '<'.$item.'>';
 554						elseif(!strncmp($item, 'a ', 2)) {
 555							$formatted .= '<'.$item.'>';
 556							$inside = TRUE;
 557						} else
 558							$formatted .= '<'.$item.'>';
 559						break;
 560
 561					}
 562					$where++;
 563				}
 564				break;
 565
 566			case 1: // area boundary
 567				$tag = $area;
 568				break;
 569
 570			case 2: // pre-formatted area - left unmodified
 571
 572				// inside a link, or regular text
 573				if($inside)
 574					$target .= '<'.$tag.'>'.$area.'</'.$tag.'>';
 575				else
 576					$formatted .= '<'.$tag.'>'.$area.'</'.$tag.'>';
 577				break;
 578
 579			}
 580			$index++;
 581		}
 582
 583		// post-optimization
 584		if($variant == 'text')
 585			$formatted = preg_replace('#</ul>\n{0,1}<ul>#', '', $formatted);
 586		$formatted = preg_replace('#\n\n+<ul#', "\n<ul", $formatted);
 587
 588		// restore escaped areas
 589		$formatted = str_replace(array('<escape>', '</escape>', '<list>', '</list>', '<php>', '</php>', '<snippet>', '</snippet>'),
 590			array('[escape]', '[/escape]', '[list]', '[/list]', '[php]', '[/php]', '[snippet]', '[/snippet]'), $formatted);
 591
 592		return $formatted;
 593	}
 594
 595	/**
 596	 * format an introduction
 597	 *
 598	 * @param string raw introduction
 599	 * @return string finalized title
 600	 */
 601	function &beautify_introduction($text) {
 602
 603		// render codes
 604		$output =& Codes::render($text);
 605
 606		// render smileys after codes, else it will break escaped strings
 607		if(is_callable(array('Smileys', 'render_smileys')))
 608			$output =& Smileys::render_smileys($output);
 609
 610		// return by reference
 611		return $output;
 612	}
 613
 614	/**
 615	 * format a title
 616	 *
 617	 * New lines and images are the only things accepted in titles.
 618	 * The goal is to provide a faster service than beautify()
 619	 *
 620	 * @param string raw title
 621	 * @return string finalized title
 622	 */
 623	function &beautify_title($text) {
 624
 625		// suppress pairing codes
 626		$output =& Codes::strip($text);
 627
 628		// the only code transformed in titles
 629		$output = str_replace(array('[nl]', '[NL]'), '<br />', $output);
 630
 631		// remove everything, except links, breaks and images, and selected tags
 632		$output = strip_tags($output, '<a><abbr><acronym><b><big><br><code><del><div><dfn><em><i><img><ins><p><q><small><span><strong><sub><sup><tt><u>');
 633
 634		// return by reference
 635		return $output;
 636	}
 637
 638	/**
 639	 * determine if a code is already in some text
 640	 *
 641	 * @param string the text to check
 642	 * @param string code to check (e.g., 'embed')
 643	 * @param int the id of the object
 644	 * @return boolean TRUE if the code is present, false otherwise
 645	 */
 646	function check_embedded($text, $code, $id) {
 647
 648		// we check the string of digits
 649		$id = strval($id);
 650
 651		// parse the full string
 652		$count = strlen($text);
 653		$position = 0;
 654
 655		// look for '[embed' or similar
 656		while(($position = strpos($text, '['.$code, $position)) !== FALSE) {
 657			$position += 1+strlen($code);
 658
 659			// parse remaining chars
 660			while($position < $count) {
 661
 662				// digits just follow the '=' sign
 663				if($text[$position] == '=') {
 664					$position++;
 665
 666					// exact match
 667					if(($position + 2 + strlen($id) < $count) && !strcmp(substr($text, $position, strlen($id)), $id))
 668						return TRUE;
 669
 670					// not in this code, look at next one
 671					break;
 672
 673				// malformed code
 674				} elseif($text[$position] == ']') {
 675					$position++;
 676					break;
 677				}
 678
 679				// next char
 680				$position++;
 681			}
 682		}
 683
 684		// not found
 685		return FALSE;
 686	}
 687
 688	/**
 689	 * delete a code if it is present in some text
 690	 *
 691	 * @param string the text to check
 692	 * @param string code to check (e.g., 'embed')
 693	 * @param int the id of the object
 694	 * @return string the resulting string
 695	 */
 696	function delete_embedded($text, $code, $id) {
 697
 698		// we check the string of digits
 699		$id = strval($id);
 700
 701		// parse the full string
 702		$count = strlen($text);
 703		$position = 0;
 704
 705		// look for '[embed' or similar
 706		while(($position = strpos($text, '['.$code, $position)) !== FALSE) {
 707
 708			// we have to take everything before that point
 709			$prefix = $position;
 710
 711			// next char
 712			$position += 1+strlen($code);
 713
 714			// parse remaining chars
 715			while($position < $count) {
 716
 717				// digits just follow the '=' sign
 718				if($text[$position] == '=') {
 719					$position++;
 720
 721					// exact match
 722					if(($position + strlen($id) <= $count) && !strcmp(substr($text, $position, strlen($id)), $id)) {
 723						$position += strlen($id);
 724
 725						// look for ']'
 726						while($position < $count) {
 727							if($text[$position] == ']') {
 728								$position++;
 729								break;
 730							}
 731							$position++;
 732						}
 733
 734						// do the deletion
 735						$modified = '';
 736						if($prefix > 0)
 737							$modified .= substr($text, 0, $prefix);
 738						if($position < $count)
 739							$modified .= substr($text, $position, $count-$position);
 740						return $modified;
 741					}
 742
 743					// not in this code, look at next one
 744					break;
 745
 746				// malformed code
 747				} elseif($text[$position] == ']') {
 748					$position++;
 749					break;
 750				}
 751
 752				// next char
 753				$position++;
 754			}
 755		}
 756
 757		// not found
 758		return $text;
 759	}
 760
 761	/**
 762	 * fix line breaks introduced by FCKEditor
 763	 *
 764	 * This function moves unclosed tags to the beginning of content.
 765	 *
 766	 * @param string input
 767	 * @return string original or modified content
 768	 */
 769	function &fix_tags($text) {
 770
 771		// look for opening tag at content end
 772		$last_open = strrpos($text, '<p>');
 773		$last_close = strrpos($text, '</p');
 774		if($last_open && (($last_close === FALSE) || ($last_open > $last_close))) {
 775
 776			// trail
 777			$trail = '';
 778			if(strlen($text) > $last_open + 3)
 779				$trail = substr($text, $last_open + 3);
 780
 781			// move it to content start to restore pairing tags
 782			$text = '<p>'.substr($text, 0, $last_open).$trail;
 783
 784		}
 785
 786		// also fix broken img tags, if any
 787		$text = preg_replace('/\<(img[^\<\/]+)\>/i', '<\\1 />', $text);
 788
 789		// remove slashes added by preg_replace -- only for double quotes
 790		$text = str_replace('\"', '"', $text);
 791
 792		// done
 793		return $text;
 794	}
 795
 796	/**
 797	 * get the value of one global parameter
 798	 *
 799	 * @param string name of the parameter
 800	 * @param mixed default value, if any
 801	 * @return the actual value of this parameter, else the default value, else ''
 802	 */
 803	function &get_parameter($name, $default='') {
 804		global $context;
 805
 806		if(isset($context[$name])) {
 807			$output =& $context[$name];
 808			return $output;
 809		}
 810
 811		$output = $default;
 812		return $output;
 813	}
 814
 815	/**
 816	 * reset global variables used for rendering
 817	 *
 818	 * This function should be called between the processing of different articles in a loop
 819	 *
 820	 * @param string the target URL for this rendering (e.g., 'articles/view.php/123')
 821	 */
 822	function initialize($main_target=NULL) {
 823		global $context;
 824
 825		if($main_target)
 826			$context['self_url'] = $context['url_to_root'].$main_target;
 827
 828	}
 829
 830	/**
 831	 * list all ids matching some code
 832	 *
 833	 * @param string the text to check
 834	 * @param string code to check (e.g., 'embed')
 835	 * @return array the list of matching ids
 836	 */
 837	function list_embedded($text, $code='embed') {
 838
 839		// all ids we have found
 840		$ids = array();
 841
 842		// parse the full string
 843		$count = strlen($text);
 844		$position = 0;
 845
 846		// look for '[embed' or similar
 847		while(($position = strpos($text, '['.$code, $position)) !== FALSE) {
 848			$position += 1+strlen($code);
 849
 850			// parse remaining chars
 851			while($position < $count) {
 852
 853				// digits just follow the '=' sign
 854				if($text[$position] == '=') {
 855					$position++;
 856
 857					// capture all digits
 858					$id = '';
 859					while($position < $count) {
 860						if(($text[$position] >= '0') && ($text[$position] <= '9')) {
 861							$id .= $text[$position];
 862							$position++;
 863						} else
 864							break;
 865					}
 866
 867					// save this id
 868					if(strlen($id))
 869						$ids[] = $id;
 870
 871					// look at next code
 872					break;
 873
 874				// malformed code
 875				} elseif($text[$position] == ']') {
 876					$position++;
 877					break;
 878				}
 879
 880				// next char
 881				$position++;
 882			}
 883		}
 884
 885		// job done
 886		return $ids;
 887	}
 888
 889	/**
 890	 * transform codes to html
 891	 *
 892	 * [php]
 893	 * // build the page
 894	 * $context['text'] .= ...
 895	 *
 896	 * // transform codes
 897	 * $context['text'] = Codes::render($context['text']);
 898	 *
 899	 * // final rendering
 900	 * render_skin();
 901	 * [/php]
 902	 *
 903	 * @param string the input string
 904	 * @return string the transformed string
 905	 */
 906	function &render($text) {
 907		global $context;
 908
 909		// streamline newlines, even if this has been done elsewhere
 910		$text = str_replace(array("\r\n", "\r"), "\n", $text);
 911
 912		// prevent wysiwyg editors to bracket our own tags
 913		$text = preg_replace('/^<p>(\[.+\])<\/p>$/m', '\\1', $text);
 914
 915 		// initialize only once
 916		static $pattern;
 917		if(!isset($pattern)) {
 918
 919//			$pattern[] = ;
 920//			$replace[] = ;
 921//
 922//			$pattern[] = ;
 923//			$replace[] = ;
 924//
 925//			$pattern[] = ;
 926//			$replace[] = ;
 927//
 928//			$pattern[] = ;
 929//			$replace[] = ;
 930//
 931//			$pattern[] = ;
 932//			$replace[] = ;
 933
 934			$pattern = array(
 935				"|<!-- .* -->|i",								// remove HTML comments
 936				'/\[escape\](.*?)\[\/escape\]/ise', 	// [escape]...[/escape] (before everything)
 937				'/\[php\](.*?)\[\/php\]/ise',			// [php]...[/php]
 938				'/\[snippet\](.*?)\[\/snippet\]/ise',	// [snippet]...[/snippet]
 939				'/(\[page\].*)$/is',					// [page] (provide only the first one)
 940				'/\[hidden\](.*?)\[\/hidden\]/ise', 	// [hidden]...[/hidden] (save some cycles if at the beginning)
 941				'/\[restricted\](.*?)\[\/restricted\]/ise', // [restricted]...[/restricted] (save some cycles if at the beginning)
 942				'/\[anonymous\](.*?)\[\/anonymous\]/ise', // [anonymous]...[/anonymous] (save some cycles if at the beginning)
 943				'/\[parameter=([^\]]+?)\]/ise', 		// [parameter=<name>]
 944				'/\[lang=([^\]]+?)\](.*?)\[\/lang\]/ise',		// [lang=xy]...[/lang]
 945				'/\[csv=(.)\](.*?)\[\/csv\]/ise',		// [csv=;]...[/csv] (before [table])
 946				'/\[csv\](.*?)\[\/csv\]/ise',			// [csv]...[/csv] (before [table])
 947				'/\[table=([^\]]+?)\](.*?)\[\/table\]/ise', // [table=variant]...[/table]
 948				'/\[table\](.*?)\[\/table\]/ise',		// [table]...[/table]
 949				'/\[images=([^\]]+?)\]/ie', 				// [images=<ids>] (before other links)
 950				'/\[image\](.*?)\[\/image\]/ise',		// [image]src[/image]
 951				'/\[image=([^\]]+?)\](.*?)\[\/image\]/ise', // [image=alt]src[/image]
 952				'/\[img\](.*?)\[\/img\]/ise',			// [img]src[/img]
 953				'/\[img=([^\]]+?)\](.*?)\[\/img\]/ise', 	// [img=alt]src[/img]
 954				'/\[image=([^\]]+?)\]/ie',					// [image=<id>]
 955				'/##(\S.*?\S)##/is',					// ##...##
 956				'/\[code\](.*?)\[\/code\]/is',			// [code]...[/code]
 957				'/\[indent\](.*?)\[\/indent\]/ise', 	// [indent]...[/indent]
 958				'/\[quote\](.*?)\[\/quote\]/ise',		// [quote]...[/quote]
 959				'/\[folded=([^\]]+?)\](.*?)\[\/folded\]\s*/ise',	// [folded=...]...[/folded]
 960				'/\[folded\](.*?)\[\/folded\]\s*/ise',	// [folded]...[/folded]
 961				'/\[folder=([^\]]+?)\](.*?)\[\/folder\]\s*/ise',	// [folder=...]...[/folder]
 962				'/\[folder\](.*?)\[\/folder\]\s*/ise',	// [folder]...[/folder]
 963				'/\[unfolded=([^\]]+?)\](.*?)\[\/unfolded\]\s*/ise',	// [unfolded=...]...[/unfolded]
 964				'/\[unfolded\](.*?)\[\/unfolded\]\s*/ise',	// [unfolded]...[/unfolded]
 965				'/\[sidebar=([^\]]+?)\](.*?)\[\/sidebar\]\s*/ise',	// [sidebar=...]...[/sidebar]
 966				'/\[sidebar\](.*?)\[\/sidebar\]\s*/ise',	// [sidebar]...[/sidebar]
 967				'/\[note\](.*?)\[\/note\]\s*/ise',		// [note]...[/note]
 968				'/\[caution\](.*?)\[\/caution\]\s*/ise', // [caution]...[/caution]
 969				'/\[search=([^\]]+?)\]/ise',				// [search=words]
 970				'/\[search\]/ise',						// [search]
 971				'/\[cloud=(\d+?)\]/ise',				// [cloud=12]
 972				'/\[cloud\]/ise',						// [cloud]
 973				'/\[collections\]/ise', 				// [collections]
 974				'/\[login=([^\]]+?)\]/is',				// [login=words] --obsoleted
 975				'/\[login\]/is',						// [login] --obsoleted
 976				'/\[center\](.*?)\[\/center\]/ise', 	// [center]...[/center]
 977				'/\[right\](.*?)\[\/right\]/ise',		// [right]...[/right]
 978				'/\[decorated\](.*?)\[\/decorated\]/ise',// [decorated]...[/decorated]
 979				'/\[style=([^\]]+?)\](.*?)\[\/style\]/ise', // [style=variant]...[/style]
 980				'/\[hint=([^\]]+?)\](.*?)\[\/hint\]/is',	// [hint=help]...[/hint]
 981				'/\[tiny\](.*?)\[\/tiny\]/ise', 		// [tiny]...[/tiny]
 982				'/\[small\](.*?)\[\/small\]/ise',		// [small]...[/small]
 983				'/\[big\](.*?)\[\/big\]/ise',			// [big]...[/big]
 984				'/\[huge\](.*?)\[\/huge\]/ise', 		// [huge]...[/huge]
 985				'/\[subscript\](.*?)\[\/subscript\]/is',// [subscript]...[/subscript]
 986				'/\[superscript\](.*?)\[\/superscript\]/is',// [superscript]...[/superscript]
 987				'/\+\+(\S.*?\S)\+\+/is',				// ++...++
 988				'/\[(---+|___+)\]\s*/ise',				// [---], [___] --- before inserted
 989				'/^-----*/me',							// ----
 990				'/\[inserted\](.*?)\[\/inserted\]/is',	// [inserted]...[/inserted]
 991				'/ --(\S.*?\S)--/is',					// --...--
 992				'/\[deleted\](.*?)\[\/deleted\]/is',	// [deleted]...[/deleted]
 993				'/\*\*(\S.*?\S)\*\*/is',				// **...**
 994				'/\[b\](.*?)\[\/b\]/is',				// [b]...[/b]
 995				'/ \/\/(\S.*?\w)\/\//is',				// //...//
 996				'/\[i\](.*?)\[\/i\]/is',				// [i]...[/i]
 997				'/__(\S.*?\S)__/is',					// __...__
 998				'/\[u\](.*?)\[\/u\]/is',				// [u]...[/u]
 999				'/\[color=([^\]]+?)\](.*?)\[\/color\]/is',	// [color=<color>]...[/color]
1000				'/\[new\]/ie',							// [new]
1001				'/\[popular\]/ie',						// [popular]
1002				'/\[flag=([^\]]+?)\]/ie',				// [flag=<flag>]
1003				'/\[flag\](.*?)\[\/flag\]/ise', 		// [flag]...[/flag]
1004				'/\[list\](.*?)\[\/list\]/ise', 		// [list]...[/list]
1005				'/\[list=([^\]]+?)\](.*?)\[\/list\]/ise',	// [list=1]...[/list]
1006				'/\n\n+[ \t]*\[\*\][ \t]*/ie',			// [*] (outside [list]...[/list])
1007				'/\n?[ \t]*\[\*\][ \t]*/ie',
1008				'/\[li\](.*?)\[\/li\]/is',				// [li]...[/li] (outside [list]...[/list])
1009				'/\[chart=([^\]]+?)\](.*?)\[\/chart\]/ise',	// [chart=<width>, <height>, <params>]...[/chart]
1010				'/\[embed=([^\]]+?)\]/ie',					// [embed=<id>, <width>, <height>, <params>] or [embed=<id>, window]
1011				'/\[flash=([^\]]+?)\]/ie',					// [flash=<id>, <width>, <height>, <params>] or [flash=<id>, window]
1012				'/\[sound=([^\]]+?)\]/ie',					// [sound=<id>]
1013				'/\[go=([^\]]+?)\]/ie', 					// [go=<name>]
1014				'/\[\[([^\]]+?)\]\]/ie', 					// [[<name>]]
1015				'/\[article\.description=([^\]]+?)\]/ie',	// [article.description=<id>]
1016				'/\[article=([^\]]+?)\]/ie',				// [article=<id>] or [article=<id>, title]
1017				'/\[next=([^\]]+?)\]/ie',					// [next=<id>]
1018				'/\[previous=([^\]]+?)\]/ie',				// [previous=<id>]
1019				'/\[random\]/ie',							// [random]
1020				'/\[random\.description=([^\]]+?)\]/ie',	// [random.description=section:<id>]
1021				'/\[random=([^\]]+?)\]/ie',					// [random=section:<id>] or [random=category:<id>]
1022				'/\[form=([^\]]+?)\]/ie',					// [form=<id>] or [form=<id>, title]
1023				'/\[section=([^\]]+?)\]/ie',				// [section=<id>] or [section=<id>, title]
1024				'/\[category\.description=([^\]]+?)\]\n*/ise',	// [category.description=<id>]
1025				'/\[category=([^\]]+?)\]/ie',				// [category=<id>] or [category=<id>, title]
1026				'/\[user=([^\]]+?)\]/ie',					// [user=<id>] or [user=<id>, title]
1027				'/\[server=([^\]]+?)\]/ie', 				// [server=<id>]
1028				'/\[file=([^\]]+?)\]/ie',					// [file=<id>] or [file=<id>, title]
1029				'/\[download=([^\]]+?)\]/ie',				// [download=<id>] or [download=<id>, title]
1030				'/\[action=([^\]]+?)\]/ie', 				// [action=<id>]
1031				'/\[comment=([^\]]+?)\]/ie',				// [comment=<id>] or [comment=<id>, title]
1032				'/\[decision=([^\]]+?)\]/ie',				// [decision=<id>] or [decision=<id>, title]
1033				'/\[url=([^\]]+?)\](.*?)\[\/url\]/ise', 	// [url=url]label[/url] (deprecated by [link])
1034				'/\[url\](.*?)\[\/url\]/ise',				// [url]url[/url] (deprecated by [link])
1035				'/\[link=([^\]]+?)\](.*?)\[\/link\]/ise',	// [link=label]url[/link]
1036				'/\[link\](.*?)\[\/link\]/ise', 			// [link]url[/link]
1037				'/\[button=([^\]]+?)\](.*?)\[\/button\]/ise',	// [button=label]url[/button]
1038				'/\[button=([^\|]+?)\|([^\]]+?)]/ise',		// [button=label|url]
1039				'/\[click=([^\|]+?)\|([^\]]+?)]/ise',		// [click=label|url]
1040				'/\[clicks=([^\]]+?)]/ise',					// [clicks=url]
1041				'/\[script\](.*?)\[\/script\]/ise', 		// [script]url[/script]
1042				'/\[menu\](.*?)\[\/menu\]\n*/ise',			// [menu]url[/menu]
1043				'/\[menu=([^\]]+?)\](.*?)\[\/menu\]\n{0,1}/ise',	// [menu=label]url[/menu]
1044				'/\[submenu\](.*?)\[\/submenu\]\n{0,1}/ise',	// [submenu]url[/submenu]
1045				'/\[submenu=([^\]]+?)\](.*?)\[\/submenu\]\n*/ise', // [submenu=label]url[/submenu]
1046				'/\[email=([^\]]+?)\](.*?)\[\/email\]/ise', // [email=label]url[/email]
1047				'/\[email\](.*?)\[\/email\]/ise',			// [email]url[/email]
1048				'/\[([^ ][^\]\|]+?[^ ])\|([^ ][^\]]+?[^ ])\]/ise',			// [label|url]
1049				'/\[question\](.*?)\[\/question\]\n*/ise',	// [question]...[/question]
1050				'/\[question\]/ise',						// [question]
1051				'/\[answer\]/ise',							// [answer]
1052				'/\[newsfeed=([^\]]+?)\]/ise',				// [newsfeed=url]
1053				'/\[newsfeed\.([^=\]]+?)=([^\]]+?)\]/ise',	// [newsfeed.variant=url]
1054				'/\[twitter=([^\]]+?)\]/ise',				// [twitter=id]
1055				'/\[tsearch=([^\]]+?)\]/ise',				// [tsearch=id]
1056				'/\[retweet\]/ise',							// [retweet]
1057				'/\[iframe\](.*?)\[\/iframe\]/ise',			// [iframe]<url>[/iframe]
1058				'/\[iframe=([^\]]+?)\](.*?)\[\/iframe\]/ise',	// [iframe=<width>, <height>]<url>[/iframe]
1059				'/\[scroller\](.*?)\[\/scroller\]/ise', 	// [scroller]...[/scroller]
1060				'/\[toq\]\n*/ise',							// [toq] (table of questions)
1061				'/\[title\](.*?)\[\/title\]\n*/is', 		// [title]...[/title]
1062				'/\[subtitle\](.*?)\[\/subtitle\]\n*/is',	// [subtitle]...[/subtitle]
1063				'/\[(header[1-5])\](.*?)\[\/\1\]\n*/ise',	// [header1]...[/header1] ... [header5]...[/header5]
1064				'/^======(\S.*?\S)======/me',				// ======...====== level 5 headline
1065				'/<(br \/|p)>======(\S.*?\S)======<(br \/|\/p)>/me',		// ======...====== level 5 headline
1066				'/^=====(\S.*?\S)=====/me',					// =====...===== level 4 headline
1067				'/<(br \/|p)>=====(\S.*?\S)=====<(br \/|\/p)>/me',			// =====...===== level 4 headline
1068				'/^====(\S.*?\S)====/me',					// ====...==== level 3 headline
1069				'/<(br \/|p)>====(\S.*?\S)====<(br \/|\/p)>/me',			// ====...==== level 3 headline
1070				'/^===(\S.*?\S)===/me',						// ===...=== level 2 headline
1071				'/<(br \/|p)>===(\S.*?\S)===<(br \/|\/p)>/me',				// ===...=== level 2 headline
1072				'/^==(\S.*?\S)==/me',						// ==...== level 1 headline
1073				'/<(br \/|p)>==(\S.*?\S)==<(br \/|\/p)>/me',				// ==...== level 1 headline
1074				'/\[toc\]\n*/ise',							// [toc] (table of content)
1075				'/\[published\.([^\]=]+?)=([^\]]+?)\]\n*/ise',	// [published.decorated=section:4029]
1076				'/\[published\.([^\]]+?)\]\n*/ise',			// [published.decorated]
1077				'/\[published=([^\]]+?)\]\n*/ise',			// [published=section:4029]
1078				'/\[published\]\n*/ise',					// [published]
1079				'/\[read\.([^\]=]+?)=([^\]]+?)\]\n*/ise',	// [read.decorated=section:4029]
1080				'/\[read\.([^\]]+?)\]\n*/ise',				// [read.decorated]
1081				'/\[read=([^\]]+?)\]\n*/ise',				// [read=section:4029]
1082				'/\[read\]\n*/ise', 						// [read]
1083				'/\[updated\.([^\]=]+?)=([^\]]+?)\]\n*/ise', // [updated.simple=section:4029] (a list of recent updates)
1084				'/\[updated\.([^\]]+?)\]\n*/ise', 			// [updated.simple] (a list of recent updates)
1085				'/\[updated=([^\]]+?)\]\n*/ise', 			// [updated=section:4029] (a compact list of recent updates)
1086				'/\[updated\]\n*/ise',						// [updated] (a compact list of recent updates)
1087				'/\[voted\.([^\]=]+?)=([^\]]+?)\]\n*/ise',	// [voted.decorated=section:4029]
1088				'/\[voted\.([^\]]+?)\]\n*/ise',				// [voted.decorated]
1089				'/\[voted=([^\]]+?)\]\n*/ise',				// [voted=section:4029]
1090				'/\[voted\]\n*/ise', 						// [voted]
1091				'/\[freemind\]\n*/ise', 					// [freemind] (a mind map of site content)
1092				'/\[freemind=([^\]]+?)\]\n*/ise',			// [freemind=section:4029] (a mind map of section content)
1093				'/\[sections\]\n*/ise',						// [sections] (site map)
1094				'/\[sections\.([^\]=]+?)\]\n*/ise',			// [sections.folded] (site map)
1095				'/\[sections=([^\]]+?)\]\n*/ise',			// [sections=section:4029] (sub-sections)
1096				'/\[sections\.([^\]=]+?)=([^\]]+?)\]\n*/ise',	// [sections.simple=self] (assigned)
1097				'/\[categories\]\n*/ise',					// [categories] (category tree)
1098				'/\[categories\.([^\]=]+?)\]\n*/ise',		// [categories.folded] (category tree)
1099				'/\[categories=([^\]]+?)\]\n*/ise',			// [categories=section:4029] (sub-categories)
1100				'/\[categories\.([^\]=]+?)=([^\]]+?)\]\n*/ise',	// [categories.simple=self] (assigned)
1101				'/\[calendar\]\n*/ise',					// [calendar]
1102				'/\[calendar=([^\]]+?)\]\n*/ise',		// [calendar=section:4029]
1103				'/\[users=([^\]]+?)\]/ie',					// [users=present]
1104				'/\[news=([^\]]+?)\]/ise',				// [news=flash]
1105				'/\[table=([^\]]+?)\]/ise', 			// [table=<id>]
1106				'/\[table\.([^=\]]+?)=([^\]]+?)\]/ise', // [table.json=<id>]  [table.timeplot=<id>]
1107				'/\[locations=([^\]]+?)\]/ise', 		// [locations=<id>]
1108				'/\[location=([^\]]+?)\]/ise',			// [location=<id>]
1109				'/\[wikipedia=([^\]]+?)\]/ise', 		// [wikipedia=keyword] or [wikipedia=keyword, title]
1110				'/\[digraph\](.*?)\[\/digraph\]/ise',	// [digraph]url[/digraph]
1111				'/\[be\]/i',							// [be] belgian flag
1112				'/\[ca\]/i',							// [ca] canadian flag
1113				'/\[ch\]/i',							// [ch] swiss flag
1114				'/\[de\]/i',							// [de] german flag
1115				'/\[en\]/i',							// [en] english flag
1116				'/\[es\]/i',							// [es] spanish flag
1117				'/\[fr\]/i',							// [fr] french flag
1118				'/\[gb\]/i',							// [gb] gb flag
1119				'/\[gr\]/i',							// [gr] greek flag
1120				'/\[it\]/i',							// [it] italian flag
1121				'/\[pt\]/i',							// [pt] portuguese flag
1122				'/\[us\]/i',							// [pt] us flag
1123				'/\[clear\]\n*/i',						// [clear]
1124				'/\[nl\]\n*/si',						// [nl] (after tables)
1125				'/\[br\]/i' 							// [br] (deprecated by [nl])
1126			);
1127		}
1128
1129		// initialize only once
1130		static $replace;
1131		if(!isset($replace)) {
1132			$replace = array(
1133				'',																// delete HTML comments
1134				"Codes::render_escaped(Codes::fix_tags('$1'))",						// [escape]...[/escape]
1135				"Codes::render_pre(Codes::fix_tags('$1'), 'php')",					// [php]...[/php]
1136				"Codes::render_pre(Codes::fix_tags('$1'), 'snippet')",				// [snippet]...[/snippet]
1137				'', 																// [page]
1138				"Codes::render_hidden(Codes::fix_tags('$1'), 'hidden')",			// [hidden]...[/hidden]
1139				"Codes::render_hidden(Codes::fix_tags('$1'), 'restricted')",		// [restricted]...[/restricted]
1140				"Codes::render_hidden(Codes::fix_tags('$1'), 'anonymous')",			// [anonymous]...[/anonymous]
1141				"Codes::get_parameter('\\1')",										// [parameter=<name>]
1142				"i18n::filter(Codes::fix_tags('$2'), '$1')", 						// [lang=xy]...[/lang]
1143				"utf8::encode(str_replace('$1', '|', utf8::from_unicode(Codes::fix_tags('$2'))))",	// [csv=;]...[/csv]
1144				"str_replace(',', '|', Codes::fix_tags('$1'))",						// [csv]...[/csv]
1145				"Codes::render_static_table(Codes::fix_tags('$2'), '$1')",			// [table=variant]...[/table]
1146				"Codes::render_static_table(Codes::fix_tags('$1'), '')",			// [table]...[/table]
1147				"Codes::render_object('images', '$1')",								// [images=<ids>]
1148				"'<div class=\"external_image\"><img src=\"'.encode_link('$1').'\" alt=\"\" /></div>'",	// [image]src[/image]
1149				"'<div class=\"external_image\"><img src=\"'.encode_link('$2').'\" alt=\"'.encode_link('$1').'\" /></div>'", // [image=alt]src[/image]
1150				"'<div class=\"external_image\"><img src=\"'.encode_link('$1').'\" alt=\"\" /></div>'",	// [img]src[/img]
1151				"'<div class=\"external_image\"><img src=\"'.encode_link('$2').'\" alt=\"'.encode_link('$1').'\" /></div>'", // [img=alt]src[/img]
1152				"Codes::render_object('image', Codes::fix_tags('$1'))",				// [image=<id>]
1153				'<code>\\1</code>', 												// ##...##
1154				'<code>\\1</code>', 												// [code]...[/code]
1155				"Skin::build_block(Codes::fix_tags('$1'), 'indent')", 				// [indent]...[indent]
1156				"Skin::build_block(Codes::fix_tags('$1'), 'quote')",				// [quote]...[/quote]
1157				"Skin::build_box('$1', Codes::fix_tags('$2'), 'folded')",			// [folded=title]...[/folded]
1158				"Skin::build_box(NULL, Codes::fix_tags('$1'), 'folded')", 			// [folded]...[/folded]
1159				"Skin::build_box('$1', Codes::fix_tags('$2'), 'folded')",			// [folder=title]...[/folder]
1160				"Skin::build_box(NULL, Codes::fix_tags('$1'), 'folded')", 			// [folder]...[/folder]
1161				"Skin::build_box('$1', Codes::fix_tags('$2'), 'unfolded')",			// [unfolded=title]...[/unfolded]
1162				"Skin::build_box(NULL, Codes::fix_tags('$1'), 'unfolded')", 		// [unfolded]...[/unfolded]
1163				"Skin::build_box('$1', Codes::fix_tags('$2'), 'sidebar')",			// [sidebar=title]...[/sidebar]
1164				"Skin::build_box(NULL, Codes::fix_tags('$1'), 'sidebar')",			// [sidebar]...[/sidebar]
1165				"Skin::build_block(Codes::fix_tags('$1'), 'note')",					// [note]...[/note]
1166				"Skin::build_block(Codes::fix_tags('$1'), 'caution')",				// [caution]...[/caution]
1167				"Skin::build_block('$1', 'search')",								// [search=<words>]
1168				"Skin::build_block(NULL, 'search')",								// [search]
1169				"Codes::render_cloud('$1')",										// [cloud=12]
1170				"Codes::render_cloud(20)",											// [cloud]
1171				"Codes::render_collections()",										// [collections]
1172				'', 																// [login=<words>] --obsoleted
1173				'', 																// [login] --obsoleted
1174				"Skin::build_block(Codes::fix_tags('$1'), 'center')", 				// [center]...[/center]
1175				"Skin::build_block(Codes::fix_tags('$1'), 'right')",				// [right]...[/right]
1176				"Skin::build_block(Codes::fix_tags('$1'), 'decorated')",			// [decorated]...[/decorated]
1177				"Skin::build_block(Codes::fix_tags('$2'), '$1')", 					// [style=variant]...[/style]
1178				'<acronym title="\\1">\\2</acronym>',								// [hint=help]...[/hint]
1179				"Skin::build_block(Codes::fix_tags('$1'), 'tiny')",					// [tiny]...[/tiny]
1180				"Skin::build_block(Codes::fix_tags('$1'), 'small')",				// [small]...[/small]
1181				"Skin::build_block(Codes::fix_tags('$1'), 'big')",					// [big]...[/big]
1182				"Skin::build_block(Codes::fix_tags('$1'), 'huge')",					// [huge]...[/huge]
1183				'<sub>\\1</sub>',													// [subscript]...[/subscript]
1184				'<sup>\\1</sup>',													// [superscript]...[/superscript]
1185				'<ins>\\1</ins>',													// ++...++
1186				"HORIZONTAL_RULER", 												// [---], [___]
1187				"HORIZONTAL_RULER", 												// ----
1188				'<ins>\\1</ins>',													// [inserted]...[/inserted]
1189				' <del>\\1</del>',													// --...--
1190				'<del>\\1</del>',													// [deleted]...[/deleted]
1191				'<b>\\1</b>',														// **...**
1192				'<b>\\1</b>',														// [b]...[/b]
1193				' <i>\\1</i>',														// //...//
1194				'<i>\\1</i>',														// [i]...[/i]
1195				'<span style="text-decoration: underline">\\1</span>',				// __...__
1196				'<span style="text-decoration: underline">\\1</span>',				// [u]...[/u]
1197				'<span style="color: \\1">\\2</span>',								// [color]...[/color]
1198				"NEW_FLAG", 														// [new]
1199				"POPULAR_FLAG", 													// [popular]
1200				"Skin::build_flag('\\1')",											// [flag=....]
1201				"Skin::build_flag('\\1')",											// [flag]...[/flag]
1202				"Codes::render_list(Codes::fix_tags('$1'), NULL)",					// [list]...[/list]
1203				"Codes::render_list(Codes::fix_tags('$2'), '$1')",					// [list=?]...[/list]
1204				"BR.BR.BULLET_IMG.'&nbsp;'",										// standalone [*]
1205				"BR.BULLET_IMG.'&nbsp;'",
1206				'<li>\\1</li>', 													// [li]...[/li]
1207				"Codes::render_chart(Codes::fix_tags('$2'), '$1')",					// [chart=<width>, <height>, <params>]...[/chart]
1208				"Codes::render_embed(Codes::fix_tags('$1'))",						// [embed=<id>, <width>, <height>, <params>]
1209				"Codes::render_embed(Codes::fix_tags('$1'))",						// [flash=<id>, <width>, <height>, <params>] -- obsoleted by 'embed'
1210				"Codes::render_object('sound', Codes::fix_tags('$1'))",				// [sound=<id>]
1211				"Codes::render_object('go', Codes::fix_tags('$1'))",				// [go=<name>]
1212				"Codes::render_object('go', Codes::fix_tags('$1'))",				// [[<name>]]
1213				"Codes::render_object('article.description', Codes::fix_tags('$1'))",// [article.description=<id>]
1214				"Codes::render_object('article', Codes::fix_tags('$1'))",			// [article=<id>]
1215				"Codes::render_object('next', Codes::fix_tags('$1'))",				// [next=<id>]
1216				"Codes::render_object('previous', Codes::fix_tags('$1'))",			// [previous=<id>]
1217				"Codes::render_random()",											// [random]
1218				"Codes::render_random('$1', 'description')",						// [random.description=section:<id>]
1219				"Codes::render_random('$1')",										// [random=section:<id>]
1220				"Codes::render_object('form', Codes::fix_tags('$1'))",				// [form=<id>]
1221				"Codes::render_object('section', Codes::fix_tags('$1'))",			// [section=<id>]
1222				"Codes::render_object('category.description', '$1')", 				// [category.description=<id>]
1223				"Codes::render_object('category', Codes::fix_tags('$1'))",	 		// [category=<id>]
1224				"Codes::render_object('user', Codes::fix_tags('$1'))",				// [user=<id>]
1225				"Codes::render_object('server', Codes::fix_tags('$1'))",			// [server=<id>]
1226				"Codes::render_object('file', Codes::fix_tags('$1'))",				// [file=<id>] or [file=<id>, title]
1227				"Codes::render_object('download', Codes::fix_tags('$1'))",			// [download=<id>] or [download=<id>, title]
1228				"Codes::render_object('action', Codes::fix_tags('$1'))",			// [action=<id>]
1229				"Codes::render_object('comment',…

Large files files are truncated, but you can click here to view the full file