MediaWiki REL1_37
ParserOutput.php
Go to the documentation of this file.
1<?php
2
4use MediaWiki\Json\JsonUnserializableTrait;
7use Wikimedia\Reflection\GhostFieldAccessTrait;
8
31class ParserOutput extends CacheTime {
32 use GhostFieldAccessTrait;
33 use JsonUnserializableTrait;
34
42
46 public const SUPPORTS_UNWRAP_TRANSFORM = 1;
47
51 public $mText = null;
52
58
63
67 public $mIndicators = [];
68
73
79 public $mLinks = [];
80
85 public $mLinksSpecial = [];
86
91 public $mTemplates = [];
92
97 public $mTemplateIds = [];
98
102 public $mImages = [];
103
108
112 public $mExternalLinks = [];
113
118 public $mInterwikiLinks = [];
119
123 public $mNewSection = false;
124
128 public $mHideNewSection = false;
129
133 public $mNoGallery = false;
134
138 public $mHeadItems = [];
139
143 public $mModules = [];
144
148 public $mModuleStyles = [];
149
153 public $mJsConfigVars = [];
154
158 public $mOutputHooks = [];
159
164 public $mWarnings = [];
165
169 public $mSections = [];
170
174 public $mProperties = [];
175
179 public $mTOCHTML = '';
180
185
189 public $mEnableOOUI = false;
190
194 private $mIndexPolicy = '';
195
199 private $mExtensionData = [];
200
204 private $mLimitReportData = [];
205
208
212 private $mParseStartTime = [];
213
217 private $mPreventClickjacking = false;
218
222 private $mExtraScriptSrcs = [];
223
227 private $mExtraDefaultSrcs = [];
228
232 private $mExtraStyleSrcs = [];
233
237 private $mFlags = [];
238
240 private const SPECULATIVE_FIELDS = [
241 'speculativePageIdUsed',
242 'mSpeculativeRevId',
243 'revisionTimestampUsed'
244 ];
245
252
255
260
262 private $mMaxAdaptiveExpiry = INF;
263
264 private const EDITSECTION_REGEX =
265 '#<(?:mw:)?editsection page="(.*?)" section="(.*?)"(?:/>|>(.*?)(</(?:mw:)?editsection>))#s';
266
267 // finalizeAdaptiveCacheExpiry() uses TTL = MAX( m * PARSE_TIME + b, MIN_AR_TTL)
268 // Current values imply that m=3933.333333 and b=-333.333333
269 // See https://www.nngroup.com/articles/website-response-times/
270 private const PARSE_FAST_SEC = 0.100; // perceived "fast" page parse
271 private const PARSE_SLOW_SEC = 1.0; // perceived "slow" page parse
272 private const FAST_AR_TTL = 60; // adaptive TTL for "fast" pages
273 private const SLOW_AR_TTL = 3600; // adaptive TTL for "slow" pages
274 private const MIN_AR_TTL = 15; // min adaptive TTL (for sanity, pool counter, and edit stashing)
275
285 public function __construct( $text = '', $languageLinks = [], $categoryLinks = [],
286 $unused = false, $titletext = ''
287 ) {
288 $this->mText = $text;
289 $this->mLanguageLinks = $languageLinks;
290 $this->mCategories = $categoryLinks;
291 $this->mTitleText = $titletext;
292 }
293
304 public function hasText() {
305 return ( $this->mText !== null );
306 }
307
316 public function getRawText() {
317 if ( $this->mText === null ) {
318 throw new LogicException( 'This ParserOutput contains no text!' );
319 }
320
321 return $this->mText;
322 }
323
350 public function getText( $options = [] ) {
351 $options += [
352 'allowTOC' => true,
353 'enableSectionEditLinks' => true,
354 'skin' => null,
355 'unwrap' => false,
356 'deduplicateStyles' => true,
357 'wrapperDivClass' => $this->getWrapperDivClass(),
358 ];
359 $text = $this->getRawText();
360
361 Hooks::runner()->onParserOutputPostCacheTransform( $this, $text, $options );
362
363 if ( $options['wrapperDivClass'] !== '' && !$options['unwrap'] ) {
364 $text = Html::rawElement( 'div', [ 'class' => $options['wrapperDivClass'] ], $text );
365 }
366
367 if ( $options['enableSectionEditLinks'] ) {
368 // TODO: Passing the skin should be required
369 $skin = $options['skin'] ?: RequestContext::getMain()->getSkin();
370
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;
377
378 if ( !is_object( $editsectionPage ) ) {
379 LoggerFactory::getInstance( 'Parser' )
380 ->error(
381 'ParserOutput::getText(): bad title in editsection placeholder',
382 [
383 'placeholder' => $m[0],
384 'editsectionPage' => $m[1],
385 'titletext' => $this->getTitleText(),
386 'phab' => 'T261347'
387 ]
388 );
389 return '';
390 }
391
392 return $skin->doEditSectionLink(
393 $editsectionPage,
394 $editsectionSection,
395 $editsectionContent,
396 $skin->getLanguage()
397 );
398 },
399 $text
400 );
401 } else {
402 $text = preg_replace( self::EDITSECTION_REGEX, '', $text );
403 }
404
405 if ( $options['allowTOC'] ) {
406 $text = str_replace( [ Parser::TOC_START, Parser::TOC_END ], '', $text );
407 } else {
408 $text = preg_replace(
409 '#' . preg_quote( Parser::TOC_START, '#' ) . '.*?' . preg_quote( Parser::TOC_END, '#' ) . '#s',
410 '',
411 $text
412 );
413 }
414
415 if ( $options['deduplicateStyles'] ) {
416 $seen = [];
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'] ) ) {
422 return $m[0];
423 }
424
425 $key = $attr['data-mw-deduplicate'];
426 if ( !isset( $seen[$key] ) ) {
427 $seen[$key] = true;
428 return $m[0];
429 }
430
431 // We were going to use an empty <style> here, but there
432 // was concern that would be too much overhead for browsers.
433 // So let's hope a <link> with a non-standard rel and href isn't
434 // going to be misinterpreted or mangled by any subsequent processing.
435 return Html::element( 'link', [
436 'rel' => 'mw-deduplicated-inline-style',
437 'href' => "mw-data:" . wfUrlencode( $key ),
438 ] );
439 },
440 $text
441 );
442 }
443
444 // Hydrate slot section header placeholders generated by RevisionRenderer.
445 $text = preg_replace_callback(
446 '#<mw:slotheader>(.*?)</mw:slotheader>#',
447 static function ( $m ) {
448 $role = htmlspecialchars_decode( $m[1] );
449 // TODO: map to message, using the interface language. Set lang="xyz" accordingly.
450 $headerText = $role;
451 return $headerText;
452 },
453 $text
454 );
455 return $text;
456 }
457
463 public function addCacheMessage( string $msg ) {
464 $this->mText .= "\n<!-- $msg\n -->\n";
465 }
466
472 public function addWrapperDivClass( $class ) {
473 $this->mWrapperDivClasses[$class] = true;
474 }
475
480 public function clearWrapperDivClass() {
481 $this->mWrapperDivClasses = [];
482 }
483
491 public function getWrapperDivClass() {
492 return implode( ' ', array_keys( $this->mWrapperDivClasses ) );
493 }
494
499 public function setSpeculativeRevIdUsed( $id ) {
500 $this->mSpeculativeRevId = $id;
501 }
502
507 public function getSpeculativeRevIdUsed() {
508 return $this->mSpeculativeRevId;
509 }
510
515 public function setSpeculativePageIdUsed( $id ) {
516 $this->speculativePageIdUsed = $id;
517 }
518
523 public function getSpeculativePageIdUsed() {
524 return $this->speculativePageIdUsed;
525 }
526
531 public function setRevisionTimestampUsed( $timestamp ) {
532 $this->revisionTimestampUsed = $timestamp;
533 }
534
539 public function getRevisionTimestampUsed() {
540 return $this->revisionTimestampUsed;
541 }
542
547 public function setRevisionUsedSha1Base36( $hash ) {
548 if ( $hash === null ) {
549 return; // e.g. RevisionRecord::getSha1() returned null
550 }
551
552 if (
553 $this->revisionUsedSha1Base36 !== null &&
554 $this->revisionUsedSha1Base36 !== $hash
555 ) {
556 $this->revisionUsedSha1Base36 = ''; // mismatched
557 } else {
558 $this->revisionUsedSha1Base36 = $hash;
559 }
560 }
561
566 public function getRevisionUsedSha1Base36() {
567 return $this->revisionUsedSha1Base36;
568 }
569
570 public function &getLanguageLinks() {
571 return $this->mLanguageLinks;
572 }
573
574 public function getInterwikiLinks() {
575 return $this->mInterwikiLinks;
576 }
577
578 public function getCategoryLinks() {
579 return array_keys( $this->mCategories );
580 }
581
582 public function &getCategories() {
583 return $this->mCategories;
584 }
585
590 public function getIndicators() {
591 return $this->mIndicators;
592 }
593
594 public function getTitleText() {
595 return $this->mTitleText;
596 }
597
598 public function getSections() {
599 return $this->mSections;
600 }
601
602 public function &getLinks() {
603 return $this->mLinks;
604 }
605
610 public function &getLinksSpecial() {
611 return $this->mLinksSpecial;
612 }
613
614 public function &getTemplates() {
615 return $this->mTemplates;
616 }
617
618 public function &getTemplateIds() {
619 return $this->mTemplateIds;
620 }
621
622 public function &getImages() {
623 return $this->mImages;
624 }
625
626 public function &getFileSearchOptions() {
627 return $this->mFileSearchOptions;
628 }
629
630 public function &getExternalLinks() {
631 return $this->mExternalLinks;
632 }
633
634 public function setNoGallery( $value ) {
635 $this->mNoGallery = (bool)$value;
636 }
637
638 public function getNoGallery() {
639 return $this->mNoGallery;
640 }
641
642 public function getHeadItems() {
643 return $this->mHeadItems;
644 }
645
646 public function getModules() {
647 return $this->mModules;
648 }
649
650 public function getModuleStyles() {
651 return $this->mModuleStyles;
652 }
653
658 public function getJsConfigVars() {
659 return $this->mJsConfigVars;
660 }
661
662 public function getOutputHooks() {
663 return (array)$this->mOutputHooks;
664 }
665
666 public function getWarnings() {
667 return array_keys( $this->mWarnings );
668 }
669
670 public function getIndexPolicy() {
671 return $this->mIndexPolicy;
672 }
673
674 public function getTOCHTML() {
675 return $this->mTOCHTML;
676 }
677
681 public function getTimestamp() {
682 return $this->mTimestamp;
683 }
684
685 public function getLimitReportData() {
686 return $this->mLimitReportData;
687 }
688
689 public function getLimitReportJSData() {
690 return $this->mLimitReportJSData;
691 }
692
693 public function getEnableOOUI() {
694 return $this->mEnableOOUI;
695 }
696
702 public function getExtraCSPDefaultSrcs() {
703 return $this->mExtraDefaultSrcs;
704 }
705
711 public function getExtraCSPScriptSrcs() {
712 return $this->mExtraScriptSrcs;
713 }
714
720 public function getExtraCSPStyleSrcs() {
721 return $this->mExtraStyleSrcs;
722 }
723
724 public function setText( $text ) {
725 return wfSetVar( $this->mText, $text );
726 }
727
728 public function setLanguageLinks( $ll ) {
729 return wfSetVar( $this->mLanguageLinks, $ll );
730 }
731
732 public function setCategoryLinks( $cl ) {
733 return wfSetVar( $this->mCategories, $cl );
734 }
735
736 public function setTitleText( $t ) {
737 return wfSetVar( $this->mTitleText, $t );
738 }
739
740 public function setSections( $toc ) {
741 return wfSetVar( $this->mSections, $toc );
742 }
743
744 public function setIndexPolicy( $policy ) {
745 return wfSetVar( $this->mIndexPolicy, $policy );
746 }
747
748 public function setTOCHTML( $tochtml ) {
749 return wfSetVar( $this->mTOCHTML, $tochtml );
750 }
751
752 public function setTimestamp( $timestamp ) {
753 return wfSetVar( $this->mTimestamp, $timestamp );
754 }
755
756 public function addCategory( $c, $sort ) {
757 $this->mCategories[$c] = $sort;
758 }
759
765 public function setIndicator( $id, $content ) {
766 $this->mIndicators[$id] = $content;
767 }
768
776 public function setEnableOOUI( $enable = false ) {
777 $this->mEnableOOUI = $enable;
778 }
779
780 public function addLanguageLink( $t ) {
781 $this->mLanguageLinks[] = $t;
782 }
783
784 public function addWarning( $s ) {
785 $this->mWarnings[$s] = 1;
786 }
787
788 public function addOutputHook( $hook, $data = false ) {
789 $this->mOutputHooks[] = [ $hook, $data ];
790 }
791
792 public function setNewSection( $value ) {
793 $this->mNewSection = (bool)$value;
794 }
795
796 public function hideNewSection( $value ) {
797 $this->mHideNewSection = (bool)$value;
798 }
799
800 public function getHideNewSection() {
801 return (bool)$this->mHideNewSection;
802 }
803
804 public function getNewSection() {
805 return (bool)$this->mNewSection;
806 }
807
815 public static function isLinkInternal( $internal, $url ) {
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
821 '(?:[\?\/\#]|$)/i',
822 $url
823 );
824 }
825
826 public function addExternalLink( $url ) {
827 # We don't register links pointing to our own server, unless... :-)
829
830 # Replace unnecessary URL escape codes with the referenced character
831 # This prevents spammers from hiding links from the filters
832 $url = Parser::normalizeLinkUrl( $url );
833
834 $registerExternalLink = true;
836 $registerExternalLink = !self::isLinkInternal( $wgServer, $url );
837 }
838 if ( $registerExternalLink ) {
839 $this->mExternalLinks[$url] = 1;
840 }
841 }
842
849 public function addLink( Title $title, $id = null ) {
850 if ( $title->isExternal() ) {
851 // Don't record interwikis in pagelinks
852 $this->addInterwikiLink( $title );
853 return;
854 }
855 $ns = $title->getNamespace();
856 $dbk = $title->getDBkey();
857 if ( $ns === NS_MEDIA ) {
858 // Normalize this pseudo-alias if it makes it down here...
859 $ns = NS_FILE;
860 } elseif ( $ns === NS_SPECIAL ) {
861 // We don't want to record Special: links in the database, so put them in a separate place.
862 // It might actually be wise to, but we'd need to do some normalization.
863 $this->mLinksSpecial[$dbk] = 1;
864 return;
865 } elseif ( $dbk === '' ) {
866 // Don't record self links - [[#Foo]]
867 return;
868 }
869 if ( !isset( $this->mLinks[$ns] ) ) {
870 $this->mLinks[$ns] = [];
871 }
872 if ( $id === null ) {
873 $id = $title->getArticleID();
874 }
875 $this->mLinks[$ns][$dbk] = $id;
876 }
877
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 ];
888 }
889 }
890
897 public function addTemplate( $title, $page_id, $rev_id ) {
898 $ns = $title->getNamespace();
899 $dbk = $title->getDBkey();
900 if ( !isset( $this->mTemplates[$ns] ) ) {
901 $this->mTemplates[$ns] = [];
902 }
903 $this->mTemplates[$ns][$dbk] = $page_id;
904 if ( !isset( $this->mTemplateIds[$ns] ) ) {
905 $this->mTemplateIds[$ns] = [];
906 }
907 $this->mTemplateIds[$ns][$dbk] = $rev_id; // For versioning
908 }
909
914 public function addInterwikiLink( $title ) {
915 if ( !$title->isExternal() ) {
916 throw new MWException( 'Non-interwiki link passed, internal parser error.' );
917 }
918 $prefix = $title->getInterwiki();
919 if ( !isset( $this->mInterwikiLinks[$prefix] ) ) {
920 $this->mInterwikiLinks[$prefix] = [];
921 }
922 $this->mInterwikiLinks[$prefix][$title->getDBkey()] = 1;
923 }
924
932 public function addHeadItem( $section, $tag = false ) {
933 if ( $tag !== false ) {
934 $this->mHeadItems[$tag] = $section;
935 } else {
936 $this->mHeadItems[] = $section;
937 }
938 }
939
944 public function addModules( $modules ) {
945 $this->mModules = array_merge( $this->mModules, (array)$modules );
946 }
947
952 public function addModuleStyles( $modules ) {
953 $this->mModuleStyles = array_merge( $this->mModuleStyles, (array)$modules );
954 }
955
963 public function addJsConfigVars( $keys, $value = null ) {
964 if ( is_array( $keys ) ) {
965 foreach ( $keys as $key => $value ) {
966 $this->mJsConfigVars[$key] = $value;
967 }
968 return;
969 }
970
971 $this->mJsConfigVars[$keys] = $value;
972 }
973
979 public function addOutputPageMetadata( OutputPage $out ) {
980 $this->addModules( $out->getModules() );
981 $this->addModuleStyles( $out->getModuleStyles() );
982 $this->addJsConfigVars( $out->getJsConfigVars() );
983
984 $this->mHeadItems = array_merge( $this->mHeadItems, $out->getHeadItemsArray() );
985 $this->mPreventClickjacking = $this->mPreventClickjacking || $out->getPreventClickjacking();
986 }
987
1004 public function addTrackingCategory( $msg, $title ) {
1005 if ( $title->isSpecialPage() ) {
1006 wfDebug( __METHOD__ . ": Not adding tracking category $msg to special page!" );
1007 return false;
1008 }
1009
1010 // Important to parse with correct title (T33469)
1011 $cat = wfMessage( $msg )
1012 ->page( $title )
1013 ->inContentLanguage()
1014 ->text();
1015
1016 # Allow tracking categories to be disabled by setting them to "-"
1017 if ( $cat === '-' ) {
1018 return false;
1019 }
1020
1021 $containerCategory = Title::makeTitleSafe( NS_CATEGORY, $cat );
1022 if ( $containerCategory ) {
1023 $this->addCategory( $containerCategory->getDBkey(), $this->getProperty( 'defaultsort' ) ?: '' );
1024 return true;
1025 } else {
1026 wfDebug( __METHOD__ . ": [[MediaWiki:$msg]] is not a valid title!" );
1027 return false;
1028 }
1029 }
1030
1042 public function setDisplayTitle( $text ) {
1043 $this->setTitleText( $text );
1044 $this->setProperty( 'displaytitle', $text );
1045 }
1046
1055 public function getDisplayTitle() {
1056 $t = $this->getTitleText();
1057 if ( $t === '' ) {
1058 return false;
1059 }
1060 return $t;
1061 }
1062
1068 public function setFlag( $flag ) {
1069 $this->mFlags[$flag] = true;
1070 }
1071
1076 public function getFlag( $flag ) {
1077 return isset( $this->mFlags[$flag] );
1078 }
1079
1084 public function getAllFlags() {
1085 return array_keys( $this->mFlags );
1086 }
1087
1153 public function setProperty( $name, $value ) {
1154 $this->mProperties[$name] = $value;
1155 }
1156
1165 public function getProperty( $name ) {
1166 return $this->mProperties[$name] ?? false;
1167 }
1168
1169 public function unsetProperty( $name ) {
1170 unset( $this->mProperties[$name] );
1171 }
1172
1173 public function getProperties() {
1174 if ( !isset( $this->mProperties ) ) {
1175 $this->mProperties = [];
1176 }
1177 return $this->mProperties;
1178 }
1179
1223 public function setExtensionData( $key, $value ) {
1224 if ( $value === null ) {
1225 unset( $this->mExtensionData[$key] );
1226 } else {
1227 $this->mExtensionData[$key] = $value;
1228 }
1229 }
1230
1242 public function getExtensionData( $key ) {
1243 return $this->mExtensionData[$key] ?? null;
1244 }
1245
1246 private static function getTimes( $clock = null ) {
1247 $ret = [];
1248 if ( !$clock || $clock === 'wall' ) {
1249 $ret['wall'] = microtime( true );
1250 }
1251 if ( !$clock || $clock === 'cpu' ) {
1252 $ru = getrusage( 0 /* RUSAGE_SELF */ );
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;
1255 }
1256 return $ret;
1257 }
1258
1263 public function resetParseStartTime() {
1264 $this->mParseStartTime = self::getTimes();
1265 }
1266
1278 public function getTimeSinceStart( $clock ) {
1279 if ( !isset( $this->mParseStartTime[$clock] ) ) {
1280 return null;
1281 }
1282
1283 $end = self::getTimes( $clock );
1284 return $end[$clock] - $this->mParseStartTime[$clock];
1285 }
1286
1306 public function setLimitReportData( $key, $value ) {
1307 $this->mLimitReportData[$key] = $value;
1308
1309 if ( is_array( $value ) ) {
1310 if ( array_keys( $value ) === [ 0, 1 ]
1311 && is_numeric( $value[0] )
1312 && is_numeric( $value[1] )
1313 ) {
1314 $data = [ 'value' => $value[0], 'limit' => $value[1] ];
1315 } else {
1316 $data = $value;
1317 }
1318 } else {
1319 $data = $value;
1320 }
1321
1322 if ( strpos( $key, '-' ) ) {
1323 list( $ns, $name ) = explode( '-', $key, 2 );
1324 $this->mLimitReportJSData[$ns][$name] = $data;
1325 } else {
1326 $this->mLimitReportJSData[$key] = $data;
1327 }
1328 }
1329
1346 public function hasReducedExpiry(): bool {
1348
1349 return $this->getCacheExpiry() < $wgParserCacheExpireTime;
1350 }
1351
1357 public function hasDynamicContent() {
1358 return $this->hasReducedExpiry();
1359 }
1360
1368 public function preventClickjacking( $flag = null ) {
1369 return wfSetVar( $this->mPreventClickjacking, $flag );
1370 }
1371
1378 public function updateRuntimeAdaptiveExpiry( $ttl ) {
1379 $this->mMaxAdaptiveExpiry = min( $ttl, $this->mMaxAdaptiveExpiry );
1380 $this->updateCacheExpiry( $ttl );
1381 }
1382
1392 public function addExtraCSPDefaultSrc( $src ) {
1393 $this->mExtraDefaultSrcs[] = $src;
1394 }
1395
1402 public function addExtraCSPStyleSrc( $src ) {
1403 $this->mExtraStyleSrcs[] = $src;
1404 }
1405
1414 public function addExtraCSPScriptSrc( $src ) {
1415 $this->mExtraScriptSrcs[] = $src;
1416 }
1417
1424 if ( is_infinite( $this->mMaxAdaptiveExpiry ) ) {
1425 return; // not set
1426 }
1427
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 );
1432 // SLOW_AR_TTL = PARSE_SLOW_SEC * $slope + $point
1433 $point = self::SLOW_AR_TTL - self::PARSE_SLOW_SEC * $slope;
1434
1435 $adaptiveTTL = min(
1436 max( $slope * $runtime + $point, self::MIN_AR_TTL ),
1437 $this->mMaxAdaptiveExpiry
1438 );
1439 $this->updateCacheExpiry( $adaptiveTTL );
1440 }
1441 }
1442
1443 public function __sleep() {
1444 return array_filter( array_keys( get_object_vars( $this ) ),
1445 static function ( $field ) {
1446 if ( $field === 'mParseStartTime' ) {
1447 return false;
1448 }
1449 // Unserializing unknown private fields in HHVM causes
1450 // member variables with nulls in their names (T229366)
1451 return strpos( $field, "\0" ) === false;
1452 }
1453 );
1454 }
1455
1464 $this->mOutputHooks = self::mergeList( $this->mOutputHooks, $source->getOutputHooks() );
1465 $this->mWarnings = self::mergeMap( $this->mWarnings, $source->mWarnings ); // don't use getter
1466 $this->mTimestamp = $this->useMaxValue( $this->mTimestamp, $source->getTimestamp() );
1467
1468 foreach ( self::SPECULATIVE_FIELDS as $field ) {
1469 if ( $this->$field && $source->$field && $this->$field !== $source->$field ) {
1470 wfLogWarning( __METHOD__ . ": inconsistent '$field' properties!" );
1471 }
1472 $this->$field = $this->useMaxValue( $this->$field, $source->$field );
1473 }
1474
1475 $this->mParseStartTime = $this->useEachMinValue(
1476 $this->mParseStartTime,
1477 $source->mParseStartTime
1478 );
1479
1480 $this->mFlags = self::mergeMap( $this->mFlags, $source->mFlags );
1481 $this->mParseUsedOptions = self::mergeMap( $this->mParseUsedOptions, $source->mParseUsedOptions );
1482
1483 // TODO: maintain per-slot limit reports!
1484 if ( empty( $this->mLimitReportData ) ) {
1485 $this->mLimitReportData = $source->mLimitReportData;
1486 }
1487 if ( empty( $this->mLimitReportJSData ) ) {
1488 $this->mLimitReportJSData = $source->mLimitReportJSData;
1489 }
1490 }
1491
1500 // HTML and HTTP
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()
1509 );
1510 $this->mExtraScriptSrcs = self::mergeList(
1511 $this->mExtraScriptSrcs,
1512 $source->getExtraCSPScriptSrcs()
1513 );
1514 $this->mExtraDefaultSrcs = self::mergeList(
1515 $this->mExtraDefaultSrcs,
1516 $source->getExtraCSPDefaultSrcs()
1517 );
1518
1519 // "noindex" always wins!
1520 if ( $this->mIndexPolicy === 'noindex' || $source->mIndexPolicy === 'noindex' ) {
1521 $this->mIndexPolicy = 'noindex';
1522 } elseif ( $this->mIndexPolicy !== 'index' ) {
1523 $this->mIndexPolicy = $source->mIndexPolicy;
1524 }
1525
1526 // Skin control
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();
1532
1533 // TODO: we'll have to be smarter about this!
1534 $this->mSections = array_merge( $this->mSections, $source->getSections() );
1535 $this->mTOCHTML .= $source->mTOCHTML;
1536
1537 // XXX: we don't want to concatenate title text, so first write wins.
1538 // We should use the first *modified* title text, but we don't have the original to check.
1539 if ( $this->mTitleText === null || $this->mTitleText === '' ) {
1540 $this->mTitleText = $source->mTitleText;
1541 }
1542
1543 // class names are stored in array keys
1544 $this->mWrapperDivClasses = self::mergeMap(
1545 $this->mWrapperDivClasses,
1546 $source->mWrapperDivClasses
1547 );
1548
1549 // NOTE: last write wins, same as within one ParserOutput
1550 $this->mIndicators = self::mergeMap( $this->mIndicators, $source->getIndicators() );
1551
1552 // NOTE: include extension data in "tracking meta data" as well as "html meta data"!
1553 // TODO: add a $mergeStrategy parameter to setExtensionData to allow different
1554 // kinds of extension data to be merged in different ways.
1555 $this->mExtensionData = self::mergeMap(
1556 $this->mExtensionData,
1557 $source->mExtensionData
1558 );
1559 }
1560
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()
1578 );
1579 $this->mExternalLinks = self::mergeMap( $this->mExternalLinks, $source->getExternalLinks() );
1580 $this->mInterwikiLinks = self::merge2D(
1581 $this->mInterwikiLinks,
1582 $source->getInterwikiLinks()
1583 );
1584
1585 // TODO: add a $mergeStrategy parameter to setProperty to allow different
1586 // kinds of properties to be merged in different ways.
1587 $this->mProperties = self::mergeMap( $this->mProperties, $source->getProperties() );
1588
1589 // NOTE: include extension data in "tracking meta data" as well as "html meta data"!
1590 // TODO: add a $mergeStrategy parameter to setExtensionData to allow different
1591 // kinds of extension data to be merged in different ways.
1592 $this->mExtensionData = self::mergeMap(
1593 $this->mExtensionData,
1594 $source->mExtensionData
1595 );
1596 }
1597
1598 private static function mergeMixedList( array $a, array $b ) {
1599 return array_unique( array_merge( $a, $b ), SORT_REGULAR );
1600 }
1601
1602 private static function mergeList( array $a, array $b ) {
1603 return array_values( array_unique( array_merge( $a, $b ), SORT_REGULAR ) );
1604 }
1605
1606 private static function mergeMap( array $a, array $b ) {
1607 return array_replace( $a, $b );
1608 }
1609
1610 private static function merge2D( array $a, array $b ) {
1611 $values = [];
1612 $keys = array_merge( array_keys( $a ), array_keys( $b ) );
1613
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] );
1621 } else {
1622 $values[$k] = $b[$k];
1623 }
1624 }
1625
1626 return $values;
1627 }
1628
1629 private static function useEachMinValue( array $a, array $b ) {
1630 $values = [];
1631 $keys = array_merge( array_keys( $a ), array_keys( $b ) );
1632
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] );
1636 } else {
1637 $values[$k] = self::useMinValue( $a[$k] ?? null, $b[$k] ?? null );
1638 }
1639 }
1640
1641 return $values;
1642 }
1643
1644 private static function useMinValue( $a, $b ) {
1645 if ( $a === null ) {
1646 return $b;
1647 }
1648
1649 if ( $b === null ) {
1650 return $a;
1651 }
1652
1653 return min( $a, $b );
1654 }
1655
1656 private static function useMaxValue( $a, $b ) {
1657 if ( $a === null ) {
1658 return $b;
1659 }
1660
1661 if ( $b === null ) {
1662 return $a;
1663 }
1664
1665 return max( $a, $b );
1666 }
1667
1674 protected function toJsonArray(): array {
1675 $data = [
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,
1704 // may contain arbitrary structures!
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,
1719 ];
1720
1721 // Fill in missing fields from parents. Array addition does not override existing fields.
1722 $data += parent::toJsonArray();
1723
1724 // TODO: make more fields optional!
1725
1726 if ( $this->mMaxAdaptiveExpiry !== INF ) {
1727 // NOTE: JSON can't encode infinity!
1728 $data['MaxAdaptiveExpiry'] = $this->mMaxAdaptiveExpiry;
1729 }
1730
1731 return $data;
1732 }
1733
1734 public static function newFromJsonArray( JsonUnserializer $unserializer, array $json ) {
1735 $parserOutput = new ParserOutput();
1736 $parserOutput->initFromJson( $unserializer, $json );
1737 return $parserOutput;
1738 }
1739
1745 protected function initFromJson( JsonUnserializer $unserializer, array $jsonData ) {
1746 parent::initFromJson( $unserializer, $jsonData );
1747
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;
1791 }
1792
1802 private static function detectAndEncodeBinary( array $properties ) {
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 ),
1810 ];
1811 }
1812 }
1813 }
1814
1815 return $properties;
1816 }
1817
1826 private static function detectAndDecodeBinary( array $properties ) {
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_'] );
1831 }
1832 }
1833 }
1834
1835 return $properties;
1836 }
1837
1838 public function __wakeup() {
1839 // Backwards compatibility, pre 1.36
1840 $priorAccessedOptions = $this->getGhostFieldValue( 'mAccessedOptions' );
1841 if ( $priorAccessedOptions ) {
1842 $this->mParseUsedOptions = $priorAccessedOptions;
1843 }
1844 }
1845}
$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.
const NS_FILE
Definition Defines.php:70
const NS_SPECIAL
Definition Defines.php:53
const NS_MEDIA
Definition Defines.php:52
const NS_CATEGORY
Definition Defines.php:78
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.
Definition CacheTime.php:35
getCacheExpiry()
Returns the number of seconds after which this object should expire.
MediaWiki exception.
PSR-3 logger instance factory.
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.
getProperty( $name)
array $mModuleStyles
Modules of which only the CSSS will be loaded by ResourceLoader.
unsetProperty( $name)
static getTimes( $clock=null)
hideNewSection( $value)
array $mFlags
Generic flags.
bool $mPreventClickjacking
Whether to emit X-Frame-Options: DENY.
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.
setNewSection( $value)
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)
addExternalLink( $url)
static useMaxValue( $a, $b)
setLanguageLinks( $ll)
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?
setCategoryLinks( $cl)
array $mTemplates
2-D map of NS/DBK to ID for the template references.
setRevisionUsedSha1Base36( $hash)
static merge2D(array $a, array $b)
setNoGallery( $value)
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.
addModules( $modules)
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.
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.
array $mOutputHooks
Hook tags as per $wgParserOutputHooks.
setTOCHTML( $tochtml)
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...
const EDITSECTION_REGEX
array $mFileSearchOptions
DB keys of the images used mapped to sha1 and MW timestamp.
addCategory( $c, $sort)
setIndexPolicy( $policy)
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.
const TOC_END
Definition Parser.php:154
static normalizeLinkUrl( $url)
Replace unusual escape codes in a URL with their equivalent characters.
Definition Parser.php:2287
const TOC_START
Definition Parser.php:153
Represents a title within MediaWiki.
Definition Title.php:48
unserializeArray(array $array)
Helper to unserialize an array of JsonUnserializable instances or simple types.
foreach( $mmfl['setupFiles'] as $fileName) if($queue) if(empty( $mmfl['quiet'])) $s
$source
$content
Definition router.php:76