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