MediaWiki  master
ApiQuerySiteinfo.php
Go to the documentation of this file.
1 <?php
25 
32 
33  public function __construct( ApiQuery $query, $moduleName ) {
34  parent::__construct( $query, $moduleName, 'si' );
35  }
36 
37  public function execute() {
38  $params = $this->extractRequestParams();
39  $done = [];
40  $fit = false;
41  foreach ( $params['prop'] as $p ) {
42  switch ( $p ) {
43  case 'general':
44  $fit = $this->appendGeneralInfo( $p );
45  break;
46  case 'namespaces':
47  $fit = $this->appendNamespaces( $p );
48  break;
49  case 'namespacealiases':
50  $fit = $this->appendNamespaceAliases( $p );
51  break;
52  case 'specialpagealiases':
53  $fit = $this->appendSpecialPageAliases( $p );
54  break;
55  case 'magicwords':
56  $fit = $this->appendMagicWords( $p );
57  break;
58  case 'interwikimap':
59  $fit = $this->appendInterwikiMap( $p, $params['filteriw'] );
60  break;
61  case 'dbrepllag':
62  $fit = $this->appendDbReplLagInfo( $p, $params['showalldb'] );
63  break;
64  case 'statistics':
65  $fit = $this->appendStatistics( $p );
66  break;
67  case 'usergroups':
68  $fit = $this->appendUserGroups( $p, $params['numberingroup'] );
69  break;
70  case 'libraries':
71  $fit = $this->appendInstalledLibraries( $p );
72  break;
73  case 'extensions':
74  $fit = $this->appendExtensions( $p );
75  break;
76  case 'fileextensions':
77  $fit = $this->appendFileExtensions( $p );
78  break;
79  case 'rightsinfo':
80  $fit = $this->appendRightsInfo( $p );
81  break;
82  case 'restrictions':
83  $fit = $this->appendRestrictions( $p );
84  break;
85  case 'languages':
86  $fit = $this->appendLanguages( $p );
87  break;
88  case 'languagevariants':
89  $fit = $this->appendLanguageVariants( $p );
90  break;
91  case 'skins':
92  $fit = $this->appendSkins( $p );
93  break;
94  case 'extensiontags':
95  $fit = $this->appendExtensionTags( $p );
96  break;
97  case 'functionhooks':
98  $fit = $this->appendFunctionHooks( $p );
99  break;
100  case 'showhooks':
101  $fit = $this->appendSubscribedHooks( $p );
102  break;
103  case 'variables':
104  $fit = $this->appendVariables( $p );
105  break;
106  case 'protocols':
107  $fit = $this->appendProtocols( $p );
108  break;
109  case 'defaultoptions':
110  $fit = $this->appendDefaultOptions( $p );
111  break;
112  case 'uploaddialog':
113  $fit = $this->appendUploadDialog( $p );
114  break;
115  default:
116  ApiBase::dieDebug( __METHOD__, "Unknown prop=$p" ); // @codeCoverageIgnore
117  }
118  if ( !$fit ) {
119  // Abuse siprop as a query-continue parameter
120  // and set it to all unprocessed props
121  $this->setContinueEnumParameter( 'prop', implode( '|',
122  array_diff( $params['prop'], $done ) ) );
123  break;
124  }
125  $done[] = $p;
126  }
127  }
128 
129  protected function appendGeneralInfo( $property ) {
130  $config = $this->getConfig();
131 
132  $data = [];
133  $mainPage = Title::newMainPage();
134  $data['mainpage'] = $mainPage->getPrefixedText();
135  $data['base'] = wfExpandUrl( $mainPage->getFullURL(), PROTO_CURRENT );
136  $data['sitename'] = $config->get( 'Sitename' );
137  $data['mainpageisdomainroot'] = (bool)$config->get( 'MainPageIsDomainRoot' );
138 
139  // A logo can either be a relative or an absolute path
140  // make sure we always return an absolute path
142  $data['logo'] = wfExpandUrl( $logo['1x'], PROTO_RELATIVE );
143 
144  $data['generator'] = 'MediaWiki ' . MW_VERSION;
145 
146  $data['phpversion'] = PHP_VERSION;
147  $data['phpsapi'] = PHP_SAPI;
148  $data['dbtype'] = $config->get( 'DBtype' );
149  $data['dbversion'] = $this->getDB()->getServerVersion();
150 
151  $allowFrom = [ '' ];
152  $allowException = true;
153  if ( !$config->get( 'AllowExternalImages' ) ) {
154  $data['imagewhitelistenabled'] = (bool)$config->get( 'EnableImageWhitelist' );
155  $allowFrom = $config->get( 'AllowExternalImagesFrom' );
156  $allowException = !empty( $allowFrom );
157  }
158  if ( $allowException ) {
159  $data['externalimages'] = (array)$allowFrom;
160  ApiResult::setIndexedTagName( $data['externalimages'], 'prefix' );
161  }
162 
163  $data['langconversion'] = !$config->get( 'DisableLangConversion' );
164  $data['titleconversion'] = !$config->get( 'DisableTitleConversion' );
165 
166  $contLang = MediaWikiServices::getInstance()->getContentLanguage();
167  $contLangConverter = MediaWikiServices::getInstance()->getLanguageConverterFactory()
168  ->getLanguageConverter( $contLang );
169  if ( $contLang->linkPrefixExtension() ) {
170  $linkPrefixCharset = $contLang->linkPrefixCharset();
171  $data['linkprefixcharset'] = $linkPrefixCharset;
172  // For backwards compatibility
173  $data['linkprefix'] = "/^((?>.*[^$linkPrefixCharset]|))(.+)$/sDu";
174  } else {
175  $data['linkprefixcharset'] = '';
176  $data['linkprefix'] = '';
177  }
178 
179  $linktrail = $contLang->linkTrail();
180  $data['linktrail'] = $linktrail ?: '';
181 
182  $data['legaltitlechars'] = Title::legalChars();
183  $data['invalidusernamechars'] = $config->get( 'InvalidUsernameCharacters' );
184 
185  $data['allunicodefixes'] = (bool)$config->get( 'AllUnicodeFixes' );
186  $data['fixarabicunicode'] = true; // Config removed in 1.35, always true
187  $data['fixmalayalamunicode'] = true; // Config removed in 1.35, always true
188 
189  global $IP;
191  if ( $git ) {
192  $data['git-hash'] = $git;
193  $data['git-branch'] =
195  }
196 
197  // 'case-insensitive' option is reserved for future
198  $data['case'] = $config->get( 'CapitalLinks' ) ? 'first-letter' : 'case-sensitive';
199  $data['lang'] = $config->get( 'LanguageCode' );
200 
201  $fallbacks = [];
202  foreach ( $contLang->getFallbackLanguages() as $code ) {
203  $fallbacks[] = [ 'code' => $code ];
204  }
205  $data['fallback'] = $fallbacks;
206  ApiResult::setIndexedTagName( $data['fallback'], 'lang' );
207 
208  if ( $contLangConverter->hasVariants() ) {
209  $variants = [];
210  foreach ( $contLangConverter->getVariants() as $code ) {
211  $variants[] = [
212  'code' => $code,
213  'name' => $contLang->getVariantname( $code ),
214  ];
215  }
216  $data['variants'] = $variants;
217  ApiResult::setIndexedTagName( $data['variants'], 'lang' );
218  }
219 
220  $data['rtl'] = $contLang->isRTL();
221  $data['fallback8bitEncoding'] = $contLang->fallback8bitEncoding();
222 
223  $data['readonly'] = wfReadOnly();
224  if ( $data['readonly'] ) {
225  $data['readonlyreason'] = wfReadOnlyReason();
226  }
227  $data['writeapi'] = true; // Deprecated since MW 1.32
228 
229  $data['maxarticlesize'] = $config->get( 'MaxArticleSize' ) * 1024;
230 
231  $tz = $config->get( 'Localtimezone' );
232  $offset = $config->get( 'LocalTZoffset' );
233  $data['timezone'] = $tz;
234  $data['timeoffset'] = (int)$offset;
235  $data['articlepath'] = $config->get( 'ArticlePath' );
236  $data['scriptpath'] = $config->get( 'ScriptPath' );
237  $data['script'] = $config->get( 'Script' );
238  $data['variantarticlepath'] = $config->get( 'VariantArticlePath' );
239  $data[ApiResult::META_BC_BOOLS][] = 'variantarticlepath';
240  $data['server'] = $config->get( 'Server' );
241  $data['servername'] = $config->get( 'ServerName' );
242  $data['wikiid'] = WikiMap::getCurrentWikiId();
243  $data['time'] = wfTimestamp( TS_ISO_8601, time() );
244 
245  $data['misermode'] = (bool)$config->get( 'MiserMode' );
246 
247  $data['uploadsenabled'] = UploadBase::isEnabled();
248  $data['maxuploadsize'] = UploadBase::getMaxUploadSize();
249  $data['minuploadchunksize'] = ApiUpload::getMinUploadChunkSize( $config );
250 
251  $data['galleryoptions'] = $config->get( 'GalleryOptions' );
252 
253  $data['thumblimits'] = $config->get( 'ThumbLimits' );
254  ApiResult::setArrayType( $data['thumblimits'], 'BCassoc' );
255  ApiResult::setIndexedTagName( $data['thumblimits'], 'limit' );
256  $data['imagelimits'] = [];
257  ApiResult::setArrayType( $data['imagelimits'], 'BCassoc' );
258  ApiResult::setIndexedTagName( $data['imagelimits'], 'limit' );
259  foreach ( $config->get( 'ImageLimits' ) as $k => $limit ) {
260  $data['imagelimits'][$k] = [ 'width' => $limit[0], 'height' => $limit[1] ];
261  }
262 
263  $favicon = $config->get( 'Favicon' );
264  if ( !empty( $favicon ) ) {
265  // wgFavicon can either be a relative or an absolute path
266  // make sure we always return an absolute path
267  $data['favicon'] = wfExpandUrl( $favicon, PROTO_RELATIVE );
268  }
269 
270  $data['centralidlookupprovider'] = $config->get( 'CentralIdLookupProvider' );
271  $providerIds = array_keys( $config->get( 'CentralIdLookupProviders' ) );
272  $data['allcentralidlookupproviders'] = $providerIds;
273 
274  $data['interwikimagic'] = (bool)$config->get( 'InterwikiMagic' );
275  $data['magiclinks'] = $config->get( 'EnableMagicLinks' );
276 
277  $data['categorycollation'] = $config->get( 'CategoryCollation' );
278 
279  $this->getHookRunner()->onAPIQuerySiteInfoGeneralInfo( $this, $data );
280 
281  return $this->getResult()->addValue( 'query', $property, $data );
282  }
283 
284  protected function appendNamespaces( $property ) {
285  $nsProtection = $this->getConfig()->get( 'NamespaceProtection' );
286 
287  $data = [
288  ApiResult::META_TYPE => 'assoc',
289  ];
290  $nsInfo = MediaWikiServices::getInstance()->getNamespaceInfo();
291  foreach (
292  MediaWikiServices::getInstance()->getContentLanguage()->getFormattedNamespaces()
293  as $ns => $title
294  ) {
295  $data[$ns] = [
296  'id' => (int)$ns,
297  'case' => $nsInfo->isCapitalized( $ns ) ? 'first-letter' : 'case-sensitive',
298  ];
299  ApiResult::setContentValue( $data[$ns], 'name', $title );
300  $canonical = $nsInfo->getCanonicalName( $ns );
301 
302  $data[$ns]['subpages'] = $nsInfo->hasSubpages( $ns );
303 
304  if ( $canonical ) {
305  $data[$ns]['canonical'] = strtr( $canonical, '_', ' ' );
306  }
307 
308  $data[$ns]['content'] = $nsInfo->isContent( $ns );
309  $data[$ns]['nonincludable'] = $nsInfo->isNonincludable( $ns );
310 
311  if ( isset( $nsProtection[$ns] ) ) {
312  if ( is_array( $nsProtection[$ns] ) ) {
313  $specificNs = implode( "|", array_filter( $nsProtection[$ns] ) );
314  } elseif ( $nsProtection[$ns] !== '' ) {
315  $specificNs = $nsProtection[$ns];
316  }
317  if ( isset( $specificNs ) && $specificNs !== '' ) {
318  $data[$ns]['namespaceprotection'] = $specificNs;
319  }
320  }
321 
322  $contentmodel = $nsInfo->getNamespaceContentModel( $ns );
323  if ( $contentmodel ) {
324  $data[$ns]['defaultcontentmodel'] = $contentmodel;
325  }
326  }
327 
328  ApiResult::setArrayType( $data, 'assoc' );
329  ApiResult::setIndexedTagName( $data, 'ns' );
330 
331  return $this->getResult()->addValue( 'query', $property, $data );
332  }
333 
334  protected function appendNamespaceAliases( $property ) {
335  $contLang = MediaWikiServices::getInstance()->getContentLanguage();
336  $aliases = $contLang->getNamespaceAliases();
337  $namespaces = $contLang->getNamespaces();
338  $data = [];
339  foreach ( $aliases as $title => $ns ) {
340  if ( $namespaces[$ns] == $title ) {
341  // Don't list duplicates
342  continue;
343  }
344  $item = [
345  'id' => (int)$ns
346  ];
347  ApiResult::setContentValue( $item, 'alias', strtr( $title, '_', ' ' ) );
348  $data[] = $item;
349  }
350 
351  sort( $data );
352 
353  ApiResult::setIndexedTagName( $data, 'ns' );
354 
355  return $this->getResult()->addValue( 'query', $property, $data );
356  }
357 
358  protected function appendSpecialPageAliases( $property ) {
359  $data = [];
360  $services = MediaWikiServices::getInstance();
361  $aliases = $services->getContentLanguage()->getSpecialPageAliases();
362  foreach ( $services->getSpecialPageFactory()->getNames() as $specialpage ) {
363  if ( isset( $aliases[$specialpage] ) ) {
364  $arr = [ 'realname' => $specialpage, 'aliases' => $aliases[$specialpage] ];
365  ApiResult::setIndexedTagName( $arr['aliases'], 'alias' );
366  $data[] = $arr;
367  }
368  }
369  ApiResult::setIndexedTagName( $data, 'specialpage' );
370 
371  return $this->getResult()->addValue( 'query', $property, $data );
372  }
373 
374  protected function appendMagicWords( $property ) {
375  $data = [];
376  foreach (
377  MediaWikiServices::getInstance()->getContentLanguage()->getMagicWords()
378  as $magicword => $aliases
379  ) {
380  $caseSensitive = array_shift( $aliases );
381  $arr = [ 'name' => $magicword, 'aliases' => $aliases ];
382  $arr['case-sensitive'] = (bool)$caseSensitive;
383  ApiResult::setIndexedTagName( $arr['aliases'], 'alias' );
384  $data[] = $arr;
385  }
386  ApiResult::setIndexedTagName( $data, 'magicword' );
387 
388  return $this->getResult()->addValue( 'query', $property, $data );
389  }
390 
391  protected function appendInterwikiMap( $property, $filter ) {
392  if ( $filter === 'local' ) {
393  $local = 1;
394  } elseif ( $filter === '!local' ) {
395  $local = 0;
396  } else {
397  // $filter === null
398  $local = null;
399  }
400 
401  $params = $this->extractRequestParams();
402  $langCode = $params['inlanguagecode'] ?? '';
403  $interwikiMagic = $this->getConfig()->get( 'InterwikiMagic' );
404 
405  if ( $interwikiMagic ) {
406  $langNames = MediaWikiServices::getInstance()
407  ->getLanguageNameUtils()
408  ->getLanguageNames( $langCode );
409  }
410 
411  $getPrefixes = MediaWikiServices::getInstance()->getInterwikiLookup()->getAllPrefixes( $local );
412  $extraLangPrefixes = $this->getConfig()->get( 'ExtraInterlanguageLinkPrefixes' );
413  $localInterwikis = $this->getConfig()->get( 'LocalInterwikis' );
414  $data = [];
415 
416  foreach ( $getPrefixes as $row ) {
417  $prefix = $row['iw_prefix'];
418  $val = [];
419  $val['prefix'] = $prefix;
420  if ( isset( $row['iw_local'] ) && $row['iw_local'] == '1' ) {
421  $val['local'] = true;
422  }
423  if ( isset( $row['iw_trans'] ) && $row['iw_trans'] == '1' ) {
424  $val['trans'] = true;
425  }
426 
427  if ( $interwikiMagic && isset( $langNames[$prefix] ) ) {
428  $val['language'] = $langNames[$prefix];
429  }
430  if ( in_array( $prefix, $localInterwikis ) ) {
431  $val['localinterwiki'] = true;
432  }
433  if ( $interwikiMagic && in_array( $prefix, $extraLangPrefixes ) ) {
434  $val['extralanglink'] = true;
435 
436  $linktext = wfMessage( "interlanguage-link-$prefix" );
437  if ( !$linktext->isDisabled() ) {
438  $val['linktext'] = $linktext->text();
439  }
440 
441  $sitename = wfMessage( "interlanguage-link-sitename-$prefix" );
442  if ( !$sitename->isDisabled() ) {
443  $val['sitename'] = $sitename->text();
444  }
445  }
446 
447  $val['url'] = wfExpandUrl( $row['iw_url'], PROTO_CURRENT );
448  $val['protorel'] = substr( $row['iw_url'], 0, 2 ) == '//';
449  if ( isset( $row['iw_wikiid'] ) && $row['iw_wikiid'] !== '' ) {
450  $val['wikiid'] = $row['iw_wikiid'];
451  }
452  if ( isset( $row['iw_api'] ) && $row['iw_api'] !== '' ) {
453  $val['api'] = $row['iw_api'];
454  }
455 
456  $data[] = $val;
457  }
458 
459  ApiResult::setIndexedTagName( $data, 'iw' );
460 
461  return $this->getResult()->addValue( 'query', $property, $data );
462  }
463 
464  protected function appendDbReplLagInfo( $property, $includeAll ) {
465  $data = [];
466  $lb = MediaWikiServices::getInstance()->getDBLoadBalancer();
467  $showHostnames = $this->getConfig()->get( 'ShowHostnames' );
468  if ( $includeAll ) {
469  if ( !$showHostnames ) {
470  $this->dieWithError( 'apierror-siteinfo-includealldenied', 'includeAllDenied' );
471  }
472 
473  $lags = $lb->getLagTimes();
474  foreach ( $lags as $i => $lag ) {
475  $data[] = [
476  'host' => $lb->getServerName( $i ),
477  'lag' => $lag
478  ];
479  }
480  } else {
481  list( , $lag, $index ) = $lb->getMaxLag();
482  $data[] = [
483  'host' => $showHostnames
484  ? $lb->getServerName( $index )
485  : '',
486  'lag' => $lag
487  ];
488  }
489 
490  ApiResult::setIndexedTagName( $data, 'db' );
491 
492  return $this->getResult()->addValue( 'query', $property, $data );
493  }
494 
495  protected function appendStatistics( $property ) {
496  $data = [];
497  $data['pages'] = (int)SiteStats::pages();
498  $data['articles'] = (int)SiteStats::articles();
499  $data['edits'] = (int)SiteStats::edits();
500  $data['images'] = (int)SiteStats::images();
501  $data['users'] = (int)SiteStats::users();
502  $data['activeusers'] = (int)SiteStats::activeUsers();
503  $data['admins'] = (int)SiteStats::numberingroup( 'sysop' );
504  $data['jobs'] = (int)SiteStats::jobs();
505 
506  $this->getHookRunner()->onAPIQuerySiteInfoStatisticsInfo( $data );
507 
508  return $this->getResult()->addValue( 'query', $property, $data );
509  }
510 
511  protected function appendUserGroups( $property, $numberInGroup ) {
512  $config = $this->getConfig();
513 
514  $data = [];
515  $result = $this->getResult();
516  $allGroups = array_values( User::getAllGroups() );
517  foreach ( $config->get( 'GroupPermissions' ) as $group => $permissions ) {
518  $arr = [
519  'name' => $group,
520  'rights' => array_keys( $permissions, true ),
521  ];
522 
523  if ( $numberInGroup ) {
524  $autopromote = $config->get( 'Autopromote' );
525 
526  if ( $group == 'user' ) {
527  $arr['number'] = SiteStats::users();
528  // '*' and autopromote groups have no size
529  } elseif ( $group !== '*' && !isset( $autopromote[$group] ) ) {
530  $arr['number'] = SiteStats::numberingroup( $group );
531  }
532  }
533 
534  $groupArr = [
535  'add' => $config->get( 'AddGroups' ),
536  'remove' => $config->get( 'RemoveGroups' ),
537  'add-self' => $config->get( 'GroupsAddToSelf' ),
538  'remove-self' => $config->get( 'GroupsRemoveFromSelf' )
539  ];
540 
541  foreach ( $groupArr as $type => $rights ) {
542  if ( isset( $rights[$group] ) ) {
543  if ( $rights[$group] === true ) {
544  $groups = $allGroups;
545  } else {
546  $groups = array_intersect( $rights[$group], $allGroups );
547  }
548  if ( $groups ) {
549  $arr[$type] = $groups;
550  ApiResult::setArrayType( $arr[$type], 'BCarray' );
551  ApiResult::setIndexedTagName( $arr[$type], 'group' );
552  }
553  }
554  }
555 
556  ApiResult::setIndexedTagName( $arr['rights'], 'permission' );
557  $data[] = $arr;
558  }
559 
560  ApiResult::setIndexedTagName( $data, 'group' );
561 
562  return $result->addValue( 'query', $property, $data );
563  }
564 
565  protected function appendFileExtensions( $property ) {
566  $data = [];
567  foreach ( array_unique( $this->getConfig()->get( 'FileExtensions' ) ) as $ext ) {
568  $data[] = [ 'ext' => $ext ];
569  }
570  ApiResult::setIndexedTagName( $data, 'fe' );
571 
572  return $this->getResult()->addValue( 'query', $property, $data );
573  }
574 
575  protected function appendInstalledLibraries( $property ) {
576  global $IP;
577  $path = "$IP/vendor/composer/installed.json";
578  if ( !file_exists( $path ) ) {
579  return true;
580  }
581 
582  $data = [];
583  $installed = new ComposerInstalled( $path );
584  foreach ( $installed->getInstalledDependencies() as $name => $info ) {
585  if ( strpos( $info['type'], 'mediawiki-' ) === 0 ) {
586  // Skip any extensions or skins since they'll be listed
587  // in their proper section
588  continue;
589  }
590  $data[] = [
591  'name' => $name,
592  'version' => $info['version'],
593  ];
594  }
595  ApiResult::setIndexedTagName( $data, 'library' );
596 
597  return $this->getResult()->addValue( 'query', $property, $data );
598  }
599 
600  protected function appendExtensions( $property ) {
601  $data = [];
602  $credits = SpecialVersion::getCredits(
604  $this->getConfig()
605  );
606  foreach ( $credits as $type => $extensions ) {
607  foreach ( $extensions as $ext ) {
608  $ret = [];
609  $ret['type'] = $type;
610  if ( isset( $ext['name'] ) ) {
611  $ret['name'] = $ext['name'];
612  }
613  if ( isset( $ext['namemsg'] ) ) {
614  $ret['namemsg'] = $ext['namemsg'];
615  }
616  if ( isset( $ext['description'] ) ) {
617  $ret['description'] = $ext['description'];
618  }
619  if ( isset( $ext['descriptionmsg'] ) ) {
620  // Can be a string or [ key, param1, param2, ... ]
621  if ( is_array( $ext['descriptionmsg'] ) ) {
622  $ret['descriptionmsg'] = $ext['descriptionmsg'][0];
623  $ret['descriptionmsgparams'] = array_slice( $ext['descriptionmsg'], 1 );
624  ApiResult::setIndexedTagName( $ret['descriptionmsgparams'], 'param' );
625  } else {
626  $ret['descriptionmsg'] = $ext['descriptionmsg'];
627  }
628  }
629  if ( isset( $ext['author'] ) ) {
630  $ret['author'] = is_array( $ext['author'] ) ?
631  implode( ', ', $ext['author'] ) : $ext['author'];
632  }
633  if ( isset( $ext['url'] ) ) {
634  $ret['url'] = $ext['url'];
635  }
636  if ( isset( $ext['version'] ) ) {
637  $ret['version'] = $ext['version'];
638  }
639  if ( isset( $ext['path'] ) ) {
640  $extensionPath = dirname( $ext['path'] );
641  $gitInfo = new GitInfo( $extensionPath );
642  $vcsVersion = $gitInfo->getHeadSHA1();
643  if ( $vcsVersion !== false ) {
644  $ret['vcs-system'] = 'git';
645  $ret['vcs-version'] = $vcsVersion;
646  $ret['vcs-url'] = $gitInfo->getHeadViewUrl();
647  $vcsDate = $gitInfo->getHeadCommitDate();
648  if ( $vcsDate !== false ) {
649  $ret['vcs-date'] = wfTimestamp( TS_ISO_8601, $vcsDate );
650  }
651  }
652 
653  if ( ExtensionInfo::getLicenseFileNames( $extensionPath ) ) {
654  $ret['license-name'] = $ext['license-name'] ?? '';
655  $ret['license'] = SpecialPage::getTitleFor(
656  'Version',
657  "License/{$ext['name']}"
658  )->getLinkURL();
659  }
660 
661  if ( ExtensionInfo::getAuthorsFileName( $extensionPath ) ) {
662  $ret['credits'] = SpecialPage::getTitleFor(
663  'Version',
664  "Credits/{$ext['name']}"
665  )->getLinkURL();
666  }
667  }
668  $data[] = $ret;
669  }
670  }
671 
672  ApiResult::setIndexedTagName( $data, 'ext' );
673 
674  return $this->getResult()->addValue( 'query', $property, $data );
675  }
676 
677  protected function appendRightsInfo( $property ) {
678  $config = $this->getConfig();
679  $rightsPage = $config->get( 'RightsPage' );
680  if ( is_string( $rightsPage ) ) {
681  $title = Title::newFromText( $rightsPage );
682  $url = wfExpandUrl( $title, PROTO_CURRENT );
683  } else {
684  $title = false;
685  $url = $config->get( 'RightsUrl' );
686  }
687  $text = $config->get( 'RightsText' );
688  if ( $title && !strlen( $text ) ) {
689  $text = $title->getPrefixedText();
690  }
691 
692  $data = [
693  'url' => (string)$url,
694  'text' => (string)$text,
695  ];
696 
697  return $this->getResult()->addValue( 'query', $property, $data );
698  }
699 
700  protected function appendRestrictions( $property ) {
701  $config = $this->getConfig();
702  $data = [
703  'types' => $config->get( 'RestrictionTypes' ),
704  'levels' => $config->get( 'RestrictionLevels' ),
705  'cascadinglevels' => $config->get( 'CascadingRestrictionLevels' ),
706  'semiprotectedlevels' => $config->get( 'SemiprotectedRestrictionLevels' ),
707  ];
708 
709  ApiResult::setArrayType( $data['types'], 'BCarray' );
710  ApiResult::setArrayType( $data['levels'], 'BCarray' );
711  ApiResult::setArrayType( $data['cascadinglevels'], 'BCarray' );
712  ApiResult::setArrayType( $data['semiprotectedlevels'], 'BCarray' );
713 
714  ApiResult::setIndexedTagName( $data['types'], 'type' );
715  ApiResult::setIndexedTagName( $data['levels'], 'level' );
716  ApiResult::setIndexedTagName( $data['cascadinglevels'], 'level' );
717  ApiResult::setIndexedTagName( $data['semiprotectedlevels'], 'level' );
718 
719  return $this->getResult()->addValue( 'query', $property, $data );
720  }
721 
722  public function appendLanguages( $property ) {
723  $params = $this->extractRequestParams();
724  $langCode = $params['inlanguagecode'] ?? '';
725  $langNames = MediaWikiServices::getInstance()
726  ->getLanguageNameUtils()
727  ->getLanguageNames( $langCode );
728 
729  $data = [];
730 
731  foreach ( $langNames as $code => $name ) {
732  $lang = [
733  'code' => $code,
734  'bcp47' => LanguageCode::bcp47( $code ),
735  ];
736  ApiResult::setContentValue( $lang, 'name', $name );
737  $data[] = $lang;
738  }
739  ApiResult::setIndexedTagName( $data, 'lang' );
740 
741  return $this->getResult()->addValue( 'query', $property, $data );
742  }
743 
744  // Export information about which page languages will trigger
745  // language conversion. (T153341)
746  public function appendLanguageVariants( $property ) {
748  if ( $this->getConfig()->get( 'DisableLangConversion' ) ) {
749  // Ensure result is empty if language conversion is disabled.
750  $langNames = [];
751  }
752  sort( $langNames );
753 
754  $data = [];
755  foreach ( $langNames as $langCode ) {
756  $lang = MediaWikiServices::getInstance()->getLanguageFactory()
757  ->getLanguage( $langCode );
758  $langConverter = MediaWikiServices::getInstance()->getLanguageConverterFactory()
759  ->getLanguageConverter( $lang );
760  if ( !$langConverter->hasVariants() ) {
761  // Only languages which has conversions can be processed
762  continue;
763  }
764  $data[$langCode] = [];
765  ApiResult::setIndexedTagName( $data[$langCode], 'variant' );
766  ApiResult::setArrayType( $data[$langCode], 'kvp', 'code' );
767 
768  $variants = $lang->getVariants();
769  sort( $variants );
770  foreach ( $variants as $v ) {
771  $fallbacks = $langConverter->getVariantFallbacks( $v );
772  if ( !is_array( $fallbacks ) ) {
773  $fallbacks = [ $fallbacks ];
774  }
775  $data[$langCode][$v] = [
776  'fallbacks' => $fallbacks,
777  ];
779  $data[$langCode][$v]['fallbacks'], 'variant'
780  );
781  }
782  }
783  ApiResult::setIndexedTagName( $data, 'lang' );
784  ApiResult::setArrayType( $data, 'kvp', 'code' );
785 
786  return $this->getResult()->addValue( 'query', $property, $data );
787  }
788 
789  public function appendSkins( $property ) {
790  $data = [];
791  $allowed = Skin::getAllowedSkins();
792  $default = Skin::normalizeKey( 'default' );
793  $languageNameUtils = MediaWikiServices::getInstance()->getLanguageNameUtils();
794  foreach ( Skin::getSkinNames() as $name => $displayName ) {
795  $msg = $this->msg( "skinname-{$name}" );
796  $code = $this->getParameter( 'inlanguagecode' );
797  if ( $code && $languageNameUtils->isValidCode( $code ) ) {
798  $msg->inLanguage( $code );
799  } else {
800  $msg->inContentLanguage();
801  }
802  if ( $msg->exists() ) {
803  $displayName = $msg->text();
804  }
805  $skin = [ 'code' => $name ];
806  ApiResult::setContentValue( $skin, 'name', $displayName );
807  if ( !isset( $allowed[$name] ) ) {
808  $skin['unusable'] = true;
809  }
810  if ( $name === $default ) {
811  $skin['default'] = true;
812  }
813  $data[] = $skin;
814  }
815  ApiResult::setIndexedTagName( $data, 'skin' );
816 
817  return $this->getResult()->addValue( 'query', $property, $data );
818  }
819 
820  public function appendExtensionTags( $property ) {
821  $tags = array_map(
822  function ( $item ) {
823  return "<$item>";
824  },
825  MediaWikiServices::getInstance()->getParser()->getTags()
826  );
827  ApiResult::setArrayType( $tags, 'BCarray' );
828  ApiResult::setIndexedTagName( $tags, 't' );
829 
830  return $this->getResult()->addValue( 'query', $property, $tags );
831  }
832 
833  public function appendFunctionHooks( $property ) {
834  $hooks = MediaWikiServices::getInstance()->getParser()->getFunctionHooks();
835  ApiResult::setArrayType( $hooks, 'BCarray' );
836  ApiResult::setIndexedTagName( $hooks, 'h' );
837 
838  return $this->getResult()->addValue( 'query', $property, $hooks );
839  }
840 
841  public function appendVariables( $property ) {
842  $variables = MediaWikiServices::getInstance()->getMagicWordFactory()->getVariableIDs();
843  ApiResult::setArrayType( $variables, 'BCarray' );
844  ApiResult::setIndexedTagName( $variables, 'v' );
845 
846  return $this->getResult()->addValue( 'query', $property, $variables );
847  }
848 
849  public function appendProtocols( $property ) {
850  // Make a copy of the global so we don't try to set the _element key of it - T47130
851  $protocols = array_values( $this->getConfig()->get( 'UrlProtocols' ) );
852  ApiResult::setArrayType( $protocols, 'BCarray' );
853  ApiResult::setIndexedTagName( $protocols, 'p' );
854 
855  return $this->getResult()->addValue( 'query', $property, $protocols );
856  }
857 
858  public function appendDefaultOptions( $property ) {
859  $options = User::getDefaultOptions();
860  $options[ApiResult::META_BC_BOOLS] = array_keys( $options );
861  return $this->getResult()->addValue( 'query', $property, $options );
862  }
863 
864  public function appendUploadDialog( $property ) {
865  $config = $this->getConfig()->get( 'UploadDialog' );
866  return $this->getResult()->addValue( 'query', $property, $config );
867  }
868 
869  public function appendSubscribedHooks( $property ) {
870  $hooks = $this->getConfig()->get( 'Hooks' );
871  $myWgHooks = $hooks;
872  ksort( $myWgHooks );
873 
874  $data = [];
875  foreach ( $myWgHooks as $name => $subscribers ) {
876  $arr = [
877  'name' => $name,
878  'subscribers' => array_map( [ SpecialVersion::class, 'arrayToString' ], $subscribers ),
879  ];
880 
881  ApiResult::setArrayType( $arr['subscribers'], 'array' );
882  ApiResult::setIndexedTagName( $arr['subscribers'], 's' );
883  $data[] = $arr;
884  }
885 
886  ApiResult::setIndexedTagName( $data, 'hook' );
887 
888  return $this->getResult()->addValue( 'query', $property, $data );
889  }
890 
891  public function getCacheMode( $params ) {
892  // Messages for $wgExtraInterlanguageLinkPrefixes depend on user language
893  if (
894  count( $this->getConfig()->get( 'ExtraInterlanguageLinkPrefixes' ) ) &&
895  $params['prop'] !== null &&
896  in_array( 'interwikimap', $params['prop'] )
897  ) {
898  return 'anon-public-user-private';
899  }
900 
901  return 'public';
902  }
903 
904  public function getAllowedParams() {
905  return [
906  'prop' => [
907  ApiBase::PARAM_DFLT => 'general',
908  ApiBase::PARAM_ISMULTI => true,
910  'general',
911  'namespaces',
912  'namespacealiases',
913  'specialpagealiases',
914  'magicwords',
915  'interwikimap',
916  'dbrepllag',
917  'statistics',
918  'usergroups',
919  'libraries',
920  'extensions',
921  'fileextensions',
922  'rightsinfo',
923  'restrictions',
924  'languages',
925  'languagevariants',
926  'skins',
927  'extensiontags',
928  'functionhooks',
929  'showhooks',
930  'variables',
931  'protocols',
932  'defaultoptions',
933  'uploaddialog',
934  ],
936  ],
937  'filteriw' => [
939  'local',
940  '!local',
941  ]
942  ],
943  'showalldb' => false,
944  'numberingroup' => false,
945  'inlanguagecode' => null,
946  ];
947  }
948 
949  protected function getExamplesMessages() {
950  return [
951  'action=query&meta=siteinfo&siprop=general|namespaces|namespacealiases|statistics'
952  => 'apihelp-query+siteinfo-example-simple',
953  'action=query&meta=siteinfo&siprop=interwikimap&sifilteriw=local'
954  => 'apihelp-query+siteinfo-example-interwiki',
955  'action=query&meta=siteinfo&siprop=dbrepllag&sishowalldb='
956  => 'apihelp-query+siteinfo-example-replag',
957  ];
958  }
959 
960  public function getHelpUrls() {
961  return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Siteinfo';
962  }
963 }
SiteStats\articles
static articles()
Definition: SiteStats.php:103
ContextSource\getConfig
getConfig()
Definition: ContextSource.php:67
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:329
ApiQuery
This is the main query class.
Definition: ApiQuery.php:37
ApiQuerySiteinfo\appendProtocols
appendProtocols( $property)
Definition: ApiQuerySiteinfo.php:849
SiteStats\users
static users()
Definition: SiteStats.php:121
SiteStats\activeUsers
static activeUsers()
Definition: SiteStats.php:130
ApiQuerySiteinfo\appendInterwikiMap
appendInterwikiMap( $property, $filter)
Definition: ApiQuerySiteinfo.php:391
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:152
$lang
if(!isset( $args[0])) $lang
Definition: testCompression.php:37
ApiResult\META_TYPE
const META_TYPE
Key for the 'type' metadata item.
Definition: ApiResult.php:110
ApiBase\dieWithError
dieWithError( $msg, $code=null, $data=null, $httpCode=null)
Abort execution with an error.
Definition: ApiBase.php:1436
ApiQuerySiteinfo\appendFileExtensions
appendFileExtensions( $property)
Definition: ApiQuerySiteinfo.php:565
wfTimestamp
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
Definition: GlobalFunctions.php:1808
UploadBase\isEnabled
static isEnabled()
Returns true if uploads are enabled.
Definition: UploadBase.php:141
ApiBase\PARAM_TYPE
const PARAM_TYPE
(boolean) Inverse of IntegerDef::PARAM_IGNORE_RANGE
Definition: ApiBase.php:70
SiteStats\pages
static pages()
Definition: SiteStats.php:112
ApiBase\getResult
getResult()
Get the result object.
Definition: ApiBase.php:564
MW_VERSION
const MW_VERSION
The running version of MediaWiki.
Definition: Defines.php:39
SiteStats\numberingroup
static numberingroup( $group)
Find the number of users in a given user group.
Definition: SiteStats.php:150
ApiQuerySiteinfo\__construct
__construct(ApiQuery $query, $moduleName)
Definition: ApiQuerySiteinfo.php:33
ApiQuerySiteinfo\appendNamespaceAliases
appendNamespaceAliases( $property)
Definition: ApiQuerySiteinfo.php:334
wfReadOnly
wfReadOnly()
Check whether the wiki is in read-only mode.
Definition: GlobalFunctions.php:1125
ApiQuerySiteinfo\execute
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
Definition: ApiQuerySiteinfo.php:37
wfMessage
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
Definition: GlobalFunctions.php:1219
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:92
Title\newMainPage
static newMainPage(MessageLocalizer $localizer=null)
Create a new Title for the Main Page.
Definition: Title.php:654
ApiQuerySiteinfo\appendVariables
appendVariables( $property)
Definition: ApiQuerySiteinfo.php:841
WikiMap\getCurrentWikiId
static getCurrentWikiId()
Definition: WikiMap.php:303
ApiQuerySiteinfo\appendExtensionTags
appendExtensionTags( $property)
Definition: ApiQuerySiteinfo.php:820
ApiQuerySiteinfo\appendRightsInfo
appendRightsInfo( $property)
Definition: ApiQuerySiteinfo.php:677
Skin\getSkinNames
static getSkinNames()
Fetch the set of available skins.
Definition: Skin.php:66
User\getDefaultOptions
static getDefaultOptions()
Combine the language default options with any site-specific options and add the default language vari...
Definition: User.php:1539
SiteStats\images
static images()
Definition: SiteStats.php:139
ApiResult\setContentValue
static setContentValue(array &$arr, $name, $value, $flags=0)
Add an output value to the array by name and mark as META_CONTENT.
Definition: ApiResult.php:466
ExtensionRegistry\getInstance
static getInstance()
Definition: ExtensionRegistry.php:136
ApiQuerySiteinfo\appendDbReplLagInfo
appendDbReplLagInfo( $property, $includeAll)
Definition: ApiQuerySiteinfo.php:464
ApiQuerySiteinfo
A query action to return meta information about the wiki site.
Definition: ApiQuerySiteinfo.php:31
ApiQuerySiteinfo\appendLanguageVariants
appendLanguageVariants( $property)
Definition: ApiQuerySiteinfo.php:746
ApiResult\setArrayType
static setArrayType(array &$arr, $type, $kvpKeyName=null)
Set the array data type.
Definition: ApiResult.php:716
Skin\normalizeKey
static normalizeKey( $key)
Normalize a skin preference value to a form that can be loaded.
Definition: Skin.php:103
ApiQuerySiteinfo\appendFunctionHooks
appendFunctionHooks( $property)
Definition: ApiQuerySiteinfo.php:833
ApiQuerySiteinfo\appendDefaultOptions
appendDefaultOptions( $property)
Definition: ApiQuerySiteinfo.php:858
ApiQueryBase
This is a base class for all Query modules.
Definition: ApiQueryBase.php:37
ApiUpload\getMinUploadChunkSize
static getMinUploadChunkSize(Config $config)
Definition: ApiUpload.php:177
ApiQueryBase\getDB
getDB()
Get the Query database connection (read-only) Stable for overriding.
Definition: ApiQueryBase.php:119
ApiQuerySiteinfo\getExamplesMessages
getExamplesMessages()
Returns usage examples for this module.
Definition: ApiQuerySiteinfo.php:949
PROTO_CURRENT
const PROTO_CURRENT
Definition: Defines.php:211
ApiResult\META_BC_BOOLS
const META_BC_BOOLS
Key for the 'BC bools' metadata item.
Definition: ApiResult.php:136
ApiBase\extractRequestParams
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition: ApiBase.php:716
$title
$title
Definition: testCompression.php:38
ResourceLoaderSkinModule\getAvailableLogos
static getAvailableLogos( $conf)
Return an array of all available logos that a skin may use.
Definition: ResourceLoaderSkinModule.php:328
ApiQuerySiteinfo\appendUploadDialog
appendUploadDialog( $property)
Definition: ApiQuerySiteinfo.php:864
ContextSource\msg
msg( $key,... $params)
Get a Message object with context set Parameters are the same as wfMessage()
Definition: ContextSource.php:184
ApiResult\setIndexedTagName
static setIndexedTagName(array &$arr, $tag)
Set the tag name for numeric-keyed values in XML format.
Definition: ApiResult.php:604
GitInfo
@newable
Definition: GitInfo.php:34
SpecialVersion\getGitCurrentBranch
static getGitCurrentBranch( $dir)
Definition: SpecialVersion.php:1199
SpecialVersion\getCredits
static getCredits(ExtensionRegistry $reg, Config $conf)
Definition: SpecialVersion.php:63
ApiQuerySiteinfo\appendExtensions
appendExtensions( $property)
Definition: ApiQuerySiteinfo.php:600
SiteStats\jobs
static jobs()
Total number of jobs in the job queue.
Definition: SiteStats.php:179
PROTO_RELATIVE
const PROTO_RELATIVE
Definition: Defines.php:210
SpecialVersion\getGitHeadSha1
static getGitHeadSha1( $dir)
Definition: SpecialVersion.php:1189
User\getAllGroups
static getAllGroups()
Return the set of defined explicit groups.
Definition: User.php:4281
$linkPrefixCharset
$linkPrefixCharset
Definition: MessagesCrh_cyrl.php:101
UploadBase\getMaxUploadSize
static getMaxUploadSize( $forType=null)
Get MediaWiki's maximum uploaded file size for given type of upload, based on $wgMaxUploadSize.
Definition: UploadBase.php:2218
ApiQuerySiteinfo\appendLanguages
appendLanguages( $property)
Definition: ApiQuerySiteinfo.php:722
LanguageConverter\$languagesWithVariants
static array $languagesWithVariants
languages supporting variants
Definition: LanguageConverter.php:43
ApiQuerySiteinfo\appendSkins
appendSkins( $property)
Definition: ApiQuerySiteinfo.php:789
ApiQuerySiteinfo\appendUserGroups
appendUserGroups( $property, $numberInGroup)
Definition: ApiQuerySiteinfo.php:511
wfReadOnlyReason
wfReadOnlyReason()
Check if the site is in read-only mode and return the message if so.
Definition: GlobalFunctions.php:1138
$path
$path
Definition: NoLocalSettings.php:25
ApiBase\PARAM_DFLT
const PARAM_DFLT
(boolean) Inverse of IntegerDef::PARAM_IGNORE_RANGE
Definition: ApiBase.php:68
ApiBase\getParameter
getParameter( $paramName, $parseLimit=true)
Get a value for the given parameter.
Definition: ApiBase.php:836
LanguageCode\bcp47
static bcp47( $code)
Get the normalised IETF language tag See unit test for examples.
Definition: LanguageCode.php:175
ApiQuerySiteinfo\appendMagicWords
appendMagicWords( $property)
Definition: ApiQuerySiteinfo.php:374
ApiBase\PARAM_ISMULTI
const PARAM_ISMULTI
(boolean) Inverse of IntegerDef::PARAM_IGNORE_RANGE
Definition: ApiBase.php:69
ApiQuerySiteinfo\appendStatistics
appendStatistics( $property)
Definition: ApiQuerySiteinfo.php:495
$ext
if(!is_readable( $file)) $ext
Definition: router.php:48
ApiQuerySiteinfo\getCacheMode
getCacheMode( $params)
Get the cache mode for the data generated by this module.
Definition: ApiQuerySiteinfo.php:891
ApiQuerySiteinfo\getHelpUrls
getHelpUrls()
Return links to more detailed help pages about the module.
Definition: ApiQuerySiteinfo.php:960
ApiQuerySiteinfo\appendRestrictions
appendRestrictions( $property)
Definition: ApiQuerySiteinfo.php:700
ApiQuerySiteinfo\appendGeneralInfo
appendGeneralInfo( $property)
Definition: ApiQuerySiteinfo.php:129
Title\legalChars
static legalChars()
Get a regex character class describing the legal characters in a link.
Definition: Title.php:700
ApiQueryBase\setContinueEnumParameter
setContinueEnumParameter( $paramName, $paramValue)
Set a query-continue value.
Definition: ApiQueryBase.php:519
Skin\getAllowedSkins
static getAllowedSkins()
Fetch the list of user-selectable skins in regards to $wgSkipSkins.
Definition: Skin.php:78
ApiBase\PARAM_HELP_MSG_PER_VALUE
const PARAM_HELP_MSG_PER_VALUE
((string|array|Message)[]) When PARAM_TYPE is an array, this is an array mapping those values to $msg...
Definition: ApiBase.php:139
ApiBase\getHookRunner
getHookRunner()
Get an ApiHookRunner for running core API hooks.
Definition: ApiBase.php:661
$IP
$IP
Definition: WebStart.php:49
ApiBase\dieDebug
static dieDebug( $method, $message)
Internal code errors should be reported with this method.
Definition: ApiBase.php:1628
MediaWiki\ExtensionInfo
Definition: ExtensionInfo.php:8
ComposerInstalled
Reads an installed.json file and provides accessors to get what is installed.
Definition: ComposerInstalled.php:9
SiteStats\edits
static edits()
Definition: SiteStats.php:94
$GLOBALS
$GLOBALS['IP']
Definition: ComposerHookHandler.php:6
ApiQuerySiteinfo\getAllowedParams
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
Definition: ApiQuerySiteinfo.php:904
wfExpandUrl
wfExpandUrl( $url, $defaultProto=PROTO_CURRENT)
Expand a potentially local URL to a fully-qualified URL.
Definition: GlobalFunctions.php:490
ApiQuerySiteinfo\appendInstalledLibraries
appendInstalledLibraries( $property)
Definition: ApiQuerySiteinfo.php:575
ApiQuerySiteinfo\appendSubscribedHooks
appendSubscribedHooks( $property)
Definition: ApiQuerySiteinfo.php:869
ApiQuerySiteinfo\appendSpecialPageAliases
appendSpecialPageAliases( $property)
Definition: ApiQuerySiteinfo.php:358
$type
$type
Definition: testCompression.php:52
ApiQuerySiteinfo\appendNamespaces
appendNamespaces( $property)
Definition: ApiQuerySiteinfo.php:284