X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2Fparser%2FParser.php;h=db0407752b33f307113511ab53100847927f139b;hb=b3f03fd75efbf1a01910ccb27e9e8860de70aa29;hp=51c04ea035e7d912b593a1ad4547c9189fac23ad;hpb=32a243c457c4af126d697a6a591662c252e1f1d0;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/parser/Parser.php b/includes/parser/Parser.php index 51c04ea035..db0407752b 100644 --- a/includes/parser/Parser.php +++ b/includes/parser/Parser.php @@ -273,27 +273,32 @@ class Parser { /** @var SpecialPageFactory */ private $specialPageFactory; + /** @var Config */ + private $siteConfig; + /** - * @param array $conf See $wgParserConf documentation + * @param array $parserConf See $wgParserConf documentation * @param MagicWordFactory|null $magicWordFactory * @param Language|null $contLang Content language * @param ParserFactory|null $factory * @param string|null $urlProtocols As returned from wfUrlProtocols() * @param SpecialPageFactory|null $spFactory + * @param Config|null $siteConfig */ public function __construct( - array $conf = [], MagicWordFactory $magicWordFactory = null, Language $contLang = null, - ParserFactory $factory = null, $urlProtocols = null, SpecialPageFactory $spFactory = null + array $parserConf = [], MagicWordFactory $magicWordFactory = null, + Language $contLang = null, ParserFactory $factory = null, $urlProtocols = null, + SpecialPageFactory $spFactory = null, Config $siteConfig = null ) { - $this->mConf = $conf; + $this->mConf = $parserConf; $this->mUrlProtocols = $urlProtocols ?? wfUrlProtocols(); $this->mExtLinkBracketedRegex = '/\[(((?i)' . $this->mUrlProtocols . ')' . self::EXT_LINK_ADDR . self::EXT_LINK_URL_CLASS . '*)\p{Zs}*([^\]\\x00-\\x08\\x0a-\\x1F\\x{FFFD}]*?)\]/Su'; - if ( isset( $conf['preprocessorClass'] ) ) { - $this->mPreprocessorClass = $conf['preprocessorClass']; - } elseif ( defined( 'HPHP_VERSION' ) ) { - # Preprocessor_Hash is much faster than Preprocessor_DOM under HipHop + if ( isset( $parserConf['preprocessorClass'] ) ) { + $this->mPreprocessorClass = $parserConf['preprocessorClass']; + } elseif ( wfIsHHVM() ) { + # Under HHVM Preprocessor_Hash is much faster than Preprocessor_DOM $this->mPreprocessorClass = Preprocessor_Hash::class; } elseif ( extension_loaded( 'domxml' ) ) { # PECL extension that conflicts with the core DOM extension (T15770) @@ -314,6 +319,7 @@ class Parser { $this->factory = $factory ?? $services->getParserFactory(); $this->specialPageFactory = $spFactory ?? $services->getSpecialPageFactory(); + $this->siteConfig = $siteConfig ?? MediaWikiServices::getInstance()->getMainConfig(); } /** @@ -542,8 +548,6 @@ class Parser { * @return string */ protected function makeLimitReport() { - global $wgShowHostnames; - $maxIncludeSize = $this->mOptions->getMaxIncludeSize(); $cpuTime = $this->mOutput->getTimeSinceStart( 'cpu' ); @@ -584,7 +588,7 @@ class Parser { Hooks::run( 'ParserLimitReportPrepare', [ $this, $this->mOutput ] ); $limitReport = "NewPP limit report\n"; - if ( $wgShowHostnames ) { + if ( $this->siteConfig->get( 'ShowHostnames' ) ) { $limitReport .= 'Parsed by ' . wfHostname() . "\n"; } $limitReport .= 'Cached time: ' . $this->mOutput->getCacheTime() . "\n"; @@ -612,8 +616,6 @@ class Parser { // Since we're not really outputting HTML, decode the entities and // then re-encode the things that need hiding inside HTML comments. $limitReport = htmlspecialchars_decode( $limitReport ); - // Run deprecated hook - Hooks::run( 'ParserLimitReport', [ $this, &$limitReport ], '1.22' ); // Sanitize for comment. Note '‐' in the replacement is U+2010, // which looks much like the problematic '-'. @@ -637,7 +639,7 @@ class Parser { $this->mOutput->setLimitReportData( 'limitreport-timingprofile', $profileReport ); // Add other cache related metadata - if ( $wgShowHostnames ) { + if ( $this->siteConfig->get( 'ShowHostnames' ) ) { $this->mOutput->setLimitReportData( 'cachereport-origin', wfHostname() ); } $this->mOutput->setLimitReportData( 'cachereport-timestamp', @@ -2155,8 +2157,6 @@ class Parser { * @private */ public function replaceInternalLinks2( &$s ) { - global $wgExtraInterlanguageLinkPrefixes; - static $tc = false, $e1, $e1_img; # the % is needed to support urlencoded titles as well if ( !$tc ) { @@ -2361,7 +2361,7 @@ class Parser { if ( $iw && $this->mOptions->getInterwikiMagic() && $nottalk && ( Language::fetchLanguageName( $iw, null, 'mw' ) || - in_array( $iw, $wgExtraInterlanguageLinkPrefixes ) + in_array( $iw, $this->siteConfig->get( 'ExtraInterlanguageLinkPrefixes' ) ) ) ) { # T26502: filter duplicates @@ -2543,9 +2543,6 @@ class Parser { * @return string */ public function getVariableValue( $index, $frame = false ) { - global $wgSitename, $wgServer, $wgServerName; - global $wgArticlePath, $wgScriptPath, $wgStylePath; - if ( is_null( $this->mTitle ) ) { // If no title set, bad things are going to happen // later. Title should always be set since this @@ -2847,22 +2844,21 @@ class Parser { $value = SpecialVersion::getVersion(); break; case 'articlepath': - return $wgArticlePath; + return $this->siteConfig->get( 'ArticlePath' ); case 'sitename': - return $wgSitename; + return $this->siteConfig->get( 'Sitename' ); case 'server': - return $wgServer; + return $this->siteConfig->get( 'Server' ); case 'servername': - return $wgServerName; + return $this->siteConfig->get( 'ServerName' ); case 'scriptpath': - return $wgScriptPath; + return $this->siteConfig->get( 'ScriptPath' ); case 'stylepath': - return $wgStylePath; + return $this->siteConfig->get( 'StylePath' ); case 'directionmark': return $pageLang->getDirMark(); case 'contentlanguage': - global $wgLanguageCode; - return $wgLanguageCode; + return $this->siteConfig->get( 'LanguageCode' ); case 'pagelanguage': $value = $pageLang->getCode(); break; @@ -3805,9 +3801,7 @@ class Parser { * @return string */ public function interwikiTransclude( $title, $action ) { - global $wgEnableScaryTranscluding, $wgTranscludeCacheExpiry; - - if ( !$wgEnableScaryTranscluding ) { + if ( !$this->siteConfig->get( 'EnableScaryTranscluding' ) ) { return wfMessage( 'scarytranscludedisabled' )->inContentLanguage()->text(); } @@ -3827,7 +3821,7 @@ class Parser { ( $wikiId !== false ) ? $wikiId : 'external', sha1( $url ) ), - $wgTranscludeCacheExpiry, + $this->siteConfig->get( 'TranscludeCacheExpiry' ), function ( $oldValue, &$ttl ) use ( $url, $fname, $cache ) { $req = MWHttpRequest::factory( $url, [], $fname ); @@ -4129,8 +4123,6 @@ class Parser { * @private */ public function formatHeadings( $text, $origText, $isMain = true ) { - global $wgMaxTocLevel; - # Inhibit editsection links if requested in the page if ( isset( $this->mDoubleUnderscores['noeditsection'] ) ) { $maybeShowEditLink = false; @@ -4201,6 +4193,7 @@ class Parser { $headlines = $numMatches !== false ? $matches[3] : []; + $maxTocLevel = $this->siteConfig->get( 'MaxTocLevel' ); foreach ( $headlines as $headline ) { $isTemplate = false; $titleText = false; @@ -4223,7 +4216,7 @@ class Parser { # Increase TOC level $toclevel++; $sublevelCount[$toclevel] = 0; - if ( $toclevel < $wgMaxTocLevel ) { + if ( $toclevel < $maxTocLevel ) { $prevtoclevel = $toclevel; $toc .= Linker::tocIndent(); $numVisible++; @@ -4245,8 +4238,8 @@ class Parser { if ( $i == 0 ) { $toclevel = 1; } - if ( $toclevel < $wgMaxTocLevel ) { - if ( $prevtoclevel < $wgMaxTocLevel ) { + if ( $toclevel < $maxTocLevel ) { + if ( $prevtoclevel < $maxTocLevel ) { # Unindent only if the previous toc level was shown :p $toc .= Linker::tocUnindent( $prevtoclevel - $toclevel ); $prevtoclevel = $toclevel; @@ -4256,7 +4249,7 @@ class Parser { } } else { # No change in level, end TOC line - if ( $toclevel < $wgMaxTocLevel ) { + if ( $toclevel < $maxTocLevel ) { $toc .= Linker::tocLineEnd(); } } @@ -4381,7 +4374,7 @@ class Parser { ) . ' ' . $headline; } - if ( $enoughToc && ( !isset( $wgMaxTocLevel ) || $toclevel < $wgMaxTocLevel ) ) { + if ( $enoughToc && ( !isset( $maxTocLevel ) || $toclevel < $maxTocLevel ) ) { $toc .= Linker::tocLine( $linkAnchor, $tocline, $numbering, $toclevel, ( $isTemplate ? false : $sectionIndex ) ); } @@ -4462,7 +4455,7 @@ class Parser { } if ( $enoughToc ) { - if ( $prevtoclevel > 0 && $prevtoclevel < $wgMaxTocLevel ) { + if ( $prevtoclevel > 0 && $prevtoclevel < $maxTocLevel ) { $toc .= Linker::tocUnindent( $prevtoclevel - 1 ); } $toc = Linker::tocList( $toc, $this->mOptions->getUserLangObj() ); @@ -4641,8 +4634,6 @@ class Parser { * @return string */ public function getUserSig( &$user, $nickname = false, $fancySig = null ) { - global $wgMaxSigChars; - $username = $user->getName(); # If not given, retrieve from the user object. @@ -4656,7 +4647,7 @@ class Parser { $nickname = $nickname == null ? $username : $nickname; - if ( mb_strlen( $nickname ) > $wgMaxSigChars ) { + if ( mb_strlen( $nickname ) > $this->siteConfig->get( 'MaxSigChars' ) ) { $nickname = $username; wfDebug( __METHOD__ . ": $username has overlong signature.\n" ); } elseif ( $fancySig !== false ) { @@ -5143,24 +5134,18 @@ class Parser { break; case 'gallery-internal-link': $linkValue = strip_tags( $this->replaceLinkHoldersText( $match ) ); - $chars = self::EXT_LINK_URL_CLASS; - $addr = self::EXT_LINK_ADDR; - $prots = $this->mUrlProtocols; - // check to see if link matches an absolute url, if not then it must be a wiki link. if ( preg_match( '/^-{R|(.*)}-$/', $linkValue ) ) { // Result of LanguageConverter::markNoConversion // invoked on an external link. $linkValue = substr( $linkValue, 4, -2 ); } - if ( preg_match( "/^($prots)$addr$chars*$/u", $linkValue ) ) { - $link = $linkValue; - $this->mOutput->addExternalLink( $link ); - } else { - $localLinkTitle = Title::newFromText( $linkValue ); - if ( $localLinkTitle !== null ) { - $this->mOutput->addLink( $localLinkTitle ); - $link = $localLinkTitle->getLinkURL(); - } + list( $type, $target ) = $this->parseLinkParameter( $linkValue ); + if ( $type === 'link-url' ) { + $link = $target; + $this->mOutput->addExternalLink( $target ); + } elseif ( $type === 'link-title' ) { + $link = $target->getLinkURL(); + $this->mOutput->addLink( $target ); } break; default: @@ -5342,29 +5327,16 @@ class Parser { $value = $this->stripAltText( $value, $holders ); break; case 'link': - $chars = self::EXT_LINK_URL_CLASS; - $addr = self::EXT_LINK_ADDR; - $prots = $this->mUrlProtocols; - if ( $value === '' ) { - $paramName = 'no-link'; - $value = true; + list( $paramName, $value ) = $this->parseLinkParameter( $value ); + if ( $paramName ) { $validated = true; - } elseif ( preg_match( "/^((?i)$prots)/", $value ) ) { - if ( preg_match( "/^((?i)$prots)$addr$chars*$/u", $value, $m ) ) { - $paramName = 'link-url'; - $this->mOutput->addExternalLink( $value ); + if ( $paramName === 'no-link' ) { + $value = true; + } + if ( $paramName === 'link-url' ) { if ( $this->mOptions->getExternalLinkTarget() ) { $params[$type]['link-target'] = $this->mOptions->getExternalLinkTarget(); } - $validated = true; - } - } else { - $linkTitle = Title::newFromText( $value ); - if ( $linkTitle ) { - $paramName = 'link-title'; - $value = $linkTitle; - $this->mOutput->addLink( $linkTitle ); - $validated = true; } } break; @@ -5459,6 +5431,48 @@ class Parser { return $ret; } + /** + * Parse the value of 'link' parameter in image syntax (`[[File:Foo.jpg|link=]]`). + * + * Adds an entry to appropriate link tables. + * + * @since 1.32 + * @return array of `[ type, target ]`, where: + * - `type` is one of: + * - `null`: Given value is not a valid link target, use default + * - `'no-link'`: Given value is empty, do not generate a link + * - `'link-url'`: Given value is a valid external link + * - `'link-title'`: Given value is a valid internal link + * - `target` is: + * - When `type` is `null` or `'no-link'`: `false` + * - When `type` is `'link-url'`: URL string corresponding to given value + * - When `type` is `'link-title'`: Title object corresponding to given value + */ + public function parseLinkParameter( $value ) { + $chars = self::EXT_LINK_URL_CLASS; + $addr = self::EXT_LINK_ADDR; + $prots = $this->mUrlProtocols; + $type = null; + $target = false; + if ( $value === '' ) { + $type = 'no-link'; + } elseif ( preg_match( "/^((?i)$prots)/", $value ) ) { + if ( preg_match( "/^((?i)$prots)$addr$chars*$/u", $value, $m ) ) { + $this->mOutput->addExternalLink( $value ); + $type = 'link-url'; + $target = $value; + } + } else { + $linkTitle = Title::newFromText( $value ); + if ( $linkTitle ) { + $this->mOutput->addLink( $linkTitle ); + $type = 'link-title'; + $target = $linkTitle; + } + } + return [ $type, $target ]; + } + /** * @param string $caption * @param LinkHolderArray|bool $holders @@ -5770,13 +5784,27 @@ class Parser { // NOTE: try to get the RevisionObject even if mRevisionId is null. // This is useful when parsing revision that has not yet been saved. + // However, if we get back a saved revision even though we are in + // preview mode, we'll have to ignore it, see below. + // NOTE: This callback may be used to inject an OLD revision that was + // already loaded, so "current" is a bit of a misnomer. We can't just + // skip it if mRevisionId is set. $rev = call_user_func( $this->mOptions->getCurrentRevisionCallback(), $this->getTitle(), $this ); - # If the parse is for a new revision, then the callback should have - # already been set to force the object and should match mRevisionId. - # If not, try to fetch by mRevisionId for sanity. + if ( $this->mRevisionId === null && $rev && $rev->getId() ) { + // We are in preview mode (mRevisionId is null), and the current revision callback + // returned an existing revision. Ignore it and return null, it's probably the page's + // current revision, which is not what we want here. Note that we do want to call the + // callback to allow the unsaved revision to be injected here, e.g. for + // self-transclusion previews. + return null; + } + + // If the parse is for a new revision, then the callback should have + // already been set to force the object and should match mRevisionId. + // If not, try to fetch by mRevisionId for sanity. if ( $this->mRevisionId && $rev && $rev->getId() != $this->mRevisionId ) { $rev = Revision::newFromId( $this->mRevisionId ); } @@ -5896,9 +5924,9 @@ class Parser { return '#' . Sanitizer::escapeIdForLink( $sectionName ); } - private static function makeLegacyAnchor( $sectionName ) { - global $wgFragmentMode; - if ( isset( $wgFragmentMode[1] ) && $wgFragmentMode[1] === 'legacy' ) { + private function makeLegacyAnchor( $sectionName ) { + $fragmentMode = $this->config->get( 'FragmentMode' ); + if ( isset( $fragmentMode[1] ) && $fragmentMode[1] === 'legacy' ) { // ForAttribute() and ForLink() are the same for legacy encoding $id = Sanitizer::escapeIdForAttribute( $sectionName, Sanitizer::ID_FALLBACK ); } else { @@ -5936,7 +5964,7 @@ class Parser { # Strip out wikitext links(they break the anchor) $text = $this->stripSectionName( $text ); $sectionName = self::getSectionNameFromStrippedText( $text ); - return self::makeLegacyAnchor( $sectionName ); + return $this->makeLegacyAnchor( $sectionName ); } /**