# HG changeset patch # User Dan # Date 1245558032 14400 # Node ID 98c052fc333710715509b75844bb45e62d6245a6 # Parent f0431eb8161eb02168a116648d652b5f260988f3 First implementation of new parser; Text_Wiki is now gone. VERY BETA! WiP. diff -r f0431eb8161e -r 98c052fc3337 includes/constants.php --- a/includes/constants.php Sun Jun 21 00:16:21 2009 -0400 +++ b/includes/constants.php Sun Jun 21 00:20:32 2009 -0400 @@ -106,13 +106,6 @@ // Rendering options! /** - * Render using the default engine (Text_Wiki + Enano pre- and post-processing). - * @const int - */ - -define('RENDER_WIKI_DEFAULT', 1); - -/** * Render using template/wiki hybrid syntax (Enano processing + template variable/logic access) * @const int */ @@ -124,14 +117,14 @@ * @const int */ -define('RENDER_BLOCKONLY', 4); +define('RENDER_BLOCK', 4); /** * Only render inline-level things, like links. * @const int */ -define('RENDER_INLINEONLY', 8); +define('RENDER_INLINE', 8); /** * Disable smilies when rendering. @@ -140,6 +133,19 @@ define('RENDER_NOSMILIES', 16); +/** + * Render using the default engine + * @const int + */ + +define('RENDER_WIKI_DEFAULT', RENDER_BLOCK | RENDER_INLINE); + +// parser order +define('PO_BEFORE', 1); +define('PO_AFTER', 2); +define('PO_FIRST', 3); +define('PO_LAST', 4); + // // User types - don't touch these // diff -r f0431eb8161e -r 98c052fc3337 includes/functions.php --- a/includes/functions.php Sun Jun 21 00:16:21 2009 -0400 +++ b/includes/functions.php Sun Jun 21 00:20:32 2009 -0400 @@ -1835,7 +1835,7 @@ $rand_seed = md5( sha1(microtime()) . mt_rand() ); // We need MediaWiki - require_once(ENANO_ROOT . '/includes/wikiengine/Tables.php'); + require_once(ENANO_ROOT . '/includes/wikiengine/TagSanitizer.php'); // Strip out comments that are already escaped preg_match_all('/<!--(.*?)-->/', $html, $comment_match); diff -r f0431eb8161e -r 98c052fc3337 includes/pageprocess.php --- a/includes/pageprocess.php Sun Jun 21 00:16:21 2009 -0400 +++ b/includes/pageprocess.php Sun Jun 21 00:20:32 2009 -0400 @@ -502,7 +502,7 @@ // Rebuild the search index $paths->rebuild_page_index($this->page_id, $this->namespace); - $this->text_cache = $text; + $this->text_cache = $text_undb; return true; diff -r f0431eb8161e -r 98c052fc3337 includes/render.php --- a/includes/render.php Sun Jun 21 00:16:21 2009 -0400 +++ b/includes/render.php Sun Jun 21 00:20:32 2009 -0400 @@ -185,21 +185,17 @@ global $db, $session, $paths, $template, $plugins; // Common objects global $lang; - require_once(ENANO_ROOT.'/includes/wikiformat.php'); - require_once(ENANO_ROOT.'/includes/wikiengine/Tables.php'); + profiler_log("RenderMan: starting wikitext render"); + require_once( ENANO_ROOT . '/includes/wikiformat.php' ); + require_once( ENANO_ROOT . '/includes/wikiengine/TagSanitizer.php' ); + require_once( ENANO_ROOT . '/includes/wikiengine/Tables.php' ); - profiler_log("RenderMan: starting wikitext render"); - + // this is still needed by parser plugins $random_id = md5( time() . mt_rand() ); // Strip out sections and PHP code - $nw = preg_match_all('#(.*?)<\/nowiki>#is', $text, $nowiki); - - for($i=0;$i'.$nowiki[1][$i].'', '{NOWIKI:'.$random_id.':'.$i.'}', $text); - } + self::nowiki_strip($text, $nowiki_stripped); $code = $plugins->setHook('render_wikiformat_veryearly'); foreach ( $code as $cmd ) @@ -207,131 +203,173 @@ eval($cmd); } - $php = preg_match_all('#<\?php(.*?)\?>#is', $text, $phpsec); + self::php_strip($text, $php_stripped); - for($i=0;$iflags = $flags; + $carpenter->hook(array(__CLASS__, 'hook_pre'), PO_AFTER, 'lang'); + $carpenter->hook(array(__CLASS__, 'hook_posttemplates'), PO_AFTER, 'templates'); + if ( $flags & RENDER_WIKI_TEMPLATE ) { - $text = str_replace('', '{PHP:'.$random_id.':'.$i.'}', $text); + // FIXME: process noinclude/nodisplay + } + $text = $carpenter->render($text); + + // For plugin compat + $result =& $text; + + $code = $plugins->setHook('render_wikiformat_post'); + foreach ( $code as $cmd ) + { + eval($cmd); } + /* $text = preg_replace('/(.*?)<\/noinclude>/is', '\\1', $text); if ( $paths->namespace == 'Template' ) { $text = preg_replace('/(.*?)<\/nodisplay>/is', '', $text); } - if ( !($flags & RENDER_BLOCKONLY) ) - { - preg_match_all('/([\w\W]+?)<\/lang>/', $text, $langmatch); - foreach ( $langmatch[0] as $i => $match ) - { - if ( $langmatch[1][$i] == $lang->lang_code ) - { - $text = str_replace_once($match, $langmatch[2][$i], $text); - } - else - { - $text = str_replace_once($match, '', $text); - } - } - - $code = $plugins->setHook('render_wikiformat_pre'); - foreach ( $code as $cmd ) - { - eval($cmd); - } - - //$template_regex = "/\{\{([^\]]+?)((\n([ ]*?)[A-z0-9]+([ ]*?)=([ ]*?)(.+?))*)\}\}/is"; - $template_regex = "/\{\{(.+)((\n|\|[ ]*([A-z0-9]+)[ ]*=[ ]*(.+))*)\}\}/isU"; - $i = 0; - while ( preg_match($template_regex, $text) ) - { - $i++; - if ( $i == 5 ) - break; - $text = RenderMan::include_templates($text); - } - - $code = $plugins->setHook('render_wikiformat_posttemplates'); - foreach ( $code as $cmd ) - { - eval($cmd); - } - - // Process images - $text = RenderMan::process_image_tags($text, $taglist); - $text = RenderMan::process_imgtags_stage2($text, $taglist); - } - - // Before shipping it out to the renderer, replace spaces in between headings and paragraphs: - $text = preg_replace('/<\/(h[0-9]|div|p)>([\s]+)<(h[0-9]|div|p)( .+?)?>/i', '<\\3\\4>', $text); - $text = process_tables($text); - - if ( !($flags & RENDER_BLOCKONLY) ) - $text = RenderMan::parse_internal_links($text); + */ - $wiki = Text_Wiki::singleton('Mediawiki'); - $wiki->setRenderConf('Xhtml', 'wikilink', 'view_url', contentPath); - $wiki->setRenderConf('Xhtml', 'Url', 'css_descr', 'external'); - if ( $flags & RENDER_BLOCKONLY ) - { - $wiki->disableRule('Freelink'); - $wiki->disableRule('Url'); - $wiki->disableRule('Toc'); - $wiki->disableRule('Image'); - } - else if ( $flags & RENDER_INLINEONLY ) - { - foreach ( array('code', 'html', 'raw', 'include', 'embed', 'horiz', 'break', 'blockquote', 'list', 'newline', 'paragraph', 'revise', 'tighten') as $rule ) - { - $wiki->disableRule($rule); - } - } - $result = $wiki->transform($text, 'Xhtml'); - - // HTML fixes - $result = preg_replace('#([\s]*?)<\/tr>#is', '', $result); - $result = preg_replace('#

([\s]*?)<\/p>#is', '', $result); - $result = preg_replace('#
([\s]*?)\n", "

", $result);
-    $result = preg_replace("/

]*?)><\/p>/", "", $result); - $result = str_replace("
\n", "\n", $result); - $result = str_replace("

", "", $result); - $result = str_replace("
", "", $result); - $result = str_replace("
", "", $result); - $result = str_replace("
", "", $result); - $result = preg_replace('/<\/table>$/', "

", $result); - $result = str_replace("

", "", $result); - $result = str_replace("

", "", $result); - - if ( !($flags & RENDER_BLOCKONLY) ) - { - $code = $plugins->setHook('render_wikiformat_post'); - foreach ( $code as $cmd ) - { - eval($cmd); - } - } - - // Reinsert sections - for($i=0;$i<$nw;$i++) - { - $result = str_replace('{NOWIKI:'.$random_id.':'.$i.'}', $nowiki[1][$i], $result); - } - - // Reinsert PHP - for($i=0;$i<$php;$i++) - { - $result = str_replace('{PHP:'.$random_id.':'.$i.'}', '', $result); - } + self::nowiki_unstrip($text, $nowiki_stripped); + self::php_unstrip($text, $php_stripped); profiler_log("RenderMan: finished wikitext render"); - return $result; + return $text; + } + + public static function hook_pre($text) + { + global $db, $session, $paths, $template, $plugins; // Common objects + + $code = $plugins->setHook('render_wikiformat_pre'); + foreach ( $code as $cmd ) + { + eval($cmd); + } + + return $text; + } + + public static function hook_posttemplates($text) + { + global $db, $session, $paths, $template, $plugins; // Common objects + + $code = $plugins->setHook('render_wikiformat_posttemplates'); + foreach ( $code as $cmd ) + { + eval($cmd); + } + + return $text; + } + + /** + * Strip out tags (to bypass parsing on them) + * @access private + */ + + private static function nowiki_strip(&$text, &$stripdata) + { + self::tag_strip('nowiki', $text, $stripdata); + } + + /** + * Restore stripped tags. + * @access private + */ + + public static function nowiki_unstrip(&$text, &$stripdata) + { + self::tag_unstrip('nowiki', $text, $stripdata); + } + + /** + * Strip out an arbitrary HTML tag. + * @access private + */ + + public static function tag_strip($tag, &$text, &$stripdata) + { + $random_id = md5( time() . mt_rand() ); + + preg_match_all("#<$tag>(.*?)#is", $text, $blocks); + + foreach ( $blocks[0] as $i => $match ) + { + $text = str_replace($match, "{{$tag}:{$random_id}:{$i}}", $text); + } + $stripdata = array( + 'random_id' => $random_id, + 'blocks' => $blocks[1] + ); } + /** + * Restore stripped tags. + * @access private + */ + + public static function tag_unstrip($tag, &$text, &$stripdata) + { + $random_id = $stripdata['random_id']; + + foreach ( $stripdata['blocks'] as $i => $block ) + { + $text = str_replace("{{$tag}:{$random_id}:{$i}}", $block, $text); + } + + $stripdata = array(); + } + + /** + * 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.) + * @access private + */ + + private static function php_strip(&$text, &$stripdata) + { + $random_id = md5( time() . mt_rand() ); + + preg_match_all('#<\?(?:php)?[\s=].+?\?>#is', $text, $blocks); + + foreach ( $blocks[0] as $i => $match ) + { + $text = str_replace($match, "{PHP:$random_id:$i}", $text); + } + + $stripdata = array( + 'random_id' => $random_id, + 'blocks' => $blocks[0] + ); + } + + /** + * Restore stripped PHP code + * @access private + */ + + private static function php_unstrip(&$text, &$stripdata) + { + $random_id = $stripdata['random_id']; + + foreach ( $stripdata['blocks'] as $i => $block ) + { + $text = str_replace("{PHP:$random_id:$i}", $block, $text); + } + + $stripdata = array(); + } + + /** + * Deprecated. + */ + public static function wikiFormat($message, $filter_links = true, $do_params = false, $plaintext = false) { global $db, $session, $paths, $template, $plugins; // Common objects @@ -781,9 +819,11 @@ /** * Preprocesses an HTML text string prior to being sent to MySQL. * @param string $text - * @param bool $strip_all_php - if true, strips all PHP regardless of user permissions. Else, strips PHP only if user level < USER_LEVEL_ADMIN. + * @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. + * @param bool $sqlescape - if true, sends text through $db->escape(). Otherwise returns unescaped text. Defaults to true. + * @param bool $reduceheadings - if true, finds HTML headings and replaces them with wikitext. Else, does not touch headings. Defaults to true. */ - public static function preprocess_text($text, $strip_all_php = true, $sqlescape = true) + public static function preprocess_text($text, $strip_all_php = true, $sqlescape = true, $reduceheadings = true) { global $db, $session, $paths, $template, $plugins; // Common objects $random_id = md5( time() . mt_rand() ); @@ -836,8 +876,9 @@ eval($cmd); } - // gently apply some reverse-processing to allow Text_Wiki to do magic with TOCs and stuff - $text = self::reverse_process_headings($text); + // gently apply some reverse-processing to allow the parser to do magic with TOCs and stuff + if ( $reduceheadings ) + $text = self::reverse_process_headings($text); // Reinsert sections for($i=0;$i<$nw;$i++) diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Default.php --- a/includes/wikiengine/Default.php Sun Jun 21 00:16:21 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version CVS: $Id: Default.php,v 1.1 2006/03/01 16:58:17 justinpatrin Exp $ - * @link http://pear.php.net/package/Text_Wiki - */ - -require_once('Text/Wiki.php'); - -/** - * This is the parser for the Default ruleset. For now, this simply extends Text_Wiki. - * - * @category Text - * @package Text_Wiki - * @version Release: @package_version@ - * @author Justin Patrin - */ -class Text_Wiki_Default extends Text_Wiki { -} diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Mediawiki.php --- a/includes/wikiengine/Mediawiki.php Sun Jun 21 00:16:21 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,93 +0,0 @@ - - * @author Paul M. Jones - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version CVS: $Id: Mediawiki.php,v 1.8 2006/02/25 09:59:34 toggg Exp $ - * @link http://pear.php.net/package/Text_Wiki - */ - -/** - * "master" class for handling the management and convenience - */ -require_once(ENANO_ROOT.'/includes/wikiformat.php'); - -/** - * Base Text_Wiki handler class extension for Mediawiki markup - * - * @category Text - * @package Text_Wiki - * @author Bertrand Gugger - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version Release: @package_version@ - * @link http://pear.php.net/package/Text_Wiki - * @see Text_Wiki::Text_Wiki() - */ -class Text_Wiki_Mediawiki extends Text_Wiki { - var $rules = array( - 'Prefilter', - 'Delimiter', - 'Code', -// 'Plugin', -// 'Function', -// 'Html', - 'Raw', -// 'Preformatted', -// 'Include', -// 'Embed', -// 'Page', -// 'Anchor', - 'Heading', - 'Toc', -// 'Titlebar', - 'Horiz', - 'Break', - 'Blockquote', - 'List', - 'Deflist', -// 'Table', -// 'Box', -// 'Image', // done by Wikilink but still possible to disable/configure -// 'Phplookup', - 'Center', - 'Newline', - 'Paragraph', - 'Url', -// 'Freelink', -// 'Colortext', - 'Wikilink', -// 'Strong', ** will be only fake inserted by Emphasis if needed for render - 'Bold', - 'Emphasis', - 'Italic', - 'Underline', - 'Tt', - 'Superscript', - 'Subscript', -// 'Specialchar', - 'Revise', -// 'Interwiki', // done by Wikilink but still possible to disable/configure - 'Tighten' - ); - - /** - * Constructor: just adds the path to Mediawiki rules - * - * @access public - * @param array $rules The set of rules to load for this object. - */ - function Text_Wiki_Mediawiki($rules = null) { - parent::Text_Wiki($rules); - $this->addPath('parse', $this->fixPath(dirname(__FILE__)).'Parse/Mediawiki'); - } -} - -?> diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Parse.php --- a/includes/wikiengine/Parse.php Sun Jun 21 00:16:21 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,264 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version CVS: $Id: Parse.php,v 1.5 2005/07/29 08:57:29 toggg Exp $ - * @link http://pear.php.net/package/Text_Wiki - */ - -/** - * Baseline rule class for extension into a "real" parser component. - * - * Text_Wiki_Rule classes do not stand on their own; they are called by a - * Text_Wiki object, typcially in the transform() method. Each rule class - * performs three main activities: parse, process, and render. - * - * The parse() method takes a regex and applies it to the whole block of - * source text at one time. Each match is sent as $matches to the - * process() method. - * - * The process() method acts on the matched text from the source, and - * then processes the source text is some way. This may mean the - * creation of a delimited token using addToken(). In every case, the - * process() method returns the text that should replace the matched text - * from parse(). - * - * @category Text - * @package Text_Wiki - * @author Paul M. Jones - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version Release: @package_version@ - * @link http://pear.php.net/package/Text_Wiki - */ -class Text_Wiki_Parse { - - - /** - * - * Configuration options for this parser rule. - * - * @access public - * - * @var string - * - */ - - var $conf = array(); - - - /** - * - * Regular expression to find matching text for this rule. - * - * @access public - * - * @var string - * - * @see parse() - * - */ - - var $regex = null; - - - /** - * - * The name of this rule for new token array elements. - * - * @access public - * - * @var string - * - */ - - var $rule = null; - - - /** - * - * A reference to the calling Text_Wiki object. - * - * This is needed so that each rule has access to the same source - * text, token set, URLs, interwiki maps, page names, etc. - * - * @access public - * - * @var object - */ - - var $wiki = null; - - - /** - * - * Constructor for this parser rule. - * - * @access public - * - * @param object &$obj The calling "parent" Text_Wiki object. - * - */ - - function Text_Wiki_Parse(&$obj) - { - // set the reference to the calling Text_Wiki object; - // this allows us access to the shared source text, token - // array, etc. - $this->wiki =& $obj; - - // set the name of this rule; generally used when adding - // to the tokens array. strip off the Text_Wiki_Parse_ portion. - // text_wiki_parse_ - // 0123456789012345 - $tmp = substr(get_class($this), 16); - $this->rule = ucwords(strtolower($tmp)); - - // override config options for the rule if specified - if (isset($this->wiki->parseConf[$this->rule]) && - is_array($this->wiki->parseConf[$this->rule])) { - - $this->conf = array_merge( - $this->conf, - $this->wiki->parseConf[$this->rule] - ); - - } - } - - - /** - * - * Abstrct method to parse source text for matches. - * - * Applies the rule's regular expression to the source text, passes - * every match to the process() method, and replaces the matched text - * with the results of the processing. - * - * @access public - * - * @see Text_Wiki_Parse::process() - * - */ - - function parse() - { - $this->wiki->source = preg_replace_callback( - $this->regex, - array(&$this, 'process'), - $this->wiki->source - ); - } - - - /** - * - * Abstract method to generate replacements for matched text. - * - * @access public - * - * @param array $matches An array of matches from the parse() method - * as generated by preg_replace_callback. $matches[0] is the full - * matched string, $matches[1] is the first matched pattern, - * $matches[2] is the second matched pattern, and so on. - * - * @return string The processed text replacement; defaults to the - * full matched string (i.e., no changes to the text). - * - * @see Text_Wiki_Parse::parse() - * - */ - - function process(&$matches) - { - return $matches[0]; - } - - - /** - * - * Simple method to safely get configuration key values. - * - * @access public - * - * @param string $key The configuration key. - * - * @param mixed $default If the key does not exist, return this value - * instead. - * - * @return mixed The configuration key value (if it exists) or the - * default value (if not). - * - */ - - function getConf($key, $default = null) - { - if (isset($this->conf[$key])) { - return $this->conf[$key]; - } else { - return $default; - } - } - - - /** - * - * Extract 'attribute="value"' portions of wiki markup. - * - * This kind of markup is typically used only in macros, but is useful - * anywhere. - * - * The syntax is pretty strict; there can be no spaces between the - * option name, the equals, and the first double-quote; the value - * must be surrounded by double-quotes. You can escape characters in - * the value with a backslash, and the backslash will be stripped for - * you. - * - * @access public - * - * @param string $text The "attributes" portion of markup. - * - * @return array An associative array of key-value pairs where the - * key is the option name and the value is the option value. - * - */ - - function getAttrs($text) - { - // find the =" sections; - $tmp = explode('="', trim($text)); - - // basic setup - $k = count($tmp) - 1; - $attrs = array(); - $key = null; - - // loop through the sections - foreach ($tmp as $i => $val) { - - // first element is always the first key - if ($i == 0) { - $key = trim($val); - continue; - } - - // find the last double-quote in the value. - // the part to the left is the value for the last key, - // the part to the right is the next key name - $pos = strrpos($val, '"'); - $attrs[$key] = stripslashes(substr($val, 0, $pos)); - $key = trim(substr($val, $pos+1)); - - } - - return $attrs; - - } -} -?> diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Parse/Default/Anchor.php --- a/includes/wikiengine/Parse/Default/Anchor.php Sun Jun 21 00:16:21 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,87 +0,0 @@ - -* -* @author Paul M. Jones -* -* @license LGPL -* -* @version $Id: Anchor.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $ -* -*/ - -/** -* -* This class implements a Text_Wiki_Parse to add an anchor target name -* in the wiki page. -* -* @author Manuel Holtgrewe -* -* @author Paul M. Jones -* -* @category Text -* -* @package Text_Wiki -* -*/ - -class Text_Wiki_Parse_Anchor extends Text_Wiki_Parse { - - - /** - * - * The regular expression used to find source text matching this - * rule. Looks like a macro: [[# anchor_name]] - * - * @access public - * - * @var string - * - */ - - var $regex = '/(\[\[# )([-_A-Za-z0-9.]+?)( .+)?(\]\])/i'; - - - /** - * - * Generates a token entry for the matched text. Token options are: - * - * 'text' => The full matched text, not including the tags. - * - * @access public - * - * @param array &$matches The array of matches from parse(). - * - * @return A delimited token number to be used as a placeholder in - * the source text. - * - */ - - function process(&$matches) { - - $name = $matches[2]; - $text = $matches[3]; - - $start = $this->wiki->addToken( - $this->rule, - array('type' => 'start', 'name' => $name) - ); - - $end = $this->wiki->addToken( - $this->rule, - array('type' => 'end', 'name' => $name) - ); - - // done, place the script output directly in the source - return $start . trim($text) . $end; - } -} -?> diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Parse/Default/Blockquote.php --- a/includes/wikiengine/Parse/Default/Blockquote.php Sun Jun 21 00:16:21 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,179 +0,0 @@ - -* -* @license LGPL -* -* @version $Id: Blockquote.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $ -* -*/ - -/** -* -* Parse for block-quoted text. -* -* Find source text marked as a blockquote, identified by any number of -* greater-than signs '>' at the start of the line, followed by a space, -* and then the quote text; each '>' indicates an additional level of -* quoting. -* -* @category Text -* -* @package Text_Wiki -* -* @author Paul M. Jones -* -*/ - -class Text_Wiki_Parse_Blockquote extends Text_Wiki_Parse { - - - /** - * - * Regex for parsing the source text. - * - * @access public - * - * @var string - * - * @see parse() - * - */ - - var $regex = '/\n((\>).*\n)(?!(\>))/Us'; - - - /** - * - * Generates a replacement for the matched text. - * - * Token options are: - * - * 'type' => - * 'start' : the start of a blockquote - * 'end' : the end of a blockquote - * - * 'level' => the indent level (0 for the first level, 1 for the - * second, etc) - * - * @access public - * - * @param array &$matches The array of matches from parse(). - * - * @return A series of text and delimited tokens marking the different - * list text and list elements. - * - */ - - function process(&$matches) - { - // the replacement text we will return to parse() - $return = ''; - - // the list of post-processing matches - $list = array(); - - // $matches[1] is the text matched as a list set by parse(); - // create an array called $list that contains a new set of - // matches for the various list-item elements. - preg_match_all( - '=^(\>+) (.*\n)=Ums', - $matches[1], - $list, - PREG_SET_ORDER - ); - - // a stack of starts and ends; we keep this so that we know what - // indent level we're at. - $stack = array(); - - // loop through each list-item element. - foreach ($list as $key => $val) { - - // $val[0] is the full matched list-item line - // $val[1] is the number of initial '>' chars (indent level) - // $val[2] is the quote text - - // we number levels starting at 1, not zero - $level = strlen($val[1]); - - // get the text of the line - $text = $val[2]; - - // add a level to the list? - while ($level > count($stack)) { - - // the current indent level is greater than the number - // of stack elements, so we must be starting a new - // level. push the new level onto the stack with a - // dummy value (boolean true)... - array_push($stack, true); - - $return .= "\n"; - - // ...and add a start token to the return. - $return .= $this->wiki->addToken( - $this->rule, - array( - 'type' => 'start', - 'level' => $level - 1 - ) - ); - - $return .= "\n\n"; - } - - // remove a level? - while (count($stack) > $level) { - - // as long as the stack count is greater than the - // current indent level, we need to end list types. - // continue adding end-list tokens until the stack count - // and the indent level are the same. - array_pop($stack); - - $return .= "\n\n"; - - $return .= $this->wiki->addToken( - $this->rule, - array ( - 'type' => 'end', - 'level' => count($stack) - ) - ); - - $return .= "\n"; - } - - // add the line text. - $return .= $text; - } - - // the last line may have been indented. go through the stack - // and create end-tokens until the stack is empty. - $return .= "\n"; - - while (count($stack) > 0) { - array_pop($stack); - $return .= $this->wiki->addToken( - $this->rule, - array ( - 'type' => 'end', - 'level' => count($stack) - ) - ); - } - - // we're done! send back the replacement text. - return "\n$return\n\n"; - } -} -?> \ No newline at end of file diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Parse/Default/Bold.php --- a/includes/wikiengine/Parse/Default/Bold.php Sun Jun 21 00:16:21 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +0,0 @@ - -* -* @license LGPL -* -* @version $Id: Bold.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $ -* -*/ - -/** -* -* Parses for bold text. -* -* This class implements a Text_Wiki_Rule to find source text marked for -* strong emphasis (bold) as defined by text surrounded by three -* single-quotes. On parsing, the text itself is left in place, but the -* starting and ending instances of three single-quotes are replaced with -* tokens. -* -* @category Text -* -* @package Text_Wiki -* -* @author Paul M. Jones -* -*/ - -class Text_Wiki_Parse_Bold extends Text_Wiki_Parse { - - - /** - * - * The regular expression used to parse the source text and find - * matches conforming to this rule. Used by the parse() method. - * - * @access public - * - * @var string - * - * @see parse() - * - */ - - var $regex = "/'''(()|[^'].*)'''/U"; - - - /** - * - * Generates a replacement for the matched text. Token options are: - * - * 'type' => ['start'|'end'] The starting or ending point of the - * emphasized text. The text itself is left in the source. - * - * @access public - * - * @param array &$matches The array of matches from parse(). - * - * @return A pair of delimited tokens to be used as a placeholder in - * the source text surrounding the text to be emphasized. - * - */ - - function process(&$matches) - { - $start = $this->wiki->addToken($this->rule, array('type' => 'start')); - $end = $this->wiki->addToken($this->rule, array('type' => 'end')); - return $start . $matches[1] . $end; - } -} -?> \ No newline at end of file diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Parse/Default/Break.php --- a/includes/wikiengine/Parse/Default/Break.php Sun Jun 21 00:16:21 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ - -* -* @license LGPL -* -* @version $Id: Break.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $ -* -*/ - -/** -* -* Parses for explicit line breaks. -* -* This class implements a Text_Wiki_Parse to mark forced line breaks in the -* source text. -* -* @category Text -* -* @package Text_Wiki -* -* @author Paul M. Jones -* -*/ - -class Text_Wiki_Parse_Break extends Text_Wiki_Parse { - - - /** - * - * The regular expression used to parse the source text and find - * matches conforming to this rule. Used by the parse() method. - * - * @access public - * - * @var string - * - * @see parse() - * - */ - - var $regex = '/ _\n/'; - - - /** - * - * Generates a replacement token for the matched text. - * - * @access public - * - * @param array &$matches The array of matches from parse(). - * - * @return string A delimited token to be used as a placeholder in - * the source text. - * - */ - - function process(&$matches) - { - return $this->wiki->addToken($this->rule); - } -} - -?> \ No newline at end of file diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Parse/Default/Center.php --- a/includes/wikiengine/Parse/Default/Center.php Sun Jun 21 00:16:21 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,78 +0,0 @@ - -* -* @license LGPL -* -* @version $Id: Center.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $ -* -*/ - -/** -* -* Parses for centered lines of text. -* -* This class implements a Text_Wiki_Parse to find lines marked for centering. -* The line must start with "= " (i.e., an equal-sign followed by a space). -* -* @category Text -* -* @package Text_Wiki -* -* @author Paul M. Jones -* -*/ - -class Text_Wiki_Parse_Center extends Text_Wiki_Parse { - - - /** - * - * The regular expression used to find source text matching this - * rule. - * - * @access public - * - * @var string - * - */ - - var $regex = '/\n\= (.*?)\n/'; - - /** - * - * Generates a token entry for the matched text. - * - * @access public - * - * @param array &$matches The array of matches from parse(). - * - * @return A delimited token number to be used as a placeholder in - * the source text. - * - */ - - function process(&$matches) - { - $start = $this->wiki->addToken( - $this->rule, - array('type' => 'start') - ); - - $end = $this->wiki->addToken( - $this->rule, - array('type' => 'end') - ); - - return "\n" . $start . $matches[1] . $end . "\n"; - } -} -?> \ No newline at end of file diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Parse/Default/Code.php --- a/includes/wikiengine/Parse/Default/Code.php Sun Jun 21 00:16:21 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,99 +0,0 @@ - -* -* @license LGPL -* -* @version $Id: Code.php,v 1.10 2006/02/21 14:33:53 toggg Exp $ -* -*/ - -/** -* -* Parses for text marked as a code example block. -* -* This class implements a Text_Wiki_Parse to find sections marked as code -* examples. Blocks are marked as the string on a line by itself, -* followed by the inline code example, and terminated with the string -* on a line by itself. The code example is run through the -* native PHP highlight_string() function to colorize it, then surrounded -* with
...
tags when rendered as XHTML. -* -* @category Text -* -* @package Text_Wiki -* -* @author Paul M. Jones -* -*/ - -class Text_Wiki_Parse_Code extends Text_Wiki_Parse { - - - /** - * - * The regular expression used to find source text matching this - * rule. - * - * @access public - * - * @var string - * - */ - -/* var $regex = '/^(\)\n(.+)\n(\<\/code\>)(\s|$)/Umsi';*/ - var $regex = ';^]*)?>((?:(?R)|.)*?)\n
(\s|$);msi'; - - /** - * - * Generates a token entry for the matched text. Token options are: - * - * 'text' => The full matched text, not including the tags. - * - * @access public - * - * @param array &$matches The array of matches from parse(). - * - * @return A delimited token number to be used as a placeholder in - * the source text. - * - */ - - function process(&$matches) - { - // are there additional attribute arguments? - $args = trim($matches[1]); - - if ($args == '') { - $options = array( - 'text' => $matches[2], - 'attr' => array('type' => '') - ); - } else { - // get the attributes... - $attr = $this->getAttrs($args); - - // ... and make sure we have a 'type' - if (! isset($attr['type'])) { - $attr['type'] = ''; - } - - // retain the options - $options = array( - 'text' => $matches[2], - 'attr' => $attr - ); - } - - return $this->wiki->addToken($this->rule, $options) . $matches[3]; - } -} -?> diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Parse/Default/Colortext.php --- a/includes/wikiengine/Parse/Default/Colortext.php Sun Jun 21 00:16:21 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,89 +0,0 @@ - -* -* @license LGPL -* -* @version $Id: Colortext.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $ -* -*/ - -/** -* -* Parses for colorized text. -* -* @category Text -* -* @package Text_Wiki -* -* @author Paul M. Jones -* -*/ - -class Text_Wiki_Parse_Colortext extends Text_Wiki_Parse { - - /** - * - * The regular expression used to parse the source text and find - * matches conforming to this rule. Used by the parse() method. - * - * @access public - * - * @var string - * - * @see parse() - * - */ - - var $regex = "/\#\#(.+?)\|(.+?)\#\#/"; - - - /** - * - * Generates a replacement for the matched text. Token options are: - * - * 'type' => ['start'|'end'] The starting or ending point of the - * emphasized text. The text itself is left in the source. - * - * 'color' => the color indicator - * - * @access public - * - * @param array &$matches The array of matches from parse(). - * - * @return string A pair of delimited tokens to be used as a - * placeholder in the source text surrounding the text to be - * emphasized. - * - */ - - function process(&$matches) - { - $start = $this->wiki->addToken( - $this->rule, - array( - 'type' => 'start', - 'color' => $matches[1] - ) - ); - - $end = $this->wiki->addToken( - $this->rule, - array( - 'type' => 'end', - 'color' => $matches[1] - ) - ); - - return $start . $matches[2] . $end; - } -} -?> \ No newline at end of file diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Parse/Default/Deflist.php --- a/includes/wikiengine/Parse/Default/Deflist.php Sun Jun 21 00:16:21 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,122 +0,0 @@ - -* -* @license LGPL -* -* @version $Id: Deflist.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $ -* -*/ - -/** -* -* Parses for definition lists. -* -* This class implements a Text_Wiki_Parse to find source text marked as a -* definition list. In short, if a line starts with ':' then it is a -* definition list item; another ':' on the same line indicates the end -* of the definition term and the beginning of the definition narrative. -* The list items must be on sequential lines (no blank lines between -* them) -- a blank line indicates the beginning of a new list. -* -* @category Text -* -* @package Text_Wiki -* -* @author Paul M. Jones -* -*/ - -class Text_Wiki_Parse_Deflist extends Text_Wiki_Parse { - - - /** - * - * The regular expression used to parse the source text and find - * matches conforming to this rule. Used by the parse() method. - * - * @access public - * - * @var string - * - * @see parse() - * - */ - - var $regex = '/\n((: ).*\n)(?!(: |\n))/Us'; - - - /** - * - * Generates a replacement for the matched text. Token options are: - * - * 'type' => - * 'list_start' : the start of a definition list - * 'list_end' : the end of a definition list - * 'term_start' : the start of a definition term - * 'term_end' : the end of a definition term - * 'narr_start' : the start of definition narrative - * 'narr_end' : the end of definition narrative - * 'unknown' : unknown type of definition portion - * - * @access public - * - * @param array &$matches The array of matches from parse(). - * - * @return A series of text and delimited tokens marking the different - * list text and list elements. - * - */ - - function process(&$matches) - { - // the replacement text we will return to parse() - $return = ''; - - // the list of post-processing matches - $list = array(); - - // start the deflist - $options = array('type' => 'list_start'); - $return .= $this->wiki->addToken($this->rule, $options); - - // $matches[1] is the text matched as a list set by parse(); - // create an array called $list that contains a new set of - // matches for the various definition-list elements. - preg_match_all( - '/^(: )(.*)?( : )(.*)?$/Ums', - $matches[1], - $list, - PREG_SET_ORDER - ); - - // add each term and narrative - foreach ($list as $key => $val) { - $return .= ( - $this->wiki->addToken($this->rule, array('type' => 'term_start')) . - trim($val[2]) . - $this->wiki->addToken($this->rule, array('type' => 'term_end')) . - $this->wiki->addToken($this->rule, array('type' => 'narr_start')) . - trim($val[4]) . - $this->wiki->addToken($this->rule, array('type' => 'narr_end')) - ); - } - - - // end the deflist - $options = array('type' => 'list_end'); - $return .= $this->wiki->addToken($this->rule, $options); - - // done! - return "\n" . $return . "\n\n"; - } -} -?> \ No newline at end of file diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Parse/Default/Delimiter.php --- a/includes/wikiengine/Parse/Default/Delimiter.php Sun Jun 21 00:16:21 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,80 +0,0 @@ - -* -* @license LGPL -* -* @version $Id: Delimiter.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $ -* -*/ - -/** -* -* Parses for Text_Wiki delimiter characters already in the source text. -* -* This class implements a Text_Wiki_Parse to find instances of the delimiter -* character already embedded in the source text; it extracts them and replaces -* them with a delimited token, then renders them as the delimiter itself -* when the target format is XHTML. -* -* @category Text -* -* @package Text_Wiki -* -* @author Paul M. Jones -* -*/ - -class Text_Wiki_Parse_Delimiter extends Text_Wiki_Parse { - - /** - * - * Constructor. Overrides the Text_Wiki_Parse constructor so that we - * can set the $regex property dynamically (we need to include the - * Text_Wiki $delim character. - * - * @param object &$obj The calling "parent" Text_Wiki object. - * - * @param string $name The token name to use for this rule. - * - */ - - function Text_Wiki_Parse_delimiter(&$obj) - { - parent::Text_Wiki_Parse($obj); - $this->regex = '/' . $this->wiki->delim . '/'; - } - - - /** - * - * Generates a token entry for the matched text. Token options are: - * - * 'text' => The full matched text. - * - * @access public - * - * @param array &$matches The array of matches from parse(). - * - * @return A delimited token number to be used as a placeholder in - * the source text. - * - */ - - function process(&$matches) - { - return $this->wiki->addToken( - $this->rule, - array('text' => $this->wiki->delim) - ); - } -} -?> \ No newline at end of file diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Parse/Default/Embed.php --- a/includes/wikiengine/Parse/Default/Embed.php Sun Jun 21 00:16:21 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,106 +0,0 @@ - -* -* @license LGPL -* -* @version $Id: Embed.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $ -* -*/ - -/** -* -* Embeds the results of a PHP script at render-time. -* -* This class implements a Text_Wiki_Parse to embed the contents of a URL -* inside the page at render-time. Typically used to get script output. -* This differs from the 'include' rule, which incorporates results at -* parse-time; 'embed' output does not get parsed by Text_Wiki, while -* 'include' ouput does. -* -* This rule is inherently not secure; it allows cross-site scripting to -* occur if the embedded output has -'; - } - } else { - $js = ''; - } - return $js.' -
-'; - case 'endContent': - return ' -
-'; - } - } -} -?> diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Render/Xhtml/Horiz.php --- a/includes/wikiengine/Render/Xhtml/Horiz.php Sun Jun 21 00:16:21 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version CVS: $Id: Horiz.php,v 1.7 2005/07/30 08:03:28 toggg Exp $ - * @link http://pear.php.net/package/Text_Wiki - */ - -/** - * This class renders an horizontal bar in XHTML. - * - * @category Text - * @package Text_Wiki - * @author Paul M. Jones - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version Release: @package_version@ - * @link http://pear.php.net/package/Text_Wiki - */ -class Text_Wiki_Render_Xhtml_Horiz extends Text_Wiki_Render { - - var $conf = array( - 'css' => null - ); - - /** - * - * Renders a token into text matching the requested format. - * - * @access public - * - * @param array $options The "options" portion of the token (second - * element). - * - * @return string The text rendered from the token options. - * - */ - - function token($options) - { - $css = $this->formatConf(' class="%s"', 'css'); - return "\n"; - } -} -?> diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Render/Xhtml/Html.php --- a/includes/wikiengine/Render/Xhtml/Html.php Sun Jun 21 00:16:21 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version CVS: $Id: Html.php,v 1.5 2005/07/30 08:03:28 toggg Exp $ - * @link http://pear.php.net/package/Text_Wiki - */ - -/** - * This class renders preformated html in XHTML. - * - * @category Text - * @package Text_Wiki - * @author Paul M. Jones - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version Release: @package_version@ - * @link http://pear.php.net/package/Text_Wiki - */ -class Text_Wiki_Render_Xhtml_Html extends Text_Wiki_Render { - - - /** - * - * Renders a token into text matching the requested format. - * - * @access public - * - * @param array $options The "options" portion of the token (second - * element). - * - * @return string The text rendered from the token options. - * - */ - - function token($options) - { - return $options['text']; - } -} -?> diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Render/Xhtml/Image.php --- a/includes/wikiengine/Render/Xhtml/Image.php Sun Jun 21 00:16:21 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,180 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version CVS: $Id: Image.php,v 1.16 2006/02/10 23:07:03 toggg Exp $ - * @link http://pear.php.net/package/Text_Wiki - */ - -/** - * This class inserts an image in XHTML. - * - * @category Text - * @package Text_Wiki - * @author Paul M. Jones - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version Release: @package_version@ - * @link http://pear.php.net/package/Text_Wiki - */ -class Text_Wiki_Render_Xhtml_Image extends Text_Wiki_Render { - - var $conf = array( - 'base' => '/', - 'url_base' => null, - 'css' => null, - 'css_link' => null - ); - - - /** - * - * Renders a token into text matching the requested format. - * - * @access public - * - * @param array $options The "options" portion of the token (second - * element). - * - * @return string The text rendered from the token options. - * - */ - - function token($options) - { - // note the image source - $src = $options['src']; - - // is the source a local file or URL? - if (strpos($src, '://') === false) { - // the source refers to a local file. - // add the URL base to it. - $src = $this->getConf('base', '/') . $src; - } - - // stephane@metacites.net - // is the image clickable? - if (isset($options['attr']['link'])) { - // yes, the image is clickable. - // are we linked to a URL or a wiki page? - if (strpos($options['attr']['link'], '://')) { - // it's a URL, prefix the URL base - $href = $this->getConf('url_base') . $options['attr']['link']; - } else { - // it's a WikiPage; assume it exists. - /** @todo This needs to honor sprintf wikilinks (pmjones) */ - /** @todo This needs to honor interwiki (pmjones) */ - /** @todo This needs to honor freelinks (pmjones) */ - $href = $this->wiki->getRenderConf('xhtml', 'wikilink', 'view_url') . - $options['attr']['link']; - } - } else { - // image is not clickable. - $href = null; - } - // unset so it won't show up as an attribute - unset($options['attr']['link']); - - // stephane@metacites.net -- 25/07/2004 - // we make up an align="center" value for the tag. - if (isset($options['attr']['align']) && - $options['attr']['align'] == 'center') { - - // unset so it won't show up as an attribute - unset($options['attr']['align']); - - // make sure we have a style attribute - if (! isset($options['attr']['style'])) { - // no style, set up a blank one - $options['attr']['style'] = ''; - } else { - // style exists, add a space - $options['attr']['style'] .= ' '; - } - - // add a "center" style to the existing style. - $options['attr']['style'] .= - 'display: block; margin-left: auto; margin-right: auto;'; - } - - // stephane@metacites.net -- 25/07/2004 - // try to guess width and height - if (! isset($options['attr']['width']) && - ! isset($options['attr']['height'])) { - - // does the source refer to a local file or a URL? - if (strpos($src,'://')) { - // is a URL link - $imageFile = $src; - } elseif ($src[0] == '.') { - // reg at dav-muz dot net -- 2005-03-07 - // is a local file on relative path. - $imageFile = $src; # ...don't do anything because it's perfect! - } else { - // is a local file on absolute path. - $imageFile = $_SERVER['DOCUMENT_ROOT'] . $src; - } - - // attempt to get the image size - $imageSize = @getimagesize($imageFile); - - if (is_array($imageSize)) { - $options['attr']['width'] = $imageSize[0]; - $options['attr']['height'] = $imageSize[1]; - } - - } - - // start the HTML output - $output = 'formatConf(' class="%s"', 'css'); - - // add the attributes to the output, and be sure to - // track whether or not we find an "alt" attribute - $alt = false; - foreach ($options['attr'] as $key => $val) { - - // track the 'alt' attribute - if (strtolower($key) == 'alt') { - $alt = true; - } - - // the 'class' attribute overrides the CSS class conf - if (strtolower($key) == 'class') { - $css = null; - } - - $key = $this->textEncode($key); - $val = $this->textEncode($val); - $output .= " $key=\"$val\""; - } - - // always add an "alt" attribute per Stephane Solliec - if (! $alt) { - $alt = $this->textEncode(basename($options['src'])); - $output .= " alt=\"$alt\""; - } - - // end the image tag with the automatic CSS class (if any) - $output .= "$css />"; - - // was the image clickable? - if ($href) { - // yes, add the href and return - $href = $this->textEncode($href); - $css = $this->formatConf(' class="%s"', 'css_link'); - $output = "$output"; - } - - return $output; - } -} -?> diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Render/Xhtml/Include.php --- a/includes/wikiengine/Render/Xhtml/Include.php Sun Jun 21 00:16:21 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version CVS: $Id: Include.php,v 1.6 2005/07/30 08:03:28 toggg Exp $ - * @link http://pear.php.net/package/Text_Wiki - */ - -/** - * This class renders included maekup in XHTML. (empty) - * - * @category Text - * @package Text_Wiki - * @author Paul M. Jones - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version Release: @package_version@ - * @link http://pear.php.net/package/Text_Wiki - */ -class Text_Wiki_Render_Xhtml_Include extends Text_Wiki_Render { - function token() - { - return ''; - } -} -?> diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Render/Xhtml/Interwiki.php --- a/includes/wikiengine/Render/Xhtml/Interwiki.php Sun Jun 21 00:16:21 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,103 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version CVS: $Id: Interwiki.php,v 1.14 2006/02/25 05:03:13 toggg Exp $ - * @link http://pear.php.net/package/Text_Wiki - */ - -/** - * This class renders inter wikis links in XHTML. - * - * @category Text - * @package Text_Wiki - * @author Paul M. Jones - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version Release: @package_version@ - * @link http://pear.php.net/package/Text_Wiki - */ -class Text_Wiki_Render_Xhtml_Interwiki extends Text_Wiki_Render { - - var $conf = array( - 'sites' => array( - 'MeatBall' => 'http://www.usemod.com/cgi-bin/mb.pl?%s', - 'Advogato' => 'http://advogato.org/%s', - 'Wiki' => 'http://c2.com/cgi/wiki?%s' - ), - 'target' => '_blank', - 'css' => null - ); - - - /** - * - * Renders a token into text matching the requested format. - * - * @access public - * - * @param array $options The "options" portion of the token (second - * element). - * - * @return string The text rendered from the token options. - * - */ - - function token($options) - { - $text = $options['text']; - if (isset($options['url'])) { - // calculated by the parser (e.g. Mediawiki) - $href = $options['url']; - } else { - $site = $options['site']; - // toggg 2006/02/05 page name must be url encoded (e.g. may contain spaces) - $page = $this->urlEncode($options['page']); - - if (isset($this->conf['sites'][$site])) { - $href = $this->conf['sites'][$site]; - } else { - return $text; - } - - // old form where page is at end, - // or new form with %s placeholder for sprintf()? - if (strpos($href, '%s') === false) { - // use the old form - $href = $href . $page; - } else { - // use the new form - $href = sprintf($href, $page); - } - } - - // allow for alternative targets - $target = $this->getConf('target'); - - // build base link - $css = $this->formatConf(' class="%s"', 'css'); - $text = $this->textEncode($text); - $output = "textEncode($target); - $output .= " onclick=\"window.open(this.href, '$target');"; - $output .= " return false;\""; - } - - $output .= ">$text"; - - return $output; - } -} -?> diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Render/Xhtml/Italic.php --- a/includes/wikiengine/Render/Xhtml/Italic.php Sun Jun 21 00:16:21 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version CVS: $Id: Italic.php,v 1.7 2005/07/30 08:03:28 toggg Exp $ - * @link http://pear.php.net/package/Text_Wiki - */ - -/** - * This class renders italic text in XHTML. - * - * @category Text - * @package Text_Wiki - * @author Paul M. Jones - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version Release: @package_version@ - * @link http://pear.php.net/package/Text_Wiki - */ -class Text_Wiki_Render_Xhtml_Italic extends Text_Wiki_Render { - - var $conf = array( - 'css' => null - ); - - /** - * - * Renders a token into text matching the requested format. - * - * @access public - * - * @param array $options The "options" portion of the token (second - * element). - * - * @return string The text rendered from the token options. - * - */ - - function token($options) - { - if ($options['type'] == 'start') { - $css = $this->formatConf(' class="%s"', 'css'); - return ""; - } - - if ($options['type'] == 'end') { - return ''; - } - } -} -?> diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Render/Xhtml/List.php --- a/includes/wikiengine/Render/Xhtml/List.php Sun Jun 21 00:16:21 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,172 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version CVS: $Id: List.php,v 1.9 2005/11/06 10:38:22 toggg Exp $ - * @link http://pear.php.net/package/Text_Wiki - */ - -/** - * This class renders bullet and ordered lists in XHTML. - * - * @category Text - * @package Text_Wiki - * @author Paul M. Jones - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version Release: @package_version@ - * @link http://pear.php.net/package/Text_Wiki - */ -class Text_Wiki_Render_Xhtml_List extends Text_Wiki_Render { - - var $conf = array( - 'css_ol' => null, - 'css_ol_li' => null, - 'css_ul' => null, - 'css_ul_li' => null - ); - - /** - * - * Renders a token into text matching the requested format. - * - * This rendering method is syntactically and semantically compliant - * with XHTML 1.1 in that sub-lists are part of the previous list item. - * - * @access public - * - * @param array $options The "options" portion of the token (second - * element). - * - * @return string The text rendered from the token options. - * - */ - - function token($options) - { - // make nice variables (type, level, count) - extract($options); - - // set up indenting so that the results look nice; we do this - // in two steps to avoid str_pad mathematics. ;-) - $pad = str_pad('', $level, "\t"); - $pad = str_replace("\t", ' ', $pad); - - switch ($type) { - - case 'bullet_list_start': - - // build the base HTML - $css = $this->formatConf(' class="%s"', 'css_ul'); - $html = ""; - - /* - // if this is the opening block for the list, - // put an extra newline in front of it so the - // output looks nice. - if ($level == 0) { - $html = "\n$html"; - } - */ - - // done! - return $html; - break; - - case 'bullet_list_end': - - // build the base HTML - $html = "\n$pad"; - - // if this is the closing block for the list, - // put extra newlines after it so the output - // looks nice. - if ($level == 0) { - $html .= "\n\n"; - } - - // done! - return $html; - break; - - case 'number_list_start': - if (isset($format)) { - $format = ' type="' . $format . '"'; - } else { - $format = ''; - } - // build the base HTML - $css = $this->formatConf(' class="%s"', 'css_ol'); - $html = ""; - - /* - // if this is the opening block for the list, - // put an extra newline in front of it so the - // output looks nice. - if ($level == 0) { - $html = "\n$html"; - } - */ - - // done! - return $html; - break; - - case 'number_list_end': - - // build the base HTML - $html = "\n$pad"; - - // if this is the closing block for the list, - // put extra newlines after it so the output - // looks nice. - if ($level == 0) { - $html .= "\n\n"; - } - - // done! - return $html; - break; - - case 'bullet_item_start': - case 'number_item_start': - - // pick the proper CSS class - if ($type == 'bullet_item_start') { - $css = $this->formatConf(' class="%s"', 'css_ul_li'); - } else { - $css = $this->formatConf(' class="%s"', 'css_ol_li'); - } - - // build the base HTML - $html = "\n$pad"; - - // for the very first item in the list, do nothing. - // but for additional items, be sure to close the - // previous item. - if ($count > 0) { - $html = "$html"; - } - - // done! - return $html; - break; - - case 'bullet_item_end': - case 'number_item_end': - default: - // ignore item endings and all other types. - // item endings are taken care of by the other types - // depending on their place in the list. - return ''; - break; - } - } -} -?> diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Render/Xhtml/Newline.php --- a/includes/wikiengine/Render/Xhtml/Newline.php Sun Jun 21 00:16:21 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version CVS: $Id: Newline.php,v 1.5 2005/07/30 08:03:29 toggg Exp $ - * @link http://pear.php.net/package/Text_Wiki - */ - -/** - * This class renders new lines in XHTML. - * - * @category Text - * @package Text_Wiki - * @author Paul M. Jones - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version Release: @package_version@ - * @link http://pear.php.net/package/Text_Wiki - */ -class Text_Wiki_Render_Xhtml_Newline extends Text_Wiki_Render { - - - function token($options) - { - return "
\n"; - } -} - -?> diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Render/Xhtml/Page.php --- a/includes/wikiengine/Render/Xhtml/Page.php Sun Jun 21 00:16:21 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version CVS: $Id: Page.php,v 1.2 2005/07/30 08:03:29 toggg Exp $ - * @link http://pear.php.net/package/Text_Wiki - */ - -/** - * This class renders page markers in XHTML. - * - * @category Text - * @package Text_Wiki - * @author Paul M. Jones - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version Release: @package_version@ - * @link http://pear.php.net/package/Text_Wiki - */ -class Text_Wiki_Render_Xhtml_Page extends Text_Wiki_Render { - - /** - * - * Renders a token into text matching the requested format. - * - * @access public - * - * @param array $options The "options" portion of the token (second - * element). - * - * @return string The text rendered from the token options. - * - */ - - function token($options) - { - return 'PAGE MARKER HERE*&^%$#^$%*PAGEMARKERHERE'; - } -} -?> diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Render/Xhtml/Paragraph.php --- a/includes/wikiengine/Render/Xhtml/Paragraph.php Sun Jun 21 00:16:21 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version CVS: $Id: Paragraph.php,v 1.7 2005/07/30 08:03:29 toggg Exp $ - * @link http://pear.php.net/package/Text_Wiki - */ - -/** - * This class renders paragraphs in XHTML. - * - * @category Text - * @package Text_Wiki - * @author Paul M. Jones - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version Release: @package_version@ - * @link http://pear.php.net/package/Text_Wiki - */ -class Text_Wiki_Render_Xhtml_Paragraph extends Text_Wiki_Render { - - var $conf = array( - 'css' => null - ); - - /** - * - * Renders a token into text matching the requested format. - * - * @access public - * - * @param array $options The "options" portion of the token (second - * element). - * - * @return string The text rendered from the token options. - * - */ - - function token($options) - { - extract($options); //type - - if ($type == 'start') { - $css = $this->formatConf(' class="%s"', 'css'); - return ""; - } - - if ($type == 'end') { - return "

\n\n"; - } - } -} -?> diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Render/Xhtml/Phplookup.php --- a/includes/wikiengine/Render/Xhtml/Phplookup.php Sun Jun 21 00:16:21 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,81 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version CVS: $Id: Phplookup.php,v 1.11 2006/02/10 23:07:03 toggg Exp $ - * @link http://pear.php.net/package/Text_Wiki - */ - -/** - * This class renders a link to php functions description in XHTML. - * - * @category Text - * @package Text_Wiki - * @author Paul M. Jones - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version Release: @package_version@ - * @link http://pear.php.net/package/Text_Wiki - */ -class Text_Wiki_Render_Xhtml_Phplookup extends Text_Wiki_Render { - - var $conf = array( - 'target' => '_blank', - 'css' => null - ); - - - /** - * - * Renders a token into text matching the requested format. - * - * @access public - * - * @param array $options The "options" portion of the token (second - * element). - * - * @return string The text rendered from the token options. - * - */ - - function token($options) - { - $text = trim($options['text']); - $css = $this->formatConf(' class="%s"', 'css'); - - // start the html - $output = "getConf('target', ''); - if ($target) { - // use a "popup" window. this is XHTML compliant, suggested by - // Aaron Kalin. uses the $target as the new window name. - $target = $this->textEncode($target); - $output .= " onclick=\"window.open(this.href, '$target');"; - $output .= " return false;\""; - } - - // take off the final parens for functions - if (substr($text, -2) == '()') { - $q = substr($text, 0, -2); - } else { - $q = $text; - } - - // toggg 2006/02/05 page name must be url encoded (e.g. may contain spaces) - $q = $this->urlEncode($q); - $text = $this->textEncode($text); - - // finish and return - $output .= " href=\"http://php.net/$q\">$text"; - return $output; - } -} -?> diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Render/Xhtml/Plugin.php --- a/includes/wikiengine/Render/Xhtml/Plugin.php Sun Jun 21 00:16:21 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version CVS: $Id: Plugin.php,v 1.2 2005/07/30 08:03:29 toggg Exp $ - * @link http://pear.php.net/package/Text_Wiki - */ - -/** - * This class renders wiki plugins in XHTML. (empty) - * - * @category Text - * @package Text_Wiki - * @author Paul M. Jones - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version Release: @package_version@ - * @link http://pear.php.net/package/Text_Wiki - */ -class Text_Wiki_Render_Xhtml_Plugin extends Text_Wiki_Render { - - /** - * - * Renders a token into text matching the requested format. - * Plugins produce wiki markup so are processed by parsing, no tokens produced - * - * @access public - * - * @param array $options The "options" portion of the token (second - * element). - * - * @return string The text rendered from the token options. - * - */ - - function token($options) - { - return ''; - } -} -?> diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Render/Xhtml/Prefilter.php --- a/includes/wikiengine/Render/Xhtml/Prefilter.php Sun Jun 21 00:16:21 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version CVS: $Id: Prefilter.php,v 1.7 2005/07/30 08:03:29 toggg Exp $ - * @link http://pear.php.net/package/Text_Wiki - */ - -/** - * This class implements a Text_Wiki_Render_Xhtml to "pre-filter" source text so - * that line endings are consistently \n, lines ending in a backslash \ - * are concatenated with the next line, and tabs are converted to spaces. - * - * @category Text - * @package Text_Wiki - * @author Paul M. Jones - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version Release: @package_version@ - * @link http://pear.php.net/package/Text_Wiki - */ -class Text_Wiki_Render_Xhtml_Prefilter extends Text_Wiki_Render { - function token() - { - return ''; - } -} -?> diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Render/Xhtml/Preformatted.php --- a/includes/wikiengine/Render/Xhtml/Preformatted.php Sun Jun 21 00:16:21 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version CVS: $Id: Preformatted.php,v 1.2 2005/07/30 08:03:29 toggg Exp $ - * @link http://pear.php.net/package/Text_Wiki - */ - -/** - * This class renders preformated text in XHTML. - * - * @category Text - * @package Text_Wiki - * @author Paul M. Jones - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version Release: @package_version@ - * @link http://pear.php.net/package/Text_Wiki - */ -class Text_Wiki_Render_Xhtml_Preformatted extends Text_Wiki_Render { - - /** - * - * Renders a token into text matching the requested format. - * - * @access public - * - * @param array $options The "options" portion of the token (second - * element). - * - * @return string The text rendered from the token options. - * - */ - - function token($options) - { - return '
'.$options['text'].'
'; - } -} -?> diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Render/Xhtml/Raw.php --- a/includes/wikiengine/Render/Xhtml/Raw.php Sun Jun 21 00:16:21 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version CVS: $Id: Raw.php,v 1.5 2005/07/30 08:03:29 toggg Exp $ - * @link http://pear.php.net/package/Text_Wiki - */ - -/** - * This class renders not processed blocks in XHTML. - * - * @category Text - * @package Text_Wiki - * @author Paul M. Jones - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version Release: @package_version@ - * @link http://pear.php.net/package/Text_Wiki - */ -class Text_Wiki_Render_Xhtml_Raw extends Text_Wiki_Render { - - /** - * - * Renders a token into text matching the requested format. - * - * @access public - * - * @param array $options The "options" portion of the token (second - * element). - * - * @return string The text rendered from the token options. - * - */ - - function token($options) - { - return $options['text']; - } -} -?> diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Render/Xhtml/Revise.php --- a/includes/wikiengine/Render/Xhtml/Revise.php Sun Jun 21 00:16:21 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version CVS: $Id: Revise.php,v 1.7 2005/07/30 08:03:29 toggg Exp $ - * @link http://pear.php.net/package/Text_Wiki - */ - -/** - * This class renders revision marks in XHTML. - * - * @category Text - * @package Text_Wiki - * @author Paul M. Jones - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version Release: @package_version@ - * @link http://pear.php.net/package/Text_Wiki - */ -class Text_Wiki_Render_Xhtml_Revise extends Text_Wiki_Render { - - var $conf = array( - 'css_ins' => null, - 'css_del' => null - ); - - - /** - * - * Renders a token into text matching the requested format. - * - * @access public - * - * @param array $options The "options" portion of the token (second - * element). - * - * @return string The text rendered from the token options. - * - */ - - function token($options) - { - if ($options['type'] == 'del_start') { - $css = $this->formatConf(' class="%s"', 'css_del'); - return ""; - } - - if ($options['type'] == 'del_end') { - return ""; - } - - if ($options['type'] == 'ins_start') { - $css = $this->formatConf(' class="%s"', 'css_ins'); - return ""; - } - - if ($options['type'] == 'ins_end') { - return ""; - } - } -} -?> diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Render/Xhtml/Smiley.php --- a/includes/wikiengine/Render/Xhtml/Smiley.php Sun Jun 21 00:16:21 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,74 +0,0 @@ - - * @copyright 2005 bertrand Gugger - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version CVS: $Id: Smiley.php,v 1.2 2006/02/10 23:07:03 toggg Exp $ - * @link http://pear.php.net/package/Text_Wiki - */ - -/** - * Smiley rule Xhtml render class - * - * @category Text - * @package Text_Wiki - * @author Bertrand Gugger - * @copyright 2005 bertrand Gugger - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version Release: @package_version@ - * @link http://pear.php.net/package/Text_Wiki - * @see Text_Wiki::Text_Wiki_Render() - */ -class Text_Wiki_Render_Xhtml_Smiley extends Text_Wiki_Render { - - /** - * Configuration keys for this rule - * 'prefix' => the path to smileys images inclusive file name prefix, - * starts with '/' ==> abolute reference - * if no file names prefix but some folder, terminates with '/' - * 'extension' => the file extension (inclusive '.'), e.g. : - * if prefix 'smileys/icon_' and extension '.gif' - * ':)' whose name is 'smile' will give relative file 'smileys/icon_smile.gif' - * if prefix '/image/smileys/' and extension '.png': absolute '/image/smileys/smile.gif' - * 'css' => optional style applied to smileys - * - * @access public - * @var array 'config-key' => mixed config-value - */ - var $conf = array( - 'prefix' => 'images/smiles/icon_', - 'extension' => '.gif', - 'css' => null - ); - - /** - * Renders a token into text matching the requested format. - * process the Smileys - * - * @access public - * @param array $options The "options" portion of the token (second element). - * @return string The text rendered from the token options. - */ - function token($options) - { - $imageFile = $this->getConf('prefix') . $options['name'] . $this->getConf('extension'); - - // attempt to get the image size - $imageSize = @getimagesize($imageFile); - - // return the HTML output - return '' . $options['desc'] . 'formatConf(' class="%s"', 'css') . ' />'; - } -} -?> diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Render/Xhtml/Specialchar.php --- a/includes/wikiengine/Render/Xhtml/Specialchar.php Sun Jun 21 00:16:21 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version CVS: $Id: Specialchar.php,v 1.2 2005/07/30 08:03:29 toggg Exp $ - * @link http://pear.php.net/package/Text_Wiki - */ - -/** - * This class renders special characters in XHTML. - * - * @category Text - * @package Text_Wiki - * @author Paul M. Jones - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version Release: @package_version@ - * @link http://pear.php.net/package/Text_Wiki - */ -class Text_Wiki_Render_Xhtml_SpecialChar extends Text_Wiki_Render { - - var $types = array('~bs~' => '\', - '~hs~' => ' ', - '~amp~' => '&', - '~ldq~' => '“', - '~rdq~' => '”', - '~lsq~' => '‘', - '~rsq~' => '’', - '~c~' => '©', - '~--~' => '—', - '" -- "' => '—', - '" -- "' => '—', - '~lt~' => '<', - '~gt~' => '>'); - - function token($options) - { - if (isset($this->types[$options['char']])) { - return $this->types[$options['char']]; - } else { - return '&#'.substr($options['char'], 1, -1).';'; - } - } -} - -?> diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Render/Xhtml/Strong.php --- a/includes/wikiengine/Render/Xhtml/Strong.php Sun Jun 21 00:16:21 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version CVS: $Id: Strong.php,v 1.7 2005/07/30 08:03:29 toggg Exp $ - * @link http://pear.php.net/package/Text_Wiki - */ - -/** - * This class renders text marked as strong in XHTML. - * - * @category Text - * @package Text_Wiki - * @author Paul M. Jones - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version Release: @package_version@ - * @link http://pear.php.net/package/Text_Wiki - */ -class Text_Wiki_Render_Xhtml_Strong extends Text_Wiki_Render { - - - var $conf = array( - 'css' => null - ); - - /** - * - * Renders a token into text matching the requested format. - * - * @access public - * - * @param array $options The "options" portion of the token (second - * element). - * - * @return string The text rendered from the token options. - * - */ - - function token($options) - { - if ($options['type'] == 'start') { - $css = $this->formatConf(' class="%s"', 'css'); - return ""; - } - - if ($options['type'] == 'end') { - return ''; - } - } -} -?> diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Render/Xhtml/Subscript.php --- a/includes/wikiengine/Render/Xhtml/Subscript.php Sun Jun 21 00:16:21 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version CVS: $Id: Subscript.php,v 1.2 2005/07/30 08:03:29 toggg Exp $ - * @link http://pear.php.net/package/Text_Wiki - */ - -/** - * This class renders subscript text in XHTML. - * - * @category Text - * @package Text_Wiki - * @author Paul M. Jones - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version Release: @package_version@ - * @link http://pear.php.net/package/Text_Wiki - */ -class Text_Wiki_Render_Xhtml_Subscript extends Text_Wiki_Render { - - var $conf = array( - 'css' => null - ); - - /** - * - * Renders a token into text matching the requested format. - * - * @access public - * - * @param array $options The "options" portion of the token (second - * element). - * - * @return string The text rendered from the token options. - * - */ - - function token($options) - { - if ($options['type'] == 'start') { - $css = $this->formatConf(' class="%s"', 'css'); - return ""; - } - - if ($options['type'] == 'end') { - return ''; - } - } -} -?> diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Render/Xhtml/Superscript.php --- a/includes/wikiengine/Render/Xhtml/Superscript.php Sun Jun 21 00:16:21 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version CVS: $Id: Superscript.php,v 1.7 2005/07/30 08:03:29 toggg Exp $ - * @link http://pear.php.net/package/Text_Wiki - */ - -/** - * This class renders superscript text in XHTML. - * - * @category Text - * @package Text_Wiki - * @author Paul M. Jones - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version Release: @package_version@ - * @link http://pear.php.net/package/Text_Wiki - */ -class Text_Wiki_Render_Xhtml_Superscript extends Text_Wiki_Render { - - var $conf = array( - 'css' => null - ); - - /** - * - * Renders a token into text matching the requested format. - * - * @access public - * - * @param array $options The "options" portion of the token (second - * element). - * - * @return string The text rendered from the token options. - * - */ - - function token($options) - { - if ($options['type'] == 'start') { - $css = $this->formatConf(' class="%s"', 'css'); - return ""; - } - - if ($options['type'] == 'end') { - return ''; - } - } -} -?> diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Render/Xhtml/Table.php --- a/includes/wikiengine/Render/Xhtml/Table.php Sun Jun 21 00:16:21 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,140 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version CVS: $Id: Table.php,v 1.12 2005/12/06 15:29:29 ritzmo Exp $ - * @link http://pear.php.net/package/Text_Wiki - */ - -/** - * This class renders tables in XHTML. - * - * @category Text - * @package Text_Wiki - * @author Paul M. Jones - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version Release: @package_version@ - * @link http://pear.php.net/package/Text_Wiki - */ -class Text_Wiki_Render_Xhtml_Table extends Text_Wiki_Render { - - var $conf = array( - 'css_table' => null, - 'css_caption' => null, - 'css_tr' => null, - 'css_th' => null, - 'css_td' => null - ); - - - /** - * - * Renders a token into text matching the requested format. - * - * @access public - * - * @param array $options The "options" portion of the token (second - * element). - * - * @return string The text rendered from the token options. - * - */ - - function token($options) - { - // make nice variable names (type, attr, span) - $span = $rowspan = 1; - extract($options); - - // free format - $format = isset($format) ? ' '. $format : ''; - - $pad = ' '; - - switch ($type) { - - case 'table_start': - $css = $this->formatConf(' class="%s"', 'css_table'); - return "\n\n\n"; - break; - - case 'table_end': - return "\n\n"; - break; - - case 'caption_start': - $css = $this->formatConf(' class="%s"', 'css_caption'); - return "\n"; - break; - - case 'caption_end': - return "\n"; - break; - - case 'row_start': - $css = $this->formatConf(' class="%s"', 'css_tr'); - return "$pad\n"; - break; - - case 'row_end': - return "$pad\n"; - break; - - case 'cell_start': - - // base html - $html = $pad . $pad; - - // is this a TH or TD cell? - if ($attr == 'header') { - // start a header cell - $css = $this->formatConf(' class="%s"', 'css_th'); - $html .= "formatConf(' class="%s"', 'css_td'); - $html .= " 1) { - $html .= " colspan=\"$span\""; - } - - // add the row span - if ($rowspan > 1) { - $html .= " rowspan=\"$rowspan\""; - } - - // add alignment - if ($attr != 'header' && $attr != '') { - $html .= " style=\"text-align: $attr;\""; - } - - // done! - $html .= "$format>"; - return $html; - break; - - case 'cell_end': - if ($attr == 'header') { - return "\n"; - } else { - return "\n"; - } - break; - - default: - return ''; - - } - } -} -?> diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Render/Xhtml/Tighten.php --- a/includes/wikiengine/Render/Xhtml/Tighten.php Sun Jun 21 00:16:21 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version CVS: $Id: Tighten.php,v 1.6 2005/07/30 08:03:29 toggg Exp $ - * @link http://pear.php.net/package/Text_Wiki - */ - -/** - * This class makes the tightening in XHTML. (empty) - * - * @category Text - * @package Text_Wiki - * @author Paul M. Jones - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version Release: @package_version@ - * @link http://pear.php.net/package/Text_Wiki - */ -class Text_Wiki_Render_Xhtml_Tighten extends Text_Wiki_Render { - - - function token() - { - return ''; - } -} -?> diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Render/Xhtml/Titlebar.php --- a/includes/wikiengine/Render/Xhtml/Titlebar.php Sun Jun 21 00:16:21 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version CVS: $Id: Titlebar.php,v 1.2 2005/07/30 08:03:29 toggg Exp $ - * @link http://pear.php.net/package/Text_Wiki - */ - -/** - * This class renders a title bar in XHTML. - * - * @category Text - * @package Text_Wiki - * @author Paul M. Jones - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version Release: @package_version@ - * @link http://pear.php.net/package/Text_Wiki - */ -class Text_Wiki_Render_Xhtml_Titlebar extends Text_Wiki_Render { - - var $conf = array( - 'css' => 'titlebar' - ); - - /** - * - * Renders a token into text matching the requested format. - * - * @access public - * - * @param array $options The "options" portion of the token (second - * element). - * - * @return string The text rendered from the token options. - * - */ - - function token($options) - { - if ($options['type'] == 'start') { - $css = $this->formatConf(' class="%s"', 'css'); - return ""; - } - - if ($options['type'] == 'end') { - return ''; - } - } -} -?> diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Render/Xhtml/Toc.php --- a/includes/wikiengine/Render/Xhtml/Toc.php Sun Jun 21 00:16:21 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,115 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version CVS: $Id: Toc.php,v 1.9 2005/07/30 08:03:29 toggg Exp $ - * @link http://pear.php.net/package/Text_Wiki - */ - -/** - * This class inserts a table of content in XHTML. - * - * @category Text - * @package Text_Wiki - * @author Paul M. Jones - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version Release: @package_version@ - * @link http://pear.php.net/package/Text_Wiki - */ -class Text_Wiki_Render_Xhtml_Toc extends Text_Wiki_Render { - - var $conf = array( - 'css_list' => null, - 'css_item' => null, - 'title' => 'Table of Contents', - 'div_id' => 'toc', - 'collapse' => true - ); - - var $min = 2; - - /** - * - * Renders a token into text matching the requested format. - * - * @access public - * - * @param array $options The "options" portion of the token (second - * element). - * - * @return string The text rendered from the token options. - * - */ - - function token($options) - { - // type, id, level, count, attr - extract($options); - - switch ($type) { - - case 'list_start': - - $css = $this->getConf('css_list'); - $html = ''; - - // collapse div within a table? - if ($this->getConf('collapse')) { - $html .= ''; - $html .= "
\n"; - } - - // add the div, class, and id - $html .= 'getConf('div_id'); - if ($div_id) { - $html .= " id=\"$div_id\""; - } - - // add the title, and done - $html .= '>'; - $html .= $this->getConf('title'); - return $html; - break; - - case 'list_end': - if ($this->getConf('collapse')) { - return "\n\n
\n\n"; - } else { - return "\n\n\n"; - } - break; - - case 'item_start': - $html = "\n\tgetConf('css_item'); - if ($css) { - $html .= " class=\"$css\""; - } - - $pad = ($level - $this->min); - $html .= " style=\"margin-left: {$pad}em;\">"; - - $html .= ""; - return $html; - break; - - case 'item_end': - return ""; - break; - } - } -} -?> diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Render/Xhtml/Tt.php --- a/includes/wikiengine/Render/Xhtml/Tt.php Sun Jun 21 00:16:21 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version CVS: $Id: Tt.php,v 1.7 2005/07/30 08:03:29 toggg Exp $ - * @link http://pear.php.net/package/Text_Wiki - */ - -/** - * This class renders monospaced text in XHTML. - * - * @category Text - * @package Text_Wiki - * @author Paul M. Jones - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version Release: @package_version@ - * @link http://pear.php.net/package/Text_Wiki - */ -class Text_Wiki_Render_Xhtml_Tt extends Text_Wiki_Render { - - - var $conf = array( - 'css' => null - ); - - /** - * - * Renders a token into text matching the requested format. - * - * @access public - * - * @param array $options The "options" portion of the token (second - * element). - * - * @return string The text rendered from the token options. - * - */ - - function token($options) - { - if ($options['type'] == 'start') { - $css = $this->formatConf(' class="%s"', 'css'); - return ""; - } - - if ($options['type'] == 'end') { - return ''; - } - } -} -?> diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Render/Xhtml/Underline.php --- a/includes/wikiengine/Render/Xhtml/Underline.php Sun Jun 21 00:16:21 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version CVS: $Id: Underline.php,v 1.2 2005/07/30 08:03:29 toggg Exp $ - * @link http://pear.php.net/package/Text_Wiki - */ - -/** - * This class renders underlined text in XHTML. - * - * @category Text - * @package Text_Wiki - * @author Paul M. Jones - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version Release: @package_version@ - * @link http://pear.php.net/package/Text_Wiki - */ -class Text_Wiki_Render_Xhtml_Underline extends Text_Wiki_Render { - - var $conf = array( - 'css' => null - ); - - /** - * - * Renders a token into text matching the requested format. - * - * @access public - * - * @param array $options The "options" portion of the token (second - * element). - * - * @return string The text rendered from the token options. - * - */ - - function token($options) - { - if ($options['type'] == 'start') { - $css = $this->formatConf(' class="%s"', 'css'); - return ""; - } - - if ($options['type'] == 'end') { - return ''; - } - } -} -?> diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Render/Xhtml/Url.php --- a/includes/wikiengine/Render/Xhtml/Url.php Sun Jun 21 00:16:21 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,134 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version CVS: $Id: Url.php,v 1.13 2006/02/10 23:07:03 toggg Exp $ - * @link http://pear.php.net/package/Text_Wiki - */ - -/** - * This class renders URL links in XHTML. - * - * @category Text - * @package Text_Wiki - * @author Paul M. Jones - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version Release: @package_version@ - * @link http://pear.php.net/package/Text_Wiki - */ -class Text_Wiki_Render_Xhtml_Url extends Text_Wiki_Render { - - - var $conf = array( - 'target' => '_blank', - 'images' => true, - 'img_ext' => array('jpg', 'jpeg', 'gif', 'png'), - 'css_inline' => null, - 'css_footnote' => null, - 'css_descr' => null, - 'css_img' => null - ); - - /** - * - * Renders a token into text matching the requested format. - * - * @access public - * - * @param array $options The "options" portion of the token (second - * element). - * - * @return string The text rendered from the token options. - * - */ - - function token($options) - { - global $email; - // create local variables from the options array (text, - // href, type) - extract($options); - - $quote = '"'; - - // find the rightmost dot and determine the filename - // extension. - $pos = strrpos($href, '.'); - $ext = strtolower(substr($href, $pos + 1)); - - if(substr($href, 0, 7) == 'mailto:') - { - $a = substr($href, 7); - $code = $email->encryptEmail($a, '', '', $text); - return $code; - } - - $href = $this->textEncode($href); - - // does the filename extension indicate an image file? - if ($this->getConf('images') && - in_array($ext, $this->getConf('img_ext', array()))) { - - // create alt text for the image - if (! isset($text) || $text == '') { - $text = basename($href); - $text = $this->textEncode($text); - } - - // generate an image tag - $css = $this->formatConf(' class="%s"', 'css_img'); - $output = ""; - - } else { - - // should we build a target clause? - if ($href{0} == '#' || - strtolower(substr($href, 0, 7)) == 'mailto:') { - // targets not allowed for on-page anchors - // and mailto: links. - $target = ''; - } else { - // allow targets on non-anchor non-mailto links - $target = $this->getConf('target'); - } - - // generate a regular link (not an image) - // $text = $this->textEncode($text); - $css = $this->formatConf(' class="%s"', "css_$type"); - $output = "/is', $text) ) - { - $output .= ' style="background-image: none; padding-right: 0;"'; - } - - if ($target) { - // use a "popup" window. this is XHTML compliant, suggested by - // Aaron Kalin. uses the $target as the new window name. - $target = $this->textEncode($target); - $output .= " onclick={$quote}window.open(this.href, '$target');"; - $output .= " return false;{$quote}"; - } - - // finish up output - $output .= " rel=".'"'."nofollow".'"'.">$text"; - - // make numbered references look like footnotes when no - // CSS class specified, make them superscript by default - if ($type == 'footnote' && ! $css) { - $output = '' . $output . ''; - } - } - - return $output; - } -} -?> diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Render/Xhtml/Wikilink.php --- a/includes/wikiengine/Render/Xhtml/Wikilink.php Sun Jun 21 00:16:21 2009 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,169 +0,0 @@ - - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version CVS: $Id: Wikilink.php,v 1.17 2006/02/28 03:15:09 justinpatrin Exp $ - * @link http://pear.php.net/package/Text_Wiki - */ - -/** - * This class renders wiki links in XHTML. - * - * @category Text - * @package Text_Wiki - * @author Paul M. Jones - * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 - * @version Release: @package_version@ - * @link http://pear.php.net/package/Text_Wiki - */ -class Text_Wiki_Render_Xhtml_Wikilink extends Text_Wiki_Render { - - var $conf; - - function Text_Wiki_Render_Xhtml_Wikilink() { - $_utemp = contentPath.'%s'; - $this->conf = array( - 'pages' => array(), // set to null or false to turn off page checks - 'view_url' => $_utemp, - 'new_url' => $_utemp, - 'new_text' => ' [x]', - 'new_text_pos' => false, // 'before', 'after', or null/false - 'css' => null, - 'css_new' => null, - 'exists_callback' => 'isPage' // call_user_func() callback - ); - } - - /** - * - * Renders a token into XHTML. - * - * @access public - * - * @param array $options The "options" portion of the token (second - * element). - * - * @return string The text rendered from the token options. - * - */ - - function token($options) - { - ## - ## THIS IS NOT WHAT YOU ARE LOOKING FOR!! - ## All of this code is deprecated. Patch RenderMan::parse_internal_links() instead! - ## - - global $session; - if ( $session->sid_super ) - { - $as = htmlspecialchars(urlSeparator) . 'auth='.$session->sid_super; - } - else - { - $as = ''; - } - // make nice variable names (page, anchor, text) - extract($options); - - // is there a "page existence" callback? - // we need to access it directly instead of through - // getConf() because we'll need a reference (for - // object instance method callbacks). - if (isset($this->conf['exists_callback'])) { - $callback =& $this->conf['exists_callback']; - } else { - $callback = false; - } - - $page = sanitize_page_id( $page ); - - if ($callback) { - // use the callback function - $exists = call_user_func($callback, $page); - } else { - // no callback, go to the naive page array. - $list = $this->getConf('pages'); - if (is_array($list)) { - // yes, check against the page list - $exists = in_array($page, $list); - } else { - // no, assume it exists - $exists = true; - } - } - - // convert *after* checking against page names so as not to mess - // up what the user typed and what we're checking. - //$page = $this->urlEncode($page); - $anchor = $this->urlEncode($anchor); - // $text = $this->textEncode($text); - - // hackish fix for the "external" image in Oxygen [added for Enano] - if ( preg_match('/<(.+?)>/is', $text) ) - { - $nobg = ' style="background-image: none; padding-right: 0;"'; - } - else - { - $nobg = ''; - } - - // does the page exist? - if ($exists) { - - // PAGE EXISTS. - - // link to the page view, but we have to build - // the HREF. we support both the old form where - // the page always comes at the end, and the new - // form that uses %s for sprintf() - $href = makeUrl($page, false, true); - - // get the CSS class and generate output - $css = $this->formatConf(' class="%s"', 'css'); - - $start = ''; - $end = ''; - } else { - - // PAGE DOES NOT EXIST. - - // link to the page view, but we have to build - // the HREF. we support both the old form where - // the page always comes at the end, and the new - // form that uses %s for sprintf() - $href = makeUrl($page, false, true); - - // get the CSS class and generate output - $css = $this->formatConf(' class="%s"', 'css'); - - $start = ''; - $end = ''; - } - if (!strlen($text)) { - $start .= $this->textEncode($options['page']); - } - if (isset($type)) { - switch ($type) { - case 'start': - $output = $start; - break; - case 'end': - $output = $end; - break; - } - } else { - $output = $start.$text.$end; - } - return $output; - } -} -?> diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/Tables.php --- a/includes/wikiengine/Tables.php Sun Jun 21 00:16:21 2009 -0400 +++ b/includes/wikiengine/Tables.php Sun Jun 21 00:20:32 2009 -0400 @@ -12,1016 +12,168 @@ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. * * This script contains code originally found in MediaWiki (http://www.mediawiki.org). MediaWiki is also licensed under - * the GPLv2; see the file GPL included with this package for details. + * the GPLv2 or later; see the file GPL included with this package for details. * * We're using the MW parser because the Text_Wiki version simply refused to work under PHP 5.2.0. Porting this was * _not_ easy. */ - global $mStripState, $wgRandomKey; - $mStripState = Array(); - - $attrib = '[a-zA-Z0-9]'; - $space = '[\x09\x0a\x0d\x20]'; +global $mStripState, $wgRandomKey; +$mStripState = Array(); + +/** + * emulate mediawiki parser, including stripping, etc. + * + * @param string $text the text to parse + * @return string + * @access public + */ + +function process_tables( $text ) +{ + // include some globals, do some parser stuff that would normally be done in the parent parser function + global $mStripState; + $x =& $mStripState; - define( 'MW_CHAR_REFS_REGEX', - '/&([A-Za-z0-9]+); - |&\#([0-9]+); - |&\#x([0-9A-Za-z]+); - |&\#X([0-9A-Za-z]+); - |(&)/x' ); + // parse the text + $text = doTableStuff($text); + + return $text; +} + +/** + * parse the wiki syntax used to render tables + * + * @param string $t the text to parse + * @return string + * @access private + */ +function doTableStuff( $t ) { - define( 'MW_ATTRIBS_REGEX', - "/(?:^|$space)($attrib+) - ($space*=$space* - (?: - # The attribute value: quoted or alone - ".'"'."([^<".'"'."]*)".'"'." - | '([^<']*)' - | ([a-zA-Z0-9!#$%&()*,\\-.\\/:;<>?@[\\]^_`{|}~]+) - | (\#[0-9a-fA-F]+) # Technically wrong, but lots of - # colors are specified like this. - # We'll be normalizing it. - ) - )?(?=$space|\$)/sx" ); - - /** - * emulate mediawiki parser, including stripping, etc. - * - * @param string $text the text to parse - * @return string - * @access public - */ - - function process_tables( $text ) + $t = explode ( "\n" , $t ) ; + $td = array () ; # Is currently a td tag open? + $ltd = array () ; # Was it TD or TH? + $tr = array () ; # Is currently a tr tag open? + $ltr = array () ; # tr attributes + $has_opened_tr = array(); # Did this table open a element? + $indent_level = 0; # indent level of the table + foreach ( $t AS $k => $x ) { - // include some globals, do some parser stuff that would normally be done in the parent parser function - global $mStripState; - $x =& $mStripState; - //$text = mwStrip( $text, $x ); - - // parse the text - $text = doTableStuff($text); - - // Unstrip it - // $text = unstrip( $text, $mStripState ); - // $text = unstripNoWiki( $text, $mStripState ); - //die('
'.print_r($mStripState, true).'
'); - return $text; + $x = trim ( $x ) ; + $fc = substr ( $x , 0 , 1 ) ; + if ( preg_match( '/^(:*)\{\|(.*)$/', $x, $matches ) ) { + $indent_level = strlen( $matches[1] ); + + $attributes = unstripForHTML( $matches[2] ); + + $t[$k] = str_repeat( '
', $indent_level ) . + '<_paragraph_bypass>' ; + array_push ( $td , false ) ; + array_push ( $ltd , '' ) ; + array_push ( $tr , false ) ; + array_push ( $ltr , '' ) ; + array_push ( $has_opened_tr, false ); + } + else if ( count ( $td ) == 0 ) { } # Don't do any of the following + else if ( '|}' == substr ( $x , 0 , 2 ) ) { + $z = "" . substr ( $x , 2); + $l = array_pop ( $ltd ) ; + if ( !array_pop ( $has_opened_tr ) ) $z = "" . $z ; + if ( array_pop ( $tr ) ) $z = '' . $z ; + if ( array_pop ( $td ) ) $z = '' . $z ; + array_pop ( $ltr ) ; + $t[$k] = $z . str_repeat( '
', $indent_level ); + } + else if ( '|-' == substr ( $x , 0 , 2 ) ) { # Allows for |--------------- + $x = substr ( $x , 1 ) ; + while ( $x != '' && substr ( $x , 0 , 1 ) == '-' ) $x = substr ( $x , 1 ) ; + $z = '' ; + $l = array_pop ( $ltd ) ; + array_pop ( $has_opened_tr ); + array_push ( $has_opened_tr , true ) ; + if ( array_pop ( $tr ) ) $z = '' . $z ; + if ( array_pop ( $td ) ) $z = '' . $z ; + array_pop ( $ltr ) ; + $t[$k] = $z ; + array_push ( $tr , false ) ; + array_push ( $td , false ) ; + array_push ( $ltd , '' ) ; + $attributes = unstripForHTML( $x ); + array_push ( $ltr , fixTagAttributes( $attributes, 'tr' ) ) ; + } + else if ( '|' == $fc || '!' == $fc || '|+' == substr ( $x , 0 , 2 ) ) { # Caption + # $x is a table row + if ( '|+' == substr ( $x , 0 , 2 ) ) { + $fc = '+' ; + $x = substr ( $x , 1 ) ; + } + $after = substr ( $x , 1 ) ; + if ( $fc == '!' ) $after = str_replace ( '!!' , '||' , $after ) ; + + // Split up multiple cells on the same line. + // FIXME: This can result in improper nesting of tags processed + // by earlier parser steps, but should avoid splitting up eg + // attribute values containing literal "||". + $after = wfExplodeMarkup( '||', $after ); + + $t[$k] = '' ; + + # Loop through each table cell + foreach ( $after AS $theline ) + { + $z = '' ; + if ( $fc != '+' ) + { + $tra = array_pop ( $ltr ) ; + if ( !array_pop ( $tr ) ) $z = '\n" ; + array_push ( $tr , true ) ; + array_push ( $ltr , '' ) ; + array_pop ( $has_opened_tr ); + array_push ( $has_opened_tr , true ) ; + } + + $l = array_pop ( $ltd ) ; + if ( array_pop ( $td ) ) $z = '' . $z ; + if ( $fc == '|' ) $l = 'td' ; + else if ( $fc == '!' ) $l = 'th' ; + else if ( $fc == '+' ) $l = 'caption' ; + else $l = '' ; + array_push ( $ltd , $l ) ; + + # Cell parameters + $y = explode ( '|' , $theline , 2 ) ; + # Note that a '|' inside an invalid link should not + # be mistaken as delimiting cell parameters + if ( strpos( $y[0], '[[' ) !== false ) { + $y = array ($theline); + } + if ( count ( $y ) == 1 ) + $y = "{$z}<{$l}>{$y[0]}" ; + else { + $attributes = unstripForHTML( $y[0] ); + $y = "{$z}<{$l}".fixTagAttributes($attributes, $l).">{$y[1]}" ; + } + $t[$k] .= $y ; + array_push ( $td , true ) ; + } + } } - /** - * parse the wiki syntax used to render tables - * - * @param string $t the text to parse - * @return string - * @access private - */ - function doTableStuff( $t ) { - - $t = explode ( "\n" , $t ) ; - $td = array () ; # Is currently a td tag open? - $ltd = array () ; # Was it TD or TH? - $tr = array () ; # Is currently a tr tag open? - $ltr = array () ; # tr attributes - $has_opened_tr = array(); # Did this table open a element? - $indent_level = 0; # indent level of the table - foreach ( $t AS $k => $x ) - { - $x = trim ( $x ) ; - $fc = substr ( $x , 0 , 1 ) ; - if ( preg_match( '/^(:*)\{\|(.*)$/', $x, $matches ) ) { - $indent_level = strlen( $matches[1] ); - - $attributes = unstripForHTML( $matches[2] ); - - $t[$k] = str_repeat( '
', $indent_level ) . - '' ; - array_push ( $td , false ) ; - array_push ( $ltd , '' ) ; - array_push ( $tr , false ) ; - array_push ( $ltr , '' ) ; - array_push ( $has_opened_tr, false ); - } - else if ( count ( $td ) == 0 ) { } # Don't do any of the following - else if ( '|}' == substr ( $x , 0 , 2 ) ) { - $z = "" . substr ( $x , 2); - $l = array_pop ( $ltd ) ; - if ( !array_pop ( $has_opened_tr ) ) $z = "" . $z ; - if ( array_pop ( $tr ) ) $z = '' . $z ; - if ( array_pop ( $td ) ) $z = '' . $z ; - array_pop ( $ltr ) ; - $t[$k] = $z . str_repeat( '
', $indent_level ); - } - else if ( '|-' == substr ( $x , 0 , 2 ) ) { # Allows for |--------------- - $x = substr ( $x , 1 ) ; - while ( $x != '' && substr ( $x , 0 , 1 ) == '-' ) $x = substr ( $x , 1 ) ; - $z = '' ; - $l = array_pop ( $ltd ) ; - array_pop ( $has_opened_tr ); - array_push ( $has_opened_tr , true ) ; - if ( array_pop ( $tr ) ) $z = '' . $z ; - if ( array_pop ( $td ) ) $z = '' . $z ; - array_pop ( $ltr ) ; - $t[$k] = $z ; - array_push ( $tr , false ) ; - array_push ( $td , false ) ; - array_push ( $ltd , '' ) ; - $attributes = unstripForHTML( $x ); - array_push ( $ltr , fixTagAttributes( $attributes, 'tr' ) ) ; - } - else if ( '|' == $fc || '!' == $fc || '|+' == substr ( $x , 0 , 2 ) ) { # Caption - # $x is a table row - if ( '|+' == substr ( $x , 0 , 2 ) ) { - $fc = '+' ; - $x = substr ( $x , 1 ) ; - } - $after = substr ( $x , 1 ) ; - if ( $fc == '!' ) $after = str_replace ( '!!' , '||' , $after ) ; - - // Split up multiple cells on the same line. - // FIXME: This can result in improper nesting of tags processed - // by earlier parser steps, but should avoid splitting up eg - // attribute values containing literal "||". - $after = wfExplodeMarkup( '||', $after ); - - $t[$k] = '' ; - - # Loop through each table cell - foreach ( $after AS $theline ) - { - $z = '' ; - if ( $fc != '+' ) - { - $tra = array_pop ( $ltr ) ; - if ( !array_pop ( $tr ) ) $z = '\n" ; - array_push ( $tr , true ) ; - array_push ( $ltr , '' ) ; - array_pop ( $has_opened_tr ); - array_push ( $has_opened_tr , true ) ; - } - - $l = array_pop ( $ltd ) ; - if ( array_pop ( $td ) ) $z = '' . $z ; - if ( $fc == '|' ) $l = 'td' ; - else if ( $fc == '!' ) $l = 'th' ; - else if ( $fc == '+' ) $l = 'caption' ; - else $l = '' ; - array_push ( $ltd , $l ) ; - - # Cell parameters - $y = explode ( '|' , $theline , 2 ) ; - # Note that a '|' inside an invalid link should not - # be mistaken as delimiting cell parameters - if ( strpos( $y[0], '[[' ) !== false ) { - $y = array ($theline); - } - if ( count ( $y ) == 1 ) - $y = "{$z}<{$l}>{$y[0]}" ; - else { - $attributes = unstripForHTML( $y[0] ); - $y = "{$z}<{$l}".fixTagAttributes($attributes, $l).">{$y[1]}" ; - } - $t[$k] .= $y ; - array_push ( $td , true ) ; - } - } - } - - # Closing open td, tr && table - while ( count ( $td ) > 0 ) - { - $l = array_pop ( $ltd ) ; - if ( array_pop ( $td ) ) $t[] = '' ; - if ( array_pop ( $tr ) ) $t[] = '' ; - if ( !array_pop ( $has_opened_tr ) ) $t[] = "" ; - $t[] = '' ; - } - - $t = implode ( "\n" , $t ) ; - - # special case: don't return empty table - if($t == "\n\n
") - $t = ''; - return $t ; - } - - /** - * Take a tag soup fragment listing an HTML element's attributes - * and normalize it to well-formed XML, discarding unwanted attributes. - * Output is safe for further wikitext processing, with escaping of - * values that could trigger problems. - * - * - Normalizes attribute names to lowercase - * - Discards attributes not on a whitelist for the given element - * - Turns broken or invalid entities into plaintext - * - Double-quotes all attribute values - * - Attributes without values are given the name as attribute - * - Double attributes are discarded - * - Unsafe style attributes are discarded - * - Prepends space if there are attributes. - * - * @param string $text - * @param string $element - * @return string - */ - function fixTagAttributes( $text, $element ) { - if( trim( $text ) == '' ) { - return ''; - } - - $stripped = validateTagAttributes( - decodeTagAttributes( $text ), $element ); - - $attribs = array(); - foreach( $stripped as $attribute => $value ) { - $encAttribute = htmlspecialchars( $attribute ); - $encValue = safeEncodeAttribute( $value ); - - $attribs[] = "$encAttribute=".'"'."$encValue".'"'.""; // " - } - return count( $attribs ) ? ' ' . implode( ' ', $attribs ) : ''; - } - - /** - * Encode an attribute value for HTML tags, with extra armoring - * against further wiki processing. - * @param $text - * @return HTML-encoded text fragment - */ - function safeEncodeAttribute( $text ) { - $encValue= encodeAttribute( $text ); - - # Templates and links may be expanded in later parsing, - # creating invalid or dangerous output. Suppress this. - $encValue = strtr( $encValue, array( - '<' => '<', // This should never happen, - '>' => '>', // we've received invalid input - '"' => '"', // which should have been escaped. - '{' => '{', - '[' => '[', - "''" => '''', - 'ISBN' => 'ISBN', - 'RFC' => 'RFC', - 'PMID' => 'PMID', - '|' => '|', - '__' => '__', - ) ); - - return $encValue; - } - - /** - * Encode an attribute value for HTML output. - * @param $text - * @return HTML-encoded text fragment - */ - function encodeAttribute( $text ) { - - // In Enano 1.0.3, added this cheapo hack to keep ampersands - // from being double-sanitized. Thanks to markybob from #deluge. - - // htmlspecialchars() the "manual" way - $encValue = strtr( $text, array( - '&' => '&', - '"' => '"', - '<' => '<', - '>' => '>', - ''' => "'" - ) ); - - $encValue = strtr( $text, array( - '&' => '&', - '"' => '"', - '<' => '<', - '>' => '>', - "'" => ''' - ) ); - - - // Whitespace is normalized during attribute decoding, - // so if we've been passed non-spaces we must encode them - // ahead of time or they won't be preserved. - $encValue = strtr( $encValue, array( - "\n" => ' ', - "\r" => ' ', - "\t" => ' ', - ) ); - - return $encValue; - } - - function unstripForHTML( $text ) { - global $mStripState; - $text = unstrip( $text, $mStripState ); - $text = unstripNoWiki( $text, $mStripState ); - return $text; - } - - /** - * Always call this after unstrip() to preserve the order - * - * @private - */ - function unstripNoWiki( $text, &$state ) { - if ( !isset( $state['nowiki'] ) ) { - return $text; - } - - # TODO: good candidate for FSS - $text = strtr( $text, $state['nowiki'] ); - - return $text; - } - - /** - * Take an array of attribute names and values and normalize or discard - * illegal values for the given element type. - * - * - Discards attributes not on a whitelist for the given element - * - Unsafe style attributes are discarded - * - * @param array $attribs - * @param string $element - * @return array - * - * @todo Check for legal values where the DTD limits things. - * @todo Check for unique id attribute :P - */ - function validateTagAttributes( $attribs, $element ) { - $whitelist = array_flip( attributeWhitelist( $element ) ); - $out = array(); - foreach( $attribs as $attribute => $value ) { - if( !isset( $whitelist[$attribute] ) ) { - continue; - } - # Strip javascript "expression" from stylesheets. - # http://msdn.microsoft.com/workshop/author/dhtml/overview/recalc.asp - if( $attribute == 'style' ) { - $value = checkCss( $value ); - if( $value === false ) { - # haxx0r - continue; - } - } - - if ( $attribute === 'id' ) - $value = escapeId( $value ); - - // If this attribute was previously set, override it. - // Output should only have one attribute of each name. - $out[$attribute] = $value; - } - return $out; - } - - /** - * Pick apart some CSS and check it for forbidden or unsafe structures. - * Returns a sanitized string, or false if it was just too evil. - * - * Currently URL references, 'expression', 'tps' are forbidden. - * - * @param string $value - * @return mixed - */ - function checkCss( $value ) { - $stripped = decodeCharReferences( $value ); - - // Remove any comments; IE gets token splitting wrong - $stripped = preg_replace( '!/\\*.*?\\*/!S', '', $stripped ); - $value = $stripped; - - // ... and continue checks - $stripped = preg_replace( '!\\\\([0-9A-Fa-f]{1,6})[ \\n\\r\\t\\f]?!e', - 'codepointToUtf8(hexdec("$1"))', $stripped ); - $stripped = str_replace( '\\', '', $stripped ); - if( preg_match( '/(expression|tps*:\/\/|url\\s*\().*/is', - $stripped ) ) { - # haxx0r - return false; - } - - return $value; - } - - /** - * Decode any character references, numeric or named entities, - * in the text and return a UTF-8 string. - * - * @param string $text - * @return string - * @access public - * @static - */ - function decodeCharReferences( $text ) { - return preg_replace_callback( - MW_CHAR_REFS_REGEX, - 'decodeCharReferencesCallback', - $text ); - } - - /** - * Fetch the whitelist of acceptable attributes for a given - * element name. - * - * @param string $element - * @return array - */ - function attributeWhitelist( $element ) { - static $list; - if( !isset( $list ) ) { - $list = setupAttributeWhitelist(); - } - return isset( $list[$element] ) - ? $list[$element] - : array(); - } - - /** - * @todo Document it a bit - * @return array - */ - function setupAttributeWhitelist() { - global $db, $session, $paths, $template, $plugins; - $common = array( 'id', 'class', 'lang', 'dir', 'title', 'style' ); - $block = array_merge( $common, array( 'align' ) ); - $tablealign = array( 'align', 'char', 'charoff', 'valign' ); - $tablecell = array( 'abbr', - 'axis', - 'headers', - 'scope', - 'rowspan', - 'colspan', - 'nowrap', # deprecated - 'width', # deprecated - 'height', # deprecated - 'bgcolor' # deprecated - ); - - # Numbers refer to sections in HTML 4.01 standard describing the element. - # See: http://www.w3.org/TR/html4/ - $whitelist = array ( - # 7.5.4 - 'div' => $block, - 'center' => $common, # deprecated - 'span' => $block, # ?? - - # 7.5.5 - 'h1' => $block, - 'h2' => $block, - 'h3' => $block, - 'h4' => $block, - 'h5' => $block, - 'h6' => $block, - - # 7.5.6 - # address - - # 8.2.4 - # bdo - - # 9.2.1 - 'em' => $common, - 'strong' => $common, - 'cite' => $common, - # dfn - 'code' => $common, - # samp - # kbd - 'var' => $common, - # abbr - # acronym - - # 9.2.2 - 'blockquote' => array_merge( $common, array( 'cite' ) ), - # q - - # 9.2.3 - 'sub' => $common, - 'sup' => $common, - - # 9.3.1 - 'p' => $block, - - # 9.3.2 - 'br' => array( 'id', 'class', 'title', 'style', 'clear' ), - - # 9.3.4 - 'pre' => array_merge( $common, array( 'width' ) ), - - # 9.4 - 'ins' => array_merge( $common, array( 'cite', 'datetime' ) ), - 'del' => array_merge( $common, array( 'cite', 'datetime' ) ), - - # 10.2 - 'ul' => array_merge( $common, array( 'type' ) ), - 'ol' => array_merge( $common, array( 'type', 'start' ) ), - 'li' => array_merge( $common, array( 'type', 'value' ) ), - - # 10.3 - 'dl' => $common, - 'dd' => $common, - 'dt' => $common, - - # 11.2.1 - 'table' => array_merge( $common, - array( 'summary', 'width', 'border', 'frame', - 'rules', 'cellspacing', 'cellpadding', - 'align', 'bgcolor', - ) ), - - # 11.2.2 - 'caption' => array_merge( $common, array( 'align' ) ), + # Closing open td, tr && table + while ( count ( $td ) > 0 ) + { + $l = array_pop ( $ltd ) ; + if ( array_pop ( $td ) ) $t[] = '' ; + if ( array_pop ( $tr ) ) $t[] = '' ; + if ( !array_pop ( $has_opened_tr ) ) $t[] = "" ; + $t[] = '' ; + } - # 11.2.3 - 'thead' => array_merge( $common, $tablealign ), - 'tfoot' => array_merge( $common, $tablealign ), - 'tbody' => array_merge( $common, $tablealign ), - - # 11.2.4 - 'colgroup' => array_merge( $common, array( 'span', 'width' ), $tablealign ), - 'col' => array_merge( $common, array( 'span', 'width' ), $tablealign ), - - # 11.2.5 - 'tr' => array_merge( $common, array( 'bgcolor' ), $tablealign ), - - # 11.2.6 - 'td' => array_merge( $common, $tablecell, $tablealign ), - 'th' => array_merge( $common, $tablecell, $tablealign ), - - # 12.2 - # added by dan - 'a' => array_merge( $common, array( 'href', 'name' ) ), - - # 13.2 - # added by dan - 'img' => array_merge( $common, array( 'src', 'width', 'height', 'alt' ) ), - - # 15.2.1 - 'tt' => $common, - 'b' => $common, - 'i' => $common, - 'big' => $common, - 'small' => $common, - 'strike' => $common, - 's' => $common, - 'u' => $common, - - # 15.2.2 - 'font' => array_merge( $common, array( 'size', 'color', 'face' ) ), - # basefont - - # 15.3 - 'hr' => array_merge( $common, array( 'noshade', 'size', 'width' ) ), - - # XHTML Ruby annotation text module, simple ruby only. - # http://www.w3c.org/TR/ruby/ - 'ruby' => $common, - # rbc - # rtc - 'rb' => $common, - 'rt' => $common, #array_merge( $common, array( 'rbspan' ) ), - 'rp' => $common, - - # For compatibility with the XHTML parser. - 'nowiki' => array(), - 'noinclude' => array(), - 'nodisplay' => array(), - 'lang' => array('code'), - - # XHTML stuff - 'acronym' => $common - ); - - // custom tags can be added by plugins - $code = $plugins->setHook('html_attribute_whitelist'); - foreach ( $code as $cmd ) - { - eval($cmd); - } - - return $whitelist; - } - - /** - * Given a value escape it so that it can be used in an id attribute and - * return it, this does not validate the value however (see first link) - * - * @link http://www.w3.org/TR/html401/types.html#type-name Valid characters - * in the id and - * name attributes - * @link http://www.w3.org/TR/html401/struct/links.html#h-12.2.3 Anchors with the id attribute - * - * @bug 4461 - * - * @static - * - * @param string $id - * @return string - */ - function escapeId( $id ) { - static $replace = array( - '%3A' => ':', - '%' => '.' - ); - - $id = urlencode( decodeCharReferences( strtr( $id, ' ', '_' ) ) ); - - return str_replace( array_keys( $replace ), array_values( $replace ), $id ); - } - - /** - * More or less "markup-safe" explode() - * Ignores any instances of the separator inside <...> - * @param string $separator - * @param string $text - * @return array - */ - function wfExplodeMarkup( $separator, $text ) { - $placeholder = "\x00"; - - // Just in case... - $text = str_replace( $placeholder, '', $text ); - - // Trim stuff - $replacer = new ReplacerCallback( $separator, $placeholder ); - $cleaned = preg_replace_callback( '/(<.*?>)/', array( $replacer, 'go' ), $text ); - - $items = explode( $separator, $cleaned ); - foreach( $items as $i => $str ) { - $items[$i] = str_replace( $placeholder, $separator, $str ); - } - - return $items; - } - - class ReplacerCallback { - function ReplacerCallback( $from, $to ) { - $this->from = $from; - $this->to = $to; - } - - function go( $matches ) { - return str_replace( $this->from, $this->to, $matches[1] ); - } - } - - /** - * Return an associative array of attribute names and values from - * a partial tag string. Attribute names are forces to lowercase, - * character references are decoded to UTF-8 text. - * - * @param string - * @return array - */ - function decodeTagAttributes( $text ) { - $attribs = array(); - - if( trim( $text ) == '' ) { - return $attribs; - } - - $pairs = array(); - if( !preg_match_all( - MW_ATTRIBS_REGEX, - $text, - $pairs, - PREG_SET_ORDER ) ) { - return $attribs; - } - - foreach( $pairs as $set ) { - $attribute = strtolower( $set[1] ); - $value = getTagAttributeCallback( $set ); - - // Normalize whitespace - $value = preg_replace( '/[\t\r\n ]+/', ' ', $value ); - $value = trim( $value ); - - // Decode character references - $attribs[$attribute] = decodeCharReferences( $value ); - } - return $attribs; - } - - /** - * Pick the appropriate attribute value from a match set from the - * MW_ATTRIBS_REGEX matches. - * - * @param array $set - * @return string - * @access private - */ - function getTagAttributeCallback( $set ) { - if( isset( $set[6] ) ) { - # Illegal #XXXXXX color with no quotes. - return $set[6]; - } elseif( isset( $set[5] ) ) { - # No quotes. - return $set[5]; - } elseif( isset( $set[4] ) ) { - # Single-quoted - return $set[4]; - } elseif( isset( $set[3] ) ) { - # Double-quoted - return $set[3]; - } elseif( !isset( $set[2] ) ) { - # In XHTML, attributes must have a value. - # For 'reduced' form, return explicitly the attribute name here. - return $set[1]; - } else { - die_friendly('Parser error', "

Tag conditions not met. This should never happen and is a bug.

" ); - } - } + $t = implode ( "\n" , $t ) ; - /** - * Strips and renders nowiki, pre, math, hiero - * If $render is set, performs necessary rendering operations on plugins - * Returns the text, and fills an array with data needed in unstrip() - * If the $state is already a valid strip state, it adds to the state - * - * @param bool $stripcomments when set, HTML comments - * will be stripped in addition to other tags. This is important - * for section editing, where these comments cause confusion when - * counting the sections in the wikisource - * - * @param array dontstrip contains tags which should not be stripped; - * used to prevent stipping of when saving (fixes bug 2700) - * - * @access private - */ - function mwStrip( $text, &$state, $stripcomments = false , $dontstrip = array () ) { - global $wgRandomKey; - $render = true; - - $wgRandomKey = "\x07UNIQ" . dechex(mt_rand(0, 0x7fffffff)) . dechex(mt_rand(0, 0x7fffffff)); - $uniq_prefix =& $wgRandomKey; - $commentState = array(); - - $elements = array( 'nowiki', 'gallery' ); - - # Removing $dontstrip tags from $elements list (currently only 'gallery', fixing bug 2700) - foreach ( $elements AS $k => $v ) { - if ( !in_array ( $v , $dontstrip ) ) continue; - unset ( $elements[$k] ); - } - - $matches = array(); - $text = extractTagsAndParams( $elements, $text, $matches, $uniq_prefix ); - - foreach( $matches as $marker => $data ) { - list( $element, $content, $params, $tag ) = $data; - if( $render ) { - $tagName = strtolower( $element ); - switch( $tagName ) { - case '!--': - // Comment - if( substr( $tag, -3 ) == '-->' ) { - $output = $tag; - } else { - // Unclosed comment in input. - // Close it so later stripping can remove it - $output = "$tag-->"; - } - break; - case 'html': - if( $wgRawHtml ) { - $output = $content; - break; - } - // Shouldn't happen otherwise. :) - case 'nowiki': - $output = wfEscapeHTMLTagsOnly( $content ); - break; - default: - } - } else { - // Just stripping tags; keep the source - $output = $tag; - } - - // Unstrip the output, because unstrip() is no longer recursive so - // it won't do it itself - $output = unstrip( $output, $state ); - - if( !$stripcomments && $element == '!--' ) { - $commentState[$marker] = $output; - } elseif ( $element == 'html' || $element == 'nowiki' ) { - $state['nowiki'][$marker] = $output; - } else { - $state['general'][$marker] = $output; - } - } - - # Unstrip comments unless explicitly told otherwise. - # (The comments are always stripped prior to this point, so as to - # not invoke any extension tags / parser hooks contained within - # a comment.) - if ( !$stripcomments ) { - // Put them all back and forget them - $text = strtr( $text, $commentState ); - } - - return $text; - } - - /** - * Replaces all occurrences of HTML-style comments and the given tags - * in the text with a random marker and returns teh next text. The output - * parameter $matches will be an associative array filled with data in - * the form: - * 'UNIQ-xxxxx' => array( - * 'element', - * 'tag content', - * array( 'param' => 'x' ), - * 'tag content' ) ) - * - * @param $elements list of element names. Comments are always extracted. - * @param $text Source text string. - * @param $uniq_prefix - * - * @access private - * @static - */ - function extractTagsAndParams($elements, $text, &$matches, $uniq_prefix = ''){ - static $n = 1; - $stripped = ''; - $matches = array(); - - $taglist = implode( '|', $elements ); - $start = "/<($taglist)(\\s+[^>]*?|\\s*?)(\/?>)|<(!--)/i"; - - while ( '' != $text ) { - $p = preg_split( $start, $text, 2, PREG_SPLIT_DELIM_CAPTURE ); - $stripped .= $p[0]; - if( count( $p ) < 5 ) { - break; - } - if( count( $p ) > 5 ) { - // comment - $element = $p[4]; - $attributes = ''; - $close = ''; - $inside = $p[5]; - } else { - // tag - $element = $p[1]; - $attributes = $p[2]; - $close = $p[3]; - $inside = $p[4]; - } - - $marker = "$uniq_prefix-$element-" . sprintf('%08X', $n++) . '-QINU'; - $stripped .= $marker; - - if ( $close === '/>' ) { - // Empty element tag, - $content = null; - $text = $inside; - $tail = null; - } else { - if( $element == '!--' ) { - $end = '/(-->)/'; - } else { - $end = "/(<\\/$element\\s*>)/i"; - } - $q = preg_split( $end, $inside, 2, PREG_SPLIT_DELIM_CAPTURE ); - $content = $q[0]; - if( count( $q ) < 3 ) { - # No end tag -- let it run out to the end of the text. - $tail = ''; - $text = ''; - } else { - $tail = $q[1]; - $text = $q[2]; - } - } - - $matches[$marker] = array( $element, - $content, - decodeTagAttributes( $attributes ), - "<$element$attributes$close$content$tail" ); - } - return $stripped; - } - - /** - * Escape html tags - * Basically replacing " > and < with HTML entities ( ", >, <) - * - * @param $in String: text that might contain HTML tags. - * @return string Escaped string - */ - function wfEscapeHTMLTagsOnly( $in ) { - return str_replace( - array( '"', '>', '<' ), - array( '"', '>', '<' ), - $in ); - } - - /** - * Restores pre, math, and other extensions removed by strip() - * - * always call unstripNoWiki() after this one - * @private - */ - function unstrip( $text, &$state ) { - if ( !isset( $state['general'] ) ) { - return $text; - } - - # TODO: good candidate for FSS - $text = strtr( $text, $state['general'] ); - - return $text; - } - - /** - * Return UTF-8 string for a codepoint if that is a valid - * character reference, otherwise U+FFFD REPLACEMENT CHARACTER. - * @param int $codepoint - * @return string - * @private - */ - function decodeChar( $codepoint ) { - if( validateCodepoint( $codepoint ) ) { - return codepointToUtf8( $codepoint ); - } else { - return UTF8_REPLACEMENT; - } - } - - /** - * If the named entity is defined in the HTML 4.0/XHTML 1.0 DTD, - * return the UTF-8 encoding of that character. Otherwise, returns - * pseudo-entity source (eg &foo;) - * - * @param string $name - * @return string - */ - function decodeEntity( $name ) { - global $wgHtmlEntities; - if( isset( $wgHtmlEntities[$name] ) ) { - return codepointToUtf8( $wgHtmlEntities[$name] ); - } else { - return "&$name;"; - } - } - - /** - * Returns true if a given Unicode codepoint is a valid character in XML. - * @param int $codepoint - * @return bool - */ - function validateCodepoint( $codepoint ) { - return ($codepoint == 0x09) - || ($codepoint == 0x0a) - || ($codepoint == 0x0d) - || ($codepoint >= 0x20 && $codepoint <= 0xd7ff) - || ($codepoint >= 0xe000 && $codepoint <= 0xfffd) - || ($codepoint >= 0x10000 && $codepoint <= 0x10ffff); - } - -/** - * Return UTF-8 sequence for a given Unicode code point. - * May die if fed out of range data. - * - * @param $codepoint Integer: - * @return String - * @public - */ -function codepointToUtf8( $codepoint ) { - if($codepoint < 0x80) return chr($codepoint); - if($codepoint < 0x800) return chr($codepoint >> 6 & 0x3f | 0xc0) . - chr($codepoint & 0x3f | 0x80); - if($codepoint < 0x10000) return chr($codepoint >> 12 & 0x0f | 0xe0) . - chr($codepoint >> 6 & 0x3f | 0x80) . - chr($codepoint & 0x3f | 0x80); - if($codepoint < 0x110000) return chr($codepoint >> 18 & 0x07 | 0xf0) . - chr($codepoint >> 12 & 0x3f | 0x80) . - chr($codepoint >> 6 & 0x3f | 0x80) . - chr($codepoint & 0x3f | 0x80); - - echo "Asked for code outside of range ($codepoint)\n"; - die( -1 ); + # special case: don't return empty table + if($t == "\n\n
") + $t = ''; + return $t ; } - /** - * @param string $matches - * @return string - */ - function decodeCharReferencesCallback( $matches ) { - if( $matches[1] != '' ) { - return decodeEntity( $matches[1] ); - } elseif( $matches[2] != '' ) { - return decodeChar( intval( $matches[2] ) ); - } elseif( $matches[3] != '' ) { - return decodeChar( hexdec( $matches[3] ) ); - } elseif( $matches[4] != '' ) { - return decodeChar( hexdec( $matches[4] ) ); - } - # Last case should be an ampersand by itself - return $matches[0]; - } - -?> diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/TagSanitizer.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/includes/wikiengine/TagSanitizer.php Sun Jun 21 00:20:32 2009 -0400 @@ -0,0 +1,859 @@ +?@[\\]^_`{|}~]+) + | (\#[0-9a-fA-F]+) # Technically wrong, but lots of + # colors are specified like this. + # We'll be normalizing it. + ) + )?(?=$space|\$)/sx" ); + +/** + * Take a tag soup fragment listing an HTML element's attributes + * and normalize it to well-formed XML, discarding unwanted attributes. + * Output is safe for further wikitext processing, with escaping of + * values that could trigger problems. + * + * - Normalizes attribute names to lowercase + * - Discards attributes not on a whitelist for the given element + * - Turns broken or invalid entities into plaintext + * - Double-quotes all attribute values + * - Attributes without values are given the name as attribute + * - Double attributes are discarded + * - Unsafe style attributes are discarded + * - Prepends space if there are attributes. + * + * @param string $text + * @param string $element + * @return string + */ +function fixTagAttributes( $text, $element ) { + if( trim( $text ) == '' ) { + return ''; + } + + $stripped = validateTagAttributes( + decodeTagAttributes( $text ), $element ); + + $attribs = array(); + foreach( $stripped as $attribute => $value ) { + $encAttribute = htmlspecialchars( $attribute ); + $encValue = safeEncodeAttribute( $value ); + + $attribs[] = "$encAttribute=".'"'."$encValue".'"'.""; // " + } + return count( $attribs ) ? ' ' . implode( ' ', $attribs ) : ''; +} + +/** + * Encode an attribute value for HTML tags, with extra armoring + * against further wiki processing. + * @param $text + * @return HTML-encoded text fragment + */ +function safeEncodeAttribute( $text ) { + $encValue= encodeAttribute( $text ); + + # Templates and links may be expanded in later parsing, + # creating invalid or dangerous output. Suppress this. + $encValue = strtr( $encValue, array( + '<' => '<', // This should never happen, + '>' => '>', // we've received invalid input + '"' => '"', // which should have been escaped. + '{' => '{', + '[' => '[', + "''" => '''', + 'ISBN' => 'ISBN', + 'RFC' => 'RFC', + 'PMID' => 'PMID', + '|' => '|', + '__' => '__', + ) ); + + return $encValue; +} + +/** + * Encode an attribute value for HTML output. + * @param $text + * @return HTML-encoded text fragment + */ +function encodeAttribute( $text ) { + + // In Enano 1.0.3, added this cheapo hack to keep ampersands + // from being double-sanitized. Thanks to markybob from #deluge. + + // htmlspecialchars() the "manual" way + $encValue = strtr( $text, array( + '&' => '&', + '"' => '"', + '<' => '<', + '>' => '>', + ''' => "'" + ) ); + + $encValue = strtr( $text, array( + '&' => '&', + '"' => '"', + '<' => '<', + '>' => '>', + "'" => ''' + ) ); + + + // Whitespace is normalized during attribute decoding, + // so if we've been passed non-spaces we must encode them + // ahead of time or they won't be preserved. + $encValue = strtr( $encValue, array( + "\n" => ' ', + "\r" => ' ', + "\t" => ' ', + ) ); + + return $encValue; +} + +function unstripForHTML( $text ) { + global $mStripState; + $text = unstrip( $text, $mStripState ); + $text = unstripNoWiki( $text, $mStripState ); + return $text; +} + +/** + * Always call this after unstrip() to preserve the order + * + * @private + */ +function unstripNoWiki( $text, &$state ) { + if ( !isset( $state['nowiki'] ) ) { + return $text; + } + + # TODO: good candidate for FSS + $text = strtr( $text, $state['nowiki'] ); + + return $text; +} + +/** + * Take an array of attribute names and values and normalize or discard + * illegal values for the given element type. + * + * - Discards attributes not on a whitelist for the given element + * - Unsafe style attributes are discarded + * + * @param array $attribs + * @param string $element + * @return array + * + * @todo Check for legal values where the DTD limits things. + * @todo Check for unique id attribute :P + */ +function validateTagAttributes( $attribs, $element ) { + $whitelist = array_flip( attributeWhitelist( $element ) ); + $out = array(); + foreach( $attribs as $attribute => $value ) { + if( !isset( $whitelist[$attribute] ) ) { + continue; + } + # Strip javascript "expression" from stylesheets. + # http://msdn.microsoft.com/workshop/author/dhtml/overview/recalc.asp + if( $attribute == 'style' ) { + $value = checkCss( $value ); + if( $value === false ) { + # haxx0r + continue; + } + } + + if ( $attribute === 'id' ) + $value = escapeId( $value ); + + // If this attribute was previously set, override it. + // Output should only have one attribute of each name. + $out[$attribute] = $value; + } + return $out; +} + +/** + * Pick apart some CSS and check it for forbidden or unsafe structures. + * Returns a sanitized string, or false if it was just too evil. + * + * Currently URL references, 'expression', 'tps' are forbidden. + * + * @param string $value + * @return mixed + */ +function checkCss( $value ) { + $stripped = decodeCharReferences( $value ); + + // Remove any comments; IE gets token splitting wrong + $stripped = preg_replace( '!/\\*.*?\\*/!S', '', $stripped ); + $value = $stripped; + + // ... and continue checks + $stripped = preg_replace( '!\\\\([0-9A-Fa-f]{1,6})[ \\n\\r\\t\\f]?!e', + 'codepointToUtf8(hexdec("$1"))', $stripped ); + $stripped = str_replace( '\\', '', $stripped ); + if( preg_match( '/(expression|tps*:\/\/|url\\s*\().*/is', + $stripped ) ) { + # haxx0r + return false; + } + + return $value; +} + +/** + * Decode any character references, numeric or named entities, + * in the text and return a UTF-8 string. + * + * @param string $text + * @return string + * @access public + * @static + */ +function decodeCharReferences( $text ) { + return preg_replace_callback( + MW_CHAR_REFS_REGEX, + 'decodeCharReferencesCallback', + $text ); +} + +/** + * Fetch the whitelist of acceptable attributes for a given + * element name. + * + * @param string $element + * @return array + */ +function attributeWhitelist( $element ) { + static $list; + if( !isset( $list ) ) { + $list = setupAttributeWhitelist(); + } + return isset( $list[$element] ) + ? $list[$element] + : array(); +} + +/** + * @todo Document it a bit + * @return array + */ +function setupAttributeWhitelist() { + global $db, $session, $paths, $template, $plugins; + $common = array( 'id', 'class', 'lang', 'dir', 'title', 'style' ); + $block = array_merge( $common, array( 'align' ) ); + $tablealign = array( 'align', 'char', 'charoff', 'valign' ); + $tablecell = array( 'abbr', + 'axis', + 'headers', + 'scope', + 'rowspan', + 'colspan', + 'nowrap', # deprecated + 'width', # deprecated + 'height', # deprecated + 'bgcolor' # deprecated + ); + + # Numbers refer to sections in HTML 4.01 standard describing the element. + # See: http://www.w3.org/TR/html4/ + $whitelist = array ( + # 7.5.4 + 'div' => $block, + 'center' => $common, # deprecated + 'span' => $block, # ?? + + # 7.5.5 + 'h1' => $block, + 'h2' => $block, + 'h3' => $block, + 'h4' => $block, + 'h5' => $block, + 'h6' => $block, + + # 7.5.6 + # address + + # 8.2.4 + # bdo + + # 9.2.1 + 'em' => $common, + 'strong' => $common, + 'cite' => $common, + # dfn + 'code' => $common, + # samp + # kbd + 'var' => $common, + # abbr + # acronym + + # 9.2.2 + 'blockquote' => array_merge( $common, array( 'cite' ) ), + # q + + # 9.2.3 + 'sub' => $common, + 'sup' => $common, + + # 9.3.1 + 'p' => $block, + + # 9.3.2 + 'br' => array( 'id', 'class', 'title', 'style', 'clear' ), + + # 9.3.4 + 'pre' => array_merge( $common, array( 'width' ) ), + + # 9.4 + 'ins' => array_merge( $common, array( 'cite', 'datetime' ) ), + 'del' => array_merge( $common, array( 'cite', 'datetime' ) ), + + # 10.2 + 'ul' => array_merge( $common, array( 'type' ) ), + 'ol' => array_merge( $common, array( 'type', 'start' ) ), + 'li' => array_merge( $common, array( 'type', 'value' ) ), + + # 10.3 + 'dl' => $common, + 'dd' => $common, + 'dt' => $common, + + # 11.2.1 + 'table' => array_merge( $common, + array( 'summary', 'width', 'border', 'frame', + 'rules', 'cellspacing', 'cellpadding', + 'align', 'bgcolor', + ) ), + + # 11.2.2 + 'caption' => array_merge( $common, array( 'align' ) ), + + # 11.2.3 + 'thead' => array_merge( $common, $tablealign ), + 'tfoot' => array_merge( $common, $tablealign ), + 'tbody' => array_merge( $common, $tablealign ), + + # 11.2.4 + 'colgroup' => array_merge( $common, array( 'span', 'width' ), $tablealign ), + 'col' => array_merge( $common, array( 'span', 'width' ), $tablealign ), + + # 11.2.5 + 'tr' => array_merge( $common, array( 'bgcolor' ), $tablealign ), + + # 11.2.6 + 'td' => array_merge( $common, $tablecell, $tablealign ), + 'th' => array_merge( $common, $tablecell, $tablealign ), + + # 12.2 + # added by dan + 'a' => array_merge( $common, array( 'href', 'name' ) ), + + # 13.2 + # added by dan + 'img' => array_merge( $common, array( 'src', 'width', 'height', 'alt' ) ), + + # 15.2.1 + 'tt' => $common, + 'b' => $common, + 'i' => $common, + 'big' => $common, + 'small' => $common, + 'strike' => $common, + 's' => $common, + 'u' => $common, + + # 15.2.2 + 'font' => array_merge( $common, array( 'size', 'color', 'face' ) ), + # basefont + + # 15.3 + 'hr' => array_merge( $common, array( 'noshade', 'size', 'width' ) ), + + # XHTML Ruby annotation text module, simple ruby only. + # http://www.w3c.org/TR/ruby/ + 'ruby' => $common, + # rbc + # rtc + 'rb' => $common, + 'rt' => $common, #array_merge( $common, array( 'rbspan' ) ), + 'rp' => $common, + + # For compatibility with the XHTML parser. + 'nowiki' => array(), + 'noinclude' => array(), + 'nodisplay' => array(), + 'lang' => array('code'), + + # XHTML stuff + 'acronym' => $common + ); + + // custom tags can be added by plugins + $code = $plugins->setHook('html_attribute_whitelist'); + foreach ( $code as $cmd ) + { + eval($cmd); + } + + return $whitelist; +} + +/** + * Given a value escape it so that it can be used in an id attribute and + * return it, this does not validate the value however (see first link) + * + * @link http://www.w3.org/TR/html401/types.html#type-name Valid characters + * in the id and + * name attributes + * @link http://www.w3.org/TR/html401/struct/links.html#h-12.2.3 Anchors with the id attribute + * + * @bug 4461 + * + * @static + * + * @param string $id + * @return string + */ +function escapeId( $id ) { + static $replace = array( + '%3A' => ':', + '%' => '.' + ); + + $id = urlencode( decodeCharReferences( strtr( $id, ' ', '_' ) ) ); + + return str_replace( array_keys( $replace ), array_values( $replace ), $id ); +} + +/** + * More or less "markup-safe" explode() + * Ignores any instances of the separator inside <...> + * @param string $separator + * @param string $text + * @return array + */ +function wfExplodeMarkup( $separator, $text ) { + $placeholder = "\x00"; + + // Just in case... + $text = str_replace( $placeholder, '', $text ); + + // Trim stuff + $replacer = new ReplacerCallback( $separator, $placeholder ); + $cleaned = preg_replace_callback( '/(<.*?>)/', array( $replacer, 'go' ), $text ); + + $items = explode( $separator, $cleaned ); + foreach( $items as $i => $str ) { + $items[$i] = str_replace( $placeholder, $separator, $str ); + } + + return $items; +} + +class ReplacerCallback { + function ReplacerCallback( $from, $to ) { + $this->from = $from; + $this->to = $to; + } + + function go( $matches ) { + return str_replace( $this->from, $this->to, $matches[1] ); + } +} + +/** + * Return an associative array of attribute names and values from + * a partial tag string. Attribute names are forces to lowercase, + * character references are decoded to UTF-8 text. + * + * @param string + * @return array + */ +function decodeTagAttributes( $text ) { + $attribs = array(); + + if( trim( $text ) == '' ) { + return $attribs; + } + + $pairs = array(); + if( !preg_match_all( + MW_ATTRIBS_REGEX, + $text, + $pairs, + PREG_SET_ORDER ) ) { + return $attribs; + } + + foreach( $pairs as $set ) { + $attribute = strtolower( $set[1] ); + $value = getTagAttributeCallback( $set ); + + // Normalize whitespace + $value = preg_replace( '/[\t\r\n ]+/', ' ', $value ); + $value = trim( $value ); + + // Decode character references + $attribs[$attribute] = decodeCharReferences( $value ); + } + return $attribs; +} + +/** + * Pick the appropriate attribute value from a match set from the + * MW_ATTRIBS_REGEX matches. + * + * @param array $set + * @return string + * @access private + */ +function getTagAttributeCallback( $set ) { + if( isset( $set[6] ) ) { + # Illegal #XXXXXX color with no quotes. + return $set[6]; + } elseif( isset( $set[5] ) ) { + # No quotes. + return $set[5]; + } elseif( isset( $set[4] ) ) { + # Single-quoted + return $set[4]; + } elseif( isset( $set[3] ) ) { + # Double-quoted + return $set[3]; + } elseif( !isset( $set[2] ) ) { + # In XHTML, attributes must have a value. + # For 'reduced' form, return explicitly the attribute name here. + return $set[1]; + } else { + die_friendly('Parser error', "

Tag conditions not met. This should never happen and is a bug.

" ); + } +} + +/** + * Strips and renders nowiki, pre, math, hiero + * If $render is set, performs necessary rendering operations on plugins + * Returns the text, and fills an array with data needed in unstrip() + * If the $state is already a valid strip state, it adds to the state + * + * @param bool $stripcomments when set, HTML comments + * will be stripped in addition to other tags. This is important + * for section editing, where these comments cause confusion when + * counting the sections in the wikisource + * + * @param array dontstrip contains tags which should not be stripped; + * used to prevent stipping of when saving (fixes bug 2700) + * + * @access private + */ +function mwStrip( $text, &$state, $stripcomments = false , $dontstrip = array () ) { + global $wgRandomKey; + $render = true; + + $wgRandomKey = "\x07UNIQ" . dechex(mt_rand(0, 0x7fffffff)) . dechex(mt_rand(0, 0x7fffffff)); + $uniq_prefix =& $wgRandomKey; + $commentState = array(); + + $elements = array( 'nowiki', 'gallery' ); + + # Removing $dontstrip tags from $elements list (currently only 'gallery', fixing bug 2700) + foreach ( $elements AS $k => $v ) { + if ( !in_array ( $v , $dontstrip ) ) continue; + unset ( $elements[$k] ); + } + + $matches = array(); + $text = extractTagsAndParams( $elements, $text, $matches, $uniq_prefix ); + + foreach( $matches as $marker => $data ) { + list( $element, $content, $params, $tag ) = $data; + if( $render ) { + $tagName = strtolower( $element ); + switch( $tagName ) { + case '!--': + // Comment + if( substr( $tag, -3 ) == '-->' ) { + $output = $tag; + } else { + // Unclosed comment in input. + // Close it so later stripping can remove it + $output = "$tag-->"; + } + break; + case 'html': + if( $wgRawHtml ) { + $output = $content; + break; + } + // Shouldn't happen otherwise. :) + case 'nowiki': + $output = wfEscapeHTMLTagsOnly( $content ); + break; + default: + } + } else { + // Just stripping tags; keep the source + $output = $tag; + } + + // Unstrip the output, because unstrip() is no longer recursive so + // it won't do it itself + $output = unstrip( $output, $state ); + + if( !$stripcomments && $element == '!--' ) { + $commentState[$marker] = $output; + } elseif ( $element == 'html' || $element == 'nowiki' ) { + $state['nowiki'][$marker] = $output; + } else { + $state['general'][$marker] = $output; + } + } + + # Unstrip comments unless explicitly told otherwise. + # (The comments are always stripped prior to this point, so as to + # not invoke any extension tags / parser hooks contained within + # a comment.) + if ( !$stripcomments ) { + // Put them all back and forget them + $text = strtr( $text, $commentState ); + } + + return $text; +} + +/** + * Replaces all occurrences of HTML-style comments and the given tags + * in the text with a random marker and returns teh next text. The output + * parameter $matches will be an associative array filled with data in + * the form: + * 'UNIQ-xxxxx' => array( + * 'element', + * 'tag content', + * array( 'param' => 'x' ), + * 'tag content' ) ) + * + * @param $elements list of element names. Comments are always extracted. + * @param $text Source text string. + * @param $uniq_prefix + * + * @access private + * @static + */ +function extractTagsAndParams($elements, $text, &$matches, $uniq_prefix = ''){ + static $n = 1; + $stripped = ''; + $matches = array(); + + $taglist = implode( '|', $elements ); + $start = "/<($taglist)(\\s+[^>]*?|\\s*?)(\/?>)|<(!--)/i"; + + while ( '' != $text ) { + $p = preg_split( $start, $text, 2, PREG_SPLIT_DELIM_CAPTURE ); + $stripped .= $p[0]; + if( count( $p ) < 5 ) { + break; + } + if( count( $p ) > 5 ) { + // comment + $element = $p[4]; + $attributes = ''; + $close = ''; + $inside = $p[5]; + } else { + // tag + $element = $p[1]; + $attributes = $p[2]; + $close = $p[3]; + $inside = $p[4]; + } + + $marker = "$uniq_prefix-$element-" . sprintf('%08X', $n++) . '-QINU'; + $stripped .= $marker; + + if ( $close === '/>' ) { + // Empty element tag, + $content = null; + $text = $inside; + $tail = null; + } else { + if( $element == '!--' ) { + $end = '/(-->)/'; + } else { + $end = "/(<\\/$element\\s*>)/i"; + } + $q = preg_split( $end, $inside, 2, PREG_SPLIT_DELIM_CAPTURE ); + $content = $q[0]; + if( count( $q ) < 3 ) { + # No end tag -- let it run out to the end of the text. + $tail = ''; + $text = ''; + } else { + $tail = $q[1]; + $text = $q[2]; + } + } + + $matches[$marker] = array( $element, + $content, + decodeTagAttributes( $attributes ), + "<$element$attributes$close$content$tail" ); + } + return $stripped; +} + +/** + * Escape html tags + * Basically replacing " > and < with HTML entities ( ", >, <) + * + * @param $in String: text that might contain HTML tags. + * @return string Escaped string + */ +function wfEscapeHTMLTagsOnly( $in ) { + return str_replace( + array( '"', '>', '<' ), + array( '"', '>', '<' ), + $in ); +} + +/** + * Restores pre, math, and other extensions removed by strip() + * + * always call unstripNoWiki() after this one + * @private + */ +function unstrip( $text, &$state ) { + if ( !isset( $state['general'] ) ) { + return $text; + } + + # TODO: good candidate for FSS + $text = strtr( $text, $state['general'] ); + + return $text; +} + +/** + * Return UTF-8 string for a codepoint if that is a valid + * character reference, otherwise U+FFFD REPLACEMENT CHARACTER. + * @param int $codepoint + * @return string + * @private + */ +function decodeChar( $codepoint ) { + if( validateCodepoint( $codepoint ) ) { + return codepointToUtf8( $codepoint ); + } else { + return UTF8_REPLACEMENT; + } +} + +/** + * If the named entity is defined in the HTML 4.0/XHTML 1.0 DTD, + * return the UTF-8 encoding of that character. Otherwise, returns + * pseudo-entity source (eg &foo;) + * + * @param string $name + * @return string + */ +function decodeEntity( $name ) { + global $wgHtmlEntities; + if( isset( $wgHtmlEntities[$name] ) ) { + return codepointToUtf8( $wgHtmlEntities[$name] ); + } else { + return "&$name;"; + } +} + +/** + * Returns true if a given Unicode codepoint is a valid character in XML. + * @param int $codepoint + * @return bool + */ +function validateCodepoint( $codepoint ) { + return ($codepoint == 0x09) + || ($codepoint == 0x0a) + || ($codepoint == 0x0d) + || ($codepoint >= 0x20 && $codepoint <= 0xd7ff) + || ($codepoint >= 0xe000 && $codepoint <= 0xfffd) + || ($codepoint >= 0x10000 && $codepoint <= 0x10ffff); +} + +/** + * Return UTF-8 sequence for a given Unicode code point. + * May die if fed out of range data. + * + * @param $codepoint Integer: + * @return String + * @public + */ +function codepointToUtf8( $codepoint ) { + if($codepoint < 0x80) return chr($codepoint); + if($codepoint < 0x800) return chr($codepoint >> 6 & 0x3f | 0xc0) . + chr($codepoint & 0x3f | 0x80); + if($codepoint < 0x10000) return chr($codepoint >> 12 & 0x0f | 0xe0) . + chr($codepoint >> 6 & 0x3f | 0x80) . + chr($codepoint & 0x3f | 0x80); + if($codepoint < 0x110000) return chr($codepoint >> 18 & 0x07 | 0xf0) . + chr($codepoint >> 12 & 0x3f | 0x80) . + chr($codepoint >> 6 & 0x3f | 0x80) . + chr($codepoint & 0x3f | 0x80); + + echo "Asked for code outside of range ($codepoint)\n"; + die( -1 ); +} + +/** + * @param string $matches + * @return string + */ +function decodeCharReferencesCallback( $matches ) { + if( $matches[1] != '' ) { + return decodeEntity( $matches[1] ); + } elseif( $matches[2] != '' ) { + return decodeChar( intval( $matches[2] ) ); + } elseif( $matches[3] != '' ) { + return decodeChar( hexdec( $matches[3] ) ); + } elseif( $matches[4] != '' ) { + return decodeChar( hexdec( $matches[4] ) ); + } + # Last case should be an ampersand by itself + return $matches[0]; +} + diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/parse_mediawiki.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/includes/wikiengine/parse_mediawiki.php Sun Jun 21 00:20:32 2009 -0400 @@ -0,0 +1,202 @@ + "/'''(.+?)'''/", + 'italic' => "/''(.+?)''/", + 'underline' => '/__(.+?)__/', + 'externalwithtext' => '#\[((?:https?|irc|ftp)://.+?) (.+?)\]#', + 'externalnotext' => '#\[((?:https?|irc|ftp)://.+?)\]#' + ); + + public function lang(&$text) + { + global $lang; + + preg_match_all('/([\w\W]+?)<\/lang>/', $text, $langmatch); + foreach ( $langmatch[0] as $i => $match ) + { + if ( $langmatch[1][$i] == $lang->lang_code ) + { + $text = str_replace_once($match, $langmatch[2][$i], $text); + } + else + { + $text = str_replace_once($match, '', $text); + } + } + + return array(); + } + + public function templates(&$text) + { + $template_regex = "/\{\{(.+)((\n|\|[ ]*([A-z0-9]+)[ ]*=[ ]*(.+))*)\}\}/isU"; + $i = 0; + while ( preg_match($template_regex, $text) ) + { + $i++; + if ( $i == 5 ) + break; + $text = RenderMan::include_templates($text); + } + + return array(); + } + + public function heading(&$text) + { + if ( !preg_match_all('/^(={1,6}) *(.+?) *\\1$/m', $text, $results) ) + return array(); + + $headings = array(); + foreach ( $results[0] as $i => $match ) + { + $headings[] = array( + 'level' => strlen($results[1][$i]), + 'text' => $results[2][$i] + ); + } + + $text = Carpenter::tokenize($text, $results[0]); + + return $headings; + } + + public function multilist(&$text) + { + // Match entire lists + $regex = '/^ + ([:#\*])+ # Initial list delimiter + [ ]* + .+? + (?: + \r?\n + (?:\\1|[ ]{2,}) + [ ]* + .+?)* + $/mx'; + + if ( !preg_match_all($regex, $text, $lists) ) + return array(); + + $types = array( + '*' => 'unordered', + '#' => 'ordered', + ':' => 'indent' + ); + + $pieces = array(); + foreach ( $lists[0] as $i => $list ) + { + $token = $lists[1][$i]; + $piece = array( + 'type' => $types[$token], + 'items' => array() + ); + + // convert windows newlines to unix + $list = str_replace("\r\n", "\n", $list); + $items_pre = explode("\n", $list); + $items = array(); + // first pass, go through and combine items that are newlined + foreach ( $items_pre as $item ) + { + if ( substr($item, 0, 1) == $token ) + { + $items[] = $item; + } + else + { + // it's a continuation of the previous LI. Don't need to worry about + // undefined indices here since the regex should filter out all invalid + // markup. Just append this line to the previous. + $items[ count($items) - 1 ] .= "\n" . trim($item); + } + } + + // second pass, separate items and tokens + unset($items_pre); + foreach ( $items as $item ) + { + // get the depth + list($itemtoken) = explode(' ', $item); + // get the text + $itemtext = trim(substr($item, strlen($itemtoken))); + $piece['items'][] = array( + // depth starts at 1 + 'depth' => strlen($itemtoken), + 'text' => $itemtext + ); + } + + $pieces[] = $piece; + } + + $text = Carpenter::tokenize($text, $lists[0]); + + return $pieces; + } + + public function paragraph(&$text) + { + // This is potentially a hack. It allows the parser to stick in <_paragraph_bypass> tags + // to prevent the paragraph parser from interfering with pretty HTML generated elsewhere. + RenderMan::tag_strip('_paragraph_bypass', $text, $_nw); + + // The trick with paragraphs is to not turn things into them when a block level element already wraps the block of text. + // First we need a list of block level elements (http://htmlhelp.com/reference/html40/block.html) + $blocklevel = 'address|blockquote|center|div|dl|fieldset|form|h1|h2|h3|h4|h5|h6|hr|ol|p|pre|table|ul'; + + $regex = "/^( + (?:(?!(?:\\n|[ ]*<(?:{$blocklevel})))) # condition for starting paragraph: not a newline character or block level element + .+? # body text + (?: + \\n # additional lines in the para + (?:(?!(?:\\n|[ ]*<(?:{$blocklevel})))) # make sure of only one newline in a row, and no block level elements + .*? + )* + )$ + /mx"; + + if ( !preg_match_all($regex, $text, $matches) ) + return array(); + + // Debugging :) + // die('
' . htmlspecialchars(print_r($matches, true)) . '
'); + + // restore stripped + RenderMan::tag_unstrip('_paragraph_bypass', $text, $_nw); + + // tokenize + $text = Carpenter::tokenize($text, $matches[0]); + + return $matches[0]; + } +} + +function parser_mediawiki_xhtml_image($text) +{ + $text = RenderMan::process_image_tags($text, $taglist); + $text = RenderMan::process_imgtags_stage2($text, $taglist); + return $text; +} + +function parser_mediawiki_xhtml_tables($text) +{ + return process_tables($text); +} + diff -r f0431eb8161e -r 98c052fc3337 includes/wikiengine/render_xhtml.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/includes/wikiengine/render_xhtml.php Sun Jun 21 00:20:32 2009 -0400 @@ -0,0 +1,133 @@ + '', + 'templates' => '', + 'bold' => '\\1', + 'italic' => '\\1', + 'underline' => '\\1', + 'externalwithtext' => '\\2', + 'externalnotext' => '\\1', + ); + + public function heading($text, $pieces) + { + static $tocid = -1; + foreach ( $pieces as $i => $piece ) + { + $tocid++; + $tag = ''; + $tag .= trim($piece['text']); + $tag .= ''; + + $text = str_replace(Carpenter::generate_token($i), $tag, $text); + } + + return $text; + } + + public function multilist($text, $pieces) + { + foreach ( $pieces as $i => $piece ) + { + switch($piece['type']) + { + case 'unordered': + default: + $btag = 'ul'; + $itag = 'li'; + break; + case 'ordered': + $btag = 'ol'; + $itag = 'li'; + break; + case 'indent': + $btag = 'dl'; + $itag = 'dd'; + break; + } + $list = "<$btag><_paragraph_bypass>\n"; + $spacing = ''; + $depth = 1; + foreach ( $piece['items'] as $j => $item ) + { + // most of this just goes into pretty formatting. + // everything else goes into meeting the PITA requirement that if you're going + // another level deep, HTML requires the next level to be INSIDE of the
/
  • tag. + $itemdepth = $item['depth']; + if ( $itemdepth > $depth ) + { + while ( $depth < $itemdepth ) + { + $spacing .= ' '; + $list .= "{$spacing}<$btag>\n"; + $depth++; + } + } + else if ( $itemdepth < $depth ) + { + while ( $depth > $itemdepth ) + { + $list .= "{$spacing}\n"; + $spacing = substr($spacing, 4); + $list .= "{$spacing}\n"; + $spacing = substr($spacing, 4); + $depth--; + } + } + $list .= "{$spacing} <$itag>" . nl2br($item['text']); + if ( ( isset($piece['items'][ ++$j ]) && $piece['items'][ $j ]['depth'] <= $itemdepth ) || !isset($piece['items'][ $j ]) ) + { + $list .= "\n"; + } + else + { + $list .= "\n"; + $spacing .= " "; + } + } + while ( $depth > 1 ) + { + $list .= "{$spacing}\n"; + $spacing = substr($spacing, 4); + $list .= "{$spacing}\n"; + $spacing = substr($spacing, 4); + $depth--; + } + $list .= "\n"; + $text = str_replace(Carpenter::generate_token($i), $list, $text); + } + return $text; + } + + public function paragraph($text, $pieces) + { + foreach ( $pieces as $i => $piece ) + { + $text = str_replace(Carpenter::generate_token($i), '

    ' . nl2br($piece) . '

    ', $text); + } + + return $text; + } +} + +// Alias internal link parsing to RenderMan's method +function parser_mediawiki_xhtml_internallink($text) +{ + return RenderMan::parse_internal_links($text); +} + diff -r f0431eb8161e -r 98c052fc3337 includes/wikiformat.php --- a/includes/wikiformat.php Sun Jun 21 00:16:21 2009 -0400 +++ b/includes/wikiformat.php Sun Jun 21 00:20:32 2009 -0400 @@ -13,633 +13,312 @@ */ /** - * Parse structured wiki text and render into arbitrary formats such as XHTML. - * - * PHP versions 4 and 5 + * Framework for parsing and rendering various formats. In Enano by default, this is MediaWiki-style wikitext being + * rendered to XHTML, but this framework allows other formats to be supported as well. * - * @category Text - * @package Text_Wiki - * @author Paul M. Jones - * @license http://www.gnu.org/licenses/lgpl.html - * @version CVS: $Id: Wiki.php,v 1.44 2006/03/02 04:04:59 justinpatrin Exp $ - * @link http://wiki.ciaweb.net/yawiki/index.php?area=Text_Wiki - * - * This code was modified for use in Enano. The Text_Wiki engine is licensed - * under the GNU Lesser General Public License; see - * http://www.gnu.org/licenses/lgpl.html for details. - * + * @package Enano + * @subpackage Content + * @author Dan Fuhry + * @copyright (C) 2009 Enano CMS Project + * @license GNU General Public License, version 2 or later */ -require_once ENANO_ROOT.'/includes/wikiengine/Parse.php'; -require_once ENANO_ROOT.'/includes/wikiengine/Render.php'; - -class Text_Wiki { - - var $rules = array( - 'Prefilter', - 'Delimiter', - 'Code', - 'Function', - 'Html', - 'Raw', - 'Include', - 'Embed', - 'Anchor', - 'Heading', - 'Toc', - 'Horiz', - 'Break', - 'Blockquote', - 'List', - 'Deflist', - 'Table', - 'Image', - 'Phplookup', - 'Center', - 'Newline', - 'Paragraph', - 'Url', - 'Freelink', - 'Interwiki', - 'Wikilink', - 'Colortext', - 'Strong', - 'Bold', - 'Emphasis', - 'Italic', - 'Underline', - 'Tt', - 'Superscript', - 'Subscript', - 'Revise', - 'Tighten' +class Carpenter +{ + /** + * Parser token + * @const string + */ + + const PARSER_TOKEN = "\xFF"; + + /** + * Parsing engine + * @var string + */ + + private $parser = 'mediawiki'; + + /** + * Rendering engine + * @var string + */ + + private $renderer = 'xhtml'; + + /** + * Rendering flags + */ + + public $flags = RENDER_WIKI_DEFAULT; + + /** + * List of rendering rules + * @var array + */ + + private $rules = array( + 'lang', + 'templates', + 'tables', + 'heading', + // note: can't be named list ("list" is a PHP language construct) + 'multilist', + 'bold', + 'italic', + 'underline', + 'externalwithtext', + 'externalnotext', + 'image', + 'internallink', + 'paragraph' ); - - var $disable = array( - 'Html', - 'Include', - 'Embed', - 'Tighten', - 'Image', - 'Wikilink' - ); - - var $parseConf = array(); - - var $renderConf = array( - 'Docbook' => array(), - 'Latex' => array(), - 'Pdf' => array(), - 'Plain' => array(), - 'Rtf' => array(), - 'Xhtml' => array() - ); - - var $formatConf = array( - 'Docbook' => array(), - 'Latex' => array(), - 'Pdf' => array(), - 'Plain' => array(), - 'Rtf' => array(), - 'Xhtml' => array() - ); - var $delim = "\xFF"; - var $tokens = array(); - var $_countRulesTokens = array(); - var $source = ''; - var $parseObj = array(); - var $renderObj = array(); - var $formatObj = array(); - var $path = array( - 'parse' => array(), - 'render' => array() - ); - var $_dirSep = DIRECTORY_SEPARATOR; - function Text_Wiki($rules = null) + + /** + * List of render hooks + * @var array + */ + + private $hooks = array(); + + /* private $rules = array('prefilter', 'delimiter', 'code', 'function', 'html', 'raw', 'include', 'embed', 'anchor', + 'heading', 'toc', 'horiz', 'break', 'blockquote', 'list', 'deflist', 'table', 'image', + 'phplookup', 'center', 'newline', 'paragraph', 'url', 'freelink', 'interwiki', + 'wikilink', 'colortext', 'strong', 'bold', 'emphasis', 'italic', 'underline', 'tt', + 'superscript', 'subscript', 'revise', 'tighten'); */ + + /** + * Render the text! + * @param string Text to render + * @return string + */ + + public function render($text) + { + $parser_class = "Carpenter_Parse_" . ucwords($this->parser); + $renderer_class = "Carpenter_Render_" . ucwords($this->renderer); + + // include files, if we haven't already + if ( !class_exists($parser_class) ) + { + require_once( ENANO_ROOT . "/includes/wikiengine/parse_{$this->parser}.php"); + } + + if ( !class_exists($renderer_class) ) { - if (is_array($rules)) { - $this->rules = $rules; + require_once( ENANO_ROOT . "/includes/wikiengine/render_{$this->renderer}.php"); + } + + $parser = new $parser_class; + $renderer = new $renderer_class; + + // run prehooks + foreach ( $this->hooks as $hook ) + { + if ( $hook['when'] === PO_FIRST ) + { + $text = call_user_func($hook['callback'], $text); + if ( !is_string($text) || empty($text) ) + { + trigger_error("Hook returned empty/invalid text: " . print_r($hook['callback'], true), E_USER_WARNING); + // *sigh* + $text = ''; } - - global $plugins; - // This code can be run from the installer, so in some cases $plugins - // isn't initted. (Bug in 1.1.2, fixed for 1.1.3) - if ( is_object($plugins) ) + } + } + + // perform render + foreach ( $this->rules as $rule ) + { + // run prehooks + foreach ( $this->hooks as $hook ) + { + if ( $hook['when'] === PO_BEFORE && $hook['rule'] === $rule ) { - $code = $plugins->setHook('text_wiki_construct'); - foreach ( $code as $cmd ) + $text = call_user_func($hook['callback'], $text); + if ( !is_string($text) || empty($text) ) { - eval($cmd); + trigger_error("Hook returned empty/invalid text: " . print_r($hook['callback'], true), E_USER_WARNING); + // *sigh* + $text = ''; } } - - $this->addPath( - 'parse', - $this->fixPath(ENANO_ROOT) . 'includes/wikiengine/Parse/Default/' - ); - $this->addPath( - 'render', - $this->fixPath(ENANO_ROOT) . 'includes/wikiengine/Render/' - ); - - } - - public static function singleton($parser = 'Default', $rules = null) - { - static $only = array(); - if (!isset($only[$parser])) { - $ret = Text_Wiki::factory($parser, $rules); - if (!$ret) { - return $ret; - } - $only[$parser] =& $ret; - } - return $only[$parser]; - } - - public static function factory($parser = 'Default', $rules = null) - { - $d=getcwd(); - chdir(ENANO_ROOT); - - $class = 'Text_Wiki_' . $parser; - $c2 = $parser; - $file = ENANO_ROOT . '/includes/wikiengine/' . str_replace('_', '/', $c2).'.php'; - if (!class_exists($class)) { - $fp = @fopen($file, 'r', true); - if ($fp === false) { - die_semicritical('Wiki formatting engine error', '

    Could not find file '.$file.' in include_path

    '); - } - fclose($fp); - include_once($file); - if (!class_exists($class)) { - die_semicritical('Wiki formatting engine error', '

    Class '.$class.' does not exist after including '.$file.'

    '); - } - } - - chdir($d); - - $obj = new $class($rules); - return $obj; - } - - function setParseConf($rule, $arg1, $arg2 = null) - { - $rule = ucwords(strtolower($rule)); - - if (! isset($this->parseConf[$rule])) { - $this->parseConf[$rule] = array(); - } - - if (is_array($arg1)) { - $this->parseConf[$rule] = $arg1; - } else { - $this->parseConf[$rule][$arg1] = $arg2; - } - } - - function getParseConf($rule, $key = null) - { - $rule = ucwords(strtolower($rule)); - - if (! isset($this->parseConf[$rule])) { - return null; - } - - if (is_null($key)) { - return $this->parseConf[$rule]; - } - - if (isset($this->parseConf[$rule][$key])) { - return $this->parseConf[$rule][$key]; - } else { - return null; - } - } - - function setRenderConf($format, $rule, $arg1, $arg2 = null) - { - $format = ucwords(strtolower($format)); - $rule = ucwords(strtolower($rule)); - - if (! isset($this->renderConf[$format])) { - $this->renderConf[$format] = array(); - } - - if (! isset($this->renderConf[$format][$rule])) { - $this->renderConf[$format][$rule] = array(); - } - - if (is_array($arg1)) { - $this->renderConf[$format][$rule] = $arg1; - } else { - $this->renderConf[$format][$rule][$arg1] = $arg2; - } - } - - function getRenderConf($format, $rule, $key = null) - { - $format = ucwords(strtolower($format)); - $rule = ucwords(strtolower($rule)); - - if (! isset($this->renderConf[$format]) || - ! isset($this->renderConf[$format][$rule])) { - return null; - } - - if (is_null($key)) { - return $this->renderConf[$format][$rule]; - } - - if (isset($this->renderConf[$format][$rule][$key])) { - return $this->renderConf[$format][$rule][$key]; - } else { - return null; - } - - } - - function setFormatConf($format, $arg1, $arg2 = null) - { - if (! is_array($this->formatConf[$format])) { - $this->formatConf[$format] = array(); } - - if (is_array($arg1)) { - $this->formatConf[$format] = $arg1; - } else { - $this->formatConf[$format][$arg1] = $arg2; - } - } - - function getFormatConf($format, $key = null) - { - if (! isset($this->formatConf[$format])) { - return null; - } - - if (is_null($key)) { - return $this->formatConf[$format]; - } - - if (isset($this->formatConf[$format][$key])) { - return $this->formatConf[$format][$key]; - } else { - return null; - } - } - - function insertRule($name, $tgt = null) - { - $name = ucwords(strtolower($name)); - if (! is_null($tgt)) { - $tgt = ucwords(strtolower($tgt)); - } - if (in_array($name, $this->rules)) { - return null; - } - - if (! is_null($tgt) && $tgt != '' && - ! in_array($tgt, $this->rules)) { - return false; - } - - if (is_null($tgt)) { - $this->rules[] = $name; - return true; - } - - if ($tgt == '') { - array_unshift($this->rules, $name); - return true; - } - - $tmp = $this->rules; - $this->rules = array(); - - foreach ($tmp as $val) { - $this->rules[] = $val; - if ($val == $tgt) { - $this->rules[] = $name; - } - } - - return true; - } - - function deleteRule($name) - { - $name = ucwords(strtolower($name)); - $key = array_search($name, $this->rules); - if ($key !== false) { - unset($this->rules[$key]); - } - } - - function changeRule($old, $new) - { - $old = ucwords(strtolower($old)); - $new = ucwords(strtolower($new)); - $key = array_search($old, $this->rules); - if ($key !== false) { - $this->deleteRule($new); - $this->rules[$key] = $new; - } - } - - function enableRule($name) - { - $name = ucwords(strtolower($name)); - $key = array_search($name, $this->disable); - if ($key !== false) { - unset($this->disable[$key]); - } - } - - function disableRule($name) - { - $name = ucwords(strtolower($name)); - $key = array_search($name, $this->disable); - if ($key === false) { - $this->disable[] = $name; - } - } - - function transform($text, $format = 'Xhtml') - { - $this->parse($text); - return $this->render($format); - } - - function parse($text) - { - $this->source = $text; - - $this->tokens = array(); - $this->_countRulesTokens = array(); - - foreach ($this->rules as $name) { - if (! in_array($name, $this->disable)) { - $this->loadParseObj($name); - - if (is_object($this->parseObj[$name])) { - $this->parseObj[$name]->parse(); + + // execute rule + $text = $this->perform_render_step($text, $rule, $parser, $renderer); + + // run posthooks + foreach ( $this->hooks as $hook ) + { + if ( $hook['when'] === PO_AFTER && $hook['rule'] === $rule ) + { + $text = call_user_func($hook['callback'], $text); + if ( !is_string($text) || empty($text) ) + { + trigger_error("Hook returned empty/invalid text: " . print_r($hook['callback'], true), E_USER_WARNING); + // *sigh* + $text = ''; } - // For debugging - // echo('

    ' . $name . ':

    '.htmlspecialchars($this->source).'
    '); } } } - - function render($format = 'Xhtml') + + // run posthooks + foreach ( $this->hooks as $hook ) { - $format = ucwords(strtolower($format)); - - $output = ''; - - $in_delim = false; - - $key = ''; - - $result = $this->loadFormatObj($format); - if ($this->isError($result)) { - return $result; - } - - if (is_object($this->formatObj[$format])) { - $output .= $this->formatObj[$format]->pre(); - } - - foreach (array_keys($this->_countRulesTokens) as $rule) { - $this->loadRenderObj($format, $rule); - } - - $k = strlen($this->source); - for ($i = 0; $i < $k; $i++) { - - $char = $this->source{$i}; - - if ($in_delim) { - - if ($char == $this->delim) { - - $key = (int)$key; - $rule = $this->tokens[$key][0]; - $opts = $this->tokens[$key][1]; - $output .= $this->renderObj[$rule]->token($opts); - $in_delim = false; - - } else { - - $key .= $char; - - } - - } else { - - if ($char == $this->delim) { - $key = ''; - $in_delim = true; - } else { - $output .= $char; - } + if ( $hook['when'] === PO_LAST ) + { + $text = call_user_func($hook['callback'], $text); + if ( !is_string($text) || empty($text) ) + { + trigger_error("Hook returned empty/invalid text: " . print_r($hook['callback'], true), E_USER_WARNING); + // *sigh* + $text = ''; } } - - if (is_object($this->formatObj[$format])) { - $output .= $this->formatObj[$format]->post(); - } - - return $output; } - - function getSource() - { - return $this->source; - } - - function getTokens($rules = null) - { - if (is_null($rules)) { - return $this->tokens; - } else { - settype($rules, 'array'); - $result = array(); - foreach ($this->tokens as $key => $val) { - if (in_array($val[0], $rules)) { - $result[$key] = $val; - } - } - return $result; - } - } - - function addToken($rule, $options = array(), $id_only = false) + + return (( defined('ENANO_DEBUG') && isset($_GET['parserdebug']) ) ? '
    ' . htmlspecialchars($text) . '
    ' : $text) . "\n\n"; + } + + /** + * Performs a step in the rendering process. + * @param string Text to render + * @param string Rule to execute + * @param object Parser instance + * @param object Renderer instance + * @return string + * @access private + */ + + private function perform_render_step($text, $rule, $parser, $renderer) + { + // First look for a direct function + if ( function_exists("parser_{$this->parser}_{$this->renderer}_{$rule}") ) { - static $id; - if (! isset($id)) { - $id = 0; - } else { - $id ++; - } - - settype($options, 'array'); - - $this->tokens[$id] = array( - 0 => $rule, - 1 => $options - ); - if (!isset($this->_countRulesTokens[$rule])) { - $this->_countRulesTokens[$rule] = 1; - } else { - ++$this->_countRulesTokens[$rule]; - } - - if ($id_only) { - return $id; - } else { - return $this->delim . $id . $this->delim; - } + return call_user_func("parser_{$this->parser}_{$this->renderer}_{$rule}", $text, $this->flags); } - - function setToken($id, $rule, $options = array()) + + // We don't have that, so start looking for other ways or means of doing this + if ( method_exists($parser, $rule) && method_exists($renderer, $rule) ) + { + // Both the parser and render have callbacks they want to use. + $pieces = $parser->$rule($text); + $text = call_user_func(array($renderer, $rule), $text, $pieces); + } + else if ( method_exists($parser, $rule) && !method_exists($renderer, $rule) && isset($renderer->rules[$rule]) ) { - $oldRule = $this->tokens[$id][0]; - $this->tokens[$id] = array( - 0 => $rule, - 1 => $options - ); - if ($rule != $oldRule) { - if (!($this->_countRulesTokens[$oldRule]--)) { - unset($this->_countRulesTokens[$oldRule]); - } - if (!isset($this->_countRulesTokens[$rule])) { - $this->_countRulesTokens[$rule] = 1; - } else { - ++$this->_countRulesTokens[$rule]; - } - } + // The parser has a callback, but the renderer does not + $pieces = $parser->$rule($text); + $text = $this->generic_render($text, $pieces, $renderer->rules[$rule]); } - - function loadParseObj($rule) + else if ( !method_exists($parser, $rule) && isset($parser->rules[$rule]) && method_exists($renderer, $rule) ) { - $rule = ucwords(strtolower($rule)); - $file = $rule . '.php'; - $class = "Text_Wiki_Parse_$rule"; - - if (! class_exists($class)) { - $loc = $this->findFile('parse', $file); - if ($loc) { - include_once $loc; - } else { - $this->parseObj[$rule] = null; - return $this->error( - "Parse rule '$rule' not found" - ); - } - } - - $this->parseObj[$rule] = new $class($this); - + // The parser has no callback, but the renderer does + $text = preg_replace_callback($parser->rules[$rule], array($renderer, $rule), $text); + } + else if ( isset($parser->rules[$rule]) && isset($renderer->rules[$rule]) ) + { + // This is a straight-up regex only rule + $text = preg_replace($parser->rules[$rule], $renderer->rules[$rule], $text); + } + else + { + // Either the renderer or parser does not support this rule, ignore it } - - function loadRenderObj($format, $rule) - { - $format = ucwords(strtolower($format)); - $rule = ucwords(strtolower($rule)); - $file = "$format/$rule.php"; - $class = "Text_Wiki_Render_$format" . "_$rule"; - - if (! class_exists($class)) { - $loc = $this->findFile('render', $file); - if ($loc) { - include_once $loc; - } else { - return $this->error( - "Render rule '$rule' in format '$format' not found" - ); - } - } - - $this->renderObj[$rule] = new $class($this); - } - - function loadFormatObj($format) - { - $format = ucwords(strtolower($format)); - $file = $format . '.php'; - $class = "Text_Wiki_Render_$format"; - - if (! class_exists($class)) { - $loc = $this->findFile('render', $file); - if ($loc) { - include_once $loc; - } else { - return $this->error( - "Rendering format class '$class' not found" - ); - } - } - - $this->formatObj[$format] = new $class($this); - } - - function addPath($type, $dir) + + return $text; + } + + /** + * Generic renderer + * @access protected + */ + + protected function generic_render($text, $pieces, $rule) + { + foreach ( $pieces as $i => $piece ) { - $dir = $this->fixPath($dir); - if (! isset($this->path[$type])) { - $this->path[$type] = array($dir); - } else { - array_unshift($this->path[$type], $dir); + $replacement = $rule; + + // if the piece is an array, replace $1, $2, etc. in the rule with each value in the piece + if ( is_array($piece) ) + { + $j = 0; + foreach ( $piece as $part ) + { + $j++; + $replacement = str_replace(array("\\$j", "\${$j}"), $part, $replacement); } + } + // else, just replace \\1 or $1 in the rule with the piece + else + { + $replacement = str_replace(array("\\1", "\$1"), $piece, $replacement); + } + + $text = str_replace(self::generate_token($i), $replacement, $text); } - - function getPath($type = null) - { - if (is_null($type)) { - return $this->path; - } elseif (! isset($this->path[$type])) { - return array(); - } else { - return $this->path[$type]; - } - } - - function findFile($type, $file) + + return $text; + } + + /** + * Add a hook into the parser. + * @param callback Function to call + * @param int PO_* constant + * @param string If PO_{BEFORE,AFTER} used, rule + */ + + public function hook($callback, $when, $rule = false) + { + if ( !is_int($when) ) + return null; + if ( ($when == PO_BEFORE || $when == PO_AFTER) && !is_string($rule) ) + return null; + if ( ( is_string($callback) && !function_exists($callback) ) || ( is_array($callback) && !method_exists($callback[0], $callback[1]) ) || ( !is_string($callback) && !is_array($callback) ) ) { - $set = $this->getPath($type); - - foreach ($set as $path) { - $fullname = $path . $file; - if (file_exists($fullname) && is_readable($fullname)) { - return $fullname; - } - } - - return false; + trigger_error("Attempt to hook with undefined function/method " . print_r($callback, true), E_USER_ERROR); + return null; } - - function fixPath($path) + + $this->hooks[] = array( + 'callback' => $callback, + 'when' => $when, + 'rule' => $rule + ); + } + + /** + * Generate a token + * @param int Token index + * @return string + * @static + */ + + public static function generate_token($i) + { + return self::PARSER_TOKEN . $i . self::PARSER_TOKEN; + } + + /** + * Tokenize string + * @param string + * @param array Matches + * @return string + * @static + */ + + public static function tokenize($text, $matches) + { + $matches = array_values($matches); + foreach ( $matches as $i => $match ) { - $len = strlen($this->_dirSep); - - if (! empty($path) && - substr($path, -1 * $len, $len) != $this->_dirSep) { - return $path . $this->_dirSep; - } else { - return $path; - } + $text = str_replace_once($match, self::generate_token($i), $text); } - - function &error($message) - { - die($message); - } - - function isError(&$obj) - { - return ( @get_class($obj) == 'PEAR_Error' ); - } + + return $text; + } } -?>