var $mTagHooks;
# Cleared with clearState():
- var $mOutput, $mAutonumber, $mDTopen, $mStripState = array();
+ var $mOutput, $mAutonumber, $mDTopen, $mStripState = array(), $mCurrentParams = array();
var $mVariables, $mIncludeCount, $mArgStack, $mLastSection, $mInPre;
var $mInterwikiLinkHolders, $mLinkHolders;
* @access public
*/
function Parser() {
- global $wgContLang;
$this->mTemplates = array();
$this->mTemplatePath = array();
$this->mTagHooks = array();
$this->mStripState = array();
$this->mArgStack = array();
$this->mInPre = false;
+ $this->mCurrentParams = array();
$this->mInterwikiLinkHolders = array(
'texts' => array(),
'titles' => array()
wfRunHooks( 'ParserBeforeTidy', array( &$this, &$text ) );
$text = Sanitizer::normalizeCharReferences( $text );
- global $wgUseTidy;
+
if ($wgUseTidy) {
$text = Parser::tidy($text);
}
}
# math
- $text = Parser::extractTags('math', $text, $math_content, $uniq_prefix);
- foreach( $math_content as $marker => $content ){
- if( $render ) {
- if( $this->mOptions->getUseTeX() ) {
+ if( $this->mOptions->getUseTeX() ) {
+ $text = Parser::extractTags('math', $text, $math_content, $uniq_prefix);
+ foreach( $math_content as $marker => $content ){
+ if( $render ) {
$math_content[$marker] = renderMath( $content );
} else {
- $math_content[$marker] = '<math>'.$content.'<math>';
+ $math_content[$marker] = '<math>'.$content.'</math>';
}
- } else {
- $math_content[$marker] = '<math>'.$content.'</math>';
}
}
$text = Parser::extractTagsAndParams( $tag, $text, $ext_content[$tag],
$ext_tags[$tag], $ext_params[$tag], $uniq_prefix );
foreach( $ext_content[$tag] as $marker => $content ) {
+ $content = $this->replaceVariables( $content, $this->mCurrentParams );
$full_tag = $ext_tags[$tag][$marker];
$params = $ext_params[$tag][$marker];
if ( $render ) {
- $ext_content[$tag][$marker] = $callback( $content, $params );
+ $ext_content[$tag][$marker] = $callback( $content, $params, $this );
} else {
$ext_content[$tag][$marker] = "$full_tag$content</$tag>";
}
* @access private
*/
function unstrip( $text, &$state ) {
+ if ( !is_array( $state ) ) {
+ return $text;
+ }
+
# Must expand in reverse order, otherwise nested tags will be corrupted
$contentDict = end( $state );
for ( $contentDict = end( $state ); $contentDict !== false; $contentDict = prev( $state ) ) {
* @access private
*/
function unstripNoWiki( $text, &$state ) {
+ if ( !is_array( $state ) ) {
+ return $text;
+ }
+
# Must expand in reverse order, otherwise nested tags will be corrupted
for ( $content = end($state['nowiki']); $content !== false; $content = prev( $state['nowiki'] ) ) {
$text = str_replace( key( $state['nowiki'] ), $content, $text );
$fc = substr ( $x , 0 , 1 ) ;
if ( preg_match( '/^(:*)\{\|(.*)$/', $x, $matches ) ) {
$indent_level = strlen( $matches[1] );
+
+ $attributes = $this->unstripForHTML( $matches[2] );
+
$t[$k] = str_repeat( '<dl><dd>', $indent_level ) .
- '<table' . Sanitizer::fixTagAttributes ( $matches[2], 'table' ) . '>' ;
+ '<table' . Sanitizer::fixTagAttributes ( $attributes, 'table' ) . '>' ;
array_push ( $td , false ) ;
array_push ( $ltd , '' ) ;
array_push ( $tr , false ) ;
array_push ( $tr , false ) ;
array_push ( $td , false ) ;
array_push ( $ltd , '' ) ;
- array_push ( $ltr , Sanitizer::fixTagAttributes ( $x, 'tr' ) ) ;
+ $attributes = $this->unstripForHTML( $x );
+ array_push ( $ltr , Sanitizer::fixTagAttributes ( $attributes, 'tr' ) ) ;
}
else if ( '|' == $fc || '!' == $fc || '|+' == substr ( $x , 0 , 2 ) ) { # Caption
# $x is a table row
}
if ( count ( $y ) == 1 )
$y = "{$z}<{$l}>{$y[0]}" ;
- else $y = $y = "{$z}<{$l}".Sanitizer::fixTagAttributes($y[0], $l).">{$y[1]}" ;
+ else {
+ $attributes = $this->unstripForHTML( $y[0] );
+ $y = "{$z}<{$l}".Sanitizer::fixTagAttributes($attributes, $l).">{$y[1]}" ;
+ }
$t[$k] .= $y ;
array_push ( $td , true ) ;
}
$fname = 'Parser::internalParse';
wfProfileIn( $fname );
- $text = Sanitizer::removeHTMLtags( $text, array( &$this, 'replaceVariables' ) );
+ # Remove <noinclude> tags and <includeonly> sections
+ $text = strtr( $text, array( '<noinclude>' => '', '</noinclude>' => '') );
+ $text = preg_replace( '/<includeonly>.*?<\/includeonly>/s', '', $text );
+
+ $text = Sanitizer::removeHTMLtags( $text, array( &$this, 'attributeStripCallback' ) );
$text = $this->replaceVariables( $text, $args );
$text = preg_replace( '/(^|\n)-----*/', '\\1<hr />', $text );
# replaceInternalLinks may sometimes leave behind
# absolute URLs, which have to be masked to hide them from replaceExternalLinks
- $text = str_replace("http-noparse://","http://",$text);
+ $text = str_replace(UNIQ_PREFIX."NOPARSE", "", $text);
$text = $this->doMagicLinks( $text );
$text = $this->doTableStuff( $text );
function doExponent( $text ) {
$fname = 'Parser::doExponent';
wfProfileIn( $fname );
- $text = preg_replace('/\^\^(.*)\^\^/','<small><sup>\\1</sup></small>', $text);
+ $text = preg_replace('/\^\^(.*?)\^\^/','<small><sup>\\1</sup></small>', $text);
wfProfileOut( $fname );
return $text;
}
if ( !$e1_img ) { $e1_img = "/^([{$tc}]+)\\|(.*)\$/sD"; }
# Match the end of a line for a word that's not followed by whitespace,
# e.g. in the case of 'The Arab al[[Razi]]', 'al' will be matched
- static $e2 = '/^(.*?)([a-zA-Z\x80-\xff]+)$/sD';
+ $e2 = wfMsgForContent( 'linkprefix' );
$useLinkPrefixExtension = $wgContLang->linkPrefixExtension();
if ( $useLinkPrefixExtension ) {
if ( preg_match( $e2, $s, $m ) ) {
$first_prefix = $m[2];
- $s = $m[1];
} else {
$first_prefix = false;
}
$link = substr($link, 1);
}
- $nt =& Title::newFromText( $this->unstripNoWiki($link, $this->mStripState) );
+ $nt = Title::newFromText( $this->unstripNoWiki($link, $this->mStripState) );
if( !$nt ) {
$s .= $prefix . '[[' . $line;
continue;
$found = false;
while (isset ($a[$k+1]) ) {
#look at the next 'line' to see if we can close it there
- $next_line = array_shift(array_splice( $a, $k + 1, 1) );
+ $spliced = array_splice( $a, $k + 1, 1 );
+ $next_line = array_shift( $spliced );
if( preg_match("/^(.*?]].*?)]](.*)$/sD", $next_line, $m) ) {
# the first ]] closes the inner link, the second the image
$found = true;
$text = $this->replaceInternalLinks($text);
# cloak any absolute URLs inside the image markup, so replaceExternalLinks() won't touch them
- $s .= $prefix . str_replace('http://', 'http-noparse://', $this->makeImage( $nt, $text ) ) . $trail;
+ $s .= $prefix . preg_replace("/\b($wgUrlProtocols)/", UNIQ_PREFIX."NOPARSE$1", $this->makeImage( $nt, $text) ) . $trail;
$wgLinkCache->addImageLinkObj( $nt );
wfProfileOut( "$fname-image" );
$s .= $prefix . $sk->makeKnownLinkObj( $nt, $text, '', $trail );
continue;
}
- if( !$nt->isExternal() && $nt->isAlwaysKnown() ) {
- /**
- * Skip lookups for special pages and self-links.
- * External interwiki links are not included here because
- * the HTTP urls would break output in the next parse step;
- * they will have placeholders kept.
- */
- $s .= $sk->makeKnownLinkObj( $nt, $text, '', $trail, $prefix );
- } else {
- /**
- * Add a link placeholder
- * Later, this will be replaced by a real link, after the existence or
- * non-existence of all the links is known
- */
- $s .= $this->makeLinkHolder( $nt, $text, '', $trail, $prefix );
- }
+ $s .= $this->makeLinkHolder( $nt, $text, '', $trail, $prefix );
}
wfProfileOut( $fname );
return $s;
}
}
- # LOCALURL and LOCALURLE
+ # LOCALURL and FULLURL
if ( !$found ) {
- $mwLocal = MagicWord::get( MAG_LOCALURL );
- $mwLocalE = MagicWord::get( MAG_LOCALURLE );
+ $mwLocal =& MagicWord::get( MAG_LOCALURL );
+ $mwLocalE =& MagicWord::get( MAG_LOCALURLE );
+ $mwFull =& MagicWord::get( MAG_FULLURL );
+ $mwFullE =& MagicWord::get( MAG_FULLURLE );
+
if ( $mwLocal->matchStartAndRemove( $part1 ) ) {
$func = 'getLocalURL';
} elseif ( $mwLocalE->matchStartAndRemove( $part1 ) ) {
$func = 'escapeLocalURL';
+ } elseif ( $mwFull->matchStartAndRemove( $part1 ) ) {
+ $func = 'getFullURL';
+ } elseif ( $mwFullE->matchStartAndRemove( $part1 ) ) {
+ $func = 'escapeFullURL';
} else {
- $func = '';
+ $func = false;
}
- if ( $func !== '' ) {
+ if ( $func !== false ) {
$title = Title::newFromText( $part1 );
if ( !is_null( $title ) ) {
if ( $argc > 0 ) {
}
}
+ # PLURAL
+ if ( !$found && $argc >= 2 ) {
+ $mwPluralForm =& MagicWord::get( MAG_PLURAL );
+ if ( $mwPluralForm->matchStartAndRemove( $part1 ) ) {
+ if ($argc==2) {$args[2]=$args[1];}
+ $text = $linestart . $wgContLang->convertPlural( $part1, $args[0], $args[1], $args[2]);
+ $found = true;
+ }
+ }
+
# Template table test
# Did we encounter this template already? If yes, it is in the cache
}
$title = Title::newFromText( $part1, $ns );
- if ($title) {
- $interwiki = Title::getInterwikiLink($title->getInterwiki());
- if ($interwiki != '' && $title->isTrans()) {
- return $this->scarytransclude($title, $interwiki);
- }
- }
+ if ($title) {
+ $interwiki = Title::getInterwikiLink($title->getInterwiki());
+ if ($interwiki != '' && $title->isTrans()) {
+ return $this->scarytransclude($title, $interwiki);
+ }
+ }
if ( !is_null( $title ) && !$title->isExternal() ) {
# Check for excessive inclusion
$found = true;
$noparse = true;
$isHTML = true;
- $this->mOutput->setCacheTime( -1 );
+ $this->disableCache();
}
} else {
$article = new Article( $title );
- $articleContent = $article->getContentWithoutUsingSoManyDamnGlobals();
+ $articleContent = $article->fetchContent(0, false);
if ( $articleContent !== false ) {
$found = true;
$text = $articleContent;
$this->mTemplatePath[$part1] = 1;
if( $this->mOutputType == OT_HTML ) {
+ # Remove <noinclude> sections and <includeonly> tags
+ $text = preg_replace( '/<noinclude>.*?<\/noinclude>/s', '', $text );
+ $text = strtr( $text, array( '<includeonly>' => '' , '</includeonly>' => '' ) );
+ # Strip <nowiki>, <pre>, etc.
+ $this->mCurrentParams = $assocArgs;
$text = $this->strip( $text, $this->mStripState );
$text = Sanitizer::removeHTMLtags( $text, array( &$this, 'replaceVariables' ), $assocArgs );
}
}
function fetchScaryTemplateMaybeFromCache($url) {
- $dbr = wfGetDB(DB_SLAVE);
+ $dbr =& wfGetDB(DB_SLAVE);
$obj = $dbr->selectRow('transcache', array('tc_time', 'tc_contents'),
array('tc_url' => $url));
if ($obj) {
if (!$text)
return wfMsg('scarytranscludefailed', $url);
- $dbw = wfGetDB(DB_MASTER);
+ $dbw =& wfGetDB(DB_MASTER);
$dbw->replace('transcache', array(), array(
'tc_url' => $url,
'tc_time' => time(),
$pdbk = $pdbks[$key] = $title->getPrefixedDBkey();
# Check if it's in the link cache already
- if ( $wgLinkCache->getGoodLinkID( $pdbk ) ) {
+ if ( $title->isAlwaysKnown() || $wgLinkCache->getGoodLinkID( $pdbk ) ) {
$colours[$pdbk] = 1;
} elseif ( $wgLinkCache->isBadLink( $pdbk ) ) {
$colours[$pdbk] = 0;
$part = explode( '|', $options);
$mwThumb =& MagicWord::get( MAG_IMG_THUMBNAIL );
+ $mwManualThumb =& MagicWord::get( MAG_IMG_MANUALTHUMB );
$mwLeft =& MagicWord::get( MAG_IMG_LEFT );
$mwRight =& MagicWord::get( MAG_IMG_RIGHT );
$mwNone =& MagicWord::get( MAG_IMG_NONE );
$manual_thumb = '' ;
foreach( $part as $key => $val ) {
- $val_parts = explode ( '=' , $val , 2 ) ;
- $left_part = array_shift ( $val_parts ) ;
if ( $wgUseImageResize && ! is_null( $mwThumb->matchVariableStartToEnd($val) ) ) {
$thumb=true;
- } elseif ( $wgUseImageResize && count ( $val_parts ) == 1 && ! is_null( $mwThumb->matchVariableStartToEnd($left_part) ) ) {
+ } elseif ( ! is_null( $match = $mwManualThumb->matchVariableStartToEnd($val) ) ) {
# use manually specified thumbnail
$thumb=true;
- $manual_thumb = array_shift ( $val_parts ) ;
+ $manual_thumb = $match;
} elseif ( ! is_null( $mwRight->matchVariableStartToEnd($val) ) ) {
# remember to set an alignment, don't render immediately
$align = 'right';
$sk =& $this->mOptions->getSkin();
return $sk->makeImageLinkObj( $nt, $caption, $alt, $align, $width, $height, $framed, $thumb, $manual_thumb );
}
+
+ /**
+ * Set a flag in the output object indicating that the content is dynamic and
+ * shouldn't be cached.
+ */
+ function disableCache() {
+ $this->mOutput->mCacheTime = -1;
+ }
+
+ /**
+ * Callback from the Sanitizer for expanding items found in HTML attribute
+ * values, so they can be safely tested and escaped.
+ * @param string $text
+ * @param array $args
+ * @return string
+ * @access private
+ */
+ function attributeStripCallback( &$text, $args ) {
+ $text = $this->replaceVariables( $text, $args );
+ $text = $this->unstripForHTML( $text );
+ return $text;
+ }
+
+ function unstripForHTML( $text ) {
+ $text = $this->unstrip( $text, $this->mStripState );
+ $text = $this->unstripNoWiki( $text, $this->mStripState );
+ return $text;
+ }
}
/**