MediaWiki  master
ParserOutput.php
Go to the documentation of this file.
1 <?php
2 
7 use Wikimedia\Reflection\GhostFieldAccessTrait;
8 
31 class ParserOutput extends CacheTime {
32  use GhostFieldAccessTrait;
34 
42 
46  public const SUPPORTS_UNWRAP_TRANSFORM = 1;
47 
51  public $mText = null;
52 
58 
62  public $mCategories;
63 
67  public $mIndicators = [];
68 
72  public $mTitleText;
73 
79  public $mLinks = [];
80 
85  public $mLinksSpecial = [];
86 
91  public $mTemplates = [];
92 
97  public $mTemplateIds = [];
98 
102  public $mImages = [];
103 
107  public $mFileSearchOptions = [];
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 
184  public $mTimestamp;
185 
189  public $mEnableOOUI = false;
190 
194  private $mIndexPolicy = '';
195 
199  private $mExtensionData = [];
200 
204  private $mLimitReportData = [];
205 
207  private $mLimitReportJSData = [];
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 
259  private $mWrapperDivClasses = [];
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() {
509  }
510 
515  public function setSpeculativePageIdUsed( $id ) {
516  $this->speculativePageIdUsed = $id;
517  }
518 
523  public function getSpeculativePageIdUsed() {
525  }
526 
531  public function setRevisionTimestampUsed( $timestamp ) {
532  $this->revisionTimestampUsed = $timestamp;
533  }
534 
539  public function getRevisionTimestampUsed() {
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() {
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() {
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() {
687  }
688 
689  public function getLimitReportJSData() {
691  }
692 
693  public function getEnableOOUI() {
694  return $this->mEnableOOUI;
695  }
696 
702  public function getExtraCSPDefaultSrcs() {
704  }
705 
711  public function getExtraCSPScriptSrcs() {
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 {
1347  global $wgParserCacheExpireTime;
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 
1423  public function finalizeAdaptiveCacheExpiry() {
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 }
ParserOutput\$mImages
array $mImages
DB keys of the images used, in the array key only.
Definition: ParserOutput.php:102
ParserOutput\$mWrapperDivClasses
$mWrapperDivClasses
string CSS classes to use for the wrapping div, stored in the array keys.
Definition: ParserOutput.php:259
ParserOutput\addCacheMessage
addCacheMessage(string $msg)
Adds a comment notice about cache state to the text of the page.
Definition: ParserOutput.php:463
ParserOutput\addOutputPageMetadata
addOutputPageMetadata(OutputPage $out)
Copy items from the OutputPage object into this one.
Definition: ParserOutput.php:979
MediaWiki\Json\JsonUnserializer
Definition: JsonUnserializer.php:33
ParserOutput\getEnableOOUI
getEnableOOUI()
Definition: ParserOutput.php:693
ParserOutput\mergeMap
static mergeMap(array $a, array $b)
Definition: ParserOutput.php:1606
ParserOutput\$mEnableOOUI
bool $mEnableOOUI
Whether OOUI should be enabled.
Definition: ParserOutput.php:189
ParserOutput\$mWarnings
array $mWarnings
Warning text to be returned to the user.
Definition: ParserOutput.php:164
ParserOutput\$mJsConfigVars
array $mJsConfigVars
JavaScript config variable for mw.config combined with this page.
Definition: ParserOutput.php:153
CacheTime\getCacheExpiry
getCacheExpiry()
Returns the number of seconds after which this object should expire.
Definition: CacheTime.php:142
ParserOutput\$mFileSearchOptions
array $mFileSearchOptions
DB keys of the images used mapped to sha1 and MW timestamp.
Definition: ParserOutput.php:107
Title\newFromText
static newFromText( $text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Definition: Title.php:383
ParserOutput\setTitleText
setTitleText( $t)
Definition: ParserOutput.php:736
ParserOutput
Definition: ParserOutput.php:31
MediaWiki\Json\JsonUnserializableTrait
trait JsonUnserializableTrait
Definition: JsonUnserializableTrait.php:24
ParserOutput\setSpeculativeRevIdUsed
setSpeculativeRevIdUsed( $id)
Definition: ParserOutput.php:499
ParserOutput\SUPPORTS_UNWRAP_TRANSFORM
const SUPPORTS_UNWRAP_TRANSFORM
Definition: ParserOutput.php:46
CacheTime
Parser cache specific expiry check.
Definition: CacheTime.php:35
ParserOutput\resetParseStartTime
resetParseStartTime()
Resets the parse start timestamps for future calls to getTimeSinceStart()
Definition: ParserOutput.php:1263
ParserOutput\setDisplayTitle
setDisplayTitle( $text)
Override the title to be used for display.
Definition: ParserOutput.php:1042
MediaWiki\Json\JsonUnserializable
Definition: JsonUnserializable.php:38
ParserOutput\$mLanguageLinks
array $mLanguageLinks
List of the full text of language links, in the order they appear.
Definition: ParserOutput.php:57
ParserOutput\setTimestamp
setTimestamp( $timestamp)
Definition: ParserOutput.php:752
ParserOutput\mergeMixedList
static mergeMixedList(array $a, array $b)
Definition: ParserOutput.php:1598
ParserOutput\addExtraCSPScriptSrc
addExtraCSPScriptSrc( $src)
Add an extra value to Content-Security-Policy script-src directive.
Definition: ParserOutput.php:1414
ParserOutput\setLimitReportData
setLimitReportData( $key, $value)
Sets parser limit report data for a key.
Definition: ParserOutput.php:1306
wfSetVar
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...
Definition: GlobalFunctions.php:1515
ParserOutput\merge2D
static merge2D(array $a, array $b)
Definition: ParserOutput.php:1610
ParserOutput\addWrapperDivClass
addWrapperDivClass( $class)
Add a CSS class to use for the wrapping div.
Definition: ParserOutput.php:472
ParserOutput\$mLimitReportJSData
array $mLimitReportJSData
Parser limit report data for JSON.
Definition: ParserOutput.php:207
ParserOutput\$mModules
array $mModules
Modules to be loaded by ResourceLoader.
Definition: ParserOutput.php:143
ParserOutput\__sleep
__sleep()
Definition: ParserOutput.php:1443
ParserOutput\setNewSection
setNewSection( $value)
Definition: ParserOutput.php:792
ParserOutput\getModules
getModules()
Definition: ParserOutput.php:646
ParserOutput\getImages
& getImages()
Definition: ParserOutput.php:622
ParserOutput\addModules
addModules( $modules)
Definition: ParserOutput.php:944
ParserOutput\MIN_AR_TTL
const MIN_AR_TTL
Definition: ParserOutput.php:274
ParserOutput\$mLinksSpecial
array $mLinksSpecial
Keys are DBKs for the links to special pages in the document.
Definition: ParserOutput.php:85
ParserOutput\$mOutputHooks
array $mOutputHooks
Hook tags as per $wgParserOutputHooks.
Definition: ParserOutput.php:158
ParserOutput\setIndicator
setIndicator( $id, $content)
Definition: ParserOutput.php:765
ParserOutput\addTemplate
addTemplate( $title, $page_id, $rev_id)
Register a template dependency for this output.
Definition: ParserOutput.php:897
ParserOutput\getJsConfigVars
getJsConfigVars()
Definition: ParserOutput.php:658
wfUrlencode
wfUrlencode( $s)
We want some things to be included as literal characters in our title URLs for prettiness,...
Definition: GlobalFunctions.php:292
ParserOutput\mergeTrackingMetaDataFrom
mergeTrackingMetaDataFrom(ParserOutput $source)
Merges dependency tracking metadata such as backlinks, images used, and extension data from $source i...
Definition: ParserOutput.php:1568
ParserOutput\addExtraCSPStyleSrc
addExtraCSPStyleSrc( $src)
Add an extra value to Content-Security-Policy style-src directive.
Definition: ParserOutput.php:1402
OutputPage\getModuleStyles
getModuleStyles( $filter=false, $position=null)
Get the list of style-only modules to load on this page.
Definition: OutputPage.php:573
ParserOutput\unsetProperty
unsetProperty( $name)
Definition: ParserOutput.php:1169
ParserOutput\setFlag
setFlag( $flag)
Attach a flag to the output so that it can be checked later to handle special cases.
Definition: ParserOutput.php:1068
ParserOutput\hideNewSection
hideNewSection( $value)
Definition: ParserOutput.php:796
ParserOutput\addLink
addLink(Title $title, $id=null)
Record a local or interwiki inline link for saving in future link tables.
Definition: ParserOutput.php:849
wfMessage
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
Definition: GlobalFunctions.php:1186
ParserOutput\$mMaxAdaptiveExpiry
int $mMaxAdaptiveExpiry
Upper bound of expiry based on parse duration.
Definition: ParserOutput.php:262
ParserOutput\__construct
__construct( $text='', $languageLinks=[], $categoryLinks=[], $unused=false, $titletext='')
Definition: ParserOutput.php:285
ParserOutput\toJsonArray
toJsonArray()
Returns a JSON serializable structure representing this ParserOutput instance.
Definition: ParserOutput.php:1674
wfLogWarning
wfLogWarning( $msg, $callerOffset=1, $level=E_USER_WARNING)
Send a warning as a PHP error and the debug log.
Definition: GlobalFunctions.php:1056
ParserOutput\EDITSECTION_REGEX
const EDITSECTION_REGEX
Definition: ParserOutput.php:264
ParserOutput\PARSE_SLOW_SEC
const PARSE_SLOW_SEC
Definition: ParserOutput.php:271
ParserOutput\getHeadItems
getHeadItems()
Definition: ParserOutput.php:642
ParserOutput\hasReducedExpiry
hasReducedExpiry()
Check whether the cache TTL was lowered from the site default.
Definition: ParserOutput.php:1346
ParserOutput\PARSE_FAST_SEC
const PARSE_FAST_SEC
Definition: ParserOutput.php:270
ParserOutput\setSpeculativePageIdUsed
setSpeculativePageIdUsed( $id)
Definition: ParserOutput.php:515
ParserOutput\getProperties
getProperties()
Definition: ParserOutput.php:1173
ParserOutput\mergeList
static mergeList(array $a, array $b)
Definition: ParserOutput.php:1602
ParserOutput\$mProperties
array $mProperties
Name/value pairs to be cached in the DB.
Definition: ParserOutput.php:174
NS_SPECIAL
const NS_SPECIAL
Definition: Defines.php:53
ParserOutput\getModuleStyles
getModuleStyles()
Definition: ParserOutput.php:650
ParserOutput\$mHeadItems
array $mHeadItems
Items to put in the <head> section.
Definition: ParserOutput.php:138
ParserOutput\$mTimestamp
string $mTimestamp
Timestamp of the revision.
Definition: ParserOutput.php:184
ParserOutput\getExtraCSPDefaultSrcs
getExtraCSPDefaultSrcs()
Get extra Content-Security-Policy 'default-src' directives.
Definition: ParserOutput.php:702
ParserOutput\addExtraCSPDefaultSrc
addExtraCSPDefaultSrc( $src)
Add an extra value to Content-Security-Policy default-src directive.
Definition: ParserOutput.php:1392
ParserOutput\getLimitReportJSData
getLimitReportJSData()
Definition: ParserOutput.php:689
MWException
MediaWiki exception.
Definition: MWException.php:29
Parser\TOC_START
const TOC_START
Definition: Parser.php:153
OutputPage\getModules
getModules( $filter=false, $position=null, $param='mModules', $type=ResourceLoaderModule::TYPE_COMBINED)
Get the list of modules to include on this page.
Definition: OutputPage.php:548
ParserOutput\getCategoryLinks
getCategoryLinks()
Definition: ParserOutput.php:578
MediaWiki\Logger\LoggerFactory
PSR-3 logger instance factory.
Definition: LoggerFactory.php:45
ParserOutput\setRevisionUsedSha1Base36
setRevisionUsedSha1Base36( $hash)
Definition: ParserOutput.php:547
ParserOutput\$mLinks
int[][] $mLinks
2-D map of NS/DBK to ID for the links in the document.
Definition: ParserOutput.php:79
ParserOutput\getFlag
getFlag( $flag)
Definition: ParserOutput.php:1076
ParserOutput\getTimestamp
getTimestamp()
Definition: ParserOutput.php:681
ParserOutput\isLinkInternal
static isLinkInternal( $internal, $url)
Checks, if a url is pointing to the own server.
Definition: ParserOutput.php:815
ParserOutput\addExternalLink
addExternalLink( $url)
Definition: ParserOutput.php:826
ParserOutput\$mExtraDefaultSrcs
array $mExtraDefaultSrcs
Extra default-src for CSP [Everything but script and style].
Definition: ParserOutput.php:227
ParserOutput\getInterwikiLinks
getInterwikiLinks()
Definition: ParserOutput.php:574
ParserOutput\$mLimitReportData
array $mLimitReportData
Parser limit report data.
Definition: ParserOutput.php:204
ParserOutput\mergeHtmlMetaDataFrom
mergeHtmlMetaDataFrom(ParserOutput $source)
Merges HTML metadata such as head items, JS config vars, and HTTP cache control info from $source int...
Definition: ParserOutput.php:1499
ParserOutput\updateRuntimeAdaptiveExpiry
updateRuntimeAdaptiveExpiry( $ttl)
Lower the runtime adaptive TTL to at most this value.
Definition: ParserOutput.php:1378
ParserOutput\getTimeSinceStart
getTimeSinceStart( $clock)
Returns the time since resetParseStartTime() was last called.
Definition: ParserOutput.php:1278
$modules
$modules
Definition: HTMLFormElement.php:15
ParserOutput\addImage
addImage( $name, $timestamp=null, $sha1=null)
Register a file dependency for this output.
Definition: ParserOutput.php:884
ParserOutput\$mHideNewSection
bool $mHideNewSection
Hide the new section link?
Definition: ParserOutput.php:128
ParserOutput\$mTemplates
array $mTemplates
2-D map of NS/DBK to ID for the template references.
Definition: ParserOutput.php:91
ParserOutput\$mNewSection
bool $mNewSection
Show a new section link?
Definition: ParserOutput.php:123
ParserOutput\__wakeup
__wakeup()
Definition: ParserOutput.php:1838
$wgParserCacheExpireTime
$wgParserCacheExpireTime
The expiry time for the parser cache, in seconds.
Definition: DefaultSettings.php:2960
ParserOutput\getTimes
static getTimes( $clock=null)
Definition: ParserOutput.php:1246
ParserOutput\addCategory
addCategory( $c, $sort)
Definition: ParserOutput.php:756
ParserOutput\useMaxValue
static useMaxValue( $a, $b)
Definition: ParserOutput.php:1656
Parser\TOC_END
const TOC_END
Definition: Parser.php:154
$title
$title
Definition: testCompression.php:38
ParserOutput\SUPPORTS_STATELESS_TRANSFORMS
const SUPPORTS_STATELESS_TRANSFORMS
Feature flags to indicate to extensions that MediaWiki core supports and uses getText() stateless tra...
Definition: ParserOutput.php:41
ParserOutput\addModuleStyles
addModuleStyles( $modules)
Definition: ParserOutput.php:952
ParserOutput\mergeInternalMetaDataFrom
mergeInternalMetaDataFrom(ParserOutput $source)
Merges internal metadata such as flags, accessed options, and profiling info from $source into this P...
Definition: ParserOutput.php:1463
ParserOutput\setText
setText( $text)
Definition: ParserOutput.php:724
ParserOutput\$mModuleStyles
array $mModuleStyles
Modules of which only the CSSS will be loaded by ResourceLoader.
Definition: ParserOutput.php:148
ParserOutput\getDisplayTitle
getDisplayTitle()
Get the title to be used for display.
Definition: ParserOutput.php:1055
ParserOutput\$mFlags
array $mFlags
Generic flags.
Definition: ParserOutput.php:237
ParserOutput\getIndicators
getIndicators()
Definition: ParserOutput.php:590
ParserOutput\setLanguageLinks
setLanguageLinks( $ll)
Definition: ParserOutput.php:728
ParserOutput\getSpeculativePageIdUsed
getSpeculativePageIdUsed()
Definition: ParserOutput.php:523
wfDebug
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
Definition: GlobalFunctions.php:894
OutputPage
This is one of the Core classes and should be read at least once by any new developers.
Definition: OutputPage.php:50
ParserOutput\getLanguageLinks
& getLanguageLinks()
Definition: ParserOutput.php:570
ParserOutput\$mPreventClickjacking
bool $mPreventClickjacking
Whether to emit X-Frame-Options: DENY.
Definition: ParserOutput.php:217
ParserOutput\getLinksSpecial
& getLinksSpecial()
Definition: ParserOutput.php:610
ParserOutput\newFromJsonArray
static newFromJsonArray(JsonUnserializer $unserializer, array $json)
Creates a new instance of the class and initialized it from the $json array.
Definition: ParserOutput.php:1734
ParserOutput\getExternalLinks
& getExternalLinks()
Definition: ParserOutput.php:630
ParserOutput\getTemplateIds
& getTemplateIds()
Definition: ParserOutput.php:618
OutputPage\getPreventClickjacking
getPreventClickjacking()
Get the prevent-clickjacking flag.
Definition: OutputPage.php:2374
ParserOutput\getTOCHTML
getTOCHTML()
Definition: ParserOutput.php:674
ParserOutput\addOutputHook
addOutputHook( $hook, $data=false)
Definition: ParserOutput.php:788
ParserOutput\getExtraCSPScriptSrcs
getExtraCSPScriptSrcs()
Get extra Content-Security-Policy 'script-src' directives.
Definition: ParserOutput.php:711
ParserOutput\SLOW_AR_TTL
const SLOW_AR_TTL
Definition: ParserOutput.php:273
ParserOutput\getTitleText
getTitleText()
Definition: ParserOutput.php:594
ParserOutput\clearWrapperDivClass
clearWrapperDivClass()
Clears the CSS class to use for the wrapping div, effectively disabling the wrapper div until addWrap...
Definition: ParserOutput.php:480
Title\makeTitleSafe
static makeTitleSafe( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:677
ParserOutput\setProperty
setProperty( $name, $value)
Set a property to be stored in the page_props database table.
Definition: ParserOutput.php:1153
ParserOutput\getNewSection
getNewSection()
Definition: ParserOutput.php:804
$content
$content
Definition: router.php:76
ParserOutput\setExtensionData
setExtensionData( $key, $value)
Attaches arbitrary data to this ParserObject.
Definition: ParserOutput.php:1223
ParserOutput\$mExtensionData
array $mExtensionData
extra data used by extensions.
Definition: ParserOutput.php:199
$s
foreach( $mmfl['setupFiles'] as $fileName) if( $queue) if(empty( $mmfl['quiet'])) $s
Definition: mergeMessageFileList.php:206
NS_MEDIA
const NS_MEDIA
Definition: Defines.php:52
OutputPage\getHeadItemsArray
getHeadItemsArray()
Get an array of head items.
Definition: OutputPage.php:655
ParserOutput\getOutputHooks
getOutputHooks()
Definition: ParserOutput.php:662
ParserOutput\detectAndDecodeBinary
static detectAndDecodeBinary(array $properties)
Finds any associative arrays that represent encoded binary strings, and replaces them with the decode...
Definition: ParserOutput.php:1826
ParserOutput\$speculativePageIdUsed
int null $speculativePageIdUsed
Assumed page ID for {{PAGEID}} if no revision is set.
Definition: ParserOutput.php:249
ParserOutput\getHideNewSection
getHideNewSection()
Definition: ParserOutput.php:800
$wgServer
$wgServer
URL of the server.
Definition: DefaultSettings.php:110
Hooks\runner
static runner()
Get a HookRunner instance for calling hooks using the new interfaces.
Definition: Hooks.php:173
ParserOutput\detectAndEncodeBinary
static detectAndEncodeBinary(array $properties)
Finds any non-utf8 strings in the given array and replaces them with an associative array that wraps ...
Definition: ParserOutput.php:1802
ParserOutput\$revisionUsedSha1Base36
string null $revisionUsedSha1Base36
SHA-1 base 36 hash of any self-transclusion.
Definition: ParserOutput.php:254
ParserOutput\$mExtraStyleSrcs
array $mExtraStyleSrcs
Extra style-src for CSP.
Definition: ParserOutput.php:232
ParserOutput\getRevisionUsedSha1Base36
getRevisionUsedSha1Base36()
Definition: ParserOutput.php:566
ParserOutput\$mExtraScriptSrcs
array $mExtraScriptSrcs
Extra script-src for CSP.
Definition: ParserOutput.php:222
ParserOutput\getNoGallery
getNoGallery()
Definition: ParserOutput.php:638
ParserOutput\addWarning
addWarning( $s)
Definition: ParserOutput.php:784
MediaWiki\Json\JsonUnserializer\unserializeArray
unserializeArray(array $array)
Helper to unserialize an array of JsonUnserializable instances or simple types.
RequestContext\getMain
static getMain()
Get the RequestContext object associated with the main request.
Definition: RequestContext.php:484
ParserOutput\$mTemplateIds
array $mTemplateIds
2-D map of NS/DBK to rev ID for the template references.
Definition: ParserOutput.php:97
ParserOutput\getTemplates
& getTemplates()
Definition: ParserOutput.php:614
ParserOutput\setSections
setSections( $toc)
Definition: ParserOutput.php:740
ParserOutput\setCategoryLinks
setCategoryLinks( $cl)
Definition: ParserOutput.php:732
ParserOutput\$mParseStartTime
array $mParseStartTime
Timestamps for getTimeSinceStart().
Definition: ParserOutput.php:212
ParserOutput\getRevisionTimestampUsed
getRevisionTimestampUsed()
Definition: ParserOutput.php:539
ParserOutput\initFromJson
initFromJson(JsonUnserializer $unserializer, array $jsonData)
Initialize member fields from an array returned by jsonSerialize().
Definition: ParserOutput.php:1745
ParserOutput\getFileSearchOptions
& getFileSearchOptions()
Definition: ParserOutput.php:626
Title
Represents a title within MediaWiki.
Definition: Title.php:48
ParserOutput\$mTOCHTML
string $mTOCHTML
HTML of the TOC.
Definition: ParserOutput.php:179
ParserOutput\getProperty
getProperty( $name)
Definition: ParserOutput.php:1165
Parser\normalizeLinkUrl
static normalizeLinkUrl( $url)
Replace unusual escape codes in a URL with their equivalent characters.
Definition: Parser.php:2287
ParserOutput\$mExternalLinks
array $mExternalLinks
External link URLs, in the key only.
Definition: ParserOutput.php:112
ParserOutput\$mIndicators
array $mIndicators
Page status indicators, usually displayed in top-right corner.
Definition: ParserOutput.php:67
ParserOutput\FAST_AR_TTL
const FAST_AR_TTL
Definition: ParserOutput.php:272
ParserOutput\addJsConfigVars
addJsConfigVars( $keys, $value=null)
Add one or more variables to be set in mw.config in JavaScript.
Definition: ParserOutput.php:963
ParserOutput\getCategories
& getCategories()
Definition: ParserOutput.php:582
ParserOutput\hasText
hasText()
Returns true if text was passed to the constructor, or set using setText().
Definition: ParserOutput.php:304
ParserOutput\$mNoGallery
bool $mNoGallery
No gallery on category page? (NOGALLERY).
Definition: ParserOutput.php:133
ParserOutput\getRawText
getRawText()
Get the cacheable text with <mw:editsection> markers still in it.
Definition: ParserOutput.php:316
Html\rawElement
static rawElement( $element, $attribs=[], $contents='')
Returns an HTML element in a string.
Definition: Html.php:210
ParserOutput\useMinValue
static useMinValue( $a, $b)
Definition: ParserOutput.php:1644
ParserOutput\$mIndexPolicy
string $mIndexPolicy
'index' or 'noindex'? Any other value will result in no change.
Definition: ParserOutput.php:194
NS_CATEGORY
const NS_CATEGORY
Definition: Defines.php:78
$keys
$keys
Definition: testCompression.php:72
ParserOutput\getLimitReportData
getLimitReportData()
Definition: ParserOutput.php:685
CacheTime\updateCacheExpiry
updateCacheExpiry( $seconds)
Sets the number of seconds after which this object should expire.
Definition: CacheTime.php:125
ParserOutput\addTrackingCategory
addTrackingCategory( $msg, $title)
Add a tracking category, getting the title from a system message, or print a debug message if the tit...
Definition: ParserOutput.php:1004
$source
$source
Definition: mwdoc-filter.php:34
ParserOutput\useEachMinValue
static useEachMinValue(array $a, array $b)
Definition: ParserOutput.php:1629
ParserOutput\getExtensionData
getExtensionData( $key)
Gets extensions data previously attached to this ParserOutput using setExtensionData().
Definition: ParserOutput.php:1242
ParserOutput\addLanguageLink
addLanguageLink( $t)
Definition: ParserOutput.php:780
ParserOutput\$mInterwikiLinks
array $mInterwikiLinks
2-D map of prefix/DBK (in keys only) for the inline interwiki links in the document.
Definition: ParserOutput.php:118
Sanitizer\decodeTagAttributes
static decodeTagAttributes( $text)
Return an associative array of attribute names and values from a partial tag string.
Definition: Sanitizer.php:1005
ParserOutput\getText
getText( $options=[])
Get the output HTML.
Definition: ParserOutput.php:350
ParserOutput\setRevisionTimestampUsed
setRevisionTimestampUsed( $timestamp)
Definition: ParserOutput.php:531
$t
$t
Definition: testCompression.php:74
Sanitizer\decodeCharReferences
static decodeCharReferences( $text)
Decode any character references, numeric or named entities, in the text and return a UTF-8 string.
Definition: Sanitizer.php:1229
Html\element
static element( $element, $attribs=[], $contents='')
Identical to rawElement(), but HTML-escapes $contents (like Xml::element()).
Definition: Html.php:232
ParserOutput\$revisionTimestampUsed
int null $revisionTimestampUsed
Assumed rev timestamp for {{REVISIONTIMESTAMP}} if no revision is set.
Definition: ParserOutput.php:251
NS_FILE
const NS_FILE
Definition: Defines.php:70
ParserOutput\$mSections
array $mSections
Table of contents.
Definition: ParserOutput.php:169
ParserOutput\$mText
string null $mText
The output text.
Definition: ParserOutput.php:51
ParserOutput\addInterwikiLink
addInterwikiLink( $title)
Definition: ParserOutput.php:914
ParserOutput\setTOCHTML
setTOCHTML( $tochtml)
Definition: ParserOutput.php:748
ParserOutput\$mTitleText
string $mTitleText
Title text of the chosen language variant, as HTML.
Definition: ParserOutput.php:72
OutputPage\getJsConfigVars
getJsConfigVars()
Get the javascript config vars to include on this page.
Definition: OutputPage.php:3259
$wgRegisterInternalExternals
$wgRegisterInternalExternals
By default MediaWiki does not register links pointing to same server in externallinks dataset,...
Definition: DefaultSettings.php:5029
ParserOutput\getSections
getSections()
Definition: ParserOutput.php:598
ParserOutput\$mSpeculativeRevId
int null $mSpeculativeRevId
Assumed rev ID for {{REVISIONID}} if no revision is set.
Definition: ParserOutput.php:239
ParserOutput\hasDynamicContent
hasDynamicContent()
Definition: ParserOutput.php:1357
ParserOutput\addHeadItem
addHeadItem( $section, $tag=false)
Add some text to the "<head>".
Definition: ParserOutput.php:932
ParserOutput\setEnableOOUI
setEnableOOUI( $enable=false)
Enables OOUI, if true, in any OutputPage instance this ParserOutput object is added to.
Definition: ParserOutput.php:776
ParserOutput\$mCategories
array $mCategories
Map of category names to sort keys.
Definition: ParserOutput.php:62
ParserOutput\finalizeAdaptiveCacheExpiry
finalizeAdaptiveCacheExpiry()
Call this when parsing is done to lower the TTL based on low parse times.
Definition: ParserOutput.php:1423
ParserOutput\getSpeculativeRevIdUsed
getSpeculativeRevIdUsed()
Definition: ParserOutput.php:507
ParserOutput\getLinks
& getLinks()
Definition: ParserOutput.php:602
ParserOutput\setIndexPolicy
setIndexPolicy( $policy)
Definition: ParserOutput.php:744
ParserOutput\setNoGallery
setNoGallery( $value)
Definition: ParserOutput.php:634
ParserOutput\getAllFlags
getAllFlags()
Definition: ParserOutput.php:1084
ParserOutput\getIndexPolicy
getIndexPolicy()
Definition: ParserOutput.php:670
ParserOutput\getExtraCSPStyleSrcs
getExtraCSPStyleSrcs()
Get extra Content-Security-Policy 'style-src' directives.
Definition: ParserOutput.php:720
ParserOutput\getWrapperDivClass
getWrapperDivClass()
Returns the class (or classes) to be used with the wrapper div for this otuput.
Definition: ParserOutput.php:491
ParserOutput\preventClickjacking
preventClickjacking( $flag=null)
Get or set the prevent-clickjacking flag.
Definition: ParserOutput.php:1368
ParserOutput\getWarnings
getWarnings()
Definition: ParserOutput.php:666