wfRunHooks( 'ParserClearState', array( &$this ) );
}
+ /**
+ * Accessor for mUniqPrefix.
+ *
+ * @access public
+ */
+ function UniqPrefix() {
+ return $this->mUniqPrefix;
+ }
+
/**
* Convert wikitext to HTML
* Do not call this function recursively.
* to internalParse() which does all the real work.
*/
- global $wgUseTidy, $wgContLang;
+ global $wgUseTidy, $wgAlwaysUseTidy, $wgContLang;
$fname = 'Parser::parse';
wfProfileIn( $fname );
$text = Sanitizer::normalizeCharReferences( $text );
- if ($wgUseTidy and $this->mOptions->mTidy) {
+ if (($wgUseTidy and $this->mOptions->mTidy) or $wgAlwaysUseTidy) {
$text = Parser::tidy($text);
}
# Replace & from obsolete syntax with &.
# All HTML entities will be escaped by makeExternalLink()
- # or maybeMakeExternalImage()
$url = str_replace( '&', '&', $url );
+ # Replace unnecessary URL escape codes with the referenced character
+ # This prevents spammers from hiding links from the filters
+ $url = Parser::replaceUnusualEscapes( $url );
# Process the trail (i.e. everything after this link up until start of the next link),
# replacing any non-bracketed links
$trail = $this->replaceFreeExternalLinks( $trail );
-
# 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 .= $sk->makeExternalLink( $url, $text, false, $linktype ) . $dtrail . $trail;
+
+ # Register link in the output object
+ $this->mOutput->addExternalLink( $url );
}
wfProfileOut( $fname );
# All HTML entities will be escaped by makeExternalLink()
# or maybeMakeExternalImage()
$url = str_replace( '&', '&', $url );
+ # Replace unnecessary URL escape codes with their equivalent characters
+ $url = Parser::replaceUnusualEscapes( $url );
# Is this an external image?
$text = $this->maybeMakeExternalImage( $url );
if ( $text === false ) {
# Not an image, make a link
$text = $sk->makeExternalLink( $url, $wgContLang->markNoConversion($url), true, 'free' );
+ # Register it in the output object
+ $this->mOutput->addExternalLink( $url );
}
$s .= $text . $trail;
} else {
return $s;
}
+ /**
+ * Replace unusual URL escape codes with their equivalent characters
+ * @param string
+ * @return string
+ * @static
+ */
+ function replaceUnusualEscapes( $url ) {
+ return preg_replace_callback( '/%[0-9A-Fa-f]{2}/',
+ array( 'Parser', 'replaceUnusualEscapesCallback' ), $url );
+ }
+
+ /**
+ * Callback function used in replaceUnusualEscapes().
+ * Replaces unusual URL escape codes with their equivalent character
+ * @static
+ * @access private
+ */
+ function replaceUnusualEscapesCallback( $matches ) {
+ $char = urldecode( $matches[0] );
+ $ord = ord( $char );
+ // Is it an unsafe or HTTP reserved character according to RFC 1738?
+ if ( $ord > 32 && $ord < 127 && strpos( '<>"#{}|\^~[]`;/?', $char ) === false ) {
+ // No, shouldn't be escaped
+ return $char;
+ } else {
+ // Yes, leave it escaped
+ return $matches[0];
+ }
+ }
+
/**
* make an image if it's allowed, either through the global
* option or through the exception
$found = false;
$nowiki = false;
$noparse = false;
+ $replaceHeadings = false;
+ $isHTML = false;
$title = NULL;
# Check for NS: (namespace expansion)
$mwNs = MagicWord::get( MAG_NS );
if ( $mwNs->matchStartAndRemove( $part1 ) ) {
- if ( intval( $part1 ) ) {
+ if ( intval( $part1 ) || $part1 == "0" ) {
$text = $linestart . $wgContLang->getNsText( intval( $part1 ) );
$found = true;
} else {
}
# Load from database
- $replaceHeadings = false;
- $isHTML = false;
$lastPathLevel = $this->mTemplatePath;
if ( !$found ) {
$ns = NS_TEMPLATE;
}
$title = Title::newFromText( $part1, $ns );
- 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
- $dbk = $title->getPrefixedDBkey();
- if ( $this->incrementIncludeCount( $dbk ) ) {
- if ( $title->getNamespace() == NS_SPECIAL && $this->mOptions->getAllowSpecialInclusion() ) {
- # Capture special page output
- $text = SpecialPage::capturePath( $title );
- if ( is_string( $text ) ) {
- $found = true;
- $noparse = true;
- $isHTML = true;
- $this->disableCache();
- }
- } else {
- $articleContent = $this->fetchTemplate( $title );
- if ( $articleContent !== false ) {
- $found = true;
- $text = $articleContent;
- $replaceHeadings = true;
+ if ( !is_null( $title ) ) {
+ if ( !$title->isExternal() ) {
+ # Check for excessive inclusion
+ $dbk = $title->getPrefixedDBkey();
+ if ( $this->incrementIncludeCount( $dbk ) ) {
+ if ( $title->getNamespace() == NS_SPECIAL && $this->mOptions->getAllowSpecialInclusion() ) {
+ # Capture special page output
+ $text = SpecialPage::capturePath( $title );
+ if ( is_string( $text ) ) {
+ $found = true;
+ $noparse = true;
+ $isHTML = true;
+ $this->disableCache();
+ }
+ } else {
+ $articleContent = $this->fetchTemplate( $title );
+ if ( $articleContent !== false ) {
+ $found = true;
+ $text = $articleContent;
+ $replaceHeadings = true;
+ }
}
}
- }
- # If the title is valid but undisplayable, make a link to it
- if ( $this->mOutputType == OT_HTML && !$found ) {
- $text = '[['.$title->getPrefixedText().']]';
- $found = true;
- }
+ # If the title is valid but undisplayable, make a link to it
+ if ( $this->mOutputType == OT_HTML && !$found ) {
+ $text = '[['.$title->getPrefixedText().']]';
+ $found = true;
+ }
- # Template cache array insertion
- if( $found ) {
- $this->mTemplates[$part1] = $text;
- $text = $linestart . $text;
+ # Template cache array insertion
+ if( $found ) {
+ $this->mTemplates[$part1] = $text;
+ $text = $linestart . $text;
+ }
+ } elseif ( $title->isTrans() ) {
+ // Interwiki transclusion
+ if ( $this->mOutputType == OT_HTML ) {
+ $text = $this->interwikiTransclude( $title, 'render' );
+ $isHTML = true;
+ $noparse = true;
+ } else {
+ $text = $this->interwikiTransclude( $title, 'raw' );
+ }
+ $found = true;
}
}
}
}
/**
- * Translude an interwiki link.
+ * Transclude an interwiki link.
*/
- function scarytransclude($title, $interwiki) {
- global $wgEnableScaryTranscluding;
+ function interwikiTransclude( $title, $action ) {
+ global $wgEnableScaryTranscluding, $wgCanonicalNamespaceNames;
if (!$wgEnableScaryTranscluding)
return wfMsg('scarytranscludedisabled');
- $articlename = "Template:" . $title->getDBkey();
- $url = str_replace('$1', urlencode($articlename), $interwiki);
+ // The namespace will actually only be 0 or 10, depending on whether there was a leading :
+ // But we'll handle it generally anyway
+ if ( $title->getNamespace() ) {
+ // Use the canonical namespace, which should work anywhere
+ $articleName = $wgCanonicalNamespaceNames[$title->getNamespace()] . ':' . $title->getDBkey();
+ } else {
+ $articleName = $title->getDBkey();
+ }
+
+ $url = str_replace('$1', urlencode($articleName), Title::getInterwikiLink($title->getInterwiki()));
+ $url .= "?action=$action";
if (strlen($url) > 255)
return wfMsg('scarytranscludetoolong');
- $text = $this->fetchScaryTemplateMaybeFromCache($url);
- $this->mIWTransData[] = $text;
- return "<!--IW_TRANSCLUDE ".(count($this->mIWTransData) - 1)."-->";
+ return $this->fetchScaryTemplateMaybeFromCache($url);
}
function fetchScaryTemplateMaybeFromCache($url) {
+ global $wgTranscludeCacheExpiry;
$dbr =& wfGetDB(DB_SLAVE);
$obj = $dbr->selectRow('transcache', array('tc_time', 'tc_contents'),
array('tc_url' => $url));
if ($obj) {
$time = $obj->tc_time;
$text = $obj->tc_contents;
- if ($time && $time < (time() + (60*60))) {
+ if ($time && time() < $time + $wgTranscludeCacheExpiry ) {
return $text;
}
}
- $text = wfGetHTTP($url . '?action=render');
+ $text = wfGetHTTP($url);
if (!$text)
return wfMsg('scarytranscludefailed', $url);
$dbw =& wfGetDB(DB_MASTER);
- $dbw->replace('transcache', array(), array(
+ $dbw->replace('transcache', array('tc_url'), array(
'tc_url' => $url,
'tc_time' => time(),
'tc_contents' => $text));
$mTitleText, # title text of the chosen language variant
$mLinks, # 2-D map of NS/DBK to ID for the links in the document. ID=zero for broken.
$mTemplates, # 2-D map of NS/DBK to ID for the template references. ID=zero for broken.
- $mImages; # DB keys of the images used, in the array key only
+ $mImages, # DB keys of the images used, in the array key only
+ $mExternalLinks; # External link URLs, in the key only
function ParserOutput( $text = '', $languageLinks = array(), $categoryLinks = array(),
$containsOldMagic = false, $titletext = '' )
$this->mLinks = array();
$this->mTemplates = array();
$this->mImages = array();
+ $this->mExternalLinks = array();
}
function getText() { return $this->mText; }
function &getLinks() { return $this->mLinks; }
function &getTemplates() { return $this->mTemplates; }
function &getImages() { return $this->mImages; }
+ function &getExternalLinks() { return $this->mExternalLinks; }
function containsOldMagic() { return $this->mContainsOldMagic; }
function setText( $text ) { return wfSetVar( $this->mText, $text ); }
function addCategory( $c, $sort ) { $this->mCategories[$c] = $sort; }
function addImage( $name ) { $this->mImages[$name] = 1; }
function addLanguageLink( $t ) { $this->mLanguageLinks[] = $t; }
+ function addExternalLink( $url ) { $this->mExternalLinks[$url] = 1; }
function addLink( $title, $id ) {
$ns = $title->getNamespace();