* Hence, we limit the number of inclusions of any given page, thus bringing any
* attack back to O(N).
*/
+
define( 'MAX_INCLUDE_REPEAT', 100 );
define( 'MAX_INCLUDE_SIZE', 1000000 ); // 1 Million
+define( 'RLH_FOR_UPDATE', 1 );
+
# Allowed values for $mOutputType
define( 'OT_HTML', 1 );
define( 'OT_WIKI', 2 );
define( 'URL_PROTOCOLS', 'http|https|ftp|irc|gopher|news|mailto' );
define( 'HTTP_PROTOCOLS', 'http|https' );
# Everything except bracket, space, or control characters
-define( 'EXT_LINK_URL_CLASS', '[^]\\x00-\\x20\\x7F]' );
-define( 'INVERSE_EXT_LINK_URL_CLASS', '[\]\\x00-\\x20\\x7F]' );
+define( 'EXT_LINK_URL_CLASS', '[^]<>"\\x00-\\x20\\x7F]' );
# Including space
define( 'EXT_LINK_TEXT_CLASS', '[^\]\\x00-\\x1F\\x7F]' );
define( 'EXT_IMAGE_FNAME_CLASS', '[A-Za-z0-9_.,~%\\-+&;#*?!=()@\\x80-\\xFF]' );
* @return ParserOutput a ParserOutput
*/
function parse( $text, &$title, $options, $linestart = true, $clearState = true ) {
- global $wgUseTidy;
+ global $wgUseTidy, $wgContLang;
$fname = 'Parser::parse';
wfProfileIn( $fname );
$stripState = NULL;
$text = $this->strip( $text, $this->mStripState );
+
$text = $this->internalParse( $text, $linestart );
$text = $this->unstrip( $text, $this->mStripState );
# Clean up special characters, only run once, next-to-last before doBlockLevels
}
# only once and last
$text = $this->doBlockLevels( $text, $linestart );
+
+ $this->replaceLinkHolders( $text );
+ $text = $wgContLang->convert($text);
+
$text = $this->unstripNoWiki( $text, $this->mStripState );
+ global $wgUseTidy;
+ if ($wgUseTidy) {
+ $text = Parser::tidy($text);
+ }
+
$this->mOutput->setText( $text );
wfProfileOut( $fname );
return $this->mOutput;
array_push ( $ltr , $this->fixTagAttributes ( $x ) ) ;
}
else if ( '|' == $fc || '!' == $fc || '|+' == substr ( $x , 0 , 2 ) ) { # Caption
+ # $x is a table row
if ( '|+' == substr ( $x , 0 , 2 ) ) {
$fc = '+' ;
$x = substr ( $x , 1 ) ;
if ( $fc == '!' ) $after = str_replace ( '!!' , '||' , $after ) ;
$after = explode ( '||' , $after ) ;
$t[$k] = '' ;
+
+ # Loop through each table cell
foreach ( $after AS $theline )
{
$z = '' ;
else if ( $fc == '+' ) $l = 'caption' ;
else $l = '' ;
array_push ( $ltd , $l ) ;
+
+ # Cell parameters
$y = explode ( '|' , $theline , 2 ) ;
- if ( count ( $y ) == 1 ) $y = "{$z}<{$l}>{$y[0]}" ;
+ # 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 $y = $y = "{$z}<{$l} ".$this->fixTagAttributes($y[0]).">{$y[1]}" ;
$t[$k] .= $y ;
array_push ( $td , true ) ;
* @access private
*/
function internalParse( $text, $linestart, $args = array(), $isMain=true ) {
- global $wgContLang;
+ global $wgContLang;
$fname = 'Parser::internalParse';
wfProfileIn( $fname );
$text = $this->removeHTMLtags( $text );
$text = $this->replaceVariables( $text, $args );
- $text = $wgContLang->convert($text);
-
$text = preg_replace( '/(^|\n)-----*/', '\\1<hr />', $text );
$text = $this->doHeadings( $text );
$text = $wgDateFormatter->reformat( $this->mOptions->getDateFormat(), $text );
}
$text = $this->doAllQuotes( $text );
- $text = $this->doMagicLinks( $text );
- $text = $this->replaceInternalLinks ( $text );
- # Another call to replace links and images inside captions of images
$text = $this->replaceInternalLinks ( $text );
$text = $this->replaceExternalLinks( $text );
+ $text = $this->doMagicLinks( $text );
$text = $this->doTableStuff( $text );
$text = $this->formatHeadings( $text, $isMain );
$sk =& $this->mOptions->getSkin();
$text = $bits[$i++];
$trail = $bits[$i++];
+ # The characters '<' and '>' (which were escaped by
+ # removeHTMLtags()) should not be included in
+ # URLs, per RFC 2396.
+ if (preg_match('/&(lt|gt);/', $url, $m2, PREG_OFFSET_CAPTURE)) {
+ $text = substr($url, $m2[0][1]) . ' ' . $text;
+ $url = substr($url, 0, $m2[0][1]);
+ }
+
# If the link text is an image URL, replace it with an <img> tag
# This happened by accident in the original parser, but some people used it extensively
$img = $this->maybeMakeImageLink( $text );
# replacing any non-bracketed links
$trail = $this->replaceFreeExternalLinks( $trail );
- $la = $sk->getExternalLinkAttributes( $url, $text );
-
# Use the encoded URL
# This means that users can paste URLs directly into the text
# Funny characters like ö aren't valid in URLs anyway
# This was changed in August 2004
- $s .= "<a href=\"{$url}\"{$la}>{$text}</a>{$dtrail}{$paren}{$trail}";
+ $s .= $sk->makeExternalLink( $url, $text, false ) . $dtrail. $paren . $trail;
}
wfProfileOut( $fname );
$url = $protocol . $m[1];
$trail = $m[2];
+ # The characters '<' and '>' (which were escaped by
+ # removeHTMLtags()) should not be included in
+ # URLs, per RFC 2396.
+ if (preg_match('/&(lt|gt);/', $url, $m2, PREG_OFFSET_CAPTURE)) {
+ $trail = substr($url, $m2[0][1]) . $trail;
+ $url = substr($url, 0, $m2[0][1]);
+ }
+
# Move trailing punctuation to $trail
$sep = ',;\.:!?';
# If there is no left bracket, then consider right brackets fair game too
$url = substr( $url, 0, -$numSepChars );
}
- # Replace & from obsolete syntax with &
+ # Replace & from obsolete syntax with &.
+ # All HTML entities will be escaped by makeExternalLink()
+ # or maybeMakeImageLink()
$url = str_replace( '&', '&', $url );
# Is this an external image?
*
* @access private
*/
+
function replaceInternalLinks( $s ) {
global $wgLang, $wgContLang, $wgLinkCache;
static $fname = 'Parser::replaceInternalLinks' ;
+ # use a counter to prevent too much unknown links from
+ # being checked for different language variants.
+ static $convertCount;
wfProfileIn( $fname );
wfProfileIn( $fname.'-setup' );
$redirect = MagicWord::get ( MAG_REDIRECT ) ;
+ #split the entire text string on occurences of [[
$a = explode( '[[', ' ' . $s );
+ #get the first element (all text up to first [[), and remove the space we added
$s = array_shift( $a );
$s = substr( $s, 1 );
# Match a link having the form [[namespace:link|alternate]]trail
static $e1 = FALSE;
if ( !$e1 ) { $e1 = "/^([{$tc}]+)(?:\\|([^]]+))?]](.*)\$/sD"; }
+ # Match cases where there is no "]]", which might still be images
+ static $e1_img = FALSE;
+ 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';
$useLinkPrefixExtension = $wgContLang->linkPrefixExtension();
- # Special and Media are pseudo-namespaces; no pages actually exist in them
$nottalk = !Namespace::isTalk( $this->mTitle->getNamespace() );
wfProfileOut( $fname.'-setup' );
- # start procedeeding each line
- foreach ( $a as $line ) {
+ # Loop for each link
+ for ($k = 0; isset( $a[$k] ); $k++) {
+ $line = $a[$k];
wfProfileIn( $fname.'-prefixhandling' );
if ( $useLinkPrefixExtension ) {
if ( preg_match( $e2, $s, $m ) ) {
}
wfProfileOut( $fname.'-prefixhandling' );
+ $might_be_img = false;
+
if ( preg_match( $e1, $line, $m ) ) { # page with normal text or alt
$text = $m[2];
# fix up urlencoded title texts
if(preg_match('/%/', $m[1] )) $m[1] = urldecode($m[1]);
$trail = $m[3];
+ } elseif( preg_match($e1_img, $line, $m) ) { # Invalid, but might be an image with a link in its caption
+ $might_be_img = true;
+ $text = $m[2];
+ if(preg_match('/%/', $m[1] )) $m[1] = urldecode($m[1]);
+ $trail = "";
} else { # Invalid form; output directly
$s .= $prefix . '[[' . $line ;
continue;
continue;
}
- # Make subpage if necessary, and check for leading ':'
- $noforce = true;
- $link = $this->maybeDoSubpageLink( $m[1], $noforce, $text );
-
- $wasblank = ( '' == $text );
- if( $wasblank ) $text = $link;
+ # Make subpage if necessary
+ $link = $this->maybeDoSubpageLink( $m[1], $text );
- $nt = Title::newFromText( $link );
+ $noforce = (substr($m[1], 0, 1) != ':');
+ if (!$noforce) {
+ # Strip off leading ':'
+ $link = substr($link, 1);
+ }
+
+ $nt = Title::newFromText( $this->unstripNoWiki($link, $this->mStripState) );
if( !$nt ) {
$s .= $prefix . '[[' . $line;
continue;
}
-
+
+ //check other language variants of the link
+ //if the article does not exist
+ global $wgContLang;
+ $variants = $wgContLang->getVariants();
+
+ if(sizeof($variants) > 1 && $convertCount < 200) {
+ $varnt = false;
+ if($nt->getArticleID() == 0) {
+ foreach ( $variants as $v ) {
+ if($v == $wgContLang->getPreferredVariant())
+ continue;
+ $convertCount ++;
+ $varlink = $wgContLang->autoConvert($link, $v);
+ $varnt = Title::newFromText($varlink);
+ if($varnt && $varnt->getArticleID()>0) {
+ break;
+ }
+ }
+ }
+ if($varnt && $varnt->getArticleID()>0) {
+ $nt = $varnt;
+ $link = $varlink;
+ }
+ }
+
$ns = $nt->getNamespace();
$iw = $nt->getInterWiki();
+ if ($might_be_img) { # if this is actually an invalid link
+ if ($ns == NS_IMAGE && $noforce) { #but might be an image
+ $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) );
+ if( preg_match("/^(.*?]].*?)]](.*)$/sD", $next_line, $m) ) {
+ # the first ]] closes the inner link, the second the image
+ $found = true;
+ $text .= '[[' . $m[1];
+ $trail = $m[2];
+ break;
+ } elseif( preg_match("/^.*?]].*$/sD", $next_line, $m) ) {
+ #if there's exactly one ]] that's fine, we'll keep looking
+ $text .= '[[' . $m[0];
+ } else {
+ #if $next_line is invalid too, we need look no further
+ $text .= '[[' . $next_line;
+ break;
+ }
+ }
+ if ( !$found ) {
+ # we couldn't find the end of this imageLink, so output it raw
+ #but don't ignore what might be perfectly normal links in the text we've examined
+ $text = $this->replaceInternalLinks($text);
+ $s .= $prefix . '[[' . $link . '|' . $text;
+ # note: no $trail, because without an end, there *is* no trail
+ continue;
+ }
+ } else { #it's not an image, so output it raw
+ $s .= $prefix . '[[' . $link . '|' . $text;
+ # note: no $trail, because without an end, there *is* no trail
+ continue;
+ }
+ }
+
+ $wasblank = ( '' == $text );
+ if( $wasblank ) $text = $link;
+
+
# Link not escaped by : , create the various objects
if( $noforce ) {
}
if ( $ns == NS_IMAGE ) {
- $s .= $prefix . $sk->makeImageLinkObj( $nt, $text ) . $trail;
+ # recursively parse links inside the image caption
+ # actually, this will parse them in any other parameters, too,
+ # but it might be hard to fix that, and it doesn't matter ATM
+ $text = $this->replaceExternalLinks($text);
+ $text = $this->replaceInternalLinks($text);
+
+ # replace the image with a link-holder so that replaceExternalLinks() can't mess with it
+ $s .= $prefix . $this->insertStripItem( $sk->makeImageLinkObj( $nt, $text ), $this->mStripState ) . $trail;
$wgLinkCache->addImageLinkObj( $nt );
continue;
}
if ( $ns == NS_CATEGORY ) {
$t = $nt->getText() ;
- $nnt = Title::newFromText ( Namespace::getCanonicalName(NS_CATEGORY).':'.$t ) ;
$wgLinkCache->suspend(); # Don't save in links/brokenlinks
$pPLC=$sk->postParseLinkColour();
$sk->postParseLinkColour( false );
- $t = $sk->makeLinkObj( $nnt, $t, '', '' , $prefix );
+ $t = $sk->makeLinkObj( $nt, $t, '', '' , $prefix );
$sk->postParseLinkColour( $pPLC );
$wgLinkCache->resume();
continue;
}
}
-
+
+ $text = $wgContLang->convert($text);
+
if( ( $nt->getPrefixedText() === $this->mTitle->getPrefixedText() ) &&
- ( strpos( $link, '#' ) === FALSE ) ) {
+ ( $nt->getFragment() === '' ) ) {
# Self-links are handled specially; generally de-link and change to bold.
$s .= $prefix . $sk->makeSelfLinkObj( $nt, $text, '', $trail );
continue;
}
+ # Special and Media are pseudo-namespaces; no pages actually exist in them
if( $ns == NS_MEDIA ) {
$s .= $prefix . $sk->makeMediaLinkObj( $nt, $text ) . $trail;
$wgLinkCache->addImageLinkObj( $nt );
/**
* Handle link to subpage if necessary
- * @param $target string the source of the link
- * @param $target set to true unless target began with ':'
- * @param &$text the link text, modified as necessary
+ * @param string $target the source of the link
+ * @param string &$text the link text, modified as necessary
* @return string the full name of the link
* @access private
*/
- function maybeDoSubpageLink($target, &$noforce, &$text) {
+ function maybeDoSubpageLink($target, &$text) {
# Valid link forms:
# Foobar -- normal
# :Foobar -- override special treatment of prefix (images, language links)
# /Foobar/ -- convert to CurrentPage/Foobar, strip the initial / from text
global $wgNamespacesWithSubpages;
+ $fname = 'Parser::maybeDoSubpageLink';
+ wfProfileIn( $fname );
# Look at the first character
- $c = $target{0};
- $noforce = ($c != ':');
-
- # subpage
- if( $c == '/' ) {
+ if( $target{0} == '/' ) {
# / at end means we don't want the slash to be shown
if(substr($target,-1,1)=='/') {
$target=substr($target,1,-1);
# no subpage allowed, use standard link
$ret = $target;
}
- } elseif( $noforce ) {
+ } else {
# no subpage
$ret = $target;
- } else {
- # We don't want to keep the first character
- $ret = substr( $target, 1 );
}
+ wfProfileOut( $fname );
return $ret;
}
# ; title : definition text
# So we check for : in the remainder text to split up the
# title and definition, without b0rking links.
- # FIXME: This is not foolproof. Something better in Tokenizer might help.
- if( preg_match( '/^(.*?(?:\s| )):(.*)$/', $t, $match ) ) {
- $term = $match[1];
+ if ($this->findColonNoLinks($t, $term, $t2) !== false) {
+ $t = $t2;
$output .= $term . $this->nextItem( ':' );
- $t = $match[2];
}
}
} elseif( $prefixLength || $lastPrefixLength ) {
if ( ';' == $char ) {
# FIXME: This is dupe of code above
- if( preg_match( '/^(.*?(?:\s| )):(.*)$/', $t, $match ) ) {
- $term = $match[1];
+ if ($this->findColonNoLinks($t, $term, $t2) !== false) {
+ $t = $t2;
$output .= $term . $this->nextItem( ':' );
- $t = $match[2];
}
}
++$commonPrefixLength;
return $output;
}
+ /**
+ * Split up a string on ':', ignoring any occurences inside
+ * <a>..</a> or <span>...</span>
+ * @param string $str the string to split
+ * @param string &$before set to everything before the ':'
+ * @param string &$after set to everything after the ':'
+ * return string the position of the ':', or false if none found
+ */
+ function findColonNoLinks($str, &$before, &$after) {
+ # I wonder if we should make this count all tags, not just <a>
+ # and <span>. That would prevent us from matching a ':' that
+ # comes in the middle of italics other such formatting....
+ # -- Wil
+ $fname = 'Parser::findColonNoLinks';
+ wfProfileIn( $fname );
+ $pos = 0;
+ do {
+ $colon = strpos($str, ':', $pos);
+
+ if ($colon !== false) {
+ $before = substr($str, 0, $colon);
+ $after = substr($str, $colon + 1);
+
+ # Skip any ':' within <a> or <span> pairs
+ $a = substr_count($before, '<a');
+ $s = substr_count($before, '<span');
+ $ca = substr_count($before, '</a>');
+ $cs = substr_count($before, '</span>');
+
+ if ($a <= $ca and $s <= $cs) {
+ # Tags are balanced before ':'; ok
+ break;
+ }
+ $pos = $colon + 1;
+ }
+ } while ($colon !== false);
+ wfProfileOut( $fname );
+ return $colon;
+ }
+
/**
* Return value of a magic variable (like PAGENAME)
*
* @access private
*/
function initialiseVariables() {
+ $fname = 'Parser::initialiseVariables';
+ wfProfileIn( $fname );
global $wgVariableIDs;
$this->mVariables = array();
foreach ( $wgVariableIDs as $id ) {
$mw =& MagicWord::get( $id );
$mw->addToArray( $this->mVariables, $this->getVariableValue( $id ) );
}
+ wfProfileOut( $fname );
}
/**
$itcamefromthedatabase = false;
if ( !$found ) {
$ns = NS_TEMPLATE;
- $part1 = $this->maybeDoSubpageLink( $part1, $noforce, $subpage='' );
+ $part1 = $this->maybeDoSubpageLink( $part1, $subpage='' );
if ($subpage !== '') {
$ns = $this->mTitle->getNamespace();
}
if( $istemplate )
$head[$headlineCount] .= $sk->editSectionLinkForOther($templatetitle, $templatesection);
else
- $head[$headlineCount] .= $sk->editSectionLink($sectionCount+1);
+ $head[$headlineCount] .= $sk->editSectionLink($this->mTitle, $sectionCount+1);
}
# Add the edit section span
if( $istemplate )
$headline = $sk->editSectionScriptForOther($templatetitle, $templatesection, $headline);
else
- $headline = $sk->editSectionScript($sectionCount+1,$headline);
+ $headline = $sk->editSectionScript($this->title, $sectionCount+1,$headline);
}
# give headline the correct <h#> tag
$this->mTagHooks[$tag] = $callback;
return $oldVal;
}
+
+ /**
+ * Replace <!--LINK--> link placeholders with actual links, in the buffer
+ * Placeholders created in Skin::makeLinkObj()
+ * Returns an array of links found, indexed by PDBK:
+ * 0 - broken
+ * 1 - normal link
+ * 2 - stub
+ * $options is a bit field, RLH_FOR_UPDATE to select for update
+ */
+ function replaceLinkHolders( &$text, $options = 0 ) {
+ global $wgUser, $wgLinkCache, $wgUseOldExistenceCheck, $wgLinkHolders;
+
+ if ( $wgUseOldExistenceCheck ) {
+ return array();
+ }
+
+ $fname = 'Parser::replaceLinkHolders';
+ wfProfileIn( $fname );
+
+ $pdbks = array();
+ $colours = array();
+
+ #if ( !empty( $tmpLinks[0] ) ) { #TODO
+ if ( !empty( $wgLinkHolders['namespaces'] ) ) {
+ wfProfileIn( $fname.'-check' );
+ $dbr =& wfGetDB( DB_SLAVE );
+ $cur = $dbr->tableName( 'cur' );
+ $sk = $wgUser->getSkin();
+ $threshold = $wgUser->getOption('stubthreshold');
+
+ # Sort by namespace
+ asort( $wgLinkHolders['namespaces'] );
+
+ # Generate query
+ $query = false;
+ foreach ( $wgLinkHolders['namespaces'] as $key => $val ) {
+ # Make title object
+ $title = $wgLinkHolders['titles'][$key];
+
+ # Skip invalid entries.
+ # Result will be ugly, but prevents crash.
+ if ( is_null( $title ) ) {
+ continue;
+ }
+ $pdbk = $pdbks[$key] = $title->getPrefixedDBkey();
+
+ # Check if it's in the link cache already
+ if ( $wgLinkCache->getGoodLinkID( $pdbk ) ) {
+ $colours[$pdbk] = 1;
+ } elseif ( $wgLinkCache->isBadLink( $pdbk ) ) {
+ $colours[$pdbk] = 0;
+ } else {
+ # Not in the link cache, add it to the query
+ if ( !isset( $current ) ) {
+ $current = $val;
+ $query = "SELECT cur_id, cur_namespace, cur_title";
+ if ( $threshold > 0 ) {
+ $query .= ", LENGTH(cur_text) AS cur_len, cur_is_redirect";
+ }
+ $query .= " FROM $cur WHERE (cur_namespace=$val AND cur_title IN(";
+ } elseif ( $current != $val ) {
+ $current = $val;
+ $query .= ")) OR (cur_namespace=$val AND cur_title IN(";
+ } else {
+ $query .= ', ';
+ }
+
+ $query .= $dbr->addQuotes( $wgLinkHolders['dbkeys'][$key] );
+ }
+ }
+ if ( $query ) {
+ $query .= '))';
+ if ( $options & RLH_FOR_UPDATE ) {
+ $query .= ' FOR UPDATE';
+ }
+
+ $res = $dbr->query( $query, $fname );
+
+ # Fetch data and form into an associative array
+ # non-existent = broken
+ # 1 = known
+ # 2 = stub
+ while ( $s = $dbr->fetchObject($res) ) {
+ $title = Title::makeTitle( $s->cur_namespace, $s->cur_title );
+ $pdbk = $title->getPrefixedDBkey();
+ $wgLinkCache->addGoodLink( $s->cur_id, $pdbk );
+
+ if ( $threshold > 0 ) {
+ $size = $s->cur_len;
+ if ( $s->cur_is_redirect || $s->cur_namespace != 0 || $length < $threshold ) {
+ $colours[$pdbk] = 1;
+ } else {
+ $colours[$pdbk] = 2;
+ }
+ } else {
+ $colours[$pdbk] = 1;
+ }
+ }
+ }
+ wfProfileOut( $fname.'-check' );
+
+ # Construct search and replace arrays
+ wfProfileIn( $fname.'-construct' );
+ global $outputReplace;
+ $outputReplace = array();
+ foreach ( $wgLinkHolders['namespaces'] as $key => $ns ) {
+ $pdbk = $pdbks[$key];
+ $searchkey = '<!--LINK '.$key.'-->';
+ $title = $wgLinkHolders['titles'][$key];
+ if ( empty( $colours[$pdbk] ) ) {
+ $wgLinkCache->addBadLink( $pdbk );
+ $colours[$pdbk] = 0;
+ $outputReplace[$searchkey] = $sk->makeBrokenLinkObj( $title,
+ $wgLinkHolders['texts'][$key],
+ $wgLinkHolders['queries'][$key] );
+ } elseif ( $colours[$pdbk] == 1 ) {
+ $outputReplace[$searchkey] = $sk->makeKnownLinkObj( $title,
+ $wgLinkHolders['texts'][$key],
+ $wgLinkHolders['queries'][$key] );
+ } elseif ( $colours[$pdbk] == 2 ) {
+ $outputReplace[$searchkey] = $sk->makeStubLinkObj( $title,
+ $wgLinkHolders['texts'][$key],
+ $wgLinkHolders['queries'][$key] );
+ }
+ }
+ wfProfileOut( $fname.'-construct' );
+
+ # Do the thing
+ wfProfileIn( $fname.'-replace' );
+
+ $text = preg_replace_callback(
+ '/(<!--LINK .*?-->)/',
+ "outputReplaceMatches",
+ $text);
+ wfProfileOut( $fname.'-replace' );
+
+ wfProfileIn( $fname.'-interwiki' );
+ global $wgInterwikiLinkHolders;
+ $outputReplace = $wgInterwikiLinkHolders;
+ $text = preg_replace_callback(
+ '/<!--IWLINK (.*?)-->/',
+ "outputReplaceMatches",
+ $text);
+ wfProfileOut( $fname.'-interwiki' );
+ }
+
+ wfProfileOut( $fname );
+ return $colours;
+ }
}
/**
}
+/**
+ * Callback function used by Parser::replaceLinkHolders()
+ * to substitute link placeholders.
+ */
+function &outputReplaceMatches($matches) {
+ global $outputReplace;
+ return $outputReplace[$matches[1]];
+}
+
+
# Regex callbacks, used in Parser::replaceVariables
function wfBraceSubstitution( $matches ) {
global $wgCurParser;