/** * Add a tracking category, getting the title from a system message, * or print a debug message if the title is invalid. * * Please add any message that you use with this function to * $wgTrackingCategories. That way they will be listed on * Special:TrackingCategories. * * @param string $msg Message key * @return bool Whether the addition was successful */ public function addTrackingCategory($msg) { if ($this->mTitle->getNamespace() === NS_SPECIAL) { wfDebug(__METHOD__ . ": Not adding tracking category {$msg} to special page!\n"); return false; } // Important to parse with correct title (bug 31469) $cat = wfMessage($msg)->title($this->getTitle())->inContentLanguage()->text(); # Allow tracking categories to be disabled by setting them to "-" if ($cat === '-') { return false; } $containerCategory = Title::makeTitleSafe(NS_CATEGORY, $cat); if ($containerCategory) { $this->mOutput->addCategory($containerCategory->getDBkey(), $this->getDefaultSort()); return true; } else { wfDebug(__METHOD__ . ": [[MediaWiki:{$msg}]] is not a valid title!\n"); return false; } }
/** * Add a tracking category, getting the title from a system message, * or print a debug message if the title is invalid. * * @param $msg String: message key * @return Boolean: whether the addition was successful */ protected function addTrackingCategory($msg) { if ($this->mTitle->getNamespace() === NS_SPECIAL) { wfDebug(__METHOD__ . ": Not adding tracking category {$msg} to special page!\n"); return false; } $cat = wfMsgForContent($msg); # Allow tracking categories to be disabled by setting them to "-" if ($cat === '-') { return false; } $containerCategory = Title::makeTitleSafe(NS_CATEGORY, $cat); if ($containerCategory) { $this->mOutput->addCategory($containerCategory->getDBkey(), $this->getDefaultSort()); return true; } else { wfDebug(__METHOD__ . ": [[MediaWiki:{$msg}]] is not a valid title!\n"); return false; } }
/** * Process [[ ]] wikilinks (RIL) * @param string $s * @throws MWException * @return LinkHolderArray * * @private */ public function replaceInternalLinks2(&$s) { global $wgExtraInterlanguageLinkPrefixes; static $tc = false, $e1, $e1_img; # the % is needed to support urlencoded titles as well if (!$tc) { $tc = Title::legalChars() . '#%'; # Match a link having the form [[namespace:link|alternate]]trail $e1 = "/^([{$tc}]+)(?:\\|(.+?))?]](.*)\$/sD"; # Match cases where there is no "]]", which might still be images $e1_img = "/^([{$tc}]+)\\|(.*)\$/sD"; } $holders = new LinkHolderArray($this); # split the entire text string on occurrences of [[ $a = StringUtils::explode('[[', ' ' . $s); # get the first element (all text up to first [[), and remove the space we added $s = $a->current(); $a->next(); $line = $a->current(); # Workaround for broken ArrayIterator::next() that returns "void" $s = substr($s, 1); $useLinkPrefixExtension = $this->getTargetLanguage()->linkPrefixExtension(); $e2 = null; if ($useLinkPrefixExtension) { # 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 global $wgContLang; $charset = $wgContLang->linkPrefixCharset(); $e2 = "/^((?>.*[^{$charset}]|))(.+)\$/sDu"; } if (is_null($this->mTitle)) { throw new MWException(__METHOD__ . ": \$this->mTitle is null\n"); } $nottalk = !$this->mTitle->isTalkPage(); if ($useLinkPrefixExtension) { $m = array(); if (preg_match($e2, $s, $m)) { $first_prefix = $m[2]; } else { $first_prefix = false; } } else { $prefix = ''; } $useSubpages = $this->areSubpagesAllowed(); // @codingStandardsIgnoreStart Squiz.WhiteSpace.SemicolonSpacing.Incorrect # Loop for each link for (; $line !== false && $line !== null; $a->next(), $line = $a->current()) { // @codingStandardsIgnoreStart # Check for excessive memory usage if ($holders->isBig()) { # Too big # Do the existence check, replace the link holders and clear the array $holders->replace($s); $holders->clear(); } if ($useLinkPrefixExtension) { if (preg_match($e2, $s, $m)) { $prefix = $m[2]; $s = $m[1]; } else { $prefix = ''; } # first link if ($first_prefix) { $prefix = $first_prefix; $first_prefix = false; } } $might_be_img = false; if (preg_match($e1, $line, $m)) { # page with normal text or alt $text = $m[2]; # If we get a ] at the beginning of $m[3] that means we have a link that's something like: # [[Image:Foo.jpg|[http://example.com desc]]] <- having three ] in a row f***s up, # the real problem is with the $e1 regex # See bug 1300. # # Still some problems for cases where the ] is meant to be outside punctuation, # and no image is in sight. See bug 2095. # if ($text !== '' && substr($m[3], 0, 1) === ']' && strpos($text, '[') !== false) { $text .= ']'; # so that replaceExternalLinks($text) works later $m[3] = substr($m[3], 1); } # fix up urlencoded title texts if (strpos($m[1], '%') !== false) { # Should anchors '#' also be rejected? $m[1] = str_replace(array('<', '>'), array('<', '>'), rawurldecode($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 (strpos($m[1], '%') !== false) { $m[1] = rawurldecode($m[1]); } $trail = ""; } else { # Invalid form; output directly $s .= $prefix . '[[' . $line; continue; } $origLink = $m[1]; # Don't allow internal links to pages containing # PROTO: where PROTO is a valid URL protocol; these # should be external links. if (preg_match('/^(?i:' . $this->mUrlProtocols . ')/', $origLink)) { $s .= $prefix . '[[' . $line; continue; } # Make subpage if necessary if ($useSubpages) { $link = $this->maybeDoSubpageLink($origLink, $text); } else { $link = $origLink; } $noforce = substr($origLink, 0, 1) !== ':'; if (!$noforce) { # Strip off leading ':' $link = substr($link, 1); } $unstrip = $this->mStripState->unstripNoWiki($link); $nt = is_string($unstrip) ? Title::newFromText($unstrip) : null; if ($nt === null) { $s .= $prefix . '[[' . $line; continue; } $ns = $nt->getNamespace(); $iw = $nt->getInterwiki(); if ($might_be_img) { # if this is actually an invalid link if ($ns == NS_FILE && $noforce) { # but might be an image $found = false; while (true) { # look at the next 'line' to see if we can close it there $a->next(); $next_line = $a->current(); if ($next_line === false || $next_line === null) { break; } $m = explode(']]', $next_line, 3); if (count($m) == 3) { # the first ]] closes the inner link, the second the image $found = true; $text .= "[[{$m[0]}]]{$m[1]}"; $trail = $m[2]; break; } elseif (count($m) == 2) { # if there's exactly one ]] that's fine, we'll keep looking $text .= "[[{$m[0]}]]{$m[1]}"; } 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 $holders->merge($this->replaceInternalLinks2($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; } else { # Bug 4598 madness. Handle the quotes only if they come from the alternate part # [[Lista d''e paise d''o munno]] -> <a href="...">Lista d''e paise d''o munno</a> # [[Criticism of Harry Potter|Criticism of ''Harry Potter'']] # -> <a href="Criticism of Harry Potter">Criticism of <i>Harry Potter</i></a> $text = $this->doQuotes($text); } # Link not escaped by : , create the various objects if ($noforce && !$nt->wasLocalInterwiki()) { # Interwikis if ($iw && $this->mOptions->getInterwikiMagic() && $nottalk && (Language::fetchLanguageName($iw, null, 'mw') || in_array($iw, $wgExtraInterlanguageLinkPrefixes))) { # Bug 24502: filter duplicates if (!isset($this->mLangLinkLanguages[$iw])) { $this->mLangLinkLanguages[$iw] = true; $this->mOutput->addLanguageLink($nt->getFullText()); } $s = rtrim($s . $prefix); $s .= trim($trail, "\n") == '' ? '' : $prefix . $trail; continue; } if ($ns == NS_FILE) { if (!wfIsBadImage($nt->getDBkey(), $this->mTitle)) { if ($wasblank) { # if no parameters were passed, $text # becomes something like "File:Foo.png", # which we don't want to pass on to the # image generator $text = ''; } else { # 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); $holders->merge($this->replaceInternalLinks2($text)); } # cloak any absolute URLs inside the image markup, so replaceExternalLinks() won't touch them $s .= $prefix . $this->armorLinks($this->makeImage($nt, $text, $holders)) . $trail; } else { $s .= $prefix . $trail; } continue; } if ($ns == NS_CATEGORY) { $s = rtrim($s . "\n"); # bug 87 if ($wasblank) { $sortkey = $this->getDefaultSort(); } else { $sortkey = $text; } $sortkey = Sanitizer::decodeCharReferences($sortkey); $sortkey = str_replace("\n", '', $sortkey); $sortkey = $this->getConverterLanguage()->convertCategoryKey($sortkey); $this->mOutput->addCategory($nt->getDBkey(), $sortkey); /** * Strip the whitespace Category links produce, see bug 87 */ $s .= trim($prefix . $trail, "\n") == '' ? '' : $prefix . $trail; continue; } } # Self-link checking. For some languages, variants of the title are checked in # LinkHolderArray::doVariants() to allow batching the existence checks necessary # for linking to a different variant. if ($ns != NS_SPECIAL && $nt->equals($this->mTitle) && !$nt->hasFragment()) { $s .= $prefix . Linker::makeSelfLinkObj($nt, $text, '', $trail); continue; } # NS_MEDIA is a pseudo-namespace for linking directly to a file # @todo FIXME: Should do batch file existence checks, see comment below if ($ns == NS_MEDIA) { # Give extensions a chance to select the file revision for us $options = array(); $descQuery = false; Hooks::run('BeforeParserFetchFileAndTitle', array($this, $nt, &$options, &$descQuery)); # Fetch and register the file (file title may be different via hooks) list($file, $nt) = $this->fetchFileAndTitle($nt, $options); # Cloak with NOPARSE to avoid replacement in replaceExternalLinks $s .= $prefix . $this->armorLinks(Linker::makeMediaLinkFile($nt, $file, $text)) . $trail; continue; } # Some titles, such as valid special pages or files in foreign repos, should # be shown as bluelinks even though they're not included in the page table # # @todo FIXME: isAlwaysKnown() can be expensive for file links; we should really do # batch file existence checks for NS_FILE and NS_MEDIA if ($iw == '' && $nt->isAlwaysKnown()) { $this->mOutput->addLink($nt); $s .= $this->makeKnownLinkHolder($nt, $text, array(), $trail, $prefix); } else { # Links will be added to the output link list after checking $s .= $holders->makeHolder($nt, $text, array(), $trail, $prefix); } } return $holders; }
/** * @param $content * @param Title $title * @param $revId * @param $options * @param $generateHtml * @param ParserOutput $output * * @return bool */ public static function onContentGetParserOutput($content, $title, $revId, $options, $generateHtml, &$output) { $output->addCategory('approvedrevs-tracking-category', ''); return true; }