Don't override action in UI and REDIRECT responses
[mediawiki.git] / includes / api / ApiQuerySiteinfo.php
blob0774651c114dd42647d3d2b2956046eab30c35dd
1 <?php
2 /**
5 * Created on Sep 25, 2006
7 * Copyright © 2006 Yuri Astrakhan "<Firstname><Lastname>@gmail.com"
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 * http://www.gnu.org/copyleft/gpl.html
24 * @file
27 /**
28 * A query action to return meta information about the wiki site.
30 * @ingroup API
32 class ApiQuerySiteinfo extends ApiQueryBase {
34 public function __construct( ApiQuery $query, $moduleName ) {
35 parent::__construct( $query, $moduleName, 'si' );
38 public function execute() {
39 $params = $this->extractRequestParams();
40 $done = [];
41 $fit = false;
42 foreach ( $params['prop'] as $p ) {
43 switch ( $p ) {
44 case 'general':
45 $fit = $this->appendGeneralInfo( $p );
46 break;
47 case 'namespaces':
48 $fit = $this->appendNamespaces( $p );
49 break;
50 case 'namespacealiases':
51 $fit = $this->appendNamespaceAliases( $p );
52 break;
53 case 'specialpagealiases':
54 $fit = $this->appendSpecialPageAliases( $p );
55 break;
56 case 'magicwords':
57 $fit = $this->appendMagicWords( $p );
58 break;
59 case 'interwikimap':
60 $filteriw = isset( $params['filteriw'] ) ? $params['filteriw'] : false;
61 $fit = $this->appendInterwikiMap( $p, $filteriw );
62 break;
63 case 'dbrepllag':
64 $fit = $this->appendDbReplLagInfo( $p, $params['showalldb'] );
65 break;
66 case 'statistics':
67 $fit = $this->appendStatistics( $p );
68 break;
69 case 'usergroups':
70 $fit = $this->appendUserGroups( $p, $params['numberingroup'] );
71 break;
72 case 'libraries':
73 $fit = $this->appendInstalledLibraries( $p );
74 break;
75 case 'extensions':
76 $fit = $this->appendExtensions( $p );
77 break;
78 case 'fileextensions':
79 $fit = $this->appendFileExtensions( $p );
80 break;
81 case 'rightsinfo':
82 $fit = $this->appendRightsInfo( $p );
83 break;
84 case 'restrictions':
85 $fit = $this->appendRestrictions( $p );
86 break;
87 case 'languages':
88 $fit = $this->appendLanguages( $p );
89 break;
90 case 'skins':
91 $fit = $this->appendSkins( $p );
92 break;
93 case 'extensiontags':
94 $fit = $this->appendExtensionTags( $p );
95 break;
96 case 'functionhooks':
97 $fit = $this->appendFunctionHooks( $p );
98 break;
99 case 'showhooks':
100 $fit = $this->appendSubscribedHooks( $p );
101 break;
102 case 'variables':
103 $fit = $this->appendVariables( $p );
104 break;
105 case 'protocols':
106 $fit = $this->appendProtocols( $p );
107 break;
108 case 'defaultoptions':
109 $fit = $this->appendDefaultOptions( $p );
110 break;
111 case 'uploaddialog':
112 $fit = $this->appendUploadDialog( $p );
113 break;
114 default:
115 ApiBase::dieDebug( __METHOD__, "Unknown prop=$p" );
117 if ( !$fit ) {
118 // Abuse siprop as a query-continue parameter
119 // and set it to all unprocessed props
120 $this->setContinueEnumParameter( 'prop', implode( '|',
121 array_diff( $params['prop'], $done ) ) );
122 break;
124 $done[] = $p;
128 protected function appendGeneralInfo( $property ) {
129 global $wgContLang;
131 $config = $this->getConfig();
133 $data = [];
134 $mainPage = Title::newMainPage();
135 $data['mainpage'] = $mainPage->getPrefixedText();
136 $data['base'] = wfExpandUrl( $mainPage->getFullURL(), PROTO_CURRENT );
137 $data['sitename'] = $config->get( 'Sitename' );
139 // wgLogo can either be a relative or an absolute path
140 // make sure we always return an absolute path
141 $data['logo'] = wfExpandUrl( $config->get( 'Logo' ), PROTO_RELATIVE );
143 $data['generator'] = "MediaWiki {$config->get( 'Version' )}";
145 $data['phpversion'] = PHP_VERSION;
146 $data['phpsapi'] = PHP_SAPI;
147 if ( defined( 'HHVM_VERSION' ) ) {
148 $data['hhvmversion'] = HHVM_VERSION;
150 $data['dbtype'] = $config->get( 'DBtype' );
151 $data['dbversion'] = $this->getDB()->getServerVersion();
153 $allowFrom = [ '' ];
154 $allowException = true;
155 if ( !$config->get( 'AllowExternalImages' ) ) {
156 $data['imagewhitelistenabled'] = (bool)$config->get( 'EnableImageWhitelist' );
157 $allowFrom = $config->get( 'AllowExternalImagesFrom' );
158 $allowException = !empty( $allowFrom );
160 if ( $allowException ) {
161 $data['externalimages'] = (array)$allowFrom;
162 ApiResult::setIndexedTagName( $data['externalimages'], 'prefix' );
165 $data['langconversion'] = !$config->get( 'DisableLangConversion' );
166 $data['titleconversion'] = !$config->get( 'DisableTitleConversion' );
168 if ( $wgContLang->linkPrefixExtension() ) {
169 $linkPrefixCharset = $wgContLang->linkPrefixCharset();
170 $data['linkprefixcharset'] = $linkPrefixCharset;
171 // For backwards compatibility
172 $data['linkprefix'] = "/^((?>.*[^$linkPrefixCharset]|))(.+)$/sDu";
173 } else {
174 $data['linkprefixcharset'] = '';
175 $data['linkprefix'] = '';
178 $linktrail = $wgContLang->linkTrail();
179 $data['linktrail'] = $linktrail ?: '';
181 $data['legaltitlechars'] = Title::legalChars();
182 $data['invalidusernamechars'] = $config->get( 'InvalidUsernameCharacters' );
184 global $IP;
185 $git = SpecialVersion::getGitHeadSha1( $IP );
186 if ( $git ) {
187 $data['git-hash'] = $git;
188 $data['git-branch'] =
189 SpecialVersion::getGitCurrentBranch( $GLOBALS['IP'] );
192 // 'case-insensitive' option is reserved for future
193 $data['case'] = $config->get( 'CapitalLinks' ) ? 'first-letter' : 'case-sensitive';
194 $data['lang'] = $config->get( 'LanguageCode' );
196 $fallbacks = [];
197 foreach ( $wgContLang->getFallbackLanguages() as $code ) {
198 $fallbacks[] = [ 'code' => $code ];
200 $data['fallback'] = $fallbacks;
201 ApiResult::setIndexedTagName( $data['fallback'], 'lang' );
203 if ( $wgContLang->hasVariants() ) {
204 $variants = [];
205 foreach ( $wgContLang->getVariants() as $code ) {
206 $variants[] = [
207 'code' => $code,
208 'name' => $wgContLang->getVariantname( $code ),
211 $data['variants'] = $variants;
212 ApiResult::setIndexedTagName( $data['variants'], 'lang' );
215 $data['rtl'] = $wgContLang->isRTL();
216 $data['fallback8bitEncoding'] = $wgContLang->fallback8bitEncoding();
218 $data['readonly'] = wfReadOnly();
219 if ( $data['readonly'] ) {
220 $data['readonlyreason'] = wfReadOnlyReason();
222 $data['writeapi'] = (bool)$config->get( 'EnableWriteAPI' );
224 $tz = $config->get( 'Localtimezone' );
225 $offset = $config->get( 'LocalTZoffset' );
226 if ( is_null( $tz ) ) {
227 $tz = 'UTC';
228 $offset = 0;
229 } elseif ( is_null( $offset ) ) {
230 $offset = 0;
232 $data['timezone'] = $tz;
233 $data['timeoffset'] = intval( $offset );
234 $data['articlepath'] = $config->get( 'ArticlePath' );
235 $data['scriptpath'] = $config->get( 'ScriptPath' );
236 $data['script'] = $config->get( 'Script' );
237 $data['variantarticlepath'] = $config->get( 'VariantArticlePath' );
238 $data[ApiResult::META_BC_BOOLS][] = 'variantarticlepath';
239 $data['server'] = $config->get( 'Server' );
240 $data['servername'] = $config->get( 'ServerName' );
241 $data['wikiid'] = wfWikiID();
242 $data['time'] = wfTimestamp( TS_ISO_8601, time() );
244 $data['misermode'] = (bool)$config->get( 'MiserMode' );
246 $data['uploadsenabled'] = UploadBase::isEnabled();
247 $data['maxuploadsize'] = UploadBase::getMaxUploadSize();
248 $data['minuploadchunksize'] = (int)$this->getConfig()->get( 'MinUploadChunkSize' );
250 $data['thumblimits'] = $config->get( 'ThumbLimits' );
251 ApiResult::setArrayType( $data['thumblimits'], 'BCassoc' );
252 ApiResult::setIndexedTagName( $data['thumblimits'], 'limit' );
253 $data['imagelimits'] = [];
254 ApiResult::setArrayType( $data['imagelimits'], 'BCassoc' );
255 ApiResult::setIndexedTagName( $data['imagelimits'], 'limit' );
256 foreach ( $config->get( 'ImageLimits' ) as $k => $limit ) {
257 $data['imagelimits'][$k] = [ 'width' => $limit[0], 'height' => $limit[1] ];
260 $favicon = $config->get( 'Favicon' );
261 if ( !empty( $favicon ) ) {
262 // wgFavicon can either be a relative or an absolute path
263 // make sure we always return an absolute path
264 $data['favicon'] = wfExpandUrl( $favicon, PROTO_RELATIVE );
267 $data['centralidlookupprovider'] = $this->getConfig()->get( 'CentralIdLookupProvider' );
268 $providerIds = array_keys( $this->getConfig()->get( 'CentralIdLookupProviders' ) );
269 $data['allcentralidlookupproviders'] = $providerIds;
271 Hooks::run( 'APIQuerySiteInfoGeneralInfo', [ $this, &$data ] );
273 return $this->getResult()->addValue( 'query', $property, $data );
276 protected function appendNamespaces( $property ) {
277 global $wgContLang;
278 $data = [
279 ApiResult::META_TYPE => 'assoc',
281 foreach ( $wgContLang->getFormattedNamespaces() as $ns => $title ) {
282 $data[$ns] = [
283 'id' => intval( $ns ),
284 'case' => MWNamespace::isCapitalized( $ns ) ? 'first-letter' : 'case-sensitive',
286 ApiResult::setContentValue( $data[$ns], 'name', $title );
287 $canonical = MWNamespace::getCanonicalName( $ns );
289 $data[$ns]['subpages'] = MWNamespace::hasSubpages( $ns );
291 if ( $canonical ) {
292 $data[$ns]['canonical'] = strtr( $canonical, '_', ' ' );
295 $data[$ns]['content'] = MWNamespace::isContent( $ns );
296 $data[$ns]['nonincludable'] = MWNamespace::isNonincludable( $ns );
298 $contentmodel = MWNamespace::getNamespaceContentModel( $ns );
299 if ( $contentmodel ) {
300 $data[$ns]['defaultcontentmodel'] = $contentmodel;
304 ApiResult::setArrayType( $data, 'assoc' );
305 ApiResult::setIndexedTagName( $data, 'ns' );
307 return $this->getResult()->addValue( 'query', $property, $data );
310 protected function appendNamespaceAliases( $property ) {
311 global $wgContLang;
312 $aliases = array_merge( $this->getConfig()->get( 'NamespaceAliases' ),
313 $wgContLang->getNamespaceAliases() );
314 $namespaces = $wgContLang->getNamespaces();
315 $data = [];
316 foreach ( $aliases as $title => $ns ) {
317 if ( $namespaces[$ns] == $title ) {
318 // Don't list duplicates
319 continue;
321 $item = [
322 'id' => intval( $ns )
324 ApiResult::setContentValue( $item, 'alias', strtr( $title, '_', ' ' ) );
325 $data[] = $item;
328 sort( $data );
330 ApiResult::setIndexedTagName( $data, 'ns' );
332 return $this->getResult()->addValue( 'query', $property, $data );
335 protected function appendSpecialPageAliases( $property ) {
336 global $wgContLang;
337 $data = [];
338 $aliases = $wgContLang->getSpecialPageAliases();
339 foreach ( SpecialPageFactory::getNames() as $specialpage ) {
340 if ( isset( $aliases[$specialpage] ) ) {
341 $arr = [ 'realname' => $specialpage, 'aliases' => $aliases[$specialpage] ];
342 ApiResult::setIndexedTagName( $arr['aliases'], 'alias' );
343 $data[] = $arr;
346 ApiResult::setIndexedTagName( $data, 'specialpage' );
348 return $this->getResult()->addValue( 'query', $property, $data );
351 protected function appendMagicWords( $property ) {
352 global $wgContLang;
353 $data = [];
354 foreach ( $wgContLang->getMagicWords() as $magicword => $aliases ) {
355 $caseSensitive = array_shift( $aliases );
356 $arr = [ 'name' => $magicword, 'aliases' => $aliases ];
357 $arr['case-sensitive'] = (bool)$caseSensitive;
358 ApiResult::setIndexedTagName( $arr['aliases'], 'alias' );
359 $data[] = $arr;
361 ApiResult::setIndexedTagName( $data, 'magicword' );
363 return $this->getResult()->addValue( 'query', $property, $data );
366 protected function appendInterwikiMap( $property, $filter ) {
367 $local = null;
368 if ( $filter === 'local' ) {
369 $local = 1;
370 } elseif ( $filter === '!local' ) {
371 $local = 0;
372 } elseif ( $filter ) {
373 ApiBase::dieDebug( __METHOD__, "Unknown filter=$filter" );
376 $params = $this->extractRequestParams();
377 $langCode = isset( $params['inlanguagecode'] ) ? $params['inlanguagecode'] : '';
378 $langNames = Language::fetchLanguageNames( $langCode );
380 $getPrefixes = Interwiki::getAllPrefixes( $local );
381 $extraLangPrefixes = $this->getConfig()->get( 'ExtraInterlanguageLinkPrefixes' );
382 $localInterwikis = $this->getConfig()->get( 'LocalInterwikis' );
383 $data = [];
385 foreach ( $getPrefixes as $row ) {
386 $prefix = $row['iw_prefix'];
387 $val = [];
388 $val['prefix'] = $prefix;
389 if ( isset( $row['iw_local'] ) && $row['iw_local'] == '1' ) {
390 $val['local'] = true;
392 if ( isset( $row['iw_trans'] ) && $row['iw_trans'] == '1' ) {
393 $val['trans'] = true;
396 if ( isset( $langNames[$prefix] ) ) {
397 $val['language'] = $langNames[$prefix];
399 if ( in_array( $prefix, $localInterwikis ) ) {
400 $val['localinterwiki'] = true;
402 if ( in_array( $prefix, $extraLangPrefixes ) ) {
403 $val['extralanglink'] = true;
405 $linktext = wfMessage( "interlanguage-link-$prefix" );
406 if ( !$linktext->isDisabled() ) {
407 $val['linktext'] = $linktext->text();
410 $sitename = wfMessage( "interlanguage-link-sitename-$prefix" );
411 if ( !$sitename->isDisabled() ) {
412 $val['sitename'] = $sitename->text();
416 $val['url'] = wfExpandUrl( $row['iw_url'], PROTO_CURRENT );
417 $val['protorel'] = substr( $row['iw_url'], 0, 2 ) == '//';
418 if ( isset( $row['iw_wikiid'] ) && $row['iw_wikiid'] !== '' ) {
419 $val['wikiid'] = $row['iw_wikiid'];
421 if ( isset( $row['iw_api'] ) && $row['iw_api'] !== '' ) {
422 $val['api'] = $row['iw_api'];
425 $data[] = $val;
428 ApiResult::setIndexedTagName( $data, 'iw' );
430 return $this->getResult()->addValue( 'query', $property, $data );
433 protected function appendDbReplLagInfo( $property, $includeAll ) {
434 $data = [];
435 $lb = wfGetLB();
436 $showHostnames = $this->getConfig()->get( 'ShowHostnames' );
437 if ( $includeAll ) {
438 if ( !$showHostnames ) {
439 $this->dieUsage(
440 'Cannot view all servers info unless $wgShowHostnames is true',
441 'includeAllDenied'
445 $lags = $lb->getLagTimes();
446 foreach ( $lags as $i => $lag ) {
447 $data[] = [
448 'host' => $lb->getServerName( $i ),
449 'lag' => $lag
452 } else {
453 list( , $lag, $index ) = $lb->getMaxLag();
454 $data[] = [
455 'host' => $showHostnames
456 ? $lb->getServerName( $index )
457 : '',
458 'lag' => intval( $lag )
462 ApiResult::setIndexedTagName( $data, 'db' );
464 return $this->getResult()->addValue( 'query', $property, $data );
467 protected function appendStatistics( $property ) {
468 $data = [];
469 $data['pages'] = intval( SiteStats::pages() );
470 $data['articles'] = intval( SiteStats::articles() );
471 $data['edits'] = intval( SiteStats::edits() );
472 $data['images'] = intval( SiteStats::images() );
473 $data['users'] = intval( SiteStats::users() );
474 $data['activeusers'] = intval( SiteStats::activeUsers() );
475 $data['admins'] = intval( SiteStats::numberingroup( 'sysop' ) );
476 $data['jobs'] = intval( SiteStats::jobs() );
478 Hooks::run( 'APIQuerySiteInfoStatisticsInfo', [ &$data ] );
480 return $this->getResult()->addValue( 'query', $property, $data );
483 protected function appendUserGroups( $property, $numberInGroup ) {
484 $config = $this->getConfig();
486 $data = [];
487 $result = $this->getResult();
488 $allGroups = array_values( User::getAllGroups() );
489 foreach ( $config->get( 'GroupPermissions' ) as $group => $permissions ) {
490 $arr = [
491 'name' => $group,
492 'rights' => array_keys( $permissions, true ),
495 if ( $numberInGroup ) {
496 $autopromote = $config->get( 'Autopromote' );
498 if ( $group == 'user' ) {
499 $arr['number'] = SiteStats::users();
500 // '*' and autopromote groups have no size
501 } elseif ( $group !== '*' && !isset( $autopromote[$group] ) ) {
502 $arr['number'] = SiteStats::numberingroup( $group );
506 $groupArr = [
507 'add' => $config->get( 'AddGroups' ),
508 'remove' => $config->get( 'RemoveGroups' ),
509 'add-self' => $config->get( 'GroupsAddToSelf' ),
510 'remove-self' => $config->get( 'GroupsRemoveFromSelf' )
513 foreach ( $groupArr as $type => $rights ) {
514 if ( isset( $rights[$group] ) ) {
515 if ( $rights[$group] === true ) {
516 $groups = $allGroups;
517 } else {
518 $groups = array_intersect( $rights[$group], $allGroups );
520 if ( $groups ) {
521 $arr[$type] = $groups;
522 ApiResult::setArrayType( $arr[$type], 'BCarray' );
523 ApiResult::setIndexedTagName( $arr[$type], 'group' );
528 ApiResult::setIndexedTagName( $arr['rights'], 'permission' );
529 $data[] = $arr;
532 ApiResult::setIndexedTagName( $data, 'group' );
534 return $result->addValue( 'query', $property, $data );
537 protected function appendFileExtensions( $property ) {
538 $data = [];
539 foreach ( array_unique( $this->getConfig()->get( 'FileExtensions' ) ) as $ext ) {
540 $data[] = [ 'ext' => $ext ];
542 ApiResult::setIndexedTagName( $data, 'fe' );
544 return $this->getResult()->addValue( 'query', $property, $data );
547 protected function appendInstalledLibraries( $property ) {
548 global $IP;
549 $path = "$IP/vendor/composer/installed.json";
550 if ( !file_exists( $path ) ) {
551 return true;
554 $data = [];
555 $installed = new ComposerInstalled( $path );
556 foreach ( $installed->getInstalledDependencies() as $name => $info ) {
557 if ( strpos( $info['type'], 'mediawiki-' ) === 0 ) {
558 // Skip any extensions or skins since they'll be listed
559 // in their proper section
560 continue;
562 $data[] = [
563 'name' => $name,
564 'version' => $info['version'],
567 ApiResult::setIndexedTagName( $data, 'library' );
569 return $this->getResult()->addValue( 'query', $property, $data );
573 protected function appendExtensions( $property ) {
574 $data = [];
575 foreach ( $this->getConfig()->get( 'ExtensionCredits' ) as $type => $extensions ) {
576 foreach ( $extensions as $ext ) {
577 $ret = [];
578 $ret['type'] = $type;
579 if ( isset( $ext['name'] ) ) {
580 $ret['name'] = $ext['name'];
582 if ( isset( $ext['namemsg'] ) ) {
583 $ret['namemsg'] = $ext['namemsg'];
585 if ( isset( $ext['description'] ) ) {
586 $ret['description'] = $ext['description'];
588 if ( isset( $ext['descriptionmsg'] ) ) {
589 // Can be a string or array( key, param1, param2, ... )
590 if ( is_array( $ext['descriptionmsg'] ) ) {
591 $ret['descriptionmsg'] = $ext['descriptionmsg'][0];
592 $ret['descriptionmsgparams'] = array_slice( $ext['descriptionmsg'], 1 );
593 ApiResult::setIndexedTagName( $ret['descriptionmsgparams'], 'param' );
594 } else {
595 $ret['descriptionmsg'] = $ext['descriptionmsg'];
598 if ( isset( $ext['author'] ) ) {
599 $ret['author'] = is_array( $ext['author'] ) ?
600 implode( ', ', $ext['author'] ) : $ext['author'];
602 if ( isset( $ext['url'] ) ) {
603 $ret['url'] = $ext['url'];
605 if ( isset( $ext['version'] ) ) {
606 $ret['version'] = $ext['version'];
608 if ( isset( $ext['path'] ) ) {
609 $extensionPath = dirname( $ext['path'] );
610 $gitInfo = new GitInfo( $extensionPath );
611 $vcsVersion = $gitInfo->getHeadSHA1();
612 if ( $vcsVersion !== false ) {
613 $ret['vcs-system'] = 'git';
614 $ret['vcs-version'] = $vcsVersion;
615 $ret['vcs-url'] = $gitInfo->getHeadViewUrl();
616 $vcsDate = $gitInfo->getHeadCommitDate();
617 if ( $vcsDate !== false ) {
618 $ret['vcs-date'] = wfTimestamp( TS_ISO_8601, $vcsDate );
622 if ( SpecialVersion::getExtLicenseFileName( $extensionPath ) ) {
623 $ret['license-name'] = isset( $ext['license-name'] ) ? $ext['license-name'] : '';
624 $ret['license'] = SpecialPage::getTitleFor(
625 'Version',
626 "License/{$ext['name']}"
627 )->getLinkURL();
630 if ( SpecialVersion::getExtAuthorsFileName( $extensionPath ) ) {
631 $ret['credits'] = SpecialPage::getTitleFor(
632 'Version',
633 "Credits/{$ext['name']}"
634 )->getLinkURL();
637 $data[] = $ret;
641 ApiResult::setIndexedTagName( $data, 'ext' );
643 return $this->getResult()->addValue( 'query', $property, $data );
646 protected function appendRightsInfo( $property ) {
647 $config = $this->getConfig();
648 $rightsPage = $config->get( 'RightsPage' );
649 if ( is_string( $rightsPage ) ) {
650 $title = Title::newFromText( $rightsPage );
651 $url = wfExpandUrl( $title, PROTO_CURRENT );
652 } else {
653 $title = false;
654 $url = $config->get( 'RightsUrl' );
656 $text = $config->get( 'RightsText' );
657 if ( !$text && $title ) {
658 $text = $title->getPrefixedText();
661 $data = [
662 'url' => $url ?: '',
663 'text' => $text ?: ''
666 return $this->getResult()->addValue( 'query', $property, $data );
669 protected function appendRestrictions( $property ) {
670 $config = $this->getConfig();
671 $data = [
672 'types' => $config->get( 'RestrictionTypes' ),
673 'levels' => $config->get( 'RestrictionLevels' ),
674 'cascadinglevels' => $config->get( 'CascadingRestrictionLevels' ),
675 'semiprotectedlevels' => $config->get( 'SemiprotectedRestrictionLevels' ),
678 ApiResult::setArrayType( $data['types'], 'BCarray' );
679 ApiResult::setArrayType( $data['levels'], 'BCarray' );
680 ApiResult::setArrayType( $data['cascadinglevels'], 'BCarray' );
681 ApiResult::setArrayType( $data['semiprotectedlevels'], 'BCarray' );
683 ApiResult::setIndexedTagName( $data['types'], 'type' );
684 ApiResult::setIndexedTagName( $data['levels'], 'level' );
685 ApiResult::setIndexedTagName( $data['cascadinglevels'], 'level' );
686 ApiResult::setIndexedTagName( $data['semiprotectedlevels'], 'level' );
688 return $this->getResult()->addValue( 'query', $property, $data );
691 public function appendLanguages( $property ) {
692 $params = $this->extractRequestParams();
693 $langCode = isset( $params['inlanguagecode'] ) ? $params['inlanguagecode'] : '';
694 $langNames = Language::fetchLanguageNames( $langCode );
696 $data = [];
698 foreach ( $langNames as $code => $name ) {
699 $lang = [ 'code' => $code ];
700 ApiResult::setContentValue( $lang, 'name', $name );
701 $data[] = $lang;
703 ApiResult::setIndexedTagName( $data, 'lang' );
705 return $this->getResult()->addValue( 'query', $property, $data );
708 public function appendSkins( $property ) {
709 $data = [];
710 $allowed = Skin::getAllowedSkins();
711 $default = Skin::normalizeKey( 'default' );
712 foreach ( Skin::getSkinNames() as $name => $displayName ) {
713 $msg = $this->msg( "skinname-{$name}" );
714 $code = $this->getParameter( 'inlanguagecode' );
715 if ( $code && Language::isValidCode( $code ) ) {
716 $msg->inLanguage( $code );
717 } else {
718 $msg->inContentLanguage();
720 if ( $msg->exists() ) {
721 $displayName = $msg->text();
723 $skin = [ 'code' => $name ];
724 ApiResult::setContentValue( $skin, 'name', $displayName );
725 if ( !isset( $allowed[$name] ) ) {
726 $skin['unusable'] = true;
728 if ( $name === $default ) {
729 $skin['default'] = true;
731 $data[] = $skin;
733 ApiResult::setIndexedTagName( $data, 'skin' );
735 return $this->getResult()->addValue( 'query', $property, $data );
738 public function appendExtensionTags( $property ) {
739 global $wgParser;
740 $wgParser->firstCallInit();
741 $tags = array_map( [ $this, 'formatParserTags' ], $wgParser->getTags() );
742 ApiResult::setArrayType( $tags, 'BCarray' );
743 ApiResult::setIndexedTagName( $tags, 't' );
745 return $this->getResult()->addValue( 'query', $property, $tags );
748 public function appendFunctionHooks( $property ) {
749 global $wgParser;
750 $wgParser->firstCallInit();
751 $hooks = $wgParser->getFunctionHooks();
752 ApiResult::setArrayType( $hooks, 'BCarray' );
753 ApiResult::setIndexedTagName( $hooks, 'h' );
755 return $this->getResult()->addValue( 'query', $property, $hooks );
758 public function appendVariables( $property ) {
759 $variables = MagicWord::getVariableIDs();
760 ApiResult::setArrayType( $variables, 'BCarray' );
761 ApiResult::setIndexedTagName( $variables, 'v' );
763 return $this->getResult()->addValue( 'query', $property, $variables );
766 public function appendProtocols( $property ) {
767 // Make a copy of the global so we don't try to set the _element key of it - bug 45130
768 $protocols = array_values( $this->getConfig()->get( 'UrlProtocols' ) );
769 ApiResult::setArrayType( $protocols, 'BCarray' );
770 ApiResult::setIndexedTagName( $protocols, 'p' );
772 return $this->getResult()->addValue( 'query', $property, $protocols );
775 public function appendDefaultOptions( $property ) {
776 $options = User::getDefaultOptions();
777 $options[ApiResult::META_BC_BOOLS] = array_keys( $options );
778 return $this->getResult()->addValue( 'query', $property, $options );
781 public function appendUploadDialog( $property ) {
782 $config = $this->getConfig()->get( 'UploadDialog' );
783 return $this->getResult()->addValue( 'query', $property, $config );
786 private function formatParserTags( $item ) {
787 return "<{$item}>";
790 public function appendSubscribedHooks( $property ) {
791 $hooks = $this->getConfig()->get( 'Hooks' );
792 $myWgHooks = $hooks;
793 ksort( $myWgHooks );
795 $data = [];
796 foreach ( $myWgHooks as $name => $subscribers ) {
797 $arr = [
798 'name' => $name,
799 'subscribers' => array_map( [ 'SpecialVersion', 'arrayToString' ], $subscribers ),
802 ApiResult::setArrayType( $arr['subscribers'], 'array' );
803 ApiResult::setIndexedTagName( $arr['subscribers'], 's' );
804 $data[] = $arr;
807 ApiResult::setIndexedTagName( $data, 'hook' );
809 return $this->getResult()->addValue( 'query', $property, $data );
812 public function getCacheMode( $params ) {
813 // Messages for $wgExtraInterlanguageLinkPrefixes depend on user language
814 if (
815 count( $this->getConfig()->get( 'ExtraInterlanguageLinkPrefixes' ) ) &&
816 !is_null( $params['prop'] ) &&
817 in_array( 'interwikimap', $params['prop'] )
819 return 'anon-public-user-private';
822 return 'public';
825 public function getAllowedParams() {
826 return [
827 'prop' => [
828 ApiBase::PARAM_DFLT => 'general',
829 ApiBase::PARAM_ISMULTI => true,
830 ApiBase::PARAM_TYPE => [
831 'general',
832 'namespaces',
833 'namespacealiases',
834 'specialpagealiases',
835 'magicwords',
836 'interwikimap',
837 'dbrepllag',
838 'statistics',
839 'usergroups',
840 'libraries',
841 'extensions',
842 'fileextensions',
843 'rightsinfo',
844 'restrictions',
845 'languages',
846 'skins',
847 'extensiontags',
848 'functionhooks',
849 'showhooks',
850 'variables',
851 'protocols',
852 'defaultoptions',
853 'uploaddialog',
855 ApiBase::PARAM_HELP_MSG_PER_VALUE => [],
857 'filteriw' => [
858 ApiBase::PARAM_TYPE => [
859 'local',
860 '!local',
863 'showalldb' => false,
864 'numberingroup' => false,
865 'inlanguagecode' => null,
869 protected function getExamplesMessages() {
870 return [
871 'action=query&meta=siteinfo&siprop=general|namespaces|namespacealiases|statistics'
872 => 'apihelp-query+siteinfo-example-simple',
873 'action=query&meta=siteinfo&siprop=interwikimap&sifilteriw=local'
874 => 'apihelp-query+siteinfo-example-interwiki',
875 'action=query&meta=siteinfo&siprop=dbrepllag&sishowalldb='
876 => 'apihelp-query+siteinfo-example-replag',
880 public function getHelpUrls() {
881 return 'https://www.mediawiki.org/wiki/API:Siteinfo';