MediaWiki  master
OutputPage.php
Go to the documentation of this file.
1 <?php
23 use MediaWiki\HookContainer\ProtectedHookAccessorTrait;
31 use Wikimedia\RelPath;
32 use Wikimedia\WrappedString;
33 use Wikimedia\WrappedStringList;
34 
50 class OutputPage extends ContextSource {
51  use ProtectedHookAccessorTrait;
52 
54  protected $mMetatags = [];
55 
57  protected $mLinktags = [];
58 
60  protected $mCanonicalUrl = false;
61 
65  private $mPageTitle = '';
66 
74  private $displayTitle;
75 
77  private $cacheIsFinal = false;
78 
83  public $mBodytext = '';
84 
86  private $mHTMLtitle = '';
87 
92  private $mIsArticle = false;
93 
95  private $mIsArticleRelated = true;
96 
98  private $mHasCopyright = false;
99 
104  private $mPrintable = false;
105 
109  private $mSections = [];
110 
115  private $mSubtitle = [];
116 
118  public $mRedirect = '';
119 
121  protected $mStatusCode;
122 
127  protected $mLastModified = '';
128 
130  protected $mCategoryLinks = [];
131 
133  protected $mCategories = [
134  'hidden' => [],
135  'normal' => [],
136  ];
137 
139  protected $mIndicators = [];
140 
142  private $mLanguageLinks = [];
143 
150  private $mScripts = '';
151 
153  protected $mInlineStyles = '';
154 
159  public $mPageLinkTitle = '';
160 
165  protected $mAdditionalHtmlClasses = [];
166 
168  protected $mHeadItems = [];
169 
171  protected $mAdditionalBodyClasses = [];
172 
174  protected $mModules = [];
175 
177  protected $mModuleStyles = [];
178 
180  protected $mResourceLoader;
181 
183  private $rlClient;
184 
187 
190 
192  protected $mJsConfigVars = [];
193 
195  protected $mTemplateIds = [];
196 
198  protected $mImageTimeKeys = [];
199 
201  public $mRedirectCode = '';
202 
203  protected $mFeedLinksAppendQuery = null;
204 
210  protected $mAllowedModules = [
211  ResourceLoaderModule::TYPE_COMBINED => ResourceLoaderModule::ORIGIN_ALL,
212  ];
213 
215  protected $mDoNothing = false;
216 
217  // Parser related.
218 
220  protected $mContainsNewMagic = 0;
221 
226  protected $mParserOptions = null;
227 
233  private $mFeedLinks = [];
234 
236  protected $mEnableClientCache = true;
237 
239  private $mArticleBodyOnly = false;
240 
242  protected $mNewSectionLink = false;
243 
245  protected $mHideNewSectionLink = false;
246 
252  public $mNoGallery = false;
253 
255  protected $mCdnMaxage = 0;
257  protected $mCdnMaxageLimit = INF;
258 
264  protected $mPreventClickjacking = true;
265 
267  private $mRevisionId = null;
268 
270  private $mRevisionTimestamp = null;
271 
273  protected $mFileVersion = null;
274 
283  protected $styles = [];
284 
285  private $mIndexPolicy = 'index';
286  private $mFollowPolicy = 'follow';
287 
293  private $mVaryHeader = [
294  'Accept-Encoding' => null,
295  ];
296 
303  private $mRedirectedFrom = null;
304 
308  private $mProperties = [];
309 
313  private $mTarget = null;
314 
318  private $mEnableTOC = false;
319 
323  private $copyrightUrl;
324 
326  private $limitReportJSData = [];
327 
329  private $contentOverrides = [];
330 
333 
337  private $mLinkHeader = [];
338 
342  private $CSP;
343 
347  private static $cacheVaryCookies = null;
348 
355  public function __construct( IContextSource $context ) {
356  $this->setContext( $context );
357  $this->CSP = new ContentSecurityPolicy(
358  $context->getRequest()->response(),
359  $context->getConfig(),
360  $this->getHookContainer()
361  );
362  }
363 
370  public function redirect( $url, $responsecode = '302' ) {
371  # Strip newlines as a paranoia check for header injection in PHP<5.1.2
372  $this->mRedirect = str_replace( "\n", '', $url );
373  $this->mRedirectCode = (string)$responsecode;
374  }
375 
381  public function getRedirect() {
382  return $this->mRedirect;
383  }
384 
393  public function setCopyrightUrl( $url ) {
394  $this->copyrightUrl = $url;
395  }
396 
402  public function setStatusCode( $statusCode ) {
403  $this->mStatusCode = $statusCode;
404  }
405 
413  public function addMeta( $name, $val ) {
414  $this->mMetatags[] = [ $name, $val ];
415  }
416 
423  public function getMetaTags() {
424  return $this->mMetatags;
425  }
426 
434  public function addLink( array $linkarr ) {
435  $this->mLinktags[] = $linkarr;
436  }
437 
444  public function getLinkTags() {
445  return $this->mLinktags;
446  }
447 
453  public function setCanonicalUrl( $url ) {
454  $this->mCanonicalUrl = $url;
455  }
456 
464  public function getCanonicalUrl() {
465  return $this->mCanonicalUrl;
466  }
467 
475  public function addScript( $script ) {
476  $this->mScripts .= $script;
477  }
478 
487  public function addScriptFile( $file, $unused = null ) {
488  $this->addScript( Html::linkedScript( $file, $this->CSP->getNonce() ) );
489  }
490 
497  public function addInlineScript( $script ) {
498  $this->mScripts .= Html::inlineScript( "\n$script\n", $this->CSP->getNonce() ) . "\n";
499  }
500 
509  protected function filterModules( array $modules, $position = null,
510  $type = ResourceLoaderModule::TYPE_COMBINED
511  ) {
512  $resourceLoader = $this->getResourceLoader();
513  $filteredModules = [];
514  foreach ( $modules as $val ) {
515  $module = $resourceLoader->getModule( $val );
516  if ( $module instanceof ResourceLoaderModule
517  && $module->getOrigin() <= $this->getAllowedModules( $type )
518  ) {
519  if ( $this->mTarget && !in_array( $this->mTarget, $module->getTargets() ) ) {
520  $this->warnModuleTargetFilter( $module->getName() );
521  continue;
522  }
523  $filteredModules[] = $val;
524  }
525  }
526  return $filteredModules;
527  }
528 
529  private function warnModuleTargetFilter( $moduleName ) {
530  static $warnings = [];
531  if ( isset( $warnings[$this->mTarget][$moduleName] ) ) {
532  return;
533  }
534  $warnings[$this->mTarget][$moduleName] = true;
535  $this->getResourceLoader()->getLogger()->debug(
536  'Module "{module}" not loadable on target "{target}".',
537  [
538  'module' => $moduleName,
539  'target' => $this->mTarget,
540  ]
541  );
542  }
543 
553  public function getModules( $filter = false, $position = null, $param = 'mModules',
554  $type = ResourceLoaderModule::TYPE_COMBINED
555  ) {
556  $modules = array_values( array_unique( $this->$param ) );
557  return $filter
558  ? $this->filterModules( $modules, null, $type )
559  : $modules;
560  }
561 
567  public function addModules( $modules ) {
568  $this->mModules = array_merge( $this->mModules, (array)$modules );
569  }
570 
578  public function getModuleStyles( $filter = false, $position = null ) {
579  return $this->getModules( $filter, null, 'mModuleStyles',
580  ResourceLoaderModule::TYPE_STYLES
581  );
582  }
583 
593  public function addModuleStyles( $modules ) {
594  $this->mModuleStyles = array_merge( $this->mModuleStyles, (array)$modules );
595  }
596 
600  public function getTarget() {
601  return $this->mTarget;
602  }
603 
609  public function setTarget( $target ) {
610  $this->mTarget = $target;
611  }
612 
620  public function addContentOverride( $target, Content $content ) {
621  if ( !$this->contentOverrides ) {
622  // Register a callback for $this->contentOverrides on the first call
623  $this->addContentOverrideCallback( function ( $target ) {
624  $key = $target->getNamespace() . ':' . $target->getDBkey();
625  return $this->contentOverrides[$key] ?? null;
626  } );
627  }
628 
629  $key = $target->getNamespace() . ':' . $target->getDBkey();
630  $this->contentOverrides[$key] = $content;
631  }
632 
640  public function addContentOverrideCallback( callable $callback ) {
641  $this->contentOverrideCallbacks[] = $callback;
642  }
643 
651  public function addHtmlClasses( $classes ) {
652  $this->mAdditionalHtmlClasses = array_merge( $this->mAdditionalHtmlClasses, (array)$classes );
653  }
654 
660  public function getHeadItemsArray() {
661  return $this->mHeadItems;
662  }
663 
676  public function addHeadItem( $name, $value ) {
677  $this->mHeadItems[$name] = $value;
678  }
679 
686  public function addHeadItems( $values ) {
687  $this->mHeadItems = array_merge( $this->mHeadItems, (array)$values );
688  }
689 
696  public function hasHeadItem( $name ) {
697  return isset( $this->mHeadItems[$name] );
698  }
699 
706  public function addBodyClasses( $classes ) {
707  $this->mAdditionalBodyClasses = array_merge( $this->mAdditionalBodyClasses, (array)$classes );
708  }
709 
717  public function setArticleBodyOnly( $only ) {
718  $this->mArticleBodyOnly = $only;
719  }
720 
726  public function getArticleBodyOnly() {
728  }
729 
737  public function setProperty( $name, $value ) {
738  $this->mProperties[$name] = $value;
739  }
740 
748  public function getProperty( $name ) {
749  return $this->mProperties[$name] ?? null;
750  }
751 
763  public function checkLastModified( $timestamp ) {
764  if ( !$timestamp || $timestamp == '19700101000000' ) {
765  wfDebug( __METHOD__ . ": CACHE DISABLED, NO TIMESTAMP" );
766  return false;
767  }
768  $config = $this->getConfig();
769  if ( !$config->get( 'CachePages' ) ) {
770  wfDebug( __METHOD__ . ": CACHE DISABLED" );
771  return false;
772  }
773 
774  $timestamp = wfTimestamp( TS_MW, $timestamp );
775  $modifiedTimes = [
776  'page' => $timestamp,
777  'user' => $this->getUser()->getTouched(),
778  'epoch' => $config->get( 'CacheEpoch' )
779  ];
780  if ( $config->get( 'UseCdn' ) ) {
781  $modifiedTimes['sepoch'] = wfTimestamp( TS_MW, $this->getCdnCacheEpoch(
782  time(),
783  $config->get( 'CdnMaxAge' )
784  ) );
785  }
786  $this->getHookRunner()->onOutputPageCheckLastModified( $modifiedTimes, $this );
787 
788  $maxModified = max( $modifiedTimes );
789  $this->mLastModified = wfTimestamp( TS_RFC2822, $maxModified );
790 
791  $clientHeader = $this->getRequest()->getHeader( 'If-Modified-Since' );
792  if ( $clientHeader === false ) {
793  wfDebug( __METHOD__ . ": client did not send If-Modified-Since header", 'private' );
794  return false;
795  }
796 
797  # IE sends sizes after the date like this:
798  # Wed, 20 Aug 2003 06:51:19 GMT; length=5202
799  # this breaks strtotime().
800  $clientHeader = preg_replace( '/;.*$/', '', $clientHeader );
801 
802  Wikimedia\suppressWarnings(); // E_STRICT system time warnings
803  $clientHeaderTime = strtotime( $clientHeader );
804  Wikimedia\restoreWarnings();
805  if ( !$clientHeaderTime ) {
806  wfDebug( __METHOD__
807  . ": unable to parse the client's If-Modified-Since header: $clientHeader" );
808  return false;
809  }
810  $clientHeaderTime = wfTimestamp( TS_MW, $clientHeaderTime );
811 
812  # Make debug info
813  $info = '';
814  foreach ( $modifiedTimes as $name => $value ) {
815  if ( $info !== '' ) {
816  $info .= ', ';
817  }
818  $info .= "$name=" . wfTimestamp( TS_ISO_8601, $value );
819  }
820 
821  wfDebug( __METHOD__ . ": client sent If-Modified-Since: " .
822  wfTimestamp( TS_ISO_8601, $clientHeaderTime ), 'private' );
823  wfDebug( __METHOD__ . ": effective Last-Modified: " .
824  wfTimestamp( TS_ISO_8601, $maxModified ), 'private' );
825  if ( $clientHeaderTime < $maxModified ) {
826  wfDebug( __METHOD__ . ": STALE, $info", 'private' );
827  return false;
828  }
829 
830  # Not modified
831  # Give a 304 Not Modified response code and disable body output
832  wfDebug( __METHOD__ . ": NOT MODIFIED, $info", 'private' );
833  ini_set( 'zlib.output_compression', 0 );
834  $this->getRequest()->response()->statusHeader( 304 );
835  $this->sendCacheControl();
836  $this->disable();
837 
838  // Don't output a compressed blob when using ob_gzhandler;
839  // it's technically against HTTP spec and seems to confuse
840  // Firefox when the response gets split over two packets.
841  wfResetOutputBuffers( false );
842 
843  return true;
844  }
845 
851  private function getCdnCacheEpoch( $reqTime, $maxAge ) {
852  // Ensure Last-Modified is never more than $wgCdnMaxAge in the past,
853  // because even if the wiki page content hasn't changed since, static
854  // resources may have changed (skin HTML, interface messages, urls, etc.)
855  // and must roll-over in a timely manner (T46570)
856  return $reqTime - $maxAge;
857  }
858 
865  public function setLastModified( $timestamp ) {
866  $this->mLastModified = wfTimestamp( TS_RFC2822, $timestamp );
867  }
868 
876  public function setRobotPolicy( $policy ) {
877  $policy = Article::formatRobotPolicy( $policy );
878 
879  if ( isset( $policy['index'] ) ) {
880  $this->setIndexPolicy( $policy['index'] );
881  }
882  if ( isset( $policy['follow'] ) ) {
883  $this->setFollowPolicy( $policy['follow'] );
884  }
885  }
886 
893  public function getRobotPolicy() {
894  return "{$this->mIndexPolicy},{$this->mFollowPolicy}";
895  }
896 
903  public function setIndexPolicy( $policy ) {
904  $policy = trim( $policy );
905  if ( in_array( $policy, [ 'index', 'noindex' ] ) ) {
906  $this->mIndexPolicy = $policy;
907  }
908  }
909 
915  public function getIndexPolicy() {
916  return $this->mIndexPolicy;
917  }
918 
925  public function setFollowPolicy( $policy ) {
926  $policy = trim( $policy );
927  if ( in_array( $policy, [ 'follow', 'nofollow' ] ) ) {
928  $this->mFollowPolicy = $policy;
929  }
930  }
931 
937  public function getFollowPolicy() {
938  return $this->mFollowPolicy;
939  }
940 
947  public function setHTMLTitle( $name ) {
948  if ( $name instanceof Message ) {
949  $this->mHTMLtitle = $name->setContext( $this->getContext() )->text();
950  } else {
951  $this->mHTMLtitle = $name;
952  }
953  }
954 
960  public function getHTMLTitle() {
961  return $this->mHTMLtitle;
962  }
963 
969  public function setRedirectedFrom( PageReference $t ) {
970  $this->mRedirectedFrom = $t;
971  }
972 
985  public function setPageTitle( $name ) {
986  if ( $name instanceof Message ) {
987  $name = $name->setContext( $this->getContext() )->text();
988  }
989 
990  # change "<script>foo&bar</script>" to "&lt;script&gt;foo&amp;bar&lt;/script&gt;"
991  # but leave "<i>foobar</i>" alone
993  $this->mPageTitle = $nameWithTags;
994 
995  # change "<i>foo&amp;bar</i>" to "foo&bar"
996  $this->setHTMLTitle(
997  $this->msg( 'pagetitle' )->plaintextParams( Sanitizer::stripAllTags( $nameWithTags ) )
998  ->inContentLanguage()
999  );
1000  }
1001 
1007  public function getPageTitle() {
1008  return $this->mPageTitle;
1009  }
1010 
1018  public function setDisplayTitle( $html ) {
1019  $this->displayTitle = $html;
1020  }
1021 
1030  public function getDisplayTitle() {
1031  $html = $this->displayTitle;
1032  if ( $html === null ) {
1033  return htmlspecialchars( $this->getTitle()->getPrefixedText(), ENT_NOQUOTES );
1034  }
1035 
1037  }
1038 
1045  public function getUnprefixedDisplayTitle() {
1046  $text = $this->getDisplayTitle();
1047  $nsPrefix = $this->getTitle()->getNsText() . ':';
1048  $prefix = preg_quote( $nsPrefix, '/' );
1049 
1050  return preg_replace( "/^$prefix/i", '', $text );
1051  }
1052 
1058  public function setTitle( PageReference $t ) {
1060 
1061  // @phan-suppress-next-next-line PhanUndeclaredMethod
1062  // @fixme Not all implementations of IContextSource have this method!
1063  $this->getContext()->setTitle( $t );
1064  }
1065 
1071  public function setSubtitle( $str ) {
1072  $this->clearSubtitle();
1073  $this->addSubtitle( $str );
1074  }
1075 
1081  public function addSubtitle( $str ) {
1082  if ( $str instanceof Message ) {
1083  $this->mSubtitle[] = $str->setContext( $this->getContext() )->parse();
1084  } else {
1085  $this->mSubtitle[] = $str;
1086  }
1087  }
1088 
1097  public static function buildBacklinkSubtitle( PageReference $page, $query = [] ) {
1098  if ( $page instanceof PageRecord || $page instanceof Title ) {
1099  // Callers will typically have a PageRecord
1100  if ( $page->isRedirect() ) {
1101  $query['redirect'] = 'no';
1102  }
1103  } elseif ( $page->getNamespace() !== NS_SPECIAL ) {
1104  // We don't know whether it's a redirect, so add the parameter, just to be sure.
1105  $query['redirect'] = 'no';
1106  }
1107 
1108  $target = TitleValue::castPageToLinkTarget( $page );
1109  $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
1110  return wfMessage( 'backlinksubtitle' )
1111  ->rawParams( $linkRenderer->makeLink( $target, null, [], $query ) );
1112  }
1113 
1120  public function addBacklinkSubtitle( PageReference $title, $query = [] ) {
1121  $this->addSubtitle( self::buildBacklinkSubtitle( $title, $query ) );
1122  }
1123 
1127  public function clearSubtitle() {
1128  $this->mSubtitle = [];
1129  }
1130 
1134  public function getSubtitle() {
1135  return implode( "<br />\n\t\t\t\t", $this->mSubtitle );
1136  }
1137 
1142  public function setPrintable() {
1143  $this->mPrintable = true;
1144  }
1145 
1151  public function isPrintable() {
1152  return $this->mPrintable;
1153  }
1154 
1158  public function disable() {
1159  $this->mDoNothing = true;
1160  }
1161 
1167  public function isDisabled() {
1168  return $this->mDoNothing;
1169  }
1170 
1176  public function showNewSectionLink() {
1177  return $this->mNewSectionLink;
1178  }
1179 
1185  public function forceHideNewSectionLink() {
1187  }
1188 
1197  public function setSyndicated( $show = true ) {
1198  if ( $show ) {
1199  $this->setFeedAppendQuery( false );
1200  } else {
1201  $this->mFeedLinks = [];
1202  }
1203  }
1204 
1211  protected function getAdvertisedFeedTypes() {
1212  if ( $this->getConfig()->get( 'Feed' ) ) {
1213  return $this->getConfig()->get( 'AdvertisedFeedTypes' );
1214  } else {
1215  return [];
1216  }
1217  }
1218 
1228  public function setFeedAppendQuery( $val ) {
1229  $this->mFeedLinks = [];
1230 
1231  foreach ( $this->getAdvertisedFeedTypes() as $type ) {
1232  $query = "feed=$type";
1233  if ( is_string( $val ) ) {
1234  $query .= '&' . $val;
1235  }
1236  $this->mFeedLinks[$type] = $this->getTitle()->getLocalURL( $query );
1237  }
1238  }
1239 
1246  public function addFeedLink( $format, $href ) {
1247  if ( in_array( $format, $this->getAdvertisedFeedTypes() ) ) {
1248  $this->mFeedLinks[$format] = $href;
1249  }
1250  }
1251 
1256  public function isSyndicated() {
1257  return count( $this->mFeedLinks ) > 0;
1258  }
1259 
1264  public function getSyndicationLinks() {
1265  return $this->mFeedLinks;
1266  }
1267 
1273  public function getFeedAppendQuery() {
1275  }
1276 
1284  public function setArticleFlag( $newVal ) {
1285  $this->mIsArticle = $newVal;
1286  if ( $newVal ) {
1287  $this->mIsArticleRelated = $newVal;
1288  }
1289  }
1290 
1297  public function isArticle() {
1298  return $this->mIsArticle;
1299  }
1300 
1307  public function setArticleRelated( $newVal ) {
1308  $this->mIsArticleRelated = $newVal;
1309  if ( !$newVal ) {
1310  $this->mIsArticle = false;
1311  }
1312  }
1313 
1319  public function isArticleRelated() {
1320  return $this->mIsArticleRelated;
1321  }
1322 
1328  public function setCopyright( $hasCopyright ) {
1329  $this->mHasCopyright = $hasCopyright;
1330  }
1331 
1341  public function showsCopyright() {
1342  return $this->isArticle() || $this->mHasCopyright;
1343  }
1344 
1351  public function addLanguageLinks( array $newLinkArray ) {
1352  $this->mLanguageLinks = array_merge( $this->mLanguageLinks, $newLinkArray );
1353  }
1354 
1361  public function setLanguageLinks( array $newLinkArray ) {
1362  $this->mLanguageLinks = $newLinkArray;
1363  }
1364 
1370  public function getLanguageLinks() {
1371  return $this->mLanguageLinks;
1372  }
1373 
1379  public function addCategoryLinks( array $categories ) {
1380  if ( !$categories ) {
1381  return;
1382  }
1383 
1384  $res = $this->addCategoryLinksToLBAndGetResult( $categories );
1385 
1386  # Set all the values to 'normal'.
1387  $categories = array_fill_keys( array_keys( $categories ), 'normal' );
1388 
1389  # Mark hidden categories
1390  foreach ( $res as $row ) {
1391  if ( isset( $row->pp_value ) ) {
1392  $categories[$row->page_title] = 'hidden';
1393  }
1394  }
1395 
1396  # Add the remaining categories to the skin
1397  if ( $this->getHookRunner()->onOutputPageMakeCategoryLinks(
1398  $this, $categories, $this->mCategoryLinks )
1399  ) {
1400  $services = MediaWikiServices::getInstance();
1401  $linkRenderer = $services->getLinkRenderer();
1402  $languageConverter = $services->getLanguageConverterFactory()
1403  ->getLanguageConverter( $services->getContentLanguage() );
1404  foreach ( $categories as $category => $type ) {
1405  // array keys will cast numeric category names to ints, so cast back to string
1406  $category = (string)$category;
1407  $origcategory = $category;
1408  $title = Title::makeTitleSafe( NS_CATEGORY, $category );
1409  if ( !$title ) {
1410  continue;
1411  }
1412  $languageConverter->findVariantLink( $category, $title, true );
1413 
1414  if ( $category != $origcategory && array_key_exists( $category, $categories ) ) {
1415  continue;
1416  }
1417  $text = $languageConverter->convertHtml( $title->getText() );
1418  $this->mCategories[$type][] = $title->getText();
1419  $this->mCategoryLinks[$type][] = $linkRenderer->makeLink( $title, new HtmlArmor( $text ) );
1420  }
1421  }
1422  }
1423 
1428  protected function addCategoryLinksToLBAndGetResult( array $categories ) {
1429  # Add the links to a LinkBatch
1430  $arr = [ NS_CATEGORY => $categories ];
1431  $linkBatchFactory = MediaWikiServices::getInstance()->getLinkBatchFactory();
1432  $lb = $linkBatchFactory->newLinkBatch();
1433  $lb->setArray( $arr );
1434 
1435  # Fetch existence plus the hiddencat property
1436  $dbr = wfGetDB( DB_REPLICA );
1437  $fields = array_merge(
1439  [ 'page_namespace', 'page_title', 'pp_value' ]
1440  );
1441 
1442  $res = $dbr->select( [ 'page', 'page_props' ],
1443  $fields,
1444  $lb->constructSet( 'page', $dbr ),
1445  __METHOD__,
1446  [],
1447  [ 'page_props' => [ 'LEFT JOIN', [
1448  'pp_propname' => 'hiddencat',
1449  'pp_page = page_id'
1450  ] ] ]
1451  );
1452 
1453  # Add the results to the link cache
1454  $linkCache = MediaWikiServices::getInstance()->getLinkCache();
1455  $lb->addResultToCache( $linkCache, $res );
1456 
1457  return $res;
1458  }
1459 
1465  public function setCategoryLinks( array $categories ) {
1466  $this->mCategoryLinks = [];
1467  $this->addCategoryLinks( $categories );
1468  }
1469 
1478  public function getCategoryLinks() {
1479  return $this->mCategoryLinks;
1480  }
1481 
1491  public function getCategories( $type = 'all' ) {
1492  if ( $type === 'all' ) {
1493  $allCategories = [];
1494  foreach ( $this->mCategories as $categories ) {
1495  $allCategories = array_merge( $allCategories, $categories );
1496  }
1497  return $allCategories;
1498  }
1499  if ( !isset( $this->mCategories[$type] ) ) {
1500  throw new InvalidArgumentException( 'Invalid category type given: ' . $type );
1501  }
1502  return $this->mCategories[$type];
1503  }
1504 
1514  public function setIndicators( array $indicators ) {
1515  $this->mIndicators = $indicators + $this->mIndicators;
1516  // Keep ordered by key
1517  ksort( $this->mIndicators );
1518  }
1519 
1528  public function getIndicators() {
1529  return $this->mIndicators;
1530  }
1531 
1540  public function addHelpLink( $to, $overrideBaseUrl = false ) {
1541  $this->addModuleStyles( 'mediawiki.helplink' );
1542  $text = $this->msg( 'helppage-top-gethelp' )->escaped();
1543 
1544  if ( $overrideBaseUrl ) {
1545  $helpUrl = $to;
1546  } else {
1547  $toUrlencoded = wfUrlencode( str_replace( ' ', '_', $to ) );
1548  $helpUrl = "https://www.mediawiki.org/wiki/Special:MyLanguage/$toUrlencoded";
1549  }
1550 
1551  $link = Html::rawElement(
1552  'a',
1553  [
1554  'href' => $helpUrl,
1555  'target' => '_blank',
1556  'class' => 'mw-helplink',
1557  ],
1558  $text
1559  );
1560 
1561  $this->setIndicators( [ 'mw-helplink' => $link ] );
1562  }
1563 
1572  public function disallowUserJs() {
1573  $this->reduceAllowedModules(
1574  ResourceLoaderModule::TYPE_SCRIPTS,
1575  ResourceLoaderModule::ORIGIN_CORE_INDIVIDUAL
1576  );
1577 
1578  // Site-wide styles are controlled by a config setting, see T73621
1579  // for background on why. User styles are never allowed.
1580  if ( $this->getConfig()->get( 'AllowSiteCSSOnRestrictedPages' ) ) {
1581  $styleOrigin = ResourceLoaderModule::ORIGIN_USER_SITEWIDE;
1582  } else {
1583  $styleOrigin = ResourceLoaderModule::ORIGIN_CORE_INDIVIDUAL;
1584  }
1585  $this->reduceAllowedModules(
1586  ResourceLoaderModule::TYPE_STYLES,
1587  $styleOrigin
1588  );
1589  }
1590 
1597  public function getAllowedModules( $type ) {
1598  if ( $type == ResourceLoaderModule::TYPE_COMBINED ) {
1599  return min( array_values( $this->mAllowedModules ) );
1600  } else {
1601  return $this->mAllowedModules[$type] ?? ResourceLoaderModule::ORIGIN_ALL;
1602  }
1603  }
1604 
1614  public function reduceAllowedModules( $type, $level ) {
1615  $this->mAllowedModules[$type] = min( $this->getAllowedModules( $type ), $level );
1616  }
1617 
1623  public function prependHTML( $text ) {
1624  $this->mBodytext = $text . $this->mBodytext;
1625  }
1626 
1632  public function addHTML( $text ) {
1633  $this->mBodytext .= $text;
1634  }
1635 
1645  public function addElement( $element, array $attribs = [], $contents = '' ) {
1646  $this->addHTML( Html::element( $element, $attribs, $contents ) );
1647  }
1648 
1652  public function clearHTML() {
1653  $this->mBodytext = '';
1654  }
1655 
1661  public function getHTML() {
1662  return $this->mBodytext;
1663  }
1664 
1671  public function parserOptions() {
1672  if ( !$this->mParserOptions ) {
1673  if ( !$this->getUser()->isSafeToLoad() ) {
1674  // Context user isn't unstubbable yet, so don't try to get a
1675  // ParserOptions for it. And don't cache this ParserOptions
1676  // either.
1678  $po->setAllowUnsafeRawHtml( false );
1679  $po->isBogus = true;
1680  return $po;
1681  }
1682 
1683  $this->mParserOptions = ParserOptions::newFromContext( $this->getContext() );
1684  $this->mParserOptions->setAllowUnsafeRawHtml( false );
1685  }
1686 
1687  return $this->mParserOptions;
1688  }
1689 
1697  public function setRevisionId( $revid ) {
1698  $val = $revid === null ? null : intval( $revid );
1699  return wfSetVar( $this->mRevisionId, $val, true );
1700  }
1701 
1707  public function getRevisionId() {
1708  return $this->mRevisionId;
1709  }
1710 
1717  public function isRevisionCurrent() {
1718  return $this->mRevisionId == 0 || $this->mRevisionId == $this->getTitle()->getLatestRevID();
1719  }
1720 
1728  public function setRevisionTimestamp( $timestamp ) {
1729  return wfSetVar( $this->mRevisionTimestamp, $timestamp, true );
1730  }
1731 
1738  public function getRevisionTimestamp() {
1740  }
1741 
1748  public function setFileVersion( $file ) {
1749  $val = null;
1750  if ( $file instanceof File && $file->exists() ) {
1751  $val = [ 'time' => $file->getTimestamp(), 'sha1' => $file->getSha1() ];
1752  }
1753  return wfSetVar( $this->mFileVersion, $val, true );
1754  }
1755 
1761  public function getFileVersion() {
1762  return $this->mFileVersion;
1763  }
1764 
1771  public function getTemplateIds() {
1772  return $this->mTemplateIds;
1773  }
1774 
1781  public function getFileSearchOptions() {
1782  return $this->mImageTimeKeys;
1783  }
1784 
1801  public function addWikiTextAsInterface(
1802  $text, $linestart = true, PageReference $title = null
1803  ) {
1804  if ( $title === null ) {
1805  $title = $this->getTitle();
1806  }
1807  if ( !$title ) {
1808  throw new MWException( 'Title is null' );
1809  }
1810  $this->addWikiTextTitleInternal( $text, $title, $linestart, /*interface*/true );
1811  }
1812 
1826  public function wrapWikiTextAsInterface(
1827  $wrapperClass, $text
1828  ) {
1829  $this->addWikiTextTitleInternal(
1830  $text, $this->getTitle(),
1831  /*linestart*/true, /*interface*/true,
1832  $wrapperClass
1833  );
1834  }
1835 
1851  public function addWikiTextAsContent(
1852  $text, $linestart = true, PageReference $title = null
1853  ) {
1854  if ( $title === null ) {
1855  $title = $this->getTitle();
1856  }
1857  if ( !$title ) {
1858  throw new MWException( 'Title is null' );
1859  }
1860  $this->addWikiTextTitleInternal( $text, $title, $linestart, /*interface*/false );
1861  }
1862 
1875  private function addWikiTextTitleInternal(
1876  $text, PageReference $title, $linestart, $interface, $wrapperClass = null
1877  ) {
1878  $parserOutput = $this->parseInternal(
1879  $text, $title, $linestart, $interface
1880  );
1881 
1882  $this->addParserOutput( $parserOutput, [
1883  'enableSectionEditLinks' => false,
1884  'wrapperDivClass' => $wrapperClass ?? '',
1885  ] );
1886  }
1887 
1893  public function setSections( array $sections ) {
1894  $this->mSections = $sections;
1895  }
1896 
1902  public function getSections(): array {
1903  return $this->mSections;
1904  }
1905 
1914  public function addParserOutputMetadata( ParserOutput $parserOutput ) {
1915  $this->mLanguageLinks =
1916  array_merge( $this->mLanguageLinks, $parserOutput->getLanguageLinks() );
1917  $this->addCategoryLinks( $parserOutput->getCategories() );
1918  $this->setIndicators( $parserOutput->getIndicators() );
1919 
1920  // FIXME: Best practice is for OutputPage to be an accumulator, as
1921  // addParserOutputMetadata() may be called multiple times, but the
1922  // following lines overwrite any previous data. These should
1923  // be migrated to an injection pattern.
1924  $this->mNewSectionLink = $parserOutput->getNewSection();
1925  $this->mHideNewSectionLink = $parserOutput->getHideNewSection();
1926  $this->mNoGallery = $parserOutput->getNoGallery();
1927 
1928  if ( !$parserOutput->isCacheable() ) {
1929  $this->enableClientCache( false );
1930  }
1931  $this->mHeadItems = array_merge( $this->mHeadItems, $parserOutput->getHeadItems() );
1932  $this->addModules( $parserOutput->getModules() );
1933  $this->addModuleStyles( $parserOutput->getModuleStyles() );
1934  $this->addJsConfigVars( $parserOutput->getJsConfigVars() );
1935  $this->mPreventClickjacking = $this->mPreventClickjacking
1936  || $parserOutput->getPreventClickjacking();
1937  $scriptSrcs = $parserOutput->getExtraCSPScriptSrcs();
1938  foreach ( $scriptSrcs as $src ) {
1939  $this->getCSP()->addScriptSrc( $src );
1940  }
1941  $defaultSrcs = $parserOutput->getExtraCSPDefaultSrcs();
1942  foreach ( $defaultSrcs as $src ) {
1943  $this->getCSP()->addDefaultSrc( $src );
1944  }
1945  $styleSrcs = $parserOutput->getExtraCSPStyleSrcs();
1946  foreach ( $styleSrcs as $src ) {
1947  $this->getCSP()->addStyleSrc( $src );
1948  }
1949 
1950  // If $wgImagePreconnect is true, and if the output contains
1951  // images, give the user-agent a hint about foreign repos from
1952  // which those images may be served. See T123582.
1953  //
1954  // TODO: We don't have an easy way to know from which remote(s)
1955  // the image(s) will be served. For now, we only hint the first
1956  // valid one.
1957  if ( $this->getConfig()->get( 'ImagePreconnect' ) && count( $parserOutput->getImages() ) ) {
1958  $preconnect = [];
1959  $repoGroup = MediaWikiServices::getInstance()->getRepoGroup();
1960  $repoGroup->forEachForeignRepo( static function ( $repo ) use ( &$preconnect ) {
1961  $preconnect[] = wfParseUrl( $repo->getZoneUrl( 'thumb' ) )['host'];
1962  } );
1963  $preconnect[] = wfParseUrl( $repoGroup->getLocalRepo()->getZoneUrl( 'thumb' ) )['host'];
1964  foreach ( $preconnect as $host ) {
1965  if ( $host ) {
1966  $this->addLink( [ 'rel' => 'preconnect', 'href' => '//' . $host ] );
1967  break;
1968  }
1969  }
1970  }
1971 
1972  // Template versioning...
1973  foreach ( (array)$parserOutput->getTemplateIds() as $ns => $dbks ) {
1974  if ( isset( $this->mTemplateIds[$ns] ) ) {
1975  $this->mTemplateIds[$ns] = $dbks + $this->mTemplateIds[$ns];
1976  } else {
1977  $this->mTemplateIds[$ns] = $dbks;
1978  }
1979  }
1980  // File versioning...
1981  foreach ( (array)$parserOutput->getFileSearchOptions() as $dbk => $data ) {
1982  $this->mImageTimeKeys[$dbk] = $data;
1983  }
1984 
1985  // Hooks registered in the object
1986  $parserOutputHooks = $this->getConfig()->get( 'ParserOutputHooks' );
1987  foreach ( $parserOutput->getOutputHooks() as $hookInfo ) {
1988  list( $hookName, $data ) = $hookInfo;
1989  if ( isset( $parserOutputHooks[$hookName] ) ) {
1990  $parserOutputHooks[$hookName]( $this, $parserOutput, $data );
1991  }
1992  }
1993 
1994  // Enable OOUI if requested via ParserOutput
1995  if ( $parserOutput->getEnableOOUI() ) {
1996  $this->enableOOUI();
1997  }
1998 
1999  // Include parser limit report
2000  // FIXME: This should append, rather than overwrite, or else this
2001  // data should be injected into the OutputPage like is done for the
2002  // other page-level things (like OutputPage::setSections()).
2003  if ( !$this->limitReportJSData ) {
2004  $this->limitReportJSData = $parserOutput->getLimitReportJSData();
2005  }
2006 
2007  // Link flags are ignored for now, but may in the future be
2008  // used to mark individual language links.
2009  $linkFlags = [];
2010  $this->getHookRunner()->onLanguageLinks( $this->getTitle(), $this->mLanguageLinks, $linkFlags );
2011  $this->getHookRunner()->onOutputPageParserOutput( $this, $parserOutput );
2012 
2013  // This check must be after 'OutputPageParserOutput' runs in addParserOutputMetadata
2014  // so that extensions may modify ParserOutput to toggle TOC.
2015  // This cannot be moved to addParserOutputText because that is not
2016  // called by EditPage for Preview.
2017  if ( $parserOutput->getTOCHTML() ) {
2018  $this->mEnableTOC = true;
2019  }
2020  }
2021 
2030  public function addParserOutputContent( ParserOutput $parserOutput, $poOptions = [] ) {
2031  $this->addParserOutputText( $parserOutput, $poOptions );
2032 
2033  $this->addModules( $parserOutput->getModules() );
2034  $this->addModuleStyles( $parserOutput->getModuleStyles() );
2035 
2036  $this->addJsConfigVars( $parserOutput->getJsConfigVars() );
2037  }
2038 
2046  public function addParserOutputText( ParserOutput $parserOutput, $poOptions = [] ) {
2047  $text = $parserOutput->getText( $poOptions );
2048  $this->getHookRunner()->onOutputPageBeforeHTML( $this, $text );
2049  $this->addHTML( $text );
2050  }
2051 
2058  public function addParserOutput( ParserOutput $parserOutput, $poOptions = [] ) {
2059  $this->addParserOutputMetadata( $parserOutput );
2060  $this->addParserOutputText( $parserOutput, $poOptions );
2061  }
2062 
2068  public function addTemplate( &$template ) {
2069  $this->addHTML( $template->getHTML() );
2070  }
2071 
2083  public function parseAsContent( $text, $linestart = true ) {
2084  return $this->parseInternal(
2085  $text, $this->getTitle(), $linestart, /*interface*/false
2086  )->getText( [
2087  'enableSectionEditLinks' => false,
2088  'wrapperDivClass' => ''
2089  ] );
2090  }
2091 
2104  public function parseAsInterface( $text, $linestart = true ) {
2105  return $this->parseInternal(
2106  $text, $this->getTitle(), $linestart, /*interface*/true
2107  )->getText( [
2108  'enableSectionEditLinks' => false,
2109  'wrapperDivClass' => ''
2110  ] );
2111  }
2112 
2127  public function parseInlineAsInterface( $text, $linestart = true ) {
2129  $this->parseAsInterface( $text, $linestart )
2130  );
2131  }
2132 
2145  private function parseInternal( $text, $title, $linestart, $interface ) {
2146  if ( $title === null ) {
2147  throw new MWException( 'Empty $mTitle in ' . __METHOD__ );
2148  }
2149 
2150  $popts = $this->parserOptions();
2151 
2152  $oldInterface = $popts->setInterfaceMessage( (bool)$interface );
2153 
2154  $parserOutput = MediaWikiServices::getInstance()->getParser()->getFreshParser()->parse(
2155  $text, $title, $popts,
2156  $linestart, true, $this->mRevisionId
2157  );
2158 
2159  $popts->setInterfaceMessage( $oldInterface );
2160 
2161  return $parserOutput;
2162  }
2163 
2169  public function setCdnMaxage( $maxage ) {
2170  $this->mCdnMaxage = min( $maxage, $this->mCdnMaxageLimit );
2171  }
2172 
2182  public function lowerCdnMaxage( $maxage ) {
2183  $this->mCdnMaxageLimit = min( $maxage, $this->mCdnMaxageLimit );
2184  $this->setCdnMaxage( $this->mCdnMaxage );
2185  }
2186 
2199  public function adaptCdnTTL( $mtime, $minTTL = 0, $maxTTL = 0 ) {
2200  $minTTL = $minTTL ?: IExpiringStore::TTL_MINUTE;
2201  $maxTTL = $maxTTL ?: $this->getConfig()->get( 'CdnMaxAge' );
2202 
2203  if ( $mtime === null || $mtime === false ) {
2204  return; // entity does not exist
2205  }
2206 
2207  $age = MWTimestamp::time() - (int)wfTimestamp( TS_UNIX, $mtime );
2208  $adaptiveTTL = max( 0.9 * $age, $minTTL );
2209  $adaptiveTTL = min( $adaptiveTTL, $maxTTL );
2210 
2211  $this->lowerCdnMaxage( (int)$adaptiveTTL );
2212  }
2213 
2221  public function enableClientCache( $state ) {
2222  return wfSetVar( $this->mEnableClientCache, $state );
2223  }
2224 
2231  public function couldBePublicCached() {
2232  if ( !$this->cacheIsFinal ) {
2233  // - The entry point handles its own caching and/or doesn't use OutputPage.
2234  // (such as load.php, AjaxDispatcher, or MediaWiki\Rest\EntryPoint).
2235  //
2236  // - Or, we haven't finished processing the main part of the request yet
2237  // (e.g. Action::show, SpecialPage::execute), and the state may still
2238  // change via enableClientCache().
2239  return true;
2240  }
2241  // e.g. various error-type pages disable all client caching
2243  }
2244 
2254  public function considerCacheSettingsFinal() {
2255  $this->cacheIsFinal = true;
2256  }
2257 
2263  public function getCacheVaryCookies() {
2264  if ( self::$cacheVaryCookies === null ) {
2265  $config = $this->getConfig();
2266  self::$cacheVaryCookies = array_values( array_unique( array_merge(
2267  SessionManager::singleton()->getVaryCookies(),
2268  [
2269  'forceHTTPS',
2270  ],
2271  $config->get( 'CacheVaryCookies' )
2272  ) ) );
2273  $this->getHookRunner()->onGetCacheVaryCookies( $this, self::$cacheVaryCookies );
2274  }
2275  return self::$cacheVaryCookies;
2276  }
2277 
2284  public function haveCacheVaryCookies() {
2285  $request = $this->getRequest();
2286  foreach ( $this->getCacheVaryCookies() as $cookieName ) {
2287  if ( $request->getCookie( $cookieName, '', '' ) !== '' ) {
2288  wfDebug( __METHOD__ . ": found $cookieName" );
2289  return true;
2290  }
2291  }
2292  wfDebug( __METHOD__ . ": no cache-varying cookies found" );
2293  return false;
2294  }
2295 
2305  public function addVaryHeader( $header, array $option = null ) {
2306  if ( $option !== null && count( $option ) > 0 ) {
2308  'The $option parameter to addVaryHeader is ignored since MediaWiki 1.34',
2309  '1.34' );
2310  }
2311  if ( !array_key_exists( $header, $this->mVaryHeader ) ) {
2312  $this->mVaryHeader[$header] = null;
2313  }
2314  }
2315 
2322  public function getVaryHeader() {
2323  // If we vary on cookies, let's make sure it's always included here too.
2324  if ( $this->getCacheVaryCookies() ) {
2325  $this->addVaryHeader( 'Cookie' );
2326  }
2327 
2328  foreach ( SessionManager::singleton()->getVaryHeaders() as $header => $options ) {
2329  $this->addVaryHeader( $header, $options );
2330  }
2331  return 'Vary: ' . implode( ', ', array_keys( $this->mVaryHeader ) );
2332  }
2333 
2339  public function addLinkHeader( $header ) {
2340  $this->mLinkHeader[] = $header;
2341  }
2342 
2348  public function getLinkHeader() {
2349  if ( !$this->mLinkHeader ) {
2350  return false;
2351  }
2352 
2353  return 'Link: ' . implode( ',', $this->mLinkHeader );
2354  }
2355 
2363  private function addAcceptLanguage() {
2364  $title = $this->getTitle();
2365  if ( !$title instanceof Title ) {
2366  return;
2367  }
2368 
2369  $languageConverter = MediaWikiServices::getInstance()->getLanguageConverterFactory()
2370  ->getLanguageConverter( $title->getPageLanguage() );
2371  if ( !$this->getRequest()->getCheck( 'variant' ) && $languageConverter->hasVariants() ) {
2372  $this->addVaryHeader( 'Accept-Language' );
2373  }
2374  }
2375 
2387  public function preventClickjacking( $enable = true ) {
2388  $this->mPreventClickjacking = $enable;
2389  }
2390 
2398  public function allowClickjacking() {
2399  $this->mPreventClickjacking = false;
2400  }
2401 
2420  public function setPreventClickjacking( bool $enable ) {
2421  $this->mPreventClickjacking = $enable;
2422  }
2423 
2430  public function getPreventClickjacking() {
2432  }
2433 
2441  public function getFrameOptions() {
2442  $config = $this->getConfig();
2443  if ( $config->get( 'BreakFrames' ) ) {
2444  return 'DENY';
2445  } elseif ( $this->mPreventClickjacking && $config->get( 'EditPageFrameOptions' ) ) {
2446  return $config->get( 'EditPageFrameOptions' );
2447  }
2448  return false;
2449  }
2450 
2457  private function getOriginTrials() {
2458  $config = $this->getConfig();
2459 
2460  return $config->get( 'OriginTrials' );
2461  }
2462 
2463  private function getReportTo() {
2464  $config = $this->getConfig();
2465 
2466  $expiry = $config->get( 'ReportToExpiry' );
2467 
2468  if ( !$expiry ) {
2469  return false;
2470  }
2471 
2472  $endpoints = $config->get( 'ReportToEndpoints' );
2473 
2474  if ( !$endpoints ) {
2475  return false;
2476  }
2477 
2478  $output = [ 'max_age' => $expiry, 'endpoints' => [] ];
2479 
2480  foreach ( $endpoints as $endpoint ) {
2481  $output['endpoints'][] = [ 'url' => $endpoint ];
2482  }
2483 
2484  return json_encode( $output, JSON_UNESCAPED_SLASHES );
2485  }
2486 
2487  private function getFeaturePolicyReportOnly() {
2488  $config = $this->getConfig();
2489 
2490  $features = $config->get( 'FeaturePolicyReportOnly' );
2491  return implode( ';', $features );
2492  }
2493 
2497  public function sendCacheControl() {
2498  $response = $this->getRequest()->response();
2499  $config = $this->getConfig();
2500 
2501  $this->addVaryHeader( 'Cookie' );
2502  $this->addAcceptLanguage();
2503 
2504  # don't serve compressed data to clients who can't handle it
2505  # maintain different caches for logged-in users and non-logged in ones
2506  $response->header( $this->getVaryHeader() );
2507 
2508  if ( $this->mEnableClientCache ) {
2509  if ( !$config->get( 'UseCdn' ) ) {
2510  $privateReason = 'config';
2511  } elseif ( $response->hasCookies() ) {
2512  $privateReason = 'set-cookies';
2513  // The client might use methods other than cookies to appear logged-in.
2514  // E.g. HTTP headers, or query parameter tokens, OAuth, etc.
2515  } elseif ( SessionManager::getGlobalSession()->isPersistent() ) {
2516  $privateReason = 'session';
2517  } elseif ( $this->isPrintable() ) {
2518  $privateReason = 'printable';
2519  } elseif ( $this->mCdnMaxage == 0 ) {
2520  $privateReason = 'no-maxage';
2521  } elseif ( $this->haveCacheVaryCookies() ) {
2522  $privateReason = 'cache-vary-cookies';
2523  } else {
2524  $privateReason = false;
2525  }
2526 
2527  if ( $privateReason === false ) {
2528  # We'll purge the proxy cache for anons explicitly, but require end user agents
2529  # to revalidate against the proxy on each visit.
2530  # IMPORTANT! The CDN needs to replace the Cache-Control header with
2531  # Cache-Control: s-maxage=0, must-revalidate, max-age=0
2532  wfDebug( __METHOD__ .
2533  ": local proxy caching; {$this->mLastModified} **", 'private' );
2534  # start with a shorter timeout for initial testing
2535  # header( "Cache-Control: s-maxage=2678400, must-revalidate, max-age=0" );
2536  $response->header( "Cache-Control: " .
2537  "s-maxage={$this->mCdnMaxage}, must-revalidate, max-age=0" );
2538  } else {
2539  # We do want clients to cache if they can, but they *must* check for updates
2540  # on revisiting the page.
2541  wfDebug( __METHOD__ . ": private caching ($privateReason); {$this->mLastModified} **", 'private' );
2542 
2543  $response->header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', 0 ) . ' GMT' );
2544  $response->header( "Cache-Control: private, must-revalidate, max-age=0" );
2545  }
2546  if ( $this->mLastModified ) {
2547  $response->header( "Last-Modified: {$this->mLastModified}" );
2548  }
2549  } else {
2550  wfDebug( __METHOD__ . ": no caching **", 'private' );
2551 
2552  # In general, the absence of a last modified header should be enough to prevent
2553  # the client from using its cache. We send a few other things just to make sure.
2554  $response->header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', 0 ) . ' GMT' );
2555  $response->header( 'Cache-Control: no-cache, no-store, max-age=0, must-revalidate' );
2556  $response->header( 'Pragma: no-cache' );
2557  }
2558  }
2559 
2565  public function loadSkinModules( $sk ) {
2566  foreach ( $sk->getDefaultModules() as $group => $modules ) {
2567  if ( $group === 'styles' ) {
2568  foreach ( $modules as $key => $moduleMembers ) {
2569  $this->addModuleStyles( $moduleMembers );
2570  }
2571  } else {
2572  $this->addModules( $modules );
2573  }
2574  }
2575  }
2576 
2587  public function output( $return = false ) {
2588  if ( $this->mDoNothing ) {
2589  return $return ? '' : null;
2590  }
2591 
2592  $response = $this->getRequest()->response();
2593  $config = $this->getConfig();
2594 
2595  if ( $this->mRedirect != '' ) {
2596  # Standards require redirect URLs to be absolute
2597  $this->mRedirect = wfExpandUrl( $this->mRedirect, PROTO_CURRENT );
2598 
2599  $redirect = $this->mRedirect;
2600  $code = $this->mRedirectCode;
2601  $content = '';
2602 
2603  if ( $this->getHookRunner()->onBeforePageRedirect( $this, $redirect, $code ) ) {
2604  if ( $code == '301' || $code == '303' ) {
2605  if ( !$config->get( 'DebugRedirects' ) ) {
2606  $response->statusHeader( $code );
2607  }
2608  $this->mLastModified = wfTimestamp( TS_RFC2822 );
2609  }
2610  if ( $config->get( 'VaryOnXFP' ) ) {
2611  $this->addVaryHeader( 'X-Forwarded-Proto' );
2612  }
2613  $this->sendCacheControl();
2614 
2615  $response->header( "Content-Type: text/html; charset=utf-8" );
2616  if ( $config->get( 'DebugRedirects' ) ) {
2617  $url = htmlspecialchars( $redirect );
2618  $content = "<!DOCTYPE html>\n<html>\n<head>\n"
2619  . "<title>Redirect</title>\n</head>\n<body>\n"
2620  . "<p>Location: <a href=\"$url\">$url</a></p>\n"
2621  . "</body>\n</html>\n";
2622 
2623  if ( !$return ) {
2624  print $content;
2625  }
2626 
2627  } else {
2628  $response->header( 'Location: ' . $redirect );
2629  }
2630  }
2631 
2632  return $return ? $content : null;
2633  } elseif ( $this->mStatusCode ) {
2634  $response->statusHeader( $this->mStatusCode );
2635  }
2636 
2637  # Buffer output; final headers may depend on later processing
2638  ob_start();
2639 
2640  $response->header( 'Content-type: ' . $config->get( 'MimeType' ) . '; charset=UTF-8' );
2641  $response->header( 'Content-language: ' .
2642  MediaWikiServices::getInstance()->getContentLanguage()->getHtmlCode() );
2643 
2644  $linkHeader = $this->getLinkHeader();
2645  if ( $linkHeader ) {
2646  $response->header( $linkHeader );
2647  }
2648 
2649  // Prevent framing, if requested
2650  $frameOptions = $this->getFrameOptions();
2651  if ( $frameOptions ) {
2652  $response->header( "X-Frame-Options: $frameOptions" );
2653  }
2654 
2655  $originTrials = $this->getOriginTrials();
2656  foreach ( $originTrials as $originTrial ) {
2657  $response->header( "Origin-Trial: $originTrial", false );
2658  }
2659 
2660  $reportTo = $this->getReportTo();
2661  if ( $reportTo ) {
2662  $response->header( "Report-To: $reportTo" );
2663  }
2664 
2665  $featurePolicyReportOnly = $this->getFeaturePolicyReportOnly();
2666  if ( $featurePolicyReportOnly ) {
2667  $response->header( "Feature-Policy-Report-Only: $featurePolicyReportOnly" );
2668  }
2669 
2670  if ( $this->mArticleBodyOnly ) {
2671  $this->CSP->sendHeaders();
2672  echo $this->mBodytext;
2673  } else {
2674  // Enable safe mode if requested (T152169)
2675  if ( $this->getRequest()->getBool( 'safemode' ) ) {
2676  $this->disallowUserJs();
2677  }
2678 
2679  $sk = $this->getSkin();
2680  $this->loadSkinModules( $sk );
2681 
2682  MWDebug::addModules( $this );
2683 
2684  // Hook that allows last minute changes to the output page, e.g.
2685  // adding of CSS or Javascript by extensions, adding CSP sources.
2686  $this->getHookRunner()->onBeforePageDisplay( $this, $sk );
2687 
2688  $this->CSP->sendHeaders();
2689 
2690  try {
2691  $sk->outputPage();
2692  } catch ( Exception $e ) {
2693  ob_end_clean(); // bug T129657
2694  throw $e;
2695  }
2696  }
2697 
2698  try {
2699  // This hook allows last minute changes to final overall output by modifying output buffer
2700  $this->getHookRunner()->onAfterFinalPageOutput( $this );
2701  } catch ( Exception $e ) {
2702  ob_end_clean(); // bug T129657
2703  throw $e;
2704  }
2705 
2706  $this->sendCacheControl();
2707 
2708  if ( $return ) {
2709  return ob_get_clean();
2710  } else {
2711  ob_end_flush();
2712  return null;
2713  }
2714  }
2715 
2726  public function prepareErrorPage( $pageTitle, $htmlTitle = false ) {
2727  $this->setPageTitle( $pageTitle );
2728  if ( $htmlTitle !== false ) {
2729  $this->setHTMLTitle( $htmlTitle );
2730  }
2731  $this->setRobotPolicy( 'noindex,nofollow' );
2732  $this->setArticleRelated( false );
2733  $this->enableClientCache( false );
2734  $this->mRedirect = '';
2735  $this->clearSubtitle();
2736  $this->clearHTML();
2737  }
2738 
2751  public function showErrorPage( $title, $msg, $params = [] ) {
2752  if ( !$title instanceof Message ) {
2753  $title = $this->msg( $title );
2754  }
2755 
2756  $this->prepareErrorPage( $title );
2757 
2758  if ( $msg instanceof Message ) {
2759  if ( $params !== [] ) {
2760  trigger_error( 'Argument ignored: $params. The message parameters argument '
2761  . 'is discarded when the $msg argument is a Message object instead of '
2762  . 'a string.', E_USER_NOTICE );
2763  }
2764  $this->addHTML( $msg->parseAsBlock() );
2765  } else {
2766  $this->addWikiMsgArray( $msg, $params );
2767  }
2768 
2769  $this->returnToMain();
2770  }
2771 
2778  public function showPermissionsErrorPage( array $errors, $action = null ) {
2779  $services = MediaWikiServices::getInstance();
2780  $permissionManager = $services->getPermissionManager();
2781  foreach ( $errors as $key => $error ) {
2782  $errors[$key] = (array)$error;
2783  }
2784 
2785  // For some action (read, edit, create and upload), display a "login to do this action"
2786  // error if all of the following conditions are met:
2787  // 1. the user is not logged in
2788  // 2. the only error is insufficient permissions (i.e. no block or something else)
2789  // 3. the error can be avoided simply by logging in
2790 
2791  if ( in_array( $action, [ 'read', 'edit', 'createpage', 'createtalk', 'upload' ] )
2792  && $this->getUser()->isAnon() && count( $errors ) == 1 && isset( $errors[0][0] )
2793  && ( $errors[0][0] == 'badaccess-groups' || $errors[0][0] == 'badaccess-group0' )
2794  && ( $permissionManager->groupHasPermission( 'user', $action )
2795  || $permissionManager->groupHasPermission( 'autoconfirmed', $action ) )
2796  ) {
2797  $displayReturnto = null;
2798 
2799  # Due to T34276, if a user does not have read permissions,
2800  # $this->getTitle() will just give Special:Badtitle, which is
2801  # not especially useful as a returnto parameter. Use the title
2802  # from the request instead, if there was one.
2803  $request = $this->getRequest();
2804  $returnto = Title::newFromText( $request->getText( 'title' ) );
2805  if ( $action == 'edit' ) {
2806  $msg = 'whitelistedittext';
2807  $displayReturnto = $returnto;
2808  } elseif ( $action == 'createpage' || $action == 'createtalk' ) {
2809  $msg = 'nocreatetext';
2810  } elseif ( $action == 'upload' ) {
2811  $msg = 'uploadnologintext';
2812  } else { # Read
2813  $msg = 'loginreqpagetext';
2814  $displayReturnto = Title::newMainPage();
2815  }
2816 
2817  $query = [];
2818 
2819  if ( $returnto ) {
2820  $query['returnto'] = $returnto->getPrefixedText();
2821 
2822  if ( !$request->wasPosted() ) {
2823  $returntoquery = $request->getValues();
2824  unset( $returntoquery['title'] );
2825  unset( $returntoquery['returnto'] );
2826  unset( $returntoquery['returntoquery'] );
2827  $query['returntoquery'] = wfArrayToCgi( $returntoquery );
2828  }
2829  }
2830 
2831  $title = SpecialPage::getTitleFor( 'Userlogin' );
2832  $linkRenderer = $services->getLinkRenderer();
2833  $loginUrl = $title->getLinkURL( $query, false, PROTO_RELATIVE );
2834  $loginLink = $linkRenderer->makeKnownLink(
2835  $title,
2836  $this->msg( 'loginreqlink' )->text(),
2837  [],
2838  $query
2839  );
2840 
2841  $this->prepareErrorPage( $this->msg( 'loginreqtitle' ) );
2842  $this->addHTML( $this->msg( $msg )->rawParams( $loginLink )->params( $loginUrl )->parse() );
2843 
2844  # Don't return to a page the user can't read otherwise
2845  # we'll end up in a pointless loop
2846  if ( $displayReturnto && $this->getAuthority()->probablyCan( 'read', $displayReturnto ) ) {
2847  $this->returnToMain( null, $displayReturnto );
2848  }
2849  } else {
2850  $this->prepareErrorPage( $this->msg( 'permissionserrors' ) );
2851  $this->addWikiTextAsInterface( $this->formatPermissionsErrorMessage( $errors, $action ) );
2852  }
2853  }
2854 
2861  public function versionRequired( $version ) {
2862  $this->prepareErrorPage( $this->msg( 'versionrequired', $version ) );
2863 
2864  $this->addWikiMsg( 'versionrequiredtext', $version );
2865  $this->returnToMain();
2866  }
2867 
2875  public function formatPermissionStatus( PermissionStatus $status, string $action = null ): string {
2876  if ( $status->isGood() ) {
2877  return '';
2878  }
2879  return $this->formatPermissionsErrorMessage( $status->toLegacyErrorArray(), $action );
2880  }
2881 
2890  public function formatPermissionsErrorMessage( array $errors, $action = null ) {
2891  if ( $action == null ) {
2892  $text = $this->msg( 'permissionserrorstext', count( $errors ) )->plain() . "\n\n";
2893  } else {
2894  $action_desc = $this->msg( "action-$action" )->plain();
2895  $text = $this->msg(
2896  'permissionserrorstext-withaction',
2897  count( $errors ),
2898  $action_desc
2899  )->plain() . "\n\n";
2900  }
2901 
2902  if ( count( $errors ) > 1 ) {
2903  $text .= '<ul class="permissions-errors">' . "\n";
2904 
2905  foreach ( $errors as $error ) {
2906  $text .= '<li>';
2907  $text .= $this->msg( ...$error )->plain();
2908  $text .= "</li>\n";
2909  }
2910  $text .= '</ul>';
2911  } else {
2912  $text .= "<div class=\"permissions-errors\">\n" .
2913  $this->msg( ...reset( $errors ) )->plain() .
2914  "\n</div>";
2915  }
2916 
2917  return $text;
2918  }
2919 
2929  public function showLagWarning( $lag ) {
2930  $config = $this->getConfig();
2931  if ( $lag >= $config->get( 'DatabaseReplicaLagWarning' ) ) {
2932  $lag = floor( $lag ); // floor to avoid nano seconds to display
2933  $message = $lag < $config->get( 'DatabaseReplicaLagCritical' )
2934  ? 'lag-warn-normal'
2935  : 'lag-warn-high';
2936  // For grep: mw-lag-warn-normal, mw-lag-warn-high
2937  $wrap = Html::rawElement( 'div', [ 'class' => "mw-{$message}" ], "\n$1\n" );
2938  $this->wrapWikiMsg( "$wrap\n", [ $message, $this->getLanguage()->formatNum( $lag ) ] );
2939  }
2940  }
2941 
2948  public function showFatalError( $message ) {
2949  $this->prepareErrorPage( $this->msg( 'internalerror' ) );
2950 
2951  $this->addHTML( $message );
2952  }
2953 
2962  public function addReturnTo( $title, array $query = [], $text = null, $options = [] ) {
2963  $linkRenderer = MediaWikiServices::getInstance()
2964  ->getLinkRendererFactory()->createFromLegacyOptions( $options );
2965  $link = $this->msg( 'returnto' )->rawParams(
2966  $linkRenderer->makeLink( $title, $text, [], $query ) )->escaped();
2967  $this->addHTML( "<p id=\"mw-returnto\">{$link}</p>\n" );
2968  }
2969 
2978  public function returnToMain( $unused = null, $returnto = null, $returntoquery = null ) {
2979  if ( $returnto == null ) {
2980  $returnto = $this->getRequest()->getText( 'returnto' );
2981  }
2982 
2983  if ( $returntoquery == null ) {
2984  $returntoquery = $this->getRequest()->getText( 'returntoquery' );
2985  }
2986 
2987  if ( $returnto === '' ) {
2988  $returnto = Title::newMainPage();
2989  }
2990 
2991  if ( is_object( $returnto ) ) {
2992  $linkTarget = TitleValue::castPageToLinkTarget( $returnto );
2993  } else {
2994  $linkTarget = Title::newFromText( $returnto );
2995  }
2996 
2997  // We don't want people to return to external interwiki. That
2998  // might potentially be used as part of a phishing scheme
2999  if ( !is_object( $linkTarget ) || $linkTarget->isExternal() ) {
3000  $linkTarget = Title::newMainPage();
3001  }
3002 
3003  $this->addReturnTo( $linkTarget, wfCgiToArray( $returntoquery ) );
3004  }
3005 
3006  private function getRlClientContext() {
3007  if ( !$this->rlClientContext ) {
3009  [], // modules; not relevant
3010  $this->getLanguage()->getCode(),
3011  $this->getSkin()->getSkinName(),
3012  $this->getUser()->isRegistered() ? $this->getUser()->getName() : null,
3013  null, // version; not relevant
3015  null, // only; not relevant
3016  $this->isPrintable()
3017  );
3018  $this->rlClientContext = new ResourceLoaderContext(
3019  $this->getResourceLoader(),
3020  new FauxRequest( $query )
3021  );
3022  if ( $this->contentOverrideCallbacks ) {
3023  $this->rlClientContext = new DerivativeResourceLoaderContext( $this->rlClientContext );
3024  $this->rlClientContext->setContentOverrideCallback( function ( $title ) {
3025  foreach ( $this->contentOverrideCallbacks as $callback ) {
3026  $content = $callback( $title );
3027  if ( $content !== null ) {
3028  $text = ( $content instanceof TextContent ) ? $content->getText() : '';
3029  if ( strpos( $text, '</script>' ) !== false ) {
3030  // Proactively replace this so that we can display a message
3031  // to the user, instead of letting it go to Html::inlineScript(),
3032  // where it would be considered a server-side issue.
3034  Xml::encodeJsCall( 'mw.log.error', [
3035  "Cannot preview $title due to script-closing tag."
3036  ] )
3037  );
3038  }
3039  return $content;
3040  }
3041  }
3042  return null;
3043  } );
3044  }
3045  }
3046  return $this->rlClientContext;
3047  }
3048 
3060  public function getRlClient() {
3061  if ( !$this->rlClient ) {
3062  $context = $this->getRlClientContext();
3063  $rl = $this->getResourceLoader();
3064  $this->addModules( [
3065  'user',
3066  'user.options',
3067  ] );
3068  $this->addModuleStyles( [
3069  'site.styles',
3070  'noscript',
3071  'user.styles',
3072  ] );
3073 
3074  // Prepare exempt modules for buildExemptModules()
3075  $exemptGroups = [ 'site' => [], 'noscript' => [], 'private' => [], 'user' => [] ];
3076  $exemptStates = [];
3077  $moduleStyles = $this->getModuleStyles( /*filter*/ true );
3078 
3079  // Preload getTitleInfo for isKnownEmpty calls below and in ResourceLoaderClientHtml
3080  // Separate user-specific batch for improved cache-hit ratio.
3081  $userBatch = [ 'user.styles', 'user' ];
3082  $siteBatch = array_diff( $moduleStyles, $userBatch );
3083  $dbr = wfGetDB( DB_REPLICA );
3086 
3087  // Filter out modules handled by buildExemptModules()
3088  $moduleStyles = array_filter( $moduleStyles,
3089  static function ( $name ) use ( $rl, $context, &$exemptGroups, &$exemptStates ) {
3090  $module = $rl->getModule( $name );
3091  if ( $module ) {
3092  $group = $module->getGroup();
3093  if ( isset( $exemptGroups[$group] ) ) {
3094  // The `noscript` module is excluded from the client
3095  // side registry, no need to set its state either.
3096  // But we still output it. See T291735
3097  if ( $group !== 'noscript' ) {
3098  $exemptStates[$name] = 'ready';
3099  }
3100  if ( !$module->isKnownEmpty( $context ) ) {
3101  // E.g. Don't output empty <styles>
3102  $exemptGroups[$group][] = $name;
3103  }
3104  return false;
3105  }
3106  }
3107  return true;
3108  }
3109  );
3110  $this->rlExemptStyleModules = $exemptGroups;
3111 
3113  'target' => $this->getTarget(),
3114  'nonce' => $this->CSP->getNonce(),
3115  // When 'safemode', disallowUserJs(), or reduceAllowedModules() is used
3116  // to only restrict modules to ORIGIN_CORE (ie. disallow ORIGIN_USER), the list of
3117  // modules enqueud for loading on this page is filtered to just those.
3118  // However, to make sure we also apply the restriction to dynamic dependencies and
3119  // lazy-loaded modules at run-time on the client-side, pass 'safemode' down to the
3120  // StartupModule so that the client-side registry will not contain any restricted
3121  // modules either. (T152169, T185303)
3122  'safemode' => ( $this->getAllowedModules( ResourceLoaderModule::TYPE_COMBINED )
3123  <= ResourceLoaderModule::ORIGIN_CORE_INDIVIDUAL
3124  ) ? '1' : null,
3125  ] );
3126  $rlClient->setConfig( $this->getJSVars() );
3127  $rlClient->setModules( $this->getModules( /*filter*/ true ) );
3128  $rlClient->setModuleStyles( $moduleStyles );
3129  $rlClient->setExemptStates( $exemptStates );
3130  $this->rlClient = $rlClient;
3131  }
3132  return $this->rlClient;
3133  }
3134 
3140  public function headElement( Skin $sk, $includeStyle = true ) {
3141  $config = $this->getConfig();
3142  $userdir = $this->getLanguage()->getDir();
3143  $services = MediaWikiServices::getInstance();
3144  $sitedir = $services->getContentLanguage()->getDir();
3145 
3146  $pieces = [];
3148  $this->getRlClient()->getDocumentAttributes(),
3150  ), [ 'class' => implode( ' ', $this->mAdditionalHtmlClasses ) ] );
3151  $pieces[] = Html::htmlHeader( $htmlAttribs );
3152  $pieces[] = Html::openElement( 'head' );
3153 
3154  if ( $this->getHTMLTitle() == '' ) {
3155  $this->setHTMLTitle( $this->msg( 'pagetitle', $this->getPageTitle() )->inContentLanguage() );
3156  }
3157 
3158  if ( !Html::isXmlMimeType( $config->get( 'MimeType' ) ) ) {
3159  // Add <meta charset="UTF-8">
3160  // This should be before <title> since it defines the charset used by
3161  // text including the text inside <title>.
3162  // The spec recommends defining XHTML5's charset using the XML declaration
3163  // instead of meta.
3164  // Our XML declaration is output by Html::htmlHeader.
3165  // https://html.spec.whatwg.org/multipage/semantics.html#attr-meta-http-equiv-content-type
3166  // https://html.spec.whatwg.org/multipage/semantics.html#charset
3167  $pieces[] = Html::element( 'meta', [ 'charset' => 'UTF-8' ] );
3168  }
3169 
3170  $pieces[] = Html::element( 'title', [], $this->getHTMLTitle() );
3171  $pieces[] = $this->getRlClient()->getHeadHtml( $htmlAttribs['class'] ?? null );
3172  $pieces[] = $this->buildExemptModules();
3173  $pieces = array_merge( $pieces, array_values( $this->getHeadLinksArray() ) );
3174  $pieces = array_merge( $pieces, array_values( $this->mHeadItems ) );
3175 
3176  $pieces[] = Html::closeElement( 'head' );
3177 
3178  $bodyClasses = $this->mAdditionalBodyClasses;
3179  $bodyClasses[] = 'mediawiki';
3180 
3181  # Classes for LTR/RTL directionality support
3182  $bodyClasses[] = $userdir;
3183  $bodyClasses[] = "sitedir-$sitedir";
3184 
3185  $underline = $services->getUserOptionsLookup()->getOption( $this->getUser(), 'underline' );
3186  if ( $underline < 2 ) {
3187  // The following classes can be used here:
3188  // * mw-underline-always
3189  // * mw-underline-never
3190  $bodyClasses[] = 'mw-underline-' . ( $underline ? 'always' : 'never' );
3191  }
3192 
3193  // Parser feature migration class
3194  // The idea is that this will eventually be removed, after the wikitext
3195  // which requires it is cleaned up.
3196  $bodyClasses[] = 'mw-hide-empty-elt';
3197 
3198  $bodyClasses[] = $sk->getPageClasses( $this->getTitle() );
3199  $bodyClasses[] = 'skin-' . Sanitizer::escapeClass( $sk->getSkinName() );
3200  $bodyClasses[] =
3201  'action-' . Sanitizer::escapeClass( Action::getActionName( $this->getContext() ) );
3202 
3203  if ( $sk->isResponsive() ) {
3204  $bodyClasses[] = 'skin--responsive';
3205  }
3206 
3207  $bodyAttrs = [];
3208  // While the implode() is not strictly needed, it's used for backwards compatibility
3209  // (this used to be built as a string and hooks likely still expect that).
3210  $bodyAttrs['class'] = implode( ' ', $bodyClasses );
3211 
3212  // Allow skins and extensions to add body attributes they need
3213  // Get ones from deprecated method
3214  if ( method_exists( $sk, 'addToBodyAttributes' ) ) {
3216  $sk->addToBodyAttributes( $this, $bodyAttrs );
3217  wfDeprecated( 'Skin::addToBodyAttributes method to add body attributes', '1.35' );
3218  }
3219 
3220  // Then run the hook, the recommended way of adding body attributes now
3221  $this->getHookRunner()->onOutputPageBodyAttributes( $this, $sk, $bodyAttrs );
3222 
3223  $pieces[] = Html::openElement( 'body', $bodyAttrs );
3224 
3225  return self::combineWrappedStrings( $pieces );
3226  }
3227 
3233  public function getResourceLoader() {
3234  if ( $this->mResourceLoader === null ) {
3235  // Lazy-initialise as needed
3236  $this->mResourceLoader = MediaWikiServices::getInstance()->getResourceLoader();
3237  }
3238  return $this->mResourceLoader;
3239  }
3240 
3249  public function makeResourceLoaderLink( $modules, $only, array $extraQuery = [] ) {
3250  // Apply 'target' and 'origin' filters
3251  $modules = $this->filterModules( (array)$modules, null, $only );
3252 
3254  $this->getRlClientContext(),
3255  $modules,
3256  $only,
3257  $extraQuery,
3258  $this->CSP->getNonce()
3259  );
3260  }
3261 
3268  protected static function combineWrappedStrings( array $chunks ) {
3269  // Filter out empty values
3270  $chunks = array_filter( $chunks, 'strlen' );
3271  return WrappedString::join( "\n", $chunks );
3272  }
3273 
3281  public function getBottomScripts( $extraHtml = '' ) {
3282  $chunks = [];
3283  $chunks[] = $this->getRlClient()->getBodyHtml();
3284 
3285  // Legacy non-ResourceLoader scripts
3286  $chunks[] = $this->mScripts;
3287 
3288  if ( $this->limitReportJSData ) {
3291  [ 'wgPageParseReport' => $this->limitReportJSData ]
3292  ),
3293  $this->CSP->getNonce()
3294  );
3295  }
3296  // This should be added last because the extra html comes from
3297  // SkinAfterBottomScripts hook.
3298  // TODO: Run the hook here directly and remove the parameter.
3299  $chunks[] = $extraHtml;
3300 
3301  return self::combineWrappedStrings( $chunks );
3302  }
3303 
3310  public function getJsConfigVars() {
3311  return $this->mJsConfigVars;
3312  }
3313 
3320  public function addJsConfigVars( $keys, $value = null ) {
3321  if ( is_array( $keys ) ) {
3322  foreach ( $keys as $key => $value ) {
3323  $this->mJsConfigVars[$key] = $value;
3324  }
3325  return;
3326  }
3327 
3328  $this->mJsConfigVars[$keys] = $value;
3329  }
3330 
3340  public function getJSVars() {
3341  $curRevisionId = 0;
3342  $articleId = 0;
3343  $canonicalSpecialPageName = false; # T23115
3344  $services = MediaWikiServices::getInstance();
3345 
3346  $title = $this->getTitle();
3347  $ns = $title->getNamespace();
3348  $nsInfo = $services->getNamespaceInfo();
3349  $canonicalNamespace = $nsInfo->exists( $ns )
3350  ? $nsInfo->getCanonicalName( $ns )
3351  : $title->getNsText();
3352 
3353  $sk = $this->getSkin();
3354  // Get the relevant title so that AJAX features can use the correct page name
3355  // when making API requests from certain special pages (T36972).
3356  $relevantTitle = $sk->getRelevantTitle();
3357 
3358  if ( $ns === NS_SPECIAL ) {
3359  list( $canonicalSpecialPageName, /*...*/ ) =
3360  $services->getSpecialPageFactory()->
3361  resolveAlias( $title->getDBkey() );
3362  } elseif ( $this->canUseWikiPage() ) {
3363  $wikiPage = $this->getWikiPage();
3364  $curRevisionId = $wikiPage->getLatest();
3365  $articleId = $wikiPage->getId();
3366  }
3367 
3368  $lang = $title->getPageViewLanguage();
3369 
3370  // Pre-process information
3371  $separatorTransTable = $lang->separatorTransformTable();
3372  $separatorTransTable = $separatorTransTable ?: [];
3373  $compactSeparatorTransTable = [
3374  implode( "\t", array_keys( $separatorTransTable ) ),
3375  implode( "\t", $separatorTransTable ),
3376  ];
3377  $digitTransTable = $lang->digitTransformTable();
3378  $digitTransTable = $digitTransTable ?: [];
3379  $compactDigitTransTable = [
3380  implode( "\t", array_keys( $digitTransTable ) ),
3381  implode( "\t", $digitTransTable ),
3382  ];
3383 
3384  $user = $this->getUser();
3385 
3386  // Internal variables for MediaWiki core
3387  $vars = [
3388  // @internal For mediawiki.page.ready
3389  'wgBreakFrames' => $this->getFrameOptions() == 'DENY',
3390 
3391  // @internal For jquery.tablesorter
3392  'wgSeparatorTransformTable' => $compactSeparatorTransTable,
3393  'wgDigitTransformTable' => $compactDigitTransTable,
3394  'wgDefaultDateFormat' => $lang->getDefaultDateFormat(),
3395  'wgMonthNames' => $lang->getMonthNamesArray(),
3396 
3397  // @internal For debugging purposes
3398  'wgRequestId' => WebRequest::getRequestId(),
3399 
3400  // @internal For mw.loader
3401  'wgCSPNonce' => $this->CSP->getNonce(),
3402  ];
3403 
3404  // Start of supported and stable config vars (for use by extensions/gadgets).
3405  $vars += [
3406  'wgCanonicalNamespace' => $canonicalNamespace,
3407  'wgCanonicalSpecialPageName' => $canonicalSpecialPageName,
3408  'wgNamespaceNumber' => $title->getNamespace(),
3409  'wgPageName' => $title->getPrefixedDBkey(),
3410  'wgTitle' => $title->getText(),
3411  'wgCurRevisionId' => $curRevisionId,
3412  'wgRevisionId' => (int)$this->getRevisionId(),
3413  'wgArticleId' => $articleId,
3414  'wgIsArticle' => $this->isArticle(),
3415  'wgIsRedirect' => $title->isRedirect(),
3416  'wgAction' => Action::getActionName( $this->getContext() ),
3417  'wgUserName' => $user->isAnon() ? null : $user->getName(),
3418  'wgUserGroups' => $services->getUserGroupManager()->getUserEffectiveGroups( $user ),
3419  'wgCategories' => $this->getCategories(),
3420  'wgPageContentLanguage' => $lang->getCode(),
3421  'wgPageContentModel' => $title->getContentModel(),
3422  'wgRelevantPageName' => $relevantTitle->getPrefixedDBkey(),
3423  'wgRelevantArticleId' => $relevantTitle->getArticleID(),
3424  ];
3425  if ( $user->isRegistered() ) {
3426  $vars['wgUserId'] = $user->getId();
3427  $vars['wgUserEditCount'] = $user->getEditCount();
3428  $userReg = $user->getRegistration();
3429  $vars['wgUserRegistration'] = $userReg ? (int)wfTimestamp( TS_UNIX, $userReg ) * 1000 : null;
3430  // Get the revision ID of the oldest new message on the user's talk
3431  // page. This can be used for constructing new message alerts on
3432  // the client side.
3433  $userNewMsgRevId = $this->getLastSeenUserTalkRevId();
3434  // Only occupy precious space in the <head> when it is non-null (T53640)
3435  // mw.config.get returns null by default.
3436  if ( $userNewMsgRevId ) {
3437  $vars['wgUserNewMsgRevisionId'] = $userNewMsgRevId;
3438  }
3439  }
3440  $languageConverter = $services->getLanguageConverterFactory()
3441  ->getLanguageConverter( $services->getContentLanguage() );
3442  if ( $languageConverter->hasVariants() ) {
3443  $vars['wgUserVariant'] = $languageConverter->getPreferredVariant();
3444  }
3445  // Same test as SkinTemplate
3446  $vars['wgIsProbablyEditable'] = $this->getAuthority()->probablyCan( 'edit', $title );
3447  $vars['wgRelevantPageIsProbablyEditable'] = $relevantTitle &&
3448  $this->getAuthority()->probablyCan( 'edit', $relevantTitle );
3449  foreach ( $title->getRestrictionTypes() as $type ) {
3450  // Following keys are set in $vars:
3451  // wgRestrictionCreate, wgRestrictionEdit, wgRestrictionMove, wgRestrictionUpload
3452  $vars['wgRestriction' . ucfirst( $type )] = $title->getRestrictions( $type );
3453  }
3454  if ( $title->isMainPage() ) {
3455  $vars['wgIsMainPage'] = true;
3456  }
3457 
3458  $relevantUser = $sk->getRelevantUser();
3459  if ( $relevantUser ) {
3460  $vars['wgRelevantUserName'] = $relevantUser->getName();
3461  }
3462  // End of stable config vars
3463 
3464  $titleFormatter = $services->getTitleFormatter();
3465 
3466  if ( $this->mRedirectedFrom ) {
3467  // @internal For skin JS
3468  $vars['wgRedirectedFrom'] = $titleFormatter->getPrefixedDBkey( $this->mRedirectedFrom );
3469  }
3470 
3471  // Allow extensions to add their custom variables to the mw.config map.
3472  // Use the 'ResourceLoaderGetConfigVars' hook if the variable is not
3473  // page-dependent but site-wide (without state).
3474  // Alternatively, you may want to use OutputPage->addJsConfigVars() instead.
3475  $this->getHookRunner()->onMakeGlobalVariablesScript( $vars, $this );
3476 
3477  // Merge in variables from addJsConfigVars last
3478  return array_merge( $vars, $this->getJsConfigVars() );
3479  }
3480 
3486  private function getLastSeenUserTalkRevId() {
3487  $services = MediaWikiServices::getInstance();
3488  $user = $this->getUser();
3489  $userHasNewMessages = $services
3490  ->getTalkPageNotificationManager()
3491  ->userHasNewMessages( $user );
3492  if ( !$userHasNewMessages ) {
3493  return null;
3494  }
3495 
3496  $timestamp = $services
3497  ->getTalkPageNotificationManager()
3498  ->getLatestSeenMessageTimestamp( $user );
3499 
3500  if ( !$timestamp ) {
3501  return null;
3502  }
3503 
3504  $revRecord = $services->getRevisionLookup()->getRevisionByTimestamp(
3505  $user->getTalkPage(),
3506  $timestamp
3507  );
3508 
3509  if ( !$revRecord ) {
3510  return null;
3511  }
3512 
3513  return $revRecord->getId();
3514  }
3515 
3525  public function userCanPreview() {
3526  $request = $this->getRequest();
3527  if (
3528  $request->getRawVal( 'action' ) !== 'submit' ||
3529  !$request->wasPosted()
3530  ) {
3531  return false;
3532  }
3533 
3534  $user = $this->getUser();
3535 
3536  if ( !$user->isRegistered() ) {
3537  // Anons have predictable edit tokens
3538  return false;
3539  }
3540  if ( !$user->matchEditToken( $request->getVal( 'wpEditToken' ) ) ) {
3541  return false;
3542  }
3543 
3544  $title = $this->getTitle();
3545  if ( !$this->getAuthority()->probablyCan( 'edit', $title ) ) {
3546  return false;
3547  }
3548 
3549  return true;
3550  }
3551 
3555  public function getHeadLinksArray() {
3556  $tags = [];
3557  $config = $this->getConfig();
3558 
3559  $canonicalUrl = $this->mCanonicalUrl;
3560 
3561  $tags['meta-generator'] = Html::element( 'meta', [
3562  'name' => 'generator',
3563  'content' => 'MediaWiki ' . MW_VERSION,
3564  ] );
3565 
3566  if ( $config->get( 'ReferrerPolicy' ) !== false ) {
3567  // Per https://w3c.github.io/webappsec-referrer-policy/#unknown-policy-values
3568  // fallbacks should come before the primary value so we need to reverse the array.
3569  foreach ( array_reverse( (array)$config->get( 'ReferrerPolicy' ) ) as $i => $policy ) {
3570  $tags["meta-referrer-$i"] = Html::element( 'meta', [
3571  'name' => 'referrer',
3572  'content' => $policy,
3573  ] );
3574  }
3575  }
3576 
3577  $p = "{$this->mIndexPolicy},{$this->mFollowPolicy}";
3578  if ( $p !== 'index,follow' ) {
3579  // http://www.robotstxt.org/wc/meta-user.html
3580  // Only show if it's different from the default robots policy
3581  $tags['meta-robots'] = Html::element( 'meta', [
3582  'name' => 'robots',
3583  'content' => $p,
3584  ] );
3585  }
3586 
3587  # Browser based phonenumber detection
3588  if ( $config->get( 'BrowserFormatDetection' ) !== false ) {
3589  $tags['meta-format-detection'] = Html::element( 'meta', [
3590  'name' => 'format-detection',
3591  'content' => $config->get( 'BrowserFormatDetection' ),
3592  ] );
3593  }
3594 
3595  foreach ( $this->mMetatags as $tag ) {
3596  if ( strncasecmp( $tag[0], 'http:', 5 ) === 0 ) {
3597  $a = 'http-equiv';
3598  $tag[0] = substr( $tag[0], 5 );
3599  } elseif ( strncasecmp( $tag[0], 'og:', 3 ) === 0 ) {
3600  $a = 'property';
3601  } else {
3602  $a = 'name';
3603  }
3604  $tagName = "meta-{$tag[0]}";
3605  if ( isset( $tags[$tagName] ) ) {
3606  $tagName .= $tag[1];
3607  }
3608  $tags[$tagName] = Html::element( 'meta',
3609  [
3610  $a => $tag[0],
3611  'content' => $tag[1]
3612  ]
3613  );
3614  }
3615 
3616  foreach ( $this->mLinktags as $tag ) {
3617  $tags[] = Html::element( 'link', $tag );
3618  }
3619 
3620  if ( $config->get( 'UniversalEditButton' ) && $this->isArticleRelated() ) {
3621  if ( $this->getAuthority()->probablyCan( 'edit', $this->getTitle() ) ) {
3622  $msg = $this->msg( 'edit' )->text();
3623  // Use mime type per https://phabricator.wikimedia.org/T21165#6946526
3624  $tags['universal-edit-button'] = Html::element( 'link', [
3625  'rel' => 'alternate',
3626  'type' => 'application/x-wiki',
3627  'title' => $msg,
3628  'href' => $this->getTitle()->getEditURL(),
3629  ] );
3630  }
3631  }
3632 
3633  # Generally the order of the favicon and apple-touch-icon links
3634  # should not matter, but Konqueror (3.5.9 at least) incorrectly
3635  # uses whichever one appears later in the HTML source. Make sure
3636  # apple-touch-icon is specified first to avoid this.
3637  if ( $config->get( 'AppleTouchIcon' ) !== false ) {
3638  $tags['apple-touch-icon'] = Html::element( 'link', [
3639  'rel' => 'apple-touch-icon',
3640  'href' => $config->get( 'AppleTouchIcon' )
3641  ] );
3642  }
3643 
3644  if ( $config->get( 'Favicon' ) !== false ) {
3645  $tags['favicon'] = Html::element( 'link', [
3646  'rel' => 'shortcut icon',
3647  'href' => $config->get( 'Favicon' )
3648  ] );
3649  }
3650 
3651  # OpenSearch description link
3652  $tags['opensearch'] = Html::element( 'link', [
3653  'rel' => 'search',
3654  'type' => 'application/opensearchdescription+xml',
3655  'href' => wfScript( 'opensearch_desc' ),
3656  'title' => $this->msg( 'opensearch-desc' )->inContentLanguage()->text(),
3657  ] );
3658 
3659  # Real Simple Discovery link, provides auto-discovery information
3660  # for the MediaWiki API (and potentially additional custom API
3661  # support such as WordPress or Twitter-compatible APIs for a
3662  # blogging extension, etc)
3663  $tags['rsd'] = Html::element( 'link', [
3664  'rel' => 'EditURI',
3665  'type' => 'application/rsd+xml',
3666  // Output a protocol-relative URL here if $wgServer is protocol-relative.
3667  // Whether RSD accepts relative or protocol-relative URLs is completely
3668  // undocumented, though.
3669  'href' => wfExpandUrl( wfAppendQuery(
3670  wfScript( 'api' ),
3671  [ 'action' => 'rsd' ] ),
3673  ),
3674  ] );
3675 
3676  # Language variants
3677  $services = MediaWikiServices::getInstance();
3678  $languageConverterFactory = $services->getLanguageConverterFactory();
3679  $disableLangConversion = $languageConverterFactory->isConversionDisabled();
3680  if ( !$disableLangConversion ) {
3681  $lang = $this->getTitle()->getPageLanguage();
3682  $languageConverter = $languageConverterFactory->getLanguageConverter( $lang );
3683  if ( $languageConverter->hasVariants() ) {
3684  $variants = $languageConverter->getVariants();
3685  foreach ( $variants as $variant ) {
3686  $tags["variant-$variant"] = Html::element( 'link', [
3687  'rel' => 'alternate',
3688  'hreflang' => LanguageCode::bcp47( $variant ),
3689  'href' => $this->getTitle()->getLocalURL(
3690  [ 'variant' => $variant ] )
3691  ]
3692  );
3693  }
3694  # x-default link per https://support.google.com/webmasters/answer/189077?hl=en
3695  $tags["variant-x-default"] = Html::element( 'link', [
3696  'rel' => 'alternate',
3697  'hreflang' => 'x-default',
3698  'href' => $this->getTitle()->getLocalURL() ] );
3699  }
3700  }
3701 
3702  # Copyright
3703  if ( $this->copyrightUrl !== null ) {
3704  $copyright = $this->copyrightUrl;
3705  } else {
3706  $copyright = '';
3707  if ( $config->get( 'RightsPage' ) ) {
3708  $copy = Title::newFromText( $config->get( 'RightsPage' ) );
3709 
3710  if ( $copy ) {
3711  $copyright = $copy->getLocalURL();
3712  }
3713  }
3714 
3715  if ( !$copyright && $config->get( 'RightsUrl' ) ) {
3716  $copyright = $config->get( 'RightsUrl' );
3717  }
3718  }
3719 
3720  if ( $copyright ) {
3721  $tags['copyright'] = Html::element( 'link', [
3722  'rel' => 'license',
3723  'href' => $copyright ]
3724  );
3725  }
3726 
3727  # Feeds
3728  if ( $config->get( 'Feed' ) ) {
3729  $feedLinks = [];
3730 
3731  foreach ( $this->getSyndicationLinks() as $format => $link ) {
3732  # Use the page name for the title. In principle, this could
3733  # lead to issues with having the same name for different feeds
3734  # corresponding to the same page, but we can't avoid that at
3735  # this low a level.
3736 
3737  $feedLinks[] = $this->feedLink(
3738  $format,
3739  $link,
3740  # Used messages: 'page-rss-feed' and 'page-atom-feed' (for an easier grep)
3741  $this->msg(
3742  "page-{$format}-feed", $this->getTitle()->getPrefixedText()
3743  )->text()
3744  );
3745  }
3746 
3747  # Recent changes feed should appear on every page (except recentchanges,
3748  # that would be redundant). Put it after the per-page feed to avoid
3749  # changing existing behavior. It's still available, probably via a
3750  # menu in your browser. Some sites might have a different feed they'd
3751  # like to promote instead of the RC feed (maybe like a "Recent New Articles"
3752  # or "Breaking news" one). For this, we see if $wgOverrideSiteFeed is defined.
3753  # If so, use it instead.
3754  $sitename = $config->get( 'Sitename' );
3755  $overrideSiteFeed = $config->get( 'OverrideSiteFeed' );
3756  if ( $overrideSiteFeed ) {
3757  foreach ( $overrideSiteFeed as $type => $feedUrl ) {
3758  // Note, this->feedLink escapes the url.
3759  $feedLinks[] = $this->feedLink(
3760  $type,
3761  $feedUrl,
3762  $this->msg( "site-{$type}-feed", $sitename )->text()
3763  );
3764  }
3765  } elseif ( !$this->getTitle()->isSpecial( 'Recentchanges' ) ) {
3766  $rctitle = SpecialPage::getTitleFor( 'Recentchanges' );
3767  foreach ( $this->getAdvertisedFeedTypes() as $format ) {
3768  $feedLinks[] = $this->feedLink(
3769  $format,
3770  $rctitle->getLocalURL( [ 'feed' => $format ] ),
3771  # For grep: 'site-rss-feed', 'site-atom-feed'
3772  $this->msg( "site-{$format}-feed", $sitename )->text()
3773  );
3774  }
3775  }
3776 
3777  # Allow extensions to change the list pf feeds. This hook is primarily for changing,
3778  # manipulating or removing existing feed tags. If you want to add new feeds, you should
3779  # use OutputPage::addFeedLink() instead.
3780  $this->getHookRunner()->onAfterBuildFeedLinks( $feedLinks );
3781 
3782  $tags += $feedLinks;
3783  }
3784 
3785  # Canonical URL
3786  if ( $config->get( 'EnableCanonicalServerLink' ) ) {
3787  if ( $canonicalUrl !== false ) {
3788  $canonicalUrl = wfExpandUrl( $canonicalUrl, PROTO_CANONICAL );
3789  } elseif ( $this->isArticleRelated() ) {
3790  // This affects all requests where "setArticleRelated" is true. This is
3791  // typically all requests that show content (query title, curid, oldid, diff),
3792  // and all wikipage actions (edit, delete, purge, info, history etc.).
3793  // It does not apply to File pages and Special pages.
3794  // 'history' and 'info' actions address page metadata rather than the page
3795  // content itself, so they may not be canonicalized to the view page url.
3796  // TODO: this ought to be better encapsulated in the Action class.
3797  $action = Action::getActionName( $this->getContext() );
3798  if ( in_array( $action, [ 'history', 'info' ] ) ) {
3799  $query = "action={$action}";
3800  } else {
3801  $query = '';
3802  }
3803  $canonicalUrl = $this->getTitle()->getCanonicalURL( $query );
3804  } else {
3805  $reqUrl = $this->getRequest()->getRequestURL();
3806  $canonicalUrl = wfExpandUrl( $reqUrl, PROTO_CANONICAL );
3807  }
3808  }
3809  if ( $canonicalUrl !== false ) {
3810  $tags[] = Html::element( 'link', [
3811  'rel' => 'canonical',
3812  'href' => $canonicalUrl
3813  ] );
3814  }
3815 
3816  // Allow extensions to add, remove and/or otherwise manipulate these links
3817  // If you want only to *add* <head> links, please use the addHeadItem()
3818  // (or addHeadItems() for multiple items) method instead.
3819  // This hook is provided as a last resort for extensions to modify these
3820  // links before the output is sent to client.
3821  $this->getHookRunner()->onOutputPageAfterGetHeadLinksArray( $tags, $this );
3822 
3823  return $tags;
3824  }
3825 
3834  private function feedLink( $type, $url, $text ) {
3835  return Html::element( 'link', [
3836  'rel' => 'alternate',
3837  'type' => "application/$type+xml",
3838  'title' => $text,
3839  'href' => $url ]
3840  );
3841  }
3842 
3852  public function addStyle( $style, $media = '', $condition = '', $dir = '' ) {
3853  $options = [];
3854  if ( $media ) {
3855  $options['media'] = $media;
3856  }
3857  if ( $condition ) {
3858  $options['condition'] = $condition;
3859  }
3860  if ( $dir ) {
3861  $options['dir'] = $dir;
3862  }
3863  $this->styles[$style] = $options;
3864  }
3865 
3873  public function addInlineStyle( $style_css, $flip = 'noflip' ) {
3874  if ( $flip === 'flip' && $this->getLanguage()->isRTL() ) {
3875  # If wanted, and the interface is right-to-left, flip the CSS
3876  $style_css = CSSJanus::transform( $style_css, true, false );
3877  }
3878  $this->mInlineStyles .= Html::inlineStyle( $style_css );
3879  }
3880 
3886  protected function buildExemptModules() {
3887  $chunks = [];
3888 
3889  // Requirements:
3890  // - Within modules provided by the software (core, skin, extensions),
3891  // styles from skin stylesheets should be overridden by styles
3892  // from modules dynamically loaded with JavaScript.
3893  // - Styles from site-specific, private, and user modules should override
3894  // both of the above.
3895  //
3896  // The effective order for stylesheets must thus be:
3897  // 1. Page style modules, formatted server-side by ResourceLoaderClientHtml.
3898  // 2. Dynamically-loaded styles, inserted client-side by mw.loader.
3899  // 3. Styles that are site-specific, private or from the user, formatted
3900  // server-side by this function.
3901  //
3902  // The 'ResourceLoaderDynamicStyles' marker helps JavaScript know where
3903  // point #2 is.
3904 
3905  // Add legacy styles added through addStyle()/addInlineStyle() here
3906  $chunks[] = implode( '', $this->buildCssLinksArray() ) . $this->mInlineStyles;
3907 
3908  // Things that go after the ResourceLoaderDynamicStyles marker
3909  $append = [];
3910  $separateReq = [ 'site.styles', 'user.styles' ];
3911  foreach ( $this->rlExemptStyleModules as $group => $moduleNames ) {
3912  if ( $moduleNames ) {
3913  $append[] = $this->makeResourceLoaderLink(
3914  array_diff( $moduleNames, $separateReq ),
3915  ResourceLoaderModule::TYPE_STYLES
3916  );
3917 
3918  foreach ( array_intersect( $moduleNames, $separateReq ) as $name ) {
3919  // These require their own dedicated request in order to support "@import"
3920  // syntax, which is incompatible with concatenation. (T147667, T37562)
3921  $append[] = $this->makeResourceLoaderLink( $name,
3922  ResourceLoaderModule::TYPE_STYLES
3923  );
3924  }
3925  }
3926  }
3927  if ( $append ) {
3928  $chunks[] = Html::element(
3929  'meta',
3930  [ 'name' => 'ResourceLoaderDynamicStyles', 'content' => '' ]
3931  );
3932  $chunks = array_merge( $chunks, $append );
3933  }
3934 
3935  return self::combineWrappedStrings( $chunks );
3936  }
3937 
3941  public function buildCssLinksArray() {
3942  $links = [];
3943 
3944  foreach ( $this->styles as $file => $options ) {
3945  $link = $this->styleLink( $file, $options );
3946  if ( $link ) {
3947  $links[$file] = $link;
3948  }
3949  }
3950  return $links;
3951  }
3952 
3960  protected function styleLink( $style, array $options ) {
3961  if ( isset( $options['dir'] ) && $this->getLanguage()->getDir() != $options['dir'] ) {
3962  return '';
3963  }
3964 
3965  if ( isset( $options['media'] ) ) {
3966  $media = self::transformCssMedia( $options['media'] );
3967  if ( $media === null ) {
3968  return '';
3969  }
3970  } else {
3971  $media = 'all';
3972  }
3973 
3974  if ( substr( $style, 0, 1 ) == '/' ||
3975  substr( $style, 0, 5 ) == 'http:' ||
3976  substr( $style, 0, 6 ) == 'https:' ) {
3977  $url = $style;
3978  } else {
3979  $config = $this->getConfig();
3980  // Append file hash as query parameter
3982  $config,
3983  $config->get( 'StylePath' ) . '/' . $style
3984  );
3985  }
3986 
3987  $link = Html::linkedStyle( $url, $media );
3988 
3989  if ( isset( $options['condition'] ) ) {
3990  $condition = htmlspecialchars( $options['condition'] );
3991  $link = "<!--[if $condition]>$link<![endif]-->";
3992  }
3993  return $link;
3994  }
3995 
4017  public static function transformResourcePath( Config $config, $path ) {
4018  global $IP;
4019 
4020  $localDir = $IP;
4021  $remotePathPrefix = $config->get( 'ResourceBasePath' );
4022  if ( $remotePathPrefix === '' ) {
4023  // The configured base path is required to be empty string for
4024  // wikis in the domain root
4025  $remotePath = '/';
4026  } else {
4027  $remotePath = $remotePathPrefix;
4028  }
4029  if ( strpos( $path, $remotePath ) !== 0 || substr( $path, 0, 2 ) === '//' ) {
4030  // - Path is outside wgResourceBasePath, ignore.
4031  // - Path is protocol-relative. Fixes T155310. Not supported by RelPath lib.
4032  return $path;
4033  }
4034  // For files in resources, extensions/ or skins/, ResourceBasePath is preferred here.
4035  // For other misc files in $IP, we'll fallback to that as well. There is, however, a fourth
4036  // supported dir/path pair in the configuration (wgUploadDirectory, wgUploadPath)
4037  // which is not expected to be in wgResourceBasePath on CDNs. (T155146)
4038  $uploadPath = $config->get( 'UploadPath' );
4039  if ( strpos( $path, $uploadPath ) === 0 ) {
4040  $localDir = $config->get( 'UploadDirectory' );
4041  $remotePathPrefix = $remotePath = $uploadPath;
4042  }
4043 
4044  $path = RelPath::getRelativePath( $path, $remotePath );
4045  return self::transformFilePath( $remotePathPrefix, $localDir, $path );
4046  }
4047 
4059  public static function transformFilePath( $remotePathPrefix, $localPath, $file ) {
4060  // This MUST match the equivalent logic in CSSMin::remapOne()
4061  $localFile = "$localPath/$file";
4062  $url = "$remotePathPrefix/$file";
4063  if ( file_exists( $localFile ) ) {
4064  $hash = md5_file( $localFile );
4065  if ( $hash === false ) {
4066  wfLogWarning( __METHOD__ . ": Failed to hash $localFile" );
4067  $hash = '';
4068  }
4069  $url .= '?' . substr( $hash, 0, 5 );
4070  }
4071  return $url;
4072  }
4073 
4081  public static function transformCssMedia( $media ) {
4082  global $wgRequest;
4083 
4084  if ( $wgRequest->getBool( 'printable' ) ) {
4085  // When browsing with printable=yes, apply "print" media styles
4086  // as if they are screen styles (no media, media="").
4087  if ( $media === 'print' ) {
4088  return '';
4089  }
4090 
4091  // https://www.w3.org/TR/css3-mediaqueries/#syntax
4092  //
4093  // This regex will not attempt to understand a comma-separated media_query_list
4094  // Example supported values for $media:
4095  //
4096  // 'screen', 'only screen', 'screen and (min-width: 982px)' ),
4097  //
4098  // Example NOT supported value for $media:
4099  //
4100  // '3d-glasses, screen, print and resolution > 90dpi'
4101  //
4102  // If it's a "printable" request, we disable all screen stylesheets.
4103  $screenMediaQueryRegex = '/^(?:only\s+)?screen\b/i';
4104  if ( preg_match( $screenMediaQueryRegex, $media ) === 1 ) {
4105  return null;
4106  }
4107  }
4108 
4109  return $media;
4110  }
4111 
4120  public function addWikiMsg( ...$args ) {
4121  $name = array_shift( $args );
4122  $this->addWikiMsgArray( $name, $args );
4123  }
4124 
4133  public function addWikiMsgArray( $name, $args ) {
4134  $this->addHTML( $this->msg( $name, $args )->parseAsBlock() );
4135  }
4136 
4163  public function wrapWikiMsg( $wrap, ...$msgSpecs ) {
4164  $s = $wrap;
4165  foreach ( $msgSpecs as $n => $spec ) {
4166  if ( is_array( $spec ) ) {
4167  $args = $spec;
4168  $name = array_shift( $args );
4169  } else {
4170  $args = [];
4171  $name = $spec;
4172  }
4173  $s = str_replace( '$' . ( $n + 1 ), $this->msg( $name, $args )->plain(), $s );
4174  }
4175  $this->addWikiTextAsInterface( $s );
4176  }
4177 
4183  public function isTOCEnabled() {
4184  return $this->mEnableTOC;
4185  }
4186 
4194  public static function setupOOUI( $skinName = 'default', $dir = 'ltr' ) {
4196  $theme = $themes[$skinName] ?? $themes['default'];
4197  // For example, 'OOUI\WikimediaUITheme'.
4198  $themeClass = "OOUI\\{$theme}Theme";
4199  OOUI\Theme::setSingleton( new $themeClass() );
4200  OOUI\Element::setDefaultDir( $dir );
4201  }
4202 
4209  public function enableOOUI() {
4211  strtolower( $this->getSkin()->getSkinName() ),
4212  $this->getLanguage()->getDir()
4213  );
4214  $this->addModuleStyles( [
4215  'oojs-ui-core.styles',
4216  'oojs-ui.styles.indicators',
4217  'mediawiki.widgets.styles',
4218  'oojs-ui-core.icons',
4219  ] );
4220  }
4221 
4232  public function getCSPNonce() {
4233  return $this->CSP->getNonce();
4234  }
4235 
4242  public function getCSP() {
4243  return $this->CSP;
4244  }
4245 
4255  public function tailElement( $skin ) {
4256  // T257704: Temporarily run skin hook here pending
4257  // creation dedicated outputpage hook for this
4258  $extraHtml = '';
4259  $this->getHookRunner()->onSkinAfterBottomScripts( $skin, $extraHtml );
4260 
4261  $tail = [
4262  MWDebug::getDebugHTML( $skin ),
4263  $this->getBottomScripts( $extraHtml ),
4264  wfReportTime( $this->getCSP()->getNonce() ),
4266  . Html::closeElement( 'body' )
4267  . Html::closeElement( 'html' )
4268  ];
4269 
4270  return WrappedStringList::join( "\n", $tail );
4271  }
4272 }
Action\getActionName
static getActionName(IContextSource $context)
Get the action that will be executed, not necessarily the one passed passed through the "action" requ...
Definition: Action.php:108
OutputPage\preventClickjacking
preventClickjacking( $enable=true)
Set a flag which will cause an X-Frame-Options header appropriate for edit pages to be sent.
Definition: OutputPage.php:2387
OutputPage\output
output( $return=false)
Finally, all the text has been munged and accumulated into the object, let's actually output it:
Definition: OutputPage.php:2587
ParserOutput\getEnableOOUI
getEnableOOUI()
Definition: ParserOutput.php:766
OutputPage\$mCategoryLinks
string[][] $mCategoryLinks
Definition: OutputPage.php:130
OutputPage\$mLastModified
string $mLastModified
Used for sending cache control.
Definition: OutputPage.php:127
ParserOptions
Set options of the Parser.
Definition: ParserOptions.php:45
OutputPage\getCategoryLinks
getCategoryLinks()
Get the list of category links, in a 2-D array with the following format: $arr[$type][] = $link,...
Definition: OutputPage.php:1478
OutputPage\addMeta
addMeta( $name, $val)
Add a new "<meta>" tag To add an http-equiv meta tag, precede the name with "http:".
Definition: OutputPage.php:413
ContextSource\$context
IContextSource $context
Definition: ContextSource.php:39
ContextSource\getConfig
getConfig()
Definition: ContextSource.php:72
OutputPage\getTarget
getTarget()
Definition: OutputPage.php:600
ResourceLoaderContext
Context object that contains information about the state of a specific ResourceLoader web request.
Definition: ResourceLoaderContext.php:34
OutputPage\getSubtitle
getSubtitle()
Definition: OutputPage.php:1134
Page\PageRecord
Data record representing a page that is (or used to be, or could be) an editable page on a wiki.
Definition: PageRecord.php:25
OutputPage\parseAsInterface
parseAsInterface( $text, $linestart=true)
Parse wikitext in the user interface language and return the HTML.
Definition: OutputPage.php:2104
FauxRequest
WebRequest clone which takes values from a provided array.
Definition: FauxRequest.php:35
OutputPage\enableClientCache
enableClientCache( $state)
Use enableClientCache(false) to force it to send nocache headers.
Definition: OutputPage.php:2221
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:382
ContextSource\getContext
getContext()
Get the base IContextSource object.
Definition: ContextSource.php:47
wfResetOutputBuffers
wfResetOutputBuffers( $resetGzipEncoding=true)
Clear away any user-level output buffers, discarding contents.
Definition: GlobalFunctions.php:1604
OutputPage\getLanguageLinks
getLanguageLinks()
Get the list of language links.
Definition: OutputPage.php:1370
HtmlArmor
Marks HTML that shouldn't be escaped.
Definition: HtmlArmor.php:30
ResourceLoaderClientHtml
Load and configure a ResourceLoader client on an HTML page.
Definition: ResourceLoaderClientHtml.php:30
OutputPage\reduceAllowedModules
reduceAllowedModules( $type, $level)
Limit the highest level of CSS/JS untrustworthiness allowed.
Definition: OutputPage.php:1614
MWDebug\getDebugHTML
static getDebugHTML(IContextSource $context)
Returns the HTML to add to the page for the toolbar.
Definition: MWDebug.php:609
OutputPage\$mModuleStyles
array $mModuleStyles
Definition: OutputPage.php:177
OutputPage\addSubtitle
addSubtitle( $str)
Add $str to the subtitle.
Definition: OutputPage.php:1081
OutputPage\addScriptFile
addScriptFile( $file, $unused=null)
Add a JavaScript file to be loaded as <script> on this page.
Definition: OutputPage.php:487
OutputPage\addAcceptLanguage
addAcceptLanguage()
T23672: Add Accept-Language to Vary header if there's no 'variant' parameter in GET.
Definition: OutputPage.php:2363
ParserOutput
Definition: ParserOutput.php:36
Article\formatRobotPolicy
static formatRobotPolicy( $policy)
Converts a String robot policy into an associative array, to allow merging of several policies using ...
Definition: Article.php:981
OutputPage\getJSVars
getJSVars()
Get an array containing the variables to be set in mw.config in JavaScript.
Definition: OutputPage.php:3340
ResourceLoader\makeConfigSetScript
static makeConfigSetScript(array $configuration)
Return JS code which will set the MediaWiki configuration array to the given value.
Definition: ResourceLoader.php:1620
OutputPage\getRlClientContext
getRlClientContext()
Definition: OutputPage.php:3006
OutputPage\getDisplayTitle
getDisplayTitle()
Returns page display title.
Definition: OutputPage.php:1030
Sanitizer\stripAllTags
static stripAllTags( $html)
Take a fragment of (potentially invalid) HTML and return a version with any tags removed,...
Definition: Sanitizer.php:1577
OutputPage\$mVaryHeader
array $mVaryHeader
Headers that cause the cache to vary.
Definition: OutputPage.php:293
OutputPage\showsCopyright
showsCopyright()
Return whether the standard copyright should be shown for the current page.
Definition: OutputPage.php:1341
OutputPage\addLink
addLink(array $linkarr)
Add a new <link> tag to the page header.
Definition: OutputPage.php:434
OutputPage\addCategoryLinksToLBAndGetResult
addCategoryLinksToLBAndGetResult(array $categories)
Definition: OutputPage.php:1428
OutputPage\parserOptions
parserOptions()
Get/set the ParserOptions object to use for wikitext parsing.
Definition: OutputPage.php:1671
OutputPage\hasHeadItem
hasHeadItem( $name)
Check if the header item $name is already set.
Definition: OutputPage.php:696
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:200
$lang
if(!isset( $args[0])) $lang
Definition: testCompression.php:37
OutputPage\getMetaTags
getMetaTags()
Returns the current <meta> tags.
Definition: OutputPage.php:423
OutputPage\addLanguageLinks
addLanguageLinks(array $newLinkArray)
Add new language links.
Definition: OutputPage.php:1351
OutputPage\addLinkHeader
addLinkHeader( $header)
Add an HTTP Link: header.
Definition: OutputPage.php:2339
$wgRequest
$wgRequest
Definition: Setup.php:705
OutputPage\addModuleStyles
addModuleStyles( $modules)
Load the styles of one or more style-only ResourceLoader modules on this page.
Definition: OutputPage.php:593
OutputPage\$mNewSectionLink
bool $mNewSectionLink
Definition: OutputPage.php:242
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:1512
OutputPage\getCSP
getCSP()
Get the ContentSecurityPolicy object.
Definition: OutputPage.php:4242
OutputPage\isArticleRelated
isArticleRelated()
Return whether this page is related an article on the wiki.
Definition: OutputPage.php:1319
OutputPage\setArticleBodyOnly
setArticleBodyOnly( $only)
Set whether the output should only contain the body of the article, without any skin,...
Definition: OutputPage.php:717
OutputPage\getFrameOptions
getFrameOptions()
Get the X-Frame-Options header value (without the name part), or false if there isn't one.
Definition: OutputPage.php:2441
OutputPage\__construct
__construct(IContextSource $context)
Constructor for OutputPage.
Definition: OutputPage.php:355
ResourceLoader\makeInlineScript
static makeInlineScript( $script, $nonce=null)
Make an HTML script that runs given JS code after startup and base modules.
Definition: ResourceLoader.php:1593
OutputPage\$mRedirectCode
string $mRedirectCode
Definition: OutputPage.php:201
Sanitizer\removeHTMLtags
static removeHTMLtags( $text, $processCallback=null, $args=[], $extratags=[], $removetags=[])
Cleans up HTML, removes dangerous tags and attributes, and removes HTML comments.
Definition: Sanitizer.php:240
OutputPage\getRevisionId
getRevisionId()
Get the displayed revision ID.
Definition: OutputPage.php:1707
OutputPage\clearHTML
clearHTML()
Clear the body HTML.
Definition: OutputPage.php:1652
OutputPage\addScript
addScript( $script)
Add raw HTML to the list of scripts (including <script> tag, etc.) Internal use only.
Definition: OutputPage.php:475
ParserOutput\getModules
getModules()
Definition: ParserOutput.php:719
wfTimestamp
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
Definition: GlobalFunctions.php:1665
ParserOutput\getImages
& getImages()
Definition: ParserOutput.php:695
OutputPage\returnToMain
returnToMain( $unused=null, $returnto=null, $returntoquery=null)
Add a "return to" link pointing to a specified title, or the title indicated in the request,...
Definition: OutputPage.php:2978
OutputPage\buildCssLinksArray
buildCssLinksArray()
Definition: OutputPage.php:3941
ParserOutput\getPreventClickjacking
getPreventClickjacking()
Get the prevent-clickjacking flag.
Definition: ParserOutput.php:1637
OutputPage\addParserOutputMetadata
addParserOutputMetadata(ParserOutput $parserOutput)
Add all metadata associated with a ParserOutput object, but without the actual HTML.
Definition: OutputPage.php:1914
OutputPage\combineWrappedStrings
static combineWrappedStrings(array $chunks)
Combine WrappedString chunks and filter out empty ones.
Definition: OutputPage.php:3268
Sanitizer\mergeAttributes
static mergeAttributes( $a, $b)
Merge two sets of HTML attributes.
Definition: Sanitizer.php:542
MW_VERSION
const MW_VERSION
The running version of MediaWiki.
Definition: Defines.php:36
OutputPage\$mHideNewSectionLink
bool $mHideNewSectionLink
Definition: OutputPage.php:245
OutputPage\$contentOverrides
array $contentOverrides
Map Title to Content.
Definition: OutputPage.php:329
OutputPage\$mBodytext
string $mBodytext
Contains all of the "<body>" content.
Definition: OutputPage.php:83
OutputPage\getOriginTrials
getOriginTrials()
Get the Origin-Trial header values.
Definition: OutputPage.php:2457
ParserOutput\getJsConfigVars
getJsConfigVars()
Definition: ParserOutput.php:731
wfUrlencode
wfUrlencode( $s)
We want some things to be included as literal characters in our title URLs for prettiness,...
Definition: GlobalFunctions.php:292
OutputPage\getBottomScripts
getBottomScripts( $extraHtml='')
JS stuff to put at the bottom of the <body>.
Definition: OutputPage.php:3281
OutputPage\$mEnableClientCache
bool $mEnableClientCache
Gwicke work on squid caching? Roughly from 2003.
Definition: OutputPage.php:236
MWDebug\getHTMLDebugLog
static getHTMLDebugLog()
Generate debug log in HTML for displaying at the bottom of the main content area.
Definition: MWDebug.php:643
ParserOptions\newFromAnon
static newFromAnon()
Get a ParserOptions object for an anonymous user.
Definition: ParserOptions.php:1030
OutputPage\couldBePublicCached
couldBePublicCached()
Whether the output might become publicly cached.
Definition: OutputPage.php:2231
OutputPage\addHeadItems
addHeadItems( $values)
Add one or more head items to the output.
Definition: OutputPage.php:686
OutputPage\getModuleStyles
getModuleStyles( $filter=false, $position=null)
Get the list of style-only modules to load on this page.
Definition: OutputPage.php:578
OutputPage\getFeaturePolicyReportOnly
getFeaturePolicyReportOnly()
Definition: OutputPage.php:2487
$file
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Item class for a filearchive table row.
Definition: router.php:42
Html\htmlHeader
static htmlHeader(array $attribs=[])
Constructs the opening html-tag with necessary doctypes depending on global variables.
Definition: Html.php:994
OutputPage\versionRequired
versionRequired( $version)
Display an error page indicating that a given version of MediaWiki is required to use it.
Definition: OutputPage.php:2861
ResourceLoaderClientHtml\setExemptStates
setExemptStates(array $states)
Set state of special modules that are handled by the caller manually.
Definition: ResourceLoaderClientHtml.php:108
wfMessage
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
Definition: GlobalFunctions.php:1183
MediaWiki\Permissions\PermissionStatus\toLegacyErrorArray
toLegacyErrorArray()
Returns this permission status in legacy error array format.
Definition: PermissionStatus.php:78
SpecialPage\getTitleFor
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name If you don't need a full Title object,...
Definition: SpecialPage.php:107
Sanitizer\escapeClass
static escapeClass( $class)
Given a value, escape it so that it can be used as a CSS class and return it.
Definition: Sanitizer.php:973
OutputPage\getFileVersion
getFileVersion()
Get the displayed file version.
Definition: OutputPage.php:1761
OutputPage\getSyndicationLinks
getSyndicationLinks()
Return URLs for each supported syndication format for this page.
Definition: OutputPage.php:1264
ContextSource\canUseWikiPage
canUseWikiPage()
Check whether a WikiPage object can be get with getWikiPage().
Definition: ContextSource.php:103
wfLogWarning
wfLogWarning( $msg, $callerOffset=1, $level=E_USER_WARNING)
Send a warning as a PHP error and the debug log.
Definition: GlobalFunctions.php:1056
ContextSource\getRequest
getRequest()
Definition: ContextSource.php:81
Title\newMainPage
static newMainPage(MessageLocalizer $localizer=null)
Create a new Title for the Main Page.
Definition: Title.php:712
OutputPage\getRedirect
getRedirect()
Get the URL to redirect to, or an empty string if not redirect URL set.
Definition: OutputPage.php:381
OutputPage\setCanonicalUrl
setCanonicalUrl( $url)
Set the URL to be used for the <link rel=canonical>>.
Definition: OutputPage.php:453
$res
$res
Definition: testCompression.php:57
ParserOutput\getHeadItems
getHeadItems()
Definition: ParserOutput.php:715
ContextSource\getUser
getUser()
Definition: ContextSource.php:136
ContextSource\getTitle
getTitle()
Definition: ContextSource.php:90
OutputPage\$mLinktags
array $mLinktags
Definition: OutputPage.php:57
OutputPage\$mIndexPolicy
$mIndexPolicy
Definition: OutputPage.php:285
Skin\getHtmlElementAttributes
getHtmlElementAttributes()
Return values for <html> element.
Definition: Skin.php:557
OutputPage\setIndicators
setIndicators(array $indicators)
Add an array of indicators, with their identifiers as array keys and HTML contents as values.
Definition: OutputPage.php:1514
Page\PageReference
Interface for objects (potentially) representing a page that can be viewable and linked to on a wiki.
Definition: PageReference.php:49
LinkCache\getSelectFields
static getSelectFields()
Fields that LinkCache needs to select.
Definition: LinkCache.php:383
OutputPage\addHTML
addHTML( $text)
Append $text to the body HTML.
Definition: OutputPage.php:1632
OutputPage\parseInternal
parseInternal( $text, $title, $linestart, $interface)
Parse wikitext and return the HTML (internal implementation helper)
Definition: OutputPage.php:2145
OutputPage\getReportTo
getReportTo()
Definition: OutputPage.php:2463
OutputPage\addHeadItem
addHeadItem( $name, $value)
Add or replace a head item to the output.
Definition: OutputPage.php:676
OutputPage\addContentOverrideCallback
addContentOverrideCallback(callable $callback)
Add a callback for mapping from a Title to a Content object, for things like page preview.
Definition: OutputPage.php:640
OutputPage\getRevisionTimestamp
getRevisionTimestamp()
Get the timestamp of displayed revision.
Definition: OutputPage.php:1738
OutputPage\addWikiMsgArray
addWikiMsgArray( $name, $args)
Add a wikitext-formatted message to the output.
Definition: OutputPage.php:4133
OutputPage\tailElement
tailElement( $skin)
The final bits that go to the bottom of a page HTML document including the closing tags.
Definition: OutputPage.php:4255
OutputPage\transformCssMedia
static transformCssMedia( $media)
Transform "media" attribute based on request parameters.
Definition: OutputPage.php:4081
OutputPage\setLastModified
setLastModified( $timestamp)
Override the last modified timestamp.
Definition: OutputPage.php:865
$dbr
$dbr
Definition: testCompression.php:54
ResourceLoaderClientHtml\setConfig
setConfig(array $vars)
Set mw.config variables.
Definition: ResourceLoaderClientHtml.php:77
ContextSource\getLanguage
getLanguage()
Definition: ContextSource.php:153
OutputPage\$mImageTimeKeys
array $mImageTimeKeys
Definition: OutputPage.php:198
NS_SPECIAL
const NS_SPECIAL
Definition: Defines.php:53
OutputPage\showPermissionsErrorPage
showPermissionsErrorPage(array $errors, $action=null)
Output a standard permission error page.
Definition: OutputPage.php:2778
wfAppendQuery
wfAppendQuery( $url, $query)
Append a query string to an existing URL, which may or may not already have query string parameters a...
Definition: GlobalFunctions.php:422
ParserOutput\getModuleStyles
getModuleStyles()
Definition: ParserOutput.php:723
OutputPage\getLinkTags
getLinkTags()
Returns the current <link> tags.
Definition: OutputPage.php:444
OutputPage\forceHideNewSectionLink
forceHideNewSectionLink()
Forcibly hide the new section link?
Definition: OutputPage.php:1185
Html\closeElement
static closeElement( $element)
Returns "</$element>".
Definition: Html.php:316
Xml\encodeJsCall
static encodeJsCall( $name, $args, $pretty=false)
Create a call to a JavaScript function.
Definition: Xml.php:691
OutputPage\$rlClientContext
ResourceLoaderContext $rlClientContext
Definition: OutputPage.php:186
Html\isXmlMimeType
static isXmlMimeType( $mimetype)
Determines if the given MIME type is xml.
Definition: Html.php:1032
OutputPage\setArticleRelated
setArticleRelated( $newVal)
Set whether this page is related an article on the wiki Setting false will cause the change of "artic...
Definition: OutputPage.php:1307
OutputPage\addElement
addElement( $element, array $attribs=[], $contents='')
Shortcut for adding an Html::element via addHTML.
Definition: OutputPage.php:1645
OutputPage\addParserOutputContent
addParserOutputContent(ParserOutput $parserOutput, $poOptions=[])
Add the HTML and enhancements for it (like ResourceLoader modules) associated with a ParserOutput obj...
Definition: OutputPage.php:2030
Config
Interface for configuration instances.
Definition: Config.php:30
ParserOutput\getExtraCSPDefaultSrcs
getExtraCSPDefaultSrcs()
Get extra Content-Security-Policy 'default-src' directives.
Definition: ParserOutput.php:775
StatusValue\isGood
isGood()
Returns whether the operation completed and didn't have any error or warnings.
Definition: StatusValue.php:122
wfParseUrl
wfParseUrl( $url)
parse_url() work-alike, but non-broken.
Definition: GlobalFunctions.php:776
PROTO_RELATIVE
const PROTO_RELATIVE
Definition: Defines.php:194
File
Implements some public methods and some protected utility functions which are required by multiple ch...
Definition: File.php:66
wfReportTime
wfReportTime( $nonce=null)
Returns a script tag that stores the amount of time it took MediaWiki to handle the request in millis...
Definition: GlobalFunctions.php:1266
OutputPage\addWikiTextAsInterface
addWikiTextAsInterface( $text, $linestart=true, PageReference $title=null)
Convert wikitext in the user interface language to HTML and add it to the buffer.
Definition: OutputPage.php:1801
ParserOutput\getLimitReportJSData
getLimitReportJSData()
Definition: ParserOutput.php:762
TitleValue\castPageToLinkTarget
static castPageToLinkTarget(?PageReference $page)
Casts a PageReference to a LinkTarget.
Definition: TitleValue.php:124
Html\linkedScript
static linkedScript( $url, $nonce=null)
Output a "<script>" tag linking to the given URL, e.g., "<script src=foo.js></script>".
Definition: Html.php:613
OutputPage\feedLink
feedLink( $type, $url, $text)
Generate a "<link rel/>" for a feed.
Definition: OutputPage.php:3834
wfDeprecatedMsg
wfDeprecatedMsg( $msg, $version=false, $component=false, $callerOffset=2)
Log a deprecation warning with arbitrary message text.
Definition: GlobalFunctions.php:1028
OutputPage\setPreventClickjacking
setPreventClickjacking(bool $enable)
Set the prevent-clickjacking flag.
Definition: OutputPage.php:2420
MWException
MediaWiki exception.
Definition: MWException.php:29
OutputPage\considerCacheSettingsFinal
considerCacheSettingsFinal()
Set the expectation that cache control will not change after this point.
Definition: OutputPage.php:2254
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:553
OutputPage\addStyle
addStyle( $style, $media='', $condition='', $dir='')
Add a local or specified stylesheet, with the given media options.
Definition: OutputPage.php:3852
OutputPage\sendCacheControl
sendCacheControl()
Send cache control HTTP headers.
Definition: OutputPage.php:2497
wfDeprecated
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Logs a warning that a deprecated feature was used.
Definition: GlobalFunctions.php:997
OutputPage\$mCdnMaxageLimit
int $mCdnMaxageLimit
Upper limit on mCdnMaxage.
Definition: OutputPage.php:257
OutputPage\getLastSeenUserTalkRevId
getLastSeenUserTalkRevId()
Get the revision ID for the last user talk page revision viewed by the talk page owner.
Definition: OutputPage.php:3486
OutputPage\$mTemplateIds
array $mTemplateIds
Definition: OutputPage.php:195
wfScript
wfScript( $script='index')
Get the path to a specified script file, respecting file extensions; this is a wrapper around $wgScri...
Definition: GlobalFunctions.php:2282
Wikimedia\Rdbms\IResultWrapper
Result wrapper for grabbing data queried from an IDatabase object.
Definition: IResultWrapper.php:26
ResourceLoaderWikiModule\preloadTitleInfo
static preloadTitleInfo(ResourceLoaderContext $context, IDatabase $db, array $moduleNames)
Definition: ResourceLoaderWikiModule.php:477
OutputPage\styleLink
styleLink( $style, array $options)
Generate <link> tags for stylesheets.
Definition: OutputPage.php:3960
OutputPage\$mEnableTOC
bool $mEnableTOC
Whether parser output contains a table of contents.
Definition: OutputPage.php:318
Page\PageReference\getNamespace
getNamespace()
Returns the page's namespace number.
Config\get
get( $name)
Get a configuration variable such as "Sitename" or "UploadMaintenance.".
OutputPage\$mSubtitle
array $mSubtitle
Contains the page subtitle.
Definition: OutputPage.php:115
OutputPage\setFileVersion
setFileVersion( $file)
Set the displayed file version.
Definition: OutputPage.php:1748
wfGetDB
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
Definition: GlobalFunctions.php:2200
OutputPage\getLinkHeader
getLinkHeader()
Return a Link: header.
Definition: OutputPage.php:2348
OutputPage\getResourceLoader
getResourceLoader()
Get a ResourceLoader object associated with this OutputPage.
Definition: OutputPage.php:3233
OutputPage\isTOCEnabled
isTOCEnabled()
Whether the output has a table of contents.
Definition: OutputPage.php:4183
ContextSource
The simplest way of implementing IContextSource is to hold a RequestContext as a member variable and ...
Definition: ContextSource.php:33
ContextSource\getWikiPage
getWikiPage()
Get the WikiPage object.
Definition: ContextSource.php:117
OutputPage\setFeedAppendQuery
setFeedAppendQuery( $val)
Add default feeds to the page header This is mainly kept for backward compatibility,...
Definition: OutputPage.php:1228
OutputPage\setDisplayTitle
setDisplayTitle( $html)
Same as page title but only contains name of the page, not any other text.
Definition: OutputPage.php:1018
$modules
$modules
Definition: HTMLFormElement.php:15
OutputPage\isDisabled
isDisabled()
Return whether the output will be completely disabled.
Definition: OutputPage.php:1167
OutputPage\setRevisionId
setRevisionId( $revid)
Set the revision ID which will be seen by the wiki text parser for things such as embedded {{REVISION...
Definition: OutputPage.php:1697
OutputPage\$mCategories
string[][] $mCategories
Definition: OutputPage.php:133
OutputPage\setArticleFlag
setArticleFlag( $newVal)
Set whether the displayed content is related to the source of the corresponding article on the wiki S...
Definition: OutputPage.php:1284
OutputPage\setRedirectedFrom
setRedirectedFrom(PageReference $t)
Set $mRedirectedFrom, the page which redirected us to the current page.
Definition: OutputPage.php:969
OutputPage\disallowUserJs
disallowUserJs()
Do not allow scripts which can be modified by wiki users to load on this page; only allow scripts bun...
Definition: OutputPage.php:1572
ContextSource\getSkin
getSkin()
Definition: ContextSource.php:162
OutputPage\setSubtitle
setSubtitle( $str)
Replace the subtitle with $str.
Definition: OutputPage.php:1071
$args
if( $line===false) $args
Definition: mcc.php:124
OutputPage\$mInlineStyles
string $mInlineStyles
Inline CSS styles.
Definition: OutputPage.php:153
wfCgiToArray
wfCgiToArray( $query)
This is the logical opposite of wfArrayToCgi(): it accepts a query string as its argument and returns...
Definition: GlobalFunctions.php:375
OutputPage\getVaryHeader
getVaryHeader()
Return a Vary: header on which to vary caches.
Definition: OutputPage.php:2322
OutputPage\addModules
addModules( $modules)
Load one or more ResourceLoader modules on this page.
Definition: OutputPage.php:567
OutputPage\showLagWarning
showLagWarning( $lag)
Show a warning about replica DB lag.
Definition: OutputPage.php:2929
$title
$title
Definition: testCompression.php:38
OutputPage\getCacheVaryCookies
getCacheVaryCookies()
Get the list of cookie names that will influence the cache.
Definition: OutputPage.php:2263
OutputPage\setCopyrightUrl
setCopyrightUrl( $url)
Set the copyright URL to send with the output.
Definition: OutputPage.php:393
OutputPage\$mFollowPolicy
$mFollowPolicy
Definition: OutputPage.php:286
OutputPage\$rlClient
ResourceLoaderClientHtml $rlClient
Definition: OutputPage.php:183
OutputPage\addHtmlClasses
addHtmlClasses( $classes)
Add a class to the <html> element.
Definition: OutputPage.php:651
DB_REPLICA
const DB_REPLICA
Definition: defines.php:25
PROTO_CANONICAL
const PROTO_CANONICAL
Definition: Defines.php:196
OutputPage\getIndexPolicy
getIndexPolicy()
Get the current index policy for the page as a string.
Definition: OutputPage.php:915
OutputPage\buildBacklinkSubtitle
static buildBacklinkSubtitle(PageReference $page, $query=[])
Build message object for a subtitle containing a backlink to a page.
Definition: OutputPage.php:1097
OutputPage\addBodyClasses
addBodyClasses( $classes)
Add a class to the <body> element.
Definition: OutputPage.php:706
ParserOutput\getIndicators
getIndicators()
Definition: ParserOutput.php:660
ResourceLoaderModule\getOrigin
getOrigin()
Get this module's origin.
Definition: ResourceLoaderModule.php:161
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
ContextSource\setContext
setContext(IContextSource $context)
Definition: ContextSource.php:63
OutputPage\isArticle
isArticle()
Return whether the content displayed page is related to the source of the corresponding article on th...
Definition: OutputPage.php:1297
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:623
OutputPage\addWikiTextAsContent
addWikiTextAsContent( $text, $linestart=true, PageReference $title=null)
Convert wikitext in the page content language to HTML and add it to the buffer.
Definition: OutputPage.php:1851
OutputPage\showErrorPage
showErrorPage( $title, $msg, $params=[])
Output a standard error page.
Definition: OutputPage.php:2751
OutputPage\addParserOutputText
addParserOutputText(ParserOutput $parserOutput, $poOptions=[])
Add the HTML associated with a ParserOutput object, without any metadata.
Definition: OutputPage.php:2046
OutputPage\addBacklinkSubtitle
addBacklinkSubtitle(PageReference $title, $query=[])
Add a subtitle containing a backlink to a page.
Definition: OutputPage.php:1120
OutputPage\getCSPNonce
getCSPNonce()
Get (and set if not yet set) the CSP nonce.
Definition: OutputPage.php:4232
OutputPage\$mParserOptions
ParserOptions $mParserOptions
lazy initialised, use parserOptions()
Definition: OutputPage.php:226
OutputPage\$mContainsNewMagic
int $mContainsNewMagic
Definition: OutputPage.php:220
OutputPage\setSections
setSections(array $sections)
Adds sections to OutputPage from ParserOutput.
Definition: OutputPage.php:1893
JavaScriptContent
Content for JavaScript pages.
Definition: JavaScriptContent.php:34
OutputPage\$limitReportJSData
array $limitReportJSData
Profiling data.
Definition: OutputPage.php:326
OutputPage\addInlineScript
addInlineScript( $script)
Add a self-contained script tag with the given contents Internal use only.
Definition: OutputPage.php:497
ParserOutput\getTemplateIds
& getTemplateIds()
Definition: ParserOutput.php:691
OutputPage\getArticleBodyOnly
getArticleBodyOnly()
Return whether the output will contain only the body of the article.
Definition: OutputPage.php:726
OutputPage\getPreventClickjacking
getPreventClickjacking()
Get the prevent-clickjacking flag.
Definition: OutputPage.php:2430
ParserOutput\getTOCHTML
getTOCHTML()
Definition: ParserOutput.php:747
OutputPage\$mModules
array $mModules
Definition: OutputPage.php:174
ParserOutput\getExtraCSPScriptSrcs
getExtraCSPScriptSrcs()
Get extra Content-Security-Policy 'script-src' directives.
Definition: ParserOutput.php:784
OutputPage\getCanonicalUrl
getCanonicalUrl()
Returns the URL to be used for the <link rel=canonical>> if one is set.
Definition: OutputPage.php:464
OutputPage\wrapWikiMsg
wrapWikiMsg( $wrap,... $msgSpecs)
This function takes a number of message/argument specifications, wraps them in some overall structure...
Definition: OutputPage.php:4163
OutputPage\setStatusCode
setStatusCode( $statusCode)
Set the HTTP status code to send with the output.
Definition: OutputPage.php:402
PROTO_CURRENT
const PROTO_CURRENT
Definition: Defines.php:195
OutputPage\$mRedirect
string $mRedirect
Definition: OutputPage.php:118
Html\inlineStyle
static inlineStyle( $contents, $media='all', $attribs=[])
Output a "<style>" tag with the given contents for the given media type (if any).
Definition: Html.php:636
ContextSource\msg
msg( $key,... $params)
Get a Message object with context set Parameters are the same as wfMessage()
Definition: ContextSource.php:197
OutputPage\$mIsArticle
bool $mIsArticle
Is the displayed content related to the source of the corresponding wiki article.
Definition: OutputPage.php:92
OutputPage\haveCacheVaryCookies
haveCacheVaryCookies()
Check if the request has a cache-varying cookie header If it does, it's very important that we don't ...
Definition: OutputPage.php:2284
OutputPage\getPageTitle
getPageTitle()
Return the "page title", i.e.
Definition: OutputPage.php:1007
OutputPage\disable
disable()
Disable output completely, i.e.
Definition: OutputPage.php:1158
OutputPage\setIndexPolicy
setIndexPolicy( $policy)
Set the index policy for the page, but leave the follow policy un- touched.
Definition: OutputPage.php:903
Title\makeTitleSafe
static makeTitleSafe( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:676
OutputPage\$mResourceLoader
ResourceLoader $mResourceLoader
Definition: OutputPage.php:180
ParserOutput\getNewSection
getNewSection()
Definition: ParserOutput.php:925
$content
$content
Definition: router.php:76
Skin\getPageClasses
getPageClasses( $title)
TODO: document.
Definition: Skin.php:522
OutputPage\addCategoryLinks
addCategoryLinks(array $categories)
Add an array of categories, with names in the keys.
Definition: OutputPage.php:1379
OutputPage\setRevisionTimestamp
setRevisionTimestamp( $timestamp)
Set the timestamp of the revision which will be displayed.
Definition: OutputPage.php:1728
$s
foreach( $mmfl['setupFiles'] as $fileName) if( $queue) if(empty( $mmfl['quiet'])) $s
Definition: mergeMessageFileList.php:206
OutputPage\getHeadItemsArray
getHeadItemsArray()
Get an array of head items.
Definition: OutputPage.php:660
OutputPage\$CSP
ContentSecurityPolicy $CSP
Definition: OutputPage.php:342
OutputPage\addReturnTo
addReturnTo( $title, array $query=[], $text=null, $options=[])
Add a "return to" link pointing to a specified title.
Definition: OutputPage.php:2962
OutputPage\buildExemptModules
buildExemptModules()
Build exempt modules and legacy non-ResourceLoader styles.
Definition: OutputPage.php:3886
OutputPage\$copyrightUrl
string null $copyrightUrl
The URL to send in a <link> element with rel=license.
Definition: OutputPage.php:323
OutputPage\getProperty
getProperty( $name)
Get an additional output property.
Definition: OutputPage.php:748
ParserOptions\newFromContext
static newFromContext(IContextSource $context)
Get a ParserOptions object from a IContextSource object.
Definition: ParserOptions.php:1069
OutputPage\addWikiMsg
addWikiMsg(... $args)
Add a wikitext-formatted message to the output.
Definition: OutputPage.php:4120
Html\inlineScript
static inlineScript( $contents, $nonce=null)
Output an HTML script tag with the given contents.
Definition: Html.php:589
ContextSource\getAuthority
getAuthority()
Definition: ContextSource.php:144
$header
$header
Definition: updateCredits.php:37
OutputPage\addHelpLink
addHelpLink( $to, $overrideBaseUrl=false)
Adds help link with an icon via page indicators.
Definition: OutputPage.php:1540
OutputPage\formatPermissionsErrorMessage
formatPermissionsErrorMessage(array $errors, $action=null)
Format a list of error messages.
Definition: OutputPage.php:2890
ParserOutput\getOutputHooks
getOutputHooks()
Definition: ParserOutput.php:735
OutputPage\setTarget
setTarget( $target)
Sets ResourceLoader target for load.php links.
Definition: OutputPage.php:609
OutputPage\getRobotPolicy
getRobotPolicy()
Get the current robot policy for the page as a string in the form <index policy>,<follow policy>.
Definition: OutputPage.php:893
ParserOutput\getHideNewSection
getHideNewSection()
Definition: ParserOutput.php:921
OutputPage\setTitle
setTitle(PageReference $t)
Set the Title object to use.
Definition: OutputPage.php:1058
MediaWiki\Session\SessionManager
This serves as the entry point to the MediaWiki session handling system.
Definition: SessionManager.php:83
OutputPage\addContentOverride
addContentOverride( $target, Content $content)
Force the given Content object for the given page, for things like page preview.
Definition: OutputPage.php:620
OutputPage\$contentOverrideCallbacks
callable[] $contentOverrideCallbacks
Definition: OutputPage.php:332
OutputPage\setHTMLTitle
setHTMLTitle( $name)
"HTML title" means the contents of "<title>".
Definition: OutputPage.php:947
DerivativeResourceLoaderContext
A mutable version of ResourceLoaderContext.
Definition: DerivativeResourceLoaderContext.php:33
OutputPage\$mMetatags
string[][] $mMetatags
Should be private.
Definition: OutputPage.php:54
OutputPage\setLanguageLinks
setLanguageLinks(array $newLinkArray)
Reset the language links and add new language links.
Definition: OutputPage.php:1361
OutputPage\setupOOUI
static setupOOUI( $skinName='default', $dir='ltr')
Helper function to setup the PHP implementation of OOUI to use in this request.
Definition: OutputPage.php:4194
OutputPage\$rlExemptStyleModules
array $rlExemptStyleModules
Definition: OutputPage.php:189
OutputPage\$mAdditionalHtmlClasses
array $mAdditionalHtmlClasses
Additional <html> classes; This should be rarely modified; prefer mAdditionalBodyClasses.
Definition: OutputPage.php:165
OutputPage\$mProperties
$mProperties
Additional key => value data.
Definition: OutputPage.php:308
OutputPage\prependHTML
prependHTML( $text)
Prepend $text to the body HTML.
Definition: OutputPage.php:1623
ParserOutput\getNoGallery
getNoGallery()
Definition: ParserOutput.php:711
OutputPage\getHTMLTitle
getHTMLTitle()
Return the "HTML title", i.e.
Definition: OutputPage.php:960
OutputPage\$cacheIsFinal
bool $cacheIsFinal
See OutputPage::couldBePublicCached.
Definition: OutputPage.php:77
OutputPage\clearSubtitle
clearSubtitle()
Clear the subtitles.
Definition: OutputPage.php:1127
OutputPage\warnModuleTargetFilter
warnModuleTargetFilter( $moduleName)
Definition: OutputPage.php:529
OutputPage\$mCdnMaxage
int $mCdnMaxage
Cache stuff.
Definition: OutputPage.php:255
OutputPage\enableOOUI
enableOOUI()
Add ResourceLoader module styles for OOUI and set up the PHP implementation of it for use with MediaW...
Definition: OutputPage.php:4209
TextContent
Content object implementation for representing flat text.
Definition: TextContent.php:39
OutputPage\$cacheVaryCookies
static array $cacheVaryCookies
A cache of the names of the cookies that will influence the cache.
Definition: OutputPage.php:347
OutputPage\$mScripts
$mScripts
Used for JavaScript (predates ResourceLoader)
Definition: OutputPage.php:150
OutputPage\$mAllowedModules
array $mAllowedModules
What level of 'untrustworthiness' is allowed in CSS/JS modules loaded on this page?
Definition: OutputPage.php:210
getSkinThemeMap
static getSkinThemeMap()
Return a map of skin names (in lowercase) to OOUI theme names, defining which theme a given skin shou...
Definition: ResourceLoaderOOUIModule.php:76
OutputPage\$mPrintable
bool $mPrintable
We have to set isPrintable().
Definition: OutputPage.php:104
IContextSource
Interface for objects which can provide a MediaWiki context on request.
Definition: IContextSource.php:58
OutputPage\$mLanguageLinks
array $mLanguageLinks
Array of Interwiki Prefixed (non DB key) Titles (e.g.
Definition: OutputPage.php:142
MediaWiki\Permissions\PermissionStatus
A StatusValue for permission errors.
Definition: PermissionStatus.php:35
OutputPage\setCategoryLinks
setCategoryLinks(array $categories)
Reset the category links (but not the category list) and add $categories.
Definition: OutputPage.php:1465
OutputPage\setFollowPolicy
setFollowPolicy( $policy)
Set the follow policy for the page, but leave the index policy un- touched.
Definition: OutputPage.php:925
Content
Base interface for content objects.
Definition: Content.php:35
OutputPage\setPageTitle
setPageTitle( $name)
"Page title" means the contents of <h1>.
Definition: OutputPage.php:985
OutputPage\getRlClient
getRlClient()
Call this to freeze the module queue and JS config and create a formatter.
Definition: OutputPage.php:3060
ResourceLoaderClientHtml\makeLoad
static makeLoad(ResourceLoaderContext $mainContext, array $modules, $only, array $extraQuery=[], $nonce=null)
Explicitly load or embed modules on a page.
Definition: ResourceLoaderClientHtml.php:393
OutputPage\$mFileVersion
array $mFileVersion
Definition: OutputPage.php:273
OutputPage\checkLastModified
checkLastModified( $timestamp)
checkLastModified tells the client to use the client-cached page if possible.
Definition: OutputPage.php:763
OutputPage\$mNoGallery
bool $mNoGallery
Comes from the parser.
Definition: OutputPage.php:252
OutputPage\$mHeadItems
array $mHeadItems
Array of elements in "<head>".
Definition: OutputPage.php:168
OutputPage\$mRevisionTimestamp
string $mRevisionTimestamp
Definition: OutputPage.php:270
OutputPage\$displayTitle
string $displayTitle
The displayed title of the page.
Definition: OutputPage.php:74
ParserOutput\getFileSearchOptions
& getFileSearchOptions()
Definition: ParserOutput.php:699
Title
Represents a title within MediaWiki.
Definition: Title.php:47
ResourceLoaderModule
Abstraction for ResourceLoader modules, with name registration and maxage functionality.
Definition: ResourceLoaderModule.php:39
OutputPage\setCdnMaxage
setCdnMaxage( $maxage)
Set the value of the "s-maxage" part of the "Cache-control" HTTP header.
Definition: OutputPage.php:2169
Parser\stripOuterParagraph
static stripOuterParagraph( $html)
Strip outer.
Definition: Parser.php:6378
OutputPage\getAllowedModules
getAllowedModules( $type)
Show what level of JavaScript / CSS untrustworthiness is allowed on this page.
Definition: OutputPage.php:1597
ResourceLoader
ResourceLoader is a loading system for JavaScript and CSS resources.
Definition: ResourceLoader.php:58
OutputPage\addVaryHeader
addVaryHeader( $header, array $option=null)
Add an HTTP header that will influence on the cache.
Definition: OutputPage.php:2305
OutputPage\setProperty
setProperty( $name, $value)
Set an additional output property.
Definition: OutputPage.php:737
OutputPage\isPrintable
isPrintable()
Return whether the page is "printable".
Definition: OutputPage.php:1151
OutputPage\setSyndicated
setSyndicated( $show=true)
Add or remove feed links in the page header This is mainly kept for backward compatibility,...
Definition: OutputPage.php:1197
OutputPage\wrapWikiTextAsInterface
wrapWikiTextAsInterface( $wrapperClass, $text)
Convert wikitext in the user interface language to HTML and add it to the buffer with a <div class="$...
Definition: OutputPage.php:1826
OutputPage\$mTarget
string null $mTarget
ResourceLoader target for load.php links.
Definition: OutputPage.php:313
OutputPage\addInlineStyle
addInlineStyle( $style_css, $flip='noflip')
Adds inline CSS styles Internal use only.
Definition: OutputPage.php:3873
ResourceLoaderClientHtml\setModules
setModules(array $modules)
Ensure one or more modules are loaded.
Definition: ResourceLoaderClientHtml.php:88
OutputPage\userCanPreview
userCanPreview()
To make it harder for someone to slip a user a fake JavaScript or CSS preview, a random token is asso...
Definition: OutputPage.php:3525
Html\linkedStyle
static linkedStyle( $url, $media='all')
Output a "<link rel=stylesheet>" linking to the given URL for the given media type (if any).
Definition: Html.php:665
OutputPage\$mPageTitle
string $mPageTitle
The contents of.
Definition: OutputPage.php:65
ResourceLoader\inDebugMode
static inDebugMode()
Determine whether debug mode is on.
Definition: ResourceLoader.php:1711
ResourceLoaderClientHtml\setModuleStyles
setModuleStyles(array $modules)
Ensure the styles of one or more modules are loaded.
Definition: ResourceLoaderClientHtml.php:97
OutputPage\filterModules
filterModules(array $modules, $position=null, $type=ResourceLoaderModule::TYPE_COMBINED)
Filter an array of modules to remove insufficiently trustworthy members, and modules which are no lon...
Definition: OutputPage.php:509
WebRequest\getRequestId
static getRequestId()
Get the current request ID.
Definition: WebRequest.php:333
OutputPage\redirect
redirect( $url, $responsecode='302')
Redirect to $url rather than displaying the normal page.
Definition: OutputPage.php:370
OutputPage\getUnprefixedDisplayTitle
getUnprefixedDisplayTitle()
Returns page display title without namespace prefix if possible.
Definition: OutputPage.php:1045
IContextSource\getConfig
getConfig()
Get the site configuration.
OutputPage\$mJsConfigVars
array $mJsConfigVars
Definition: OutputPage.php:192
$path
$path
Definition: NoLocalSettings.php:25
ParserOutput\getCategories
& getCategories()
Definition: ParserOutput.php:652
OutputPage\setPrintable
setPrintable()
Set the page as printable, i.e.
Definition: OutputPage.php:1142
OutputPage\getHeadLinksArray
getHeadLinksArray()
Definition: OutputPage.php:3555
OutputPage\adaptCdnTTL
adaptCdnTTL( $mtime, $minTTL=0, $maxTTL=0)
Get TTL in [$minTTL,$maxTTL] and pass it to lowerCdnMaxage()
Definition: OutputPage.php:2199
OutputPage\getCdnCacheEpoch
getCdnCacheEpoch( $reqTime, $maxAge)
Definition: OutputPage.php:851
OutputPage\allowClickjacking
allowClickjacking()
Turn off frame-breaking.
Definition: OutputPage.php:2398
LanguageCode\bcp47
static bcp47( $code)
Get the normalised IETF language tag See unit test for examples.
Definition: LanguageCode.php:175
OutputPage\loadSkinModules
loadSkinModules( $sk)
Transfer styles and JavaScript modules from skin.
Definition: OutputPage.php:2565
OutputPage\showFatalError
showFatalError( $message)
Output an error page.
Definition: OutputPage.php:2948
Html\openElement
static openElement( $element, $attribs=[])
Identical to rawElement(), but has no third parameter and omits the end tag (and the self-closing '/'...
Definition: Html.php:252
Html\rawElement
static rawElement( $element, $attribs=[], $contents='')
Returns an HTML element in a string.
Definition: Html.php:210
OutputPage\getHTML
getHTML()
Get the body HTML.
Definition: OutputPage.php:1661
Message
The Message class deals with fetching and processing of interface message into a variety of formats.
Definition: Message.php:138
OutputPage\$mRevisionId
int null $mRevisionId
To include the variable {{REVISIONID}}.
Definition: OutputPage.php:267
OutputPage\parseInlineAsInterface
parseInlineAsInterface( $text, $linestart=true)
Parse wikitext in the user interface language, strip paragraph wrapper, and return the HTML.
Definition: OutputPage.php:2127
OutputPage\$mLinkHeader
$mLinkHeader
Link: header contents.
Definition: OutputPage.php:337
NS_CATEGORY
const NS_CATEGORY
Definition: Defines.php:78
$keys
$keys
Definition: testCompression.php:72
OutputPage\$styles
array $styles
An array of stylesheet filenames (relative from skins path), with options for CSS media,...
Definition: OutputPage.php:283
OutputPage\isRevisionCurrent
isRevisionCurrent()
Whether the revision displayed is the latest revision of the page.
Definition: OutputPage.php:1717
Sanitizer\normalizeCharReferences
static normalizeCharReferences( $text)
Ensure that any entities and character references are legal for XML and XHTML specifically.
Definition: Sanitizer.php:1124
MWDebug\addModules
static addModules(OutputPage $out)
Add ResourceLoader modules to the OutputPage object if debugging is enabled.
Definition: MWDebug.php:125
CacheTime\isCacheable
isCacheable()
Definition: CacheTime.php:168
IContextSource\getRequest
getRequest()
OutputPage\showNewSectionLink
showNewSectionLink()
Show an "add new section" link?
Definition: OutputPage.php:1176
Title\castFromPageReference
static castFromPageReference(?PageReference $pageReference)
Return a Title for a given Reference.
Definition: Title.php:344
OutputPage\$mPageLinkTitle
string $mPageLinkTitle
Used by skin template.
Definition: OutputPage.php:159
ParserOutput\getText
getText( $options=[])
Get the output HTML.
Definition: ParserOutput.php:360
OutputPage\$mCanonicalUrl
string bool $mCanonicalUrl
Definition: OutputPage.php:60
OutputPage\makeResourceLoaderLink
makeResourceLoaderLink( $modules, $only, array $extraQuery=[])
Explicily load or embed modules on a page.
Definition: OutputPage.php:3249
OutputPage\getIndicators
getIndicators()
Get the indicators associated with this page.
Definition: OutputPage.php:1528
$t
$t
Definition: testCompression.php:74
Html\element
static element( $element, $attribs=[], $contents='')
Identical to rawElement(), but HTML-escapes $contents (like Xml::element()).
Definition: Html.php:232
OutputPage\addWikiTextTitleInternal
addWikiTextTitleInternal( $text, PageReference $title, $linestart, $interface, $wrapperClass=null)
Add wikitext with a custom Title object.
Definition: OutputPage.php:1875
Skin\getSkinName
getSkinName()
Definition: Skin.php:252
MediaWiki\Linker\LinkTarget
Definition: LinkTarget.php:26
OutputPage\addJsConfigVars
addJsConfigVars( $keys, $value=null)
Add one or more variables to be set in mw.config in JavaScript.
Definition: OutputPage.php:3320
OutputPage\$mPreventClickjacking
bool $mPreventClickjacking
Controls if anti-clickjacking / frame-breaking headers will be sent.
Definition: OutputPage.php:264
Skin
The main skin class which provides methods and properties for all other skins.
Definition: Skin.php:44
OutputPage\getSections
getSections()
Definition: OutputPage.php:1902
OutputPage\getFollowPolicy
getFollowPolicy()
Get the current follow policy for the page as a string.
Definition: OutputPage.php:937
OutputPage\getCategories
getCategories( $type='all')
Get the list of category names this page belongs to.
Definition: OutputPage.php:1491
OutputPage\getJsConfigVars
getJsConfigVars()
Get the javascript config vars to include on this page.
Definition: OutputPage.php:3310
OutputPage\setCopyright
setCopyright( $hasCopyright)
Set whether the standard copyright should be shown for the current page.
Definition: OutputPage.php:1328
OutputPage\getTemplateIds
getTemplateIds()
Get the templates used on this page.
Definition: OutputPage.php:1771
$IP
$IP
Definition: WebStart.php:49
OutputPage\$mIsArticleRelated
bool $mIsArticleRelated
Stores "article flag" toggle.
Definition: OutputPage.php:95
Skin\isResponsive
isResponsive()
Indicates if this skin is responsive.
Definition: Skin.php:265
OutputPage\isSyndicated
isSyndicated()
Should we output feed links for this page?
Definition: OutputPage.php:1256
OutputPage\$mFeedLinksAppendQuery
$mFeedLinksAppendQuery
Definition: OutputPage.php:203
OutputPage\getFileSearchOptions
getFileSearchOptions()
Get the files used on this page.
Definition: OutputPage.php:1781
OutputPage\$mFeedLinks
$mFeedLinks
Handles the Atom / RSS links.
Definition: OutputPage.php:233
OutputPage\$mDoNothing
bool $mDoNothing
Whether output is disabled.
Definition: OutputPage.php:215
OutputPage\$mArticleBodyOnly
bool $mArticleBodyOnly
Flag if output should only contain the body of the article.
Definition: OutputPage.php:239
OutputPage\$mRedirectedFrom
PageReference $mRedirectedFrom
If the current page was reached through a redirect, $mRedirectedFrom contains the title of the redire...
Definition: OutputPage.php:303
ResourceLoader\makeLoaderQuery
static makeLoaderQuery(array $modules, $lang, $skin, $user=null, $version=null, $debug=ResourceLoaderContext::DEBUG_OFF, $only=null, $printable=false, $handheld=null, array $extraQuery=[])
Build a query array (array representation of query string) for load.php.
Definition: ResourceLoader.php:1796
OutputPage\$mHasCopyright
bool $mHasCopyright
Is the content subject to copyright.
Definition: OutputPage.php:98
OutputPage\addParserOutput
addParserOutput(ParserOutput $parserOutput, $poOptions=[])
Add everything from a ParserOutput object.
Definition: OutputPage.php:2058
OutputPage\$mAdditionalBodyClasses
array $mAdditionalBodyClasses
Additional <body> classes; there are also <body> classes from other sources.
Definition: OutputPage.php:171
ContentSecurityPolicy
Definition: ContentSecurityPolicy.php:32
OutputPage\prepareErrorPage
prepareErrorPage( $pageTitle, $htmlTitle=false)
Prepare this object to display an error page; disable caching and indexing, clear the current text an...
Definition: OutputPage.php:2726
OutputPage\$mSections
array $mSections
sections from ParserOutput
Definition: OutputPage.php:109
OutputPage\addTemplate
addTemplate(&$template)
Add the output of a QuickTemplate to the output buffer.
Definition: OutputPage.php:2068
OutputPage\$mIndicators
string[] $mIndicators
Definition: OutputPage.php:139
OutputPage\getFeedAppendQuery
getFeedAppendQuery()
Will currently always return null.
Definition: OutputPage.php:1273
OutputPage\lowerCdnMaxage
lowerCdnMaxage( $maxage)
Set the value of the "s-maxage" part of the "Cache-control" HTTP header to $maxage if that is lower t...
Definition: OutputPage.php:2182
OutputPage\$mHTMLtitle
string $mHTMLtitle
Stores contents of "<title>" tag.
Definition: OutputPage.php:86
ParserOutput\getExtraCSPStyleSrcs
getExtraCSPStyleSrcs()
Get extra Content-Security-Policy 'style-src' directives.
Definition: ParserOutput.php:793
wfExpandUrl
wfExpandUrl( $url, $defaultProto=PROTO_CURRENT)
Expand a potentially local URL to a fully-qualified URL.
Definition: GlobalFunctions.php:474
OutputPage\addFeedLink
addFeedLink( $format, $href)
Add a feed link to the page header.
Definition: OutputPage.php:1246
OutputPage\transformResourcePath
static transformResourcePath(Config $config, $path)
Transform path to web-accessible static resource.
Definition: OutputPage.php:4017
OutputPage\parseAsContent
parseAsContent( $text, $linestart=true)
Parse wikitext in the page content language and return the HTML.
Definition: OutputPage.php:2083
OutputPage\getAdvertisedFeedTypes
getAdvertisedFeedTypes()
Return effective list of advertised feed types.
Definition: OutputPage.php:1211
OutputPage\setRobotPolicy
setRobotPolicy( $policy)
Set the robot policy for the page: http://www.robotstxt.org/meta.html
Definition: OutputPage.php:876
wfArrayToCgi
wfArrayToCgi( $array1, $array2=null, $prefix='')
This function takes one or two arrays as input, and returns a CGI-style string, e....
Definition: GlobalFunctions.php:330
OutputPage\transformFilePath
static transformFilePath( $remotePathPrefix, $localPath, $file)
Utility method for transformResourceFilePath().
Definition: OutputPage.php:4059
OutputPage\headElement
headElement(Skin $sk, $includeStyle=true)
Definition: OutputPage.php:3140
$type
$type
Definition: testCompression.php:52
OutputPage\$mStatusCode
int $mStatusCode
Definition: OutputPage.php:121
OutputPage\formatPermissionStatus
formatPermissionStatus(PermissionStatus $status, string $action=null)
Format permission $status obtained from Authority for display.
Definition: OutputPage.php:2875