4use MediaWiki\Json\JsonUnserializableTrait;
7use Wikimedia\Reflection\GhostFieldAccessTrait;
32 use GhostFieldAccessTrait;
33 use JsonUnserializableTrait;
240 private const SPECULATIVE_FIELDS = [
241 'speculativePageIdUsed',
243 'revisionTimestampUsed'
265 '#<(?:mw:)?editsection page="(.*?)" section="(.*?)"(?:/>|>(.*?)(</(?:mw:)?editsection>))#s';
285 public function __construct( $text =
'', $languageLinks = [], $categoryLinks = [],
286 $unused =
false, $titletext =
''
288 $this->mText = $text;
289 $this->mLanguageLinks = $languageLinks;
290 $this->mCategories = $categoryLinks;
291 $this->mTitleText = $titletext;
305 return ( $this->mText !==
null );
317 if ( $this->mText ===
null ) {
318 throw new LogicException(
'This ParserOutput contains no text!' );
353 'enableSectionEditLinks' =>
true,
356 'deduplicateStyles' =>
true,
361 Hooks::runner()->onParserOutputPostCacheTransform( $this, $text, $options );
363 if ( $options[
'wrapperDivClass'] !==
'' && !$options[
'unwrap'] ) {
364 $text = Html::rawElement(
'div', [
'class' => $options[
'wrapperDivClass'] ], $text );
367 if ( $options[
'enableSectionEditLinks'] ) {
369 $skin = $options[
'skin'] ?: RequestContext::getMain()->getSkin();
371 $text = preg_replace_callback(
372 self::EDITSECTION_REGEX,
373 function ( $m ) use ( $skin ) {
374 $editsectionPage = Title::newFromText( htmlspecialchars_decode( $m[1] ) );
375 $editsectionSection = htmlspecialchars_decode( $m[2] );
376 $editsectionContent = isset( $m[4] ) ? Sanitizer::decodeCharReferences( $m[3] ) :
null;
378 if ( !is_object( $editsectionPage ) ) {
379 LoggerFactory::getInstance(
'Parser' )
381 'ParserOutput::getText(): bad title in editsection placeholder',
383 'placeholder' => $m[0],
384 'editsectionPage' => $m[1],
392 return $skin->doEditSectionLink(
402 $text = preg_replace( self::EDITSECTION_REGEX,
'', $text );
405 if ( $options[
'allowTOC'] ) {
408 $text = preg_replace(
415 if ( $options[
'deduplicateStyles'] ) {
417 $text = preg_replace_callback(
418 '#<style\s+([^>]*data-mw-deduplicate\s*=[^>]*)>.*?</style>#s',
419 static function ( $m ) use ( &$seen ) {
420 $attr = Sanitizer::decodeTagAttributes( $m[1] );
421 if ( !isset( $attr[
'data-mw-deduplicate'] ) ) {
425 $key = $attr[
'data-mw-deduplicate'];
426 if ( !isset( $seen[$key] ) ) {
435 return Html::element(
'link', [
436 'rel' =>
'mw-deduplicated-inline-style',
445 $text = preg_replace_callback(
446 '#<mw:slotheader>(.*?)</mw:slotheader>#',
447 static function ( $m ) {
448 $role = htmlspecialchars_decode( $m[1] );
464 $this->mText .=
"\n<!-- $msg\n -->\n";
473 $this->mWrapperDivClasses[$class] =
true;
481 $this->mWrapperDivClasses = [];
492 return implode(
' ', array_keys( $this->mWrapperDivClasses ) );
500 $this->mSpeculativeRevId = $id;
508 return $this->mSpeculativeRevId;
516 $this->speculativePageIdUsed = $id;
524 return $this->speculativePageIdUsed;
532 $this->revisionTimestampUsed = $timestamp;
540 return $this->revisionTimestampUsed;
548 if ( $hash ===
null ) {
553 $this->revisionUsedSha1Base36 !==
null &&
554 $this->revisionUsedSha1Base36 !== $hash
556 $this->revisionUsedSha1Base36 =
'';
558 $this->revisionUsedSha1Base36 = $hash;
567 return $this->revisionUsedSha1Base36;
571 return $this->mLanguageLinks;
575 return $this->mInterwikiLinks;
579 return array_keys( $this->mCategories );
583 return $this->mCategories;
591 return $this->mIndicators;
595 return $this->mTitleText;
599 return $this->mSections;
603 return $this->mLinks;
611 return $this->mLinksSpecial;
615 return $this->mTemplates;
619 return $this->mTemplateIds;
623 return $this->mImages;
627 return $this->mFileSearchOptions;
631 return $this->mExternalLinks;
635 $this->mNoGallery = (bool)$value;
639 return $this->mNoGallery;
643 return $this->mHeadItems;
647 return $this->mModules;
651 return $this->mModuleStyles;
659 return $this->mJsConfigVars;
663 return (array)$this->mOutputHooks;
667 return array_keys( $this->mWarnings );
671 return $this->mIndexPolicy;
675 return $this->mTOCHTML;
682 return $this->mTimestamp;
686 return $this->mLimitReportData;
690 return $this->mLimitReportJSData;
694 return $this->mEnableOOUI;
703 return $this->mExtraDefaultSrcs;
712 return $this->mExtraScriptSrcs;
721 return $this->mExtraStyleSrcs;
725 return wfSetVar( $this->mText, $text );
729 return wfSetVar( $this->mLanguageLinks, $ll );
733 return wfSetVar( $this->mCategories, $cl );
741 return wfSetVar( $this->mSections, $toc );
745 return wfSetVar( $this->mIndexPolicy, $policy );
749 return wfSetVar( $this->mTOCHTML, $tochtml );
753 return wfSetVar( $this->mTimestamp, $timestamp );
757 $this->mCategories[$c] = $sort;
777 $this->mEnableOOUI = $enable;
781 $this->mLanguageLinks[] =
$t;
785 $this->mWarnings[
$s] = 1;
789 $this->mOutputHooks[] = [ $hook, $data ];
793 $this->mNewSection = (bool)$value;
797 $this->mHideNewSection = (bool)$value;
801 return (
bool)$this->mHideNewSection;
805 return (
bool)$this->mNewSection;
816 return (
bool)preg_match(
'/^' .
817 # If server is proto relative, check also
for http/https links
818 ( substr( $internal, 0, 2 ) ===
'//' ?
'(?:https?:)?' :
'' ) .
819 preg_quote( $internal,
'/' ) .
820 # check
for query/path/anchor or end of link in each
case
827 # We don't register links pointing to our own server, unless... :-)
830 # Replace unnecessary URL escape codes with the referenced character
831 # This prevents spammers from hiding links from the filters
834 $registerExternalLink =
true;
836 $registerExternalLink = !self::isLinkInternal(
$wgServer, $url );
838 if ( $registerExternalLink ) {
839 $this->mExternalLinks[$url] = 1;
850 if (
$title->isExternal() ) {
855 $ns =
$title->getNamespace();
856 $dbk =
$title->getDBkey();
863 $this->mLinksSpecial[$dbk] = 1;
865 } elseif ( $dbk ===
'' ) {
869 if ( !isset( $this->mLinks[$ns] ) ) {
870 $this->mLinks[$ns] = [];
872 if ( $id ===
null ) {
873 $id =
$title->getArticleID();
875 $this->mLinks[$ns][$dbk] = $id;
884 public function addImage( $name, $timestamp =
null, $sha1 =
null ) {
885 $this->mImages[$name] = 1;
886 if ( $timestamp !==
null && $sha1 !==
null ) {
887 $this->mFileSearchOptions[$name] = [
'time' => $timestamp,
'sha1' => $sha1 ];
898 $ns =
$title->getNamespace();
899 $dbk =
$title->getDBkey();
900 if ( !isset( $this->mTemplates[$ns] ) ) {
901 $this->mTemplates[$ns] = [];
903 $this->mTemplates[$ns][$dbk] = $page_id;
904 if ( !isset( $this->mTemplateIds[$ns] ) ) {
905 $this->mTemplateIds[$ns] = [];
907 $this->mTemplateIds[$ns][$dbk] = $rev_id;
915 if ( !
$title->isExternal() ) {
916 throw new MWException(
'Non-interwiki link passed, internal parser error.' );
918 $prefix =
$title->getInterwiki();
919 if ( !isset( $this->mInterwikiLinks[$prefix] ) ) {
920 $this->mInterwikiLinks[$prefix] = [];
922 $this->mInterwikiLinks[$prefix][
$title->getDBkey()] = 1;
933 if ( $tag !==
false ) {
934 $this->mHeadItems[$tag] = $section;
936 $this->mHeadItems[] = $section;
945 $this->mModules = array_merge( $this->mModules, (array)
$modules );
953 $this->mModuleStyles = array_merge( $this->mModuleStyles, (array)
$modules );
964 if ( is_array(
$keys ) ) {
965 foreach (
$keys as $key => $value ) {
966 $this->mJsConfigVars[$key] = $value;
971 $this->mJsConfigVars[
$keys] = $value;
1005 if (
$title->isSpecialPage() ) {
1006 wfDebug( __METHOD__ .
": Not adding tracking category $msg to special page!" );
1013 ->inContentLanguage()
1016 # Allow tracking categories to be disabled by setting them to "-"
1017 if ( $cat ===
'-' ) {
1021 $containerCategory = Title::makeTitleSafe(
NS_CATEGORY, $cat );
1022 if ( $containerCategory ) {
1023 $this->
addCategory( $containerCategory->getDBkey(), $this->getProperty(
'defaultsort' ) ?:
'' );
1026 wfDebug( __METHOD__ .
": [[MediaWiki:$msg]] is not a valid title!" );
1069 $this->mFlags[$flag] =
true;
1077 return isset( $this->mFlags[$flag] );
1085 return array_keys( $this->mFlags );
1154 $this->mProperties[$name] = $value;
1166 return $this->mProperties[$name] ??
false;
1170 unset( $this->mProperties[$name] );
1174 if ( !isset( $this->mProperties ) ) {
1175 $this->mProperties = [];
1177 return $this->mProperties;
1224 if ( $value ===
null ) {
1225 unset( $this->mExtensionData[$key] );
1227 $this->mExtensionData[$key] = $value;
1243 return $this->mExtensionData[$key] ??
null;
1248 if ( !$clock || $clock ===
'wall' ) {
1249 $ret[
'wall'] = microtime(
true );
1251 if ( !$clock || $clock ===
'cpu' ) {
1252 $ru = getrusage( 0 );
1253 $ret[
'cpu'] = $ru[
'ru_utime.tv_sec'] + $ru[
'ru_utime.tv_usec'] / 1e6;
1254 $ret[
'cpu'] += $ru[
'ru_stime.tv_sec'] + $ru[
'ru_stime.tv_usec'] / 1e6;
1264 $this->mParseStartTime = self::getTimes();
1279 if ( !isset( $this->mParseStartTime[$clock] ) ) {
1283 $end = self::getTimes( $clock );
1284 return $end[$clock] - $this->mParseStartTime[$clock];
1307 $this->mLimitReportData[$key] = $value;
1309 if ( is_array( $value ) ) {
1310 if ( array_keys( $value ) === [ 0, 1 ]
1311 && is_numeric( $value[0] )
1312 && is_numeric( $value[1] )
1314 $data = [
'value' => $value[0],
'limit' => $value[1] ];
1322 if ( strpos( $key,
'-' ) ) {
1323 list( $ns, $name ) = explode(
'-', $key, 2 );
1324 $this->mLimitReportJSData[$ns][$name] = $data;
1326 $this->mLimitReportJSData[$key] = $data;
1358 return $this->hasReducedExpiry();
1369 return wfSetVar( $this->mPreventClickjacking, $flag );
1379 $this->mMaxAdaptiveExpiry = min( $ttl, $this->mMaxAdaptiveExpiry );
1380 $this->updateCacheExpiry( $ttl );
1393 $this->mExtraDefaultSrcs[] = $src;
1403 $this->mExtraStyleSrcs[] = $src;
1415 $this->mExtraScriptSrcs[] = $src;
1424 if ( is_infinite( $this->mMaxAdaptiveExpiry ) ) {
1428 $runtime = $this->getTimeSinceStart(
'wall' );
1429 if ( is_float( $runtime ) ) {
1430 $slope = ( self::SLOW_AR_TTL - self::FAST_AR_TTL )
1431 / ( self::PARSE_SLOW_SEC - self::PARSE_FAST_SEC );
1433 $point = self::SLOW_AR_TTL - self::PARSE_SLOW_SEC * $slope;
1436 max( $slope * $runtime + $point, self::MIN_AR_TTL ),
1437 $this->mMaxAdaptiveExpiry
1439 $this->updateCacheExpiry( $adaptiveTTL );
1444 return array_filter( array_keys( get_object_vars( $this ) ),
1445 static function ( $field ) {
1446 if ( $field ===
'mParseStartTime' ) {
1451 return strpos( $field,
"\0" ) ===
false;
1464 $this->mOutputHooks = self::mergeList( $this->mOutputHooks,
$source->getOutputHooks() );
1465 $this->mWarnings = self::mergeMap( $this->mWarnings,
$source->mWarnings );
1466 $this->mTimestamp = $this->useMaxValue( $this->mTimestamp,
$source->getTimestamp() );
1468 foreach ( self::SPECULATIVE_FIELDS as $field ) {
1469 if ( $this->$field &&
$source->$field && $this->$field !==
$source->$field ) {
1470 wfLogWarning( __METHOD__ .
": inconsistent '$field' properties!" );
1472 $this->$field = $this->useMaxValue( $this->$field,
$source->$field );
1475 $this->mParseStartTime = $this->useEachMinValue(
1476 $this->mParseStartTime,
1480 $this->mFlags = self::mergeMap( $this->mFlags,
$source->mFlags );
1481 $this->mParseUsedOptions = self::mergeMap( $this->mParseUsedOptions,
$source->mParseUsedOptions );
1484 if ( empty( $this->mLimitReportData ) ) {
1485 $this->mLimitReportData =
$source->mLimitReportData;
1487 if ( empty( $this->mLimitReportJSData ) ) {
1488 $this->mLimitReportJSData =
$source->mLimitReportJSData;
1501 $this->mHeadItems = self::mergeMixedList( $this->mHeadItems,
$source->getHeadItems() );
1502 $this->mModules = self::mergeList( $this->mModules,
$source->getModules() );
1503 $this->mModuleStyles = self::mergeList( $this->mModuleStyles,
$source->getModuleStyles() );
1504 $this->mJsConfigVars = self::mergeMap( $this->mJsConfigVars,
$source->getJsConfigVars() );
1505 $this->mMaxAdaptiveExpiry = min( $this->mMaxAdaptiveExpiry,
$source->mMaxAdaptiveExpiry );
1506 $this->mExtraStyleSrcs = self::mergeList(
1507 $this->mExtraStyleSrcs,
1508 $source->getExtraCSPStyleSrcs()
1510 $this->mExtraScriptSrcs = self::mergeList(
1511 $this->mExtraScriptSrcs,
1512 $source->getExtraCSPScriptSrcs()
1514 $this->mExtraDefaultSrcs = self::mergeList(
1515 $this->mExtraDefaultSrcs,
1516 $source->getExtraCSPDefaultSrcs()
1520 if ( $this->mIndexPolicy ===
'noindex' ||
$source->mIndexPolicy ===
'noindex' ) {
1521 $this->mIndexPolicy =
'noindex';
1522 } elseif ( $this->mIndexPolicy !==
'index' ) {
1523 $this->mIndexPolicy =
$source->mIndexPolicy;
1527 $this->mNewSection = $this->mNewSection ||
$source->getNewSection();
1528 $this->mHideNewSection = $this->mHideNewSection ||
$source->getHideNewSection();
1529 $this->mNoGallery = $this->mNoGallery ||
$source->getNoGallery();
1530 $this->mEnableOOUI = $this->mEnableOOUI ||
$source->getEnableOOUI();
1531 $this->mPreventClickjacking = $this->mPreventClickjacking ||
$source->preventClickjacking();
1534 $this->mSections = array_merge( $this->mSections,
$source->getSections() );
1535 $this->mTOCHTML .=
$source->mTOCHTML;
1539 if ( $this->mTitleText ===
null || $this->mTitleText ===
'' ) {
1540 $this->mTitleText =
$source->mTitleText;
1544 $this->mWrapperDivClasses = self::mergeMap(
1545 $this->mWrapperDivClasses,
1550 $this->mIndicators = self::mergeMap( $this->mIndicators,
$source->getIndicators() );
1555 $this->mExtensionData = self::mergeMap(
1556 $this->mExtensionData,
1569 $this->mLanguageLinks = self::mergeList( $this->mLanguageLinks,
$source->getLanguageLinks() );
1570 $this->mCategories = self::mergeMap( $this->mCategories,
$source->getCategories() );
1571 $this->mLinks = self::merge2D( $this->mLinks,
$source->getLinks() );
1572 $this->mTemplates = self::merge2D( $this->mTemplates,
$source->getTemplates() );
1573 $this->mTemplateIds = self::merge2D( $this->mTemplateIds,
$source->getTemplateIds() );
1574 $this->mImages = self::mergeMap( $this->mImages,
$source->getImages() );
1575 $this->mFileSearchOptions = self::mergeMap(
1576 $this->mFileSearchOptions,
1577 $source->getFileSearchOptions()
1579 $this->mExternalLinks = self::mergeMap( $this->mExternalLinks,
$source->getExternalLinks() );
1580 $this->mInterwikiLinks = self::merge2D(
1581 $this->mInterwikiLinks,
1587 $this->mProperties = self::mergeMap( $this->mProperties,
$source->getProperties() );
1592 $this->mExtensionData = self::mergeMap(
1593 $this->mExtensionData,
1599 return array_unique( array_merge( $a, $b ), SORT_REGULAR );
1603 return array_values( array_unique( array_merge( $a, $b ), SORT_REGULAR ) );
1606 private static function mergeMap( array $a, array $b ) {
1607 return array_replace( $a, $b );
1610 private static function merge2D( array $a, array $b ) {
1612 $keys = array_merge( array_keys( $a ), array_keys( $b ) );
1614 foreach (
$keys as $k ) {
1615 if ( empty( $a[$k] ) ) {
1616 $values[$k] = $b[$k];
1617 } elseif ( empty( $b[$k] ) ) {
1618 $values[$k] = $a[$k];
1619 } elseif ( is_array( $a[$k] ) && is_array( $b[$k] ) ) {
1620 $values[$k] = array_replace( $a[$k], $b[$k] );
1622 $values[$k] = $b[$k];
1631 $keys = array_merge( array_keys( $a ), array_keys( $b ) );
1633 foreach (
$keys as $k ) {
1634 if ( is_array( $a[$k] ??
null ) && is_array( $b[$k] ??
null ) ) {
1635 $values[$k] = self::useEachMinValue( $a[$k], $b[$k] );
1637 $values[$k] = self::useMinValue( $a[$k] ??
null, $b[$k] ??
null );
1645 if ( $a ===
null ) {
1649 if ( $b ===
null ) {
1653 return min( $a, $b );
1657 if ( $a ===
null ) {
1661 if ( $b ===
null ) {
1665 return max( $a, $b );
1676 'Text' => $this->mText,
1677 'LanguageLinks' => $this->mLanguageLinks,
1678 'Categories' => $this->mCategories,
1679 'Indicators' => $this->mIndicators,
1680 'TitleText' => $this->mTitleText,
1681 'Links' => $this->mLinks,
1682 'LinksSpecial' => $this->mLinksSpecial,
1683 'Templates' => $this->mTemplates,
1684 'TemplateIds' => $this->mTemplateIds,
1685 'Images' => $this->mImages,
1686 'FileSearchOptions' => $this->mFileSearchOptions,
1687 'ExternalLinks' => $this->mExternalLinks,
1688 'InterwikiLinks' => $this->mInterwikiLinks,
1689 'NewSection' => $this->mNewSection,
1690 'HideNewSection' => $this->mHideNewSection,
1691 'NoGallery' => $this->mNoGallery,
1692 'HeadItems' => $this->mHeadItems,
1693 'Modules' => $this->mModules,
1694 'ModuleStyles' => $this->mModuleStyles,
1695 'JsConfigVars' => $this->mJsConfigVars,
1696 'OutputHooks' => $this->mOutputHooks,
1697 'Warnings' => $this->mWarnings,
1698 'Sections' => $this->mSections,
1699 'Properties' => self::detectAndEncodeBinary( $this->mProperties ),
1700 'TOCHTML' => $this->mTOCHTML,
1701 'Timestamp' => $this->mTimestamp,
1702 'EnableOOUI' => $this->mEnableOOUI,
1703 'IndexPolicy' => $this->mIndexPolicy,
1705 'ExtensionData' => $this->mExtensionData,
1706 'LimitReportData' => $this->mLimitReportData,
1707 'LimitReportJSData' => $this->mLimitReportJSData,
1708 'ParseStartTime' => $this->mParseStartTime,
1709 'PreventClickjacking' => $this->mPreventClickjacking,
1710 'ExtraScriptSrcs' => $this->mExtraScriptSrcs,
1711 'ExtraDefaultSrcs' => $this->mExtraDefaultSrcs,
1712 'ExtraStyleSrcs' => $this->mExtraStyleSrcs,
1713 'Flags' => $this->mFlags,
1714 'SpeculativeRevId' => $this->mSpeculativeRevId,
1715 'SpeculativePageIdUsed' => $this->speculativePageIdUsed,
1716 'RevisionTimestampUsed' => $this->revisionTimestampUsed,
1717 'RevisionUsedSha1Base36' => $this->revisionUsedSha1Base36,
1718 'WrapperDivClasses' => $this->mWrapperDivClasses,
1722 $data += parent::toJsonArray();
1726 if ( $this->mMaxAdaptiveExpiry !== INF ) {
1728 $data[
'MaxAdaptiveExpiry'] = $this->mMaxAdaptiveExpiry;
1736 $parserOutput->initFromJson( $unserializer, $json );
1737 return $parserOutput;
1746 parent::initFromJson( $unserializer, $jsonData );
1748 $this->mText = $jsonData[
'Text'];
1749 $this->mLanguageLinks = $jsonData[
'LanguageLinks'];
1750 $this->mCategories = $jsonData[
'Categories'];
1751 $this->mIndicators = $jsonData[
'Indicators'];
1752 $this->mTitleText = $jsonData[
'TitleText'];
1753 $this->mLinks = $jsonData[
'Links'];
1754 $this->mLinksSpecial = $jsonData[
'LinksSpecial'];
1755 $this->mTemplates = $jsonData[
'Templates'];
1756 $this->mTemplateIds = $jsonData[
'TemplateIds'];
1757 $this->mImages = $jsonData[
'Images'];
1758 $this->mFileSearchOptions = $jsonData[
'FileSearchOptions'];
1759 $this->mExternalLinks = $jsonData[
'ExternalLinks'];
1760 $this->mInterwikiLinks = $jsonData[
'InterwikiLinks'];
1761 $this->mNewSection = $jsonData[
'NewSection'];
1762 $this->mHideNewSection = $jsonData[
'HideNewSection'];
1763 $this->mNoGallery = $jsonData[
'NoGallery'];
1764 $this->mHeadItems = $jsonData[
'HeadItems'];
1765 $this->mModules = $jsonData[
'Modules'];
1766 $this->mModuleStyles = $jsonData[
'ModuleStyles'];
1767 $this->mJsConfigVars = $jsonData[
'JsConfigVars'];
1768 $this->mOutputHooks = $jsonData[
'OutputHooks'];
1769 $this->mWarnings = $jsonData[
'Warnings'];
1770 $this->mSections = $jsonData[
'Sections'];
1771 $this->mProperties = self::detectAndDecodeBinary( $jsonData[
'Properties'] );
1772 $this->mTOCHTML = $jsonData[
'TOCHTML'];
1773 $this->mTimestamp = $jsonData[
'Timestamp'];
1774 $this->mEnableOOUI = $jsonData[
'EnableOOUI'];
1775 $this->mIndexPolicy = $jsonData[
'IndexPolicy'];
1776 $this->mExtensionData = $unserializer->
unserializeArray( $jsonData[
'ExtensionData'] ?? [] );
1777 $this->mLimitReportData = $jsonData[
'LimitReportData'];
1778 $this->mLimitReportJSData = $jsonData[
'LimitReportJSData'];
1779 $this->mParseStartTime = $jsonData[
'ParseStartTime'];
1780 $this->mPreventClickjacking = $jsonData[
'PreventClickjacking'];
1781 $this->mExtraScriptSrcs = $jsonData[
'ExtraScriptSrcs'];
1782 $this->mExtraDefaultSrcs = $jsonData[
'ExtraDefaultSrcs'];
1783 $this->mExtraStyleSrcs = $jsonData[
'ExtraStyleSrcs'];
1784 $this->mFlags = $jsonData[
'Flags'];
1785 $this->mSpeculativeRevId = $jsonData[
'SpeculativeRevId'];
1786 $this->speculativePageIdUsed = $jsonData[
'SpeculativePageIdUsed'];
1787 $this->revisionTimestampUsed = $jsonData[
'RevisionTimestampUsed'];
1788 $this->revisionUsedSha1Base36 = $jsonData[
'RevisionUsedSha1Base36'];
1789 $this->mWrapperDivClasses = $jsonData[
'WrapperDivClasses'];
1790 $this->mMaxAdaptiveExpiry = $jsonData[
'MaxAdaptiveExpiry'] ?? INF;
1803 foreach ( $properties as $key => $value ) {
1804 if ( is_string( $value ) ) {
1805 if ( !mb_detect_encoding( $value,
'UTF-8',
true ) ) {
1806 $properties[$key] = [
1807 '_type_' =>
'string',
1808 '_encoding_' =>
'base64',
1809 '_data_' => base64_encode( $value ),
1827 foreach ( $properties as $key => $value ) {
1828 if ( is_array( $value ) && isset( $value[
'_encoding_'] ) ) {
1829 if ( $value[
'_encoding_'] ===
'base64' ) {
1830 $properties[$key] = base64_decode( $value[
'_data_'] );
1840 $priorAccessedOptions = $this->getGhostFieldValue(
'mAccessedOptions' );
1841 if ( $priorAccessedOptions ) {
1842 $this->mParseUsedOptions = $priorAccessedOptions;
$wgRegisterInternalExternals
By default MediaWiki does not register links pointing to same server in externallinks dataset,...
$wgParserCacheExpireTime
The expiry time for the parser cache, in seconds.
$wgServer
URL of the server.
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
wfUrlencode( $s)
We want some things to be included as literal characters in our title URLs for prettiness,...
wfSetVar(&$dest, $source, $force=false)
Sets dest to source and returns the original value of dest If source is NULL, it just returns the val...
wfLogWarning( $msg, $callerOffset=1, $level=E_USER_WARNING)
Send a warning as a PHP error and the debug log.
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
Parser cache specific expiry check.
getCacheExpiry()
Returns the number of seconds after which this object should expire.
This is one of the Core classes and should be read at least once by any new developers.
getJsConfigVars()
Get the javascript config vars to include on this page.
getHeadItemsArray()
Get an array of head items.
getModules( $filter=false, $position=null, $param='mModules', $type=ResourceLoaderModule::TYPE_COMBINED)
Get the list of modules to include on this page.
getPreventClickjacking()
Get the prevent-clickjacking flag.
getModuleStyles( $filter=false, $position=null)
Get the list of style-only modules to load on this page.
static mergeMap(array $a, array $b)
addOutputPageMetadata(OutputPage $out)
Copy items from the OutputPage object into this one.
array $mModuleStyles
Modules of which only the CSSS will be loaded by ResourceLoader.
static getTimes( $clock=null)
array $mFlags
Generic flags.
bool $mPreventClickjacking
Whether to emit X-Frame-Options: DENY.
getSpeculativeRevIdUsed()
array $mTemplateIds
2-D map of NS/DBK to rev ID for the template references.
int null $mSpeculativeRevId
Assumed rev ID for {{REVISIONID}} if no revision is set.
addOutputHook( $hook, $data=false)
const SUPPORTS_UNWRAP_TRANSFORM
mergeHtmlMetaDataFrom(ParserOutput $source)
Merges HTML metadata such as head items, JS config vars, and HTTP cache control info from $source int...
static useEachMinValue(array $a, array $b)
setDisplayTitle( $text)
Override the title to be used for display.
addJsConfigVars( $keys, $value=null)
Add one or more variables to be set in mw.config in JavaScript.
setIndicator( $id, $content)
static useMaxValue( $a, $b)
static newFromJsonArray(JsonUnserializer $unserializer, array $json)
Creates a new instance of the class and initialized it from the $json array.
addExtraCSPScriptSrc( $src)
Add an extra value to Content-Security-Policy script-src directive.
array $mJsConfigVars
JavaScript config variable for mw.config combined with this page.
bool $mHideNewSection
Hide the new section link?
array $mTemplates
2-D map of NS/DBK to ID for the template references.
setRevisionUsedSha1Base36( $hash)
static merge2D(array $a, array $b)
hasText()
Returns true if text was passed to the constructor, or set using setText().
string $mTOCHTML
HTML of the TOC.
static mergeList(array $a, array $b)
addInterwikiLink( $title)
setRevisionTimestampUsed( $timestamp)
array $mLimitReportData
Parser limit report data.
setEnableOOUI( $enable=false)
Enables OOUI, if true, in any OutputPage instance this ParserOutput object is added to.
$mWrapperDivClasses
string CSS classes to use for the wrapping div, stored in the array keys.
getDisplayTitle()
Get the title to be used for display.
addWrapperDivClass( $class)
Add a CSS class to use for the wrapping div.
int[][] $mLinks
2-D map of NS/DBK to ID for the links in the document.
addTrackingCategory( $msg, $title)
Add a tracking category, getting the title from a system message, or print a debug message if the tit...
finalizeAdaptiveCacheExpiry()
Call this when parsing is done to lower the TTL based on low parse times.
addTemplate( $title, $page_id, $rev_id)
Register a template dependency for this output.
bool $mNewSection
Show a new section link?
array $mImages
DB keys of the images used, in the array key only.
string $mTimestamp
Timestamp of the revision.
addLink(Title $title, $id=null)
Record a local or interwiki inline link for saving in future link tables.
resetParseStartTime()
Resets the parse start timestamps for future calls to getTimeSinceStart()
static mergeMixedList(array $a, array $b)
preventClickjacking( $flag=null)
Get or set the prevent-clickjacking flag.
bool $mEnableOOUI
Whether OOUI should be enabled.
mergeTrackingMetaDataFrom(ParserOutput $source)
Merges dependency tracking metadata such as backlinks, images used, and extension data from $source i...
setProperty( $name, $value)
Set a property to be stored in the page_props database table.
getRevisionTimestampUsed()
getExtraCSPStyleSrcs()
Get extra Content-Security-Policy 'style-src' directives.
addCacheMessage(string $msg)
Adds a comment notice about cache state to the text of the page.
addHeadItem( $section, $tag=false)
Add some text to the "<head>".
static detectAndEncodeBinary(array $properties)
Finds any non-utf8 strings in the given array and replaces them with an associative array that wraps ...
array $mExternalLinks
External link URLs, in the key only.
getExtraCSPScriptSrcs()
Get extra Content-Security-Policy 'script-src' directives.
array $mInterwikiLinks
2-D map of prefix/DBK (in keys only) for the inline interwiki links in the document.
array $mIndicators
Page status indicators, usually displayed in top-right corner.
static useMinValue( $a, $b)
getExtensionData( $key)
Gets extensions data previously attached to this ParserOutput using setExtensionData().
array $mExtraScriptSrcs
Extra script-src for CSP.
clearWrapperDivClass()
Clears the CSS class to use for the wrapping div, effectively disabling the wrapper div until addWrap...
array $mExtraDefaultSrcs
Extra default-src for CSP [Everything but script and style].
getText( $options=[])
Get the output HTML.
initFromJson(JsonUnserializer $unserializer, array $jsonData)
Initialize member fields from an array returned by jsonSerialize().
array $mExtensionData
extra data used by extensions.
toJsonArray()
Returns a JSON serializable structure representing this ParserOutput instance.
int null $revisionTimestampUsed
Assumed rev timestamp for {{REVISIONTIMESTAMP}} if no revision is set.
getExtraCSPDefaultSrcs()
Get extra Content-Security-Policy 'default-src' directives.
string $mTitleText
Title text of the chosen language variant, as HTML.
getRawText()
Get the cacheable text with <mw:editsection> markers still in it.
addImage( $name, $timestamp=null, $sha1=null)
Register a file dependency for this output.
updateRuntimeAdaptiveExpiry( $ttl)
Lower the runtime adaptive TTL to at most this value.
getRevisionUsedSha1Base36()
array $mOutputHooks
Hook tags as per $wgParserOutputHooks.
getSpeculativePageIdUsed()
const SUPPORTS_STATELESS_TRANSFORMS
Feature flags to indicate to extensions that MediaWiki core supports and uses getText() stateless tra...
array $mCategories
Map of category names to sort keys.
array $mSections
Table of contents.
array $mLinksSpecial
Keys are DBKs for the links to special pages in the document.
setLimitReportData( $key, $value)
Sets parser limit report data for a key.
bool $mNoGallery
No gallery on category page? (NOGALLERY).
int null $speculativePageIdUsed
Assumed page ID for {{PAGEID}} if no revision is set.
hasReducedExpiry()
Check whether the cache TTL was lowered from the site default.
setExtensionData( $key, $value)
Attaches arbitrary data to this ParserObject.
setTimestamp( $timestamp)
array $mHeadItems
Items to put in the <head> section.
array $mLanguageLinks
List of the full text of language links, in the order they appear.
setSpeculativeRevIdUsed( $id)
__construct( $text='', $languageLinks=[], $categoryLinks=[], $unused=false, $titletext='')
array $mModules
Modules to be loaded by ResourceLoader.
setSpeculativePageIdUsed( $id)
static isLinkInternal( $internal, $url)
Checks, if a url is pointing to the own server.
addExtraCSPDefaultSrc( $src)
Add an extra value to Content-Security-Policy default-src directive.
array $mProperties
Name/value pairs to be cached in the DB.
array $mWarnings
Warning text to be returned to the user.
array $mLimitReportJSData
Parser limit report data for JSON.
mergeInternalMetaDataFrom(ParserOutput $source)
Merges internal metadata such as flags, accessed options, and profiling info from $source into this P...
addModuleStyles( $modules)
getTimeSinceStart( $clock)
Returns the time since resetParseStartTime() was last called.
addExtraCSPStyleSrc( $src)
Add an extra value to Content-Security-Policy style-src directive.
string $mIndexPolicy
'index' or 'noindex'? Any other value will result in no change.
getWrapperDivClass()
Returns the class (or classes) to be used with the wrapper div for this otuput.
setFlag( $flag)
Attach a flag to the output so that it can be checked later to handle special cases.
static detectAndDecodeBinary(array $properties)
Finds any associative arrays that represent encoded binary strings, and replaces them with the decode...
array $mFileSearchOptions
DB keys of the images used mapped to sha1 and MW timestamp.
array $mParseStartTime
Timestamps for getTimeSinceStart().
string null $revisionUsedSha1Base36
SHA-1 base 36 hash of any self-transclusion.
array $mExtraStyleSrcs
Extra style-src for CSP.
int $mMaxAdaptiveExpiry
Upper bound of expiry based on parse duration.
static normalizeLinkUrl( $url)
Replace unusual escape codes in a URL with their equivalent characters.
Represents a title within MediaWiki.
foreach( $mmfl['setupFiles'] as $fileName) if($queue) if(empty( $mmfl['quiet'])) $s