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  $services = MediaWikiServices::getInstance();
791  $data = [];
792  $allowed = $services->getSkinFactory()->getAllowedSkins();
793  $default = Skin::normalizeKey( 'default' );
794  $languageNameUtils = $services->getLanguageNameUtils();
795  $skinNames = $services->getSkinFactory()->getSkinNames();
796 
797  foreach ( $skinNames as $name => $displayName ) {
798  $msg = $this->msg( "skinname-{$name}" );
799  $code = $this->getParameter( 'inlanguagecode' );
800  if ( $code && $languageNameUtils->isValidCode( $code ) ) {
801  $msg->inLanguage( $code );
802  } else {
803  $msg->inContentLanguage();
804  }
805  if ( $msg->exists() ) {
806  $displayName = $msg->text();
807  }
808  $skin = [ 'code' => $name ];
809  ApiResult::setContentValue( $skin, 'name', $displayName );
810  if ( !isset( $allowed[$name] ) ) {
811  $skin['unusable'] = true;
812  }
813  if ( $name === $default ) {
814  $skin['default'] = true;
815  }
816  $data[] = $skin;
817  }
818  ApiResult::setIndexedTagName( $data, 'skin' );
819 
820  return $this->getResult()->addValue( 'query', $property, $data );
821  }
822 
823  public function appendExtensionTags( $property ) {
824  $tags = array_map(
825  function ( $item ) {
826  return "<$item>";
827  },
828  MediaWikiServices::getInstance()->getParser()->getTags()
829  );
830  ApiResult::setArrayType( $tags, 'BCarray' );
831  ApiResult::setIndexedTagName( $tags, 't' );
832 
833  return $this->getResult()->addValue( 'query', $property, $tags );
834  }
835 
836  public function appendFunctionHooks( $property ) {
837  $hooks = MediaWikiServices::getInstance()->getParser()->getFunctionHooks();
838  ApiResult::setArrayType( $hooks, 'BCarray' );
839  ApiResult::setIndexedTagName( $hooks, 'h' );
840 
841  return $this->getResult()->addValue( 'query', $property, $hooks );
842  }
843 
844  public function appendVariables( $property ) {
845  $variables = MediaWikiServices::getInstance()->getMagicWordFactory()->getVariableIDs();
846  ApiResult::setArrayType( $variables, 'BCarray' );
847  ApiResult::setIndexedTagName( $variables, 'v' );
848 
849  return $this->getResult()->addValue( 'query', $property, $variables );
850  }
851 
852  public function appendProtocols( $property ) {
853  // Make a copy of the global so we don't try to set the _element key of it - T47130
854  $protocols = array_values( $this->getConfig()->get( 'UrlProtocols' ) );
855  ApiResult::setArrayType( $protocols, 'BCarray' );
856  ApiResult::setIndexedTagName( $protocols, 'p' );
857 
858  return $this->getResult()->addValue( 'query', $property, $protocols );
859  }
860 
861  public function appendDefaultOptions( $property ) {
862  $options = User::getDefaultOptions();
863  $options[ApiResult::META_BC_BOOLS] = array_keys( $options );
864  return $this->getResult()->addValue( 'query', $property, $options );
865  }
866 
867  public function appendUploadDialog( $property ) {
868  $config = $this->getConfig()->get( 'UploadDialog' );
869  return $this->getResult()->addValue( 'query', $property, $config );
870  }
871 
872  public function appendSubscribedHooks( $property ) {
873  $hooks = $this->getConfig()->get( 'Hooks' );
874  $myWgHooks = $hooks;
875  ksort( $myWgHooks );
876 
877  $data = [];
878  foreach ( $myWgHooks as $name => $subscribers ) {
879  $arr = [
880  'name' => $name,
881  'subscribers' => array_map( [ SpecialVersion::class, 'arrayToString' ], $subscribers ),
882  ];
883 
884  ApiResult::setArrayType( $arr['subscribers'], 'array' );
885  ApiResult::setIndexedTagName( $arr['subscribers'], 's' );
886  $data[] = $arr;
887  }
888 
889  ApiResult::setIndexedTagName( $data, 'hook' );
890 
891  return $this->getResult()->addValue( 'query', $property, $data );
892  }
893 
894  public function getCacheMode( $params ) {
895  // Messages for $wgExtraInterlanguageLinkPrefixes depend on user language
896  if (
897  count( $this->getConfig()->get( 'ExtraInterlanguageLinkPrefixes' ) ) &&
898  $params['prop'] !== null &&
899  in_array( 'interwikimap', $params['prop'] )
900  ) {
901  return 'anon-public-user-private';
902  }
903 
904  return 'public';
905  }
906 
907  public function getAllowedParams() {
908  return [
909  'prop' => [
910  ApiBase::PARAM_DFLT => 'general',
911  ApiBase::PARAM_ISMULTI => true,
913  'general',
914  'namespaces',
915  'namespacealiases',
916  'specialpagealiases',
917  'magicwords',
918  'interwikimap',
919  'dbrepllag',
920  'statistics',
921  'usergroups',
922  'libraries',
923  'extensions',
924  'fileextensions',
925  'rightsinfo',
926  'restrictions',
927  'languages',
928  'languagevariants',
929  'skins',
930  'extensiontags',
931  'functionhooks',
932  'showhooks',
933  'variables',
934  'protocols',
935  'defaultoptions',
936  'uploaddialog',
937  ],
939  ],
940  'filteriw' => [
942  'local',
943  '!local',
944  ]
945  ],
946  'showalldb' => false,
947  'numberingroup' => false,
948  'inlanguagecode' => null,
949  ];
950  }
951 
952  protected function getExamplesMessages() {
953  return [
954  'action=query&meta=siteinfo&siprop=general|namespaces|namespacealiases|statistics'
955  => 'apihelp-query+siteinfo-example-simple',
956  'action=query&meta=siteinfo&siprop=interwikimap&sifilteriw=local'
957  => 'apihelp-query+siteinfo-example-interwiki',
958  'action=query&meta=siteinfo&siprop=dbrepllag&sishowalldb='
959  => 'apihelp-query+siteinfo-example-replag',
960  ];
961  }
962 
963  public function getHelpUrls() {
964  return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Siteinfo';
965  }
966 }
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:328
ApiQuery
This is the main query class.
Definition: ApiQuery.php:37
ApiQuerySiteinfo\appendProtocols
appendProtocols( $property)
Definition: ApiQuerySiteinfo.php:852
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:157
$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:1381
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:1809
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:1126
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:1220
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:653
ApiQuerySiteinfo\appendVariables
appendVariables( $property)
Definition: ApiQuerySiteinfo.php:844
WikiMap\getCurrentWikiId
static getCurrentWikiId()
Definition: WikiMap.php:303
ApiQuerySiteinfo\appendExtensionTags
appendExtensionTags( $property)
Definition: ApiQuerySiteinfo.php:823
ApiQuerySiteinfo\appendRightsInfo
appendRightsInfo( $property)
Definition: ApiQuerySiteinfo.php:677
User\getDefaultOptions
static getDefaultOptions()
Combine the language default options with any site-specific options and add the default language vari...
Definition: User.php:1526
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:137
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:101
ApiQuerySiteinfo\appendFunctionHooks
appendFunctionHooks( $property)
Definition: ApiQuerySiteinfo.php:836
ApiQuerySiteinfo\appendDefaultOptions
appendDefaultOptions( $property)
Definition: ApiQuerySiteinfo.php:861
ApiQueryBase
This is a base class for all Query modules.
Definition: ApiQueryBase.php:37
ApiUpload\getMinUploadChunkSize
static getMinUploadChunkSize(Config $config)
Definition: ApiUpload.php:187
ApiQueryBase\getDB
getDB()
Get the Query database connection (read-only) Stable to override.
Definition: ApiQueryBase.php:119
ApiQuerySiteinfo\getExamplesMessages
getExamplesMessages()
Returns usage examples for this module.
Definition: ApiQuerySiteinfo.php:952
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:375
ApiQuerySiteinfo\appendUploadDialog
appendUploadDialog( $property)
Definition: ApiQuerySiteinfo.php:867
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:1196
SpecialVersion\getCredits
static getCredits(ExtensionRegistry $reg, Config $conf)
Definition: SpecialVersion.php:62
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:1186
User\getAllGroups
static getAllGroups()
Return the set of defined explicit groups.
Definition: User.php:4190
$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:2225
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:1139
$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:894
ApiQuerySiteinfo\getHelpUrls
getHelpUrls()
Return links to more detailed help pages about the module.
Definition: ApiQuerySiteinfo.php:963
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:702
ApiQueryBase\setContinueEnumParameter
setContinueEnumParameter( $paramName, $paramValue)
Set a query-continue value.
Definition: ApiQueryBase.php:519
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:1573
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:907
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:872
ApiQuerySiteinfo\appendSpecialPageAliases
appendSpecialPageAliases( $property)
Definition: ApiQuerySiteinfo.php:358
$type
$type
Definition: testCompression.php:52
ApiQuerySiteinfo\appendNamespaces
appendNamespaces( $property)
Definition: ApiQuerySiteinfo.php:284