Fix missing commit() flag in postgres savepoint class
[mediawiki.git] / includes / api / ApiQuerySiteinfo.php
blob99f722da9bacb76d977424314d55c3ac5199e912
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 $data['allunicodefixes'] = (bool)$config->get( 'AllUnicodeFixes' );
185 $data['fixarabicunicode'] = (bool)$config->get( 'FixArabicUnicode' );
186 $data['fixmalayalamunicode'] = (bool)$config->get( 'FixMalayalamUnicode' );
188 global $IP;
189 $git = SpecialVersion::getGitHeadSha1( $IP );
190 if ( $git ) {
191 $data['git-hash'] = $git;
192 $data['git-branch'] =
193 SpecialVersion::getGitCurrentBranch( $GLOBALS['IP'] );
196 // 'case-insensitive' option is reserved for future
197 $data['case'] = $config->get( 'CapitalLinks' ) ? 'first-letter' : 'case-sensitive';
198 $data['lang'] = $config->get( 'LanguageCode' );
200 $fallbacks = [];
201 foreach ( $wgContLang->getFallbackLanguages() as $code ) {
202 $fallbacks[] = [ 'code' => $code ];
204 $data['fallback'] = $fallbacks;
205 ApiResult::setIndexedTagName( $data['fallback'], 'lang' );
207 if ( $wgContLang->hasVariants() ) {
208 $variants = [];
209 foreach ( $wgContLang->getVariants() as $code ) {
210 $variants[] = [
211 'code' => $code,
212 'name' => $wgContLang->getVariantname( $code ),
215 $data['variants'] = $variants;
216 ApiResult::setIndexedTagName( $data['variants'], 'lang' );
219 $data['rtl'] = $wgContLang->isRTL();
220 $data['fallback8bitEncoding'] = $wgContLang->fallback8bitEncoding();
222 $data['readonly'] = wfReadOnly();
223 if ( $data['readonly'] ) {
224 $data['readonlyreason'] = wfReadOnlyReason();
226 $data['writeapi'] = (bool)$config->get( 'EnableWriteAPI' );
228 $data['maxarticlesize'] = $config->get( 'MaxArticleSize' ) * 1024;
230 $tz = $config->get( 'Localtimezone' );
231 $offset = $config->get( 'LocalTZoffset' );
232 if ( is_null( $tz ) ) {
233 $tz = 'UTC';
234 $offset = 0;
235 } elseif ( is_null( $offset ) ) {
236 $offset = 0;
238 $data['timezone'] = $tz;
239 $data['timeoffset'] = intval( $offset );
240 $data['articlepath'] = $config->get( 'ArticlePath' );
241 $data['scriptpath'] = $config->get( 'ScriptPath' );
242 $data['script'] = $config->get( 'Script' );
243 $data['variantarticlepath'] = $config->get( 'VariantArticlePath' );
244 $data[ApiResult::META_BC_BOOLS][] = 'variantarticlepath';
245 $data['server'] = $config->get( 'Server' );
246 $data['servername'] = $config->get( 'ServerName' );
247 $data['wikiid'] = wfWikiID();
248 $data['time'] = wfTimestamp( TS_ISO_8601, time() );
250 $data['misermode'] = (bool)$config->get( 'MiserMode' );
252 $data['uploadsenabled'] = UploadBase::isEnabled();
253 $data['maxuploadsize'] = UploadBase::getMaxUploadSize();
254 $data['minuploadchunksize'] = (int)$config->get( 'MinUploadChunkSize' );
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] ];
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 );
273 $data['centralidlookupprovider'] = $config->get( 'CentralIdLookupProvider' );
274 $providerIds = array_keys( $config->get( 'CentralIdLookupProviders' ) );
275 $data['allcentralidlookupproviders'] = $providerIds;
277 $data['interwikimagic'] = (bool)$config->get( 'InterwikiMagic' );
278 $data['magiclinks'] = $config->get( 'EnableMagicLinks' );
280 Hooks::run( 'APIQuerySiteInfoGeneralInfo', [ $this, &$data ] );
282 return $this->getResult()->addValue( 'query', $property, $data );
285 protected function appendNamespaces( $property ) {
286 global $wgContLang;
287 $data = [
288 ApiResult::META_TYPE => 'assoc',
290 foreach ( $wgContLang->getFormattedNamespaces() as $ns => $title ) {
291 $data[$ns] = [
292 'id' => intval( $ns ),
293 'case' => MWNamespace::isCapitalized( $ns ) ? 'first-letter' : 'case-sensitive',
295 ApiResult::setContentValue( $data[$ns], 'name', $title );
296 $canonical = MWNamespace::getCanonicalName( $ns );
298 $data[$ns]['subpages'] = MWNamespace::hasSubpages( $ns );
300 if ( $canonical ) {
301 $data[$ns]['canonical'] = strtr( $canonical, '_', ' ' );
304 $data[$ns]['content'] = MWNamespace::isContent( $ns );
305 $data[$ns]['nonincludable'] = MWNamespace::isNonincludable( $ns );
307 $contentmodel = MWNamespace::getNamespaceContentModel( $ns );
308 if ( $contentmodel ) {
309 $data[$ns]['defaultcontentmodel'] = $contentmodel;
313 ApiResult::setArrayType( $data, 'assoc' );
314 ApiResult::setIndexedTagName( $data, 'ns' );
316 return $this->getResult()->addValue( 'query', $property, $data );
319 protected function appendNamespaceAliases( $property ) {
320 global $wgContLang;
321 $aliases = array_merge( $this->getConfig()->get( 'NamespaceAliases' ),
322 $wgContLang->getNamespaceAliases() );
323 $namespaces = $wgContLang->getNamespaces();
324 $data = [];
325 foreach ( $aliases as $title => $ns ) {
326 if ( $namespaces[$ns] == $title ) {
327 // Don't list duplicates
328 continue;
330 $item = [
331 'id' => intval( $ns )
333 ApiResult::setContentValue( $item, 'alias', strtr( $title, '_', ' ' ) );
334 $data[] = $item;
337 sort( $data );
339 ApiResult::setIndexedTagName( $data, 'ns' );
341 return $this->getResult()->addValue( 'query', $property, $data );
344 protected function appendSpecialPageAliases( $property ) {
345 global $wgContLang;
346 $data = [];
347 $aliases = $wgContLang->getSpecialPageAliases();
348 foreach ( SpecialPageFactory::getNames() as $specialpage ) {
349 if ( isset( $aliases[$specialpage] ) ) {
350 $arr = [ 'realname' => $specialpage, 'aliases' => $aliases[$specialpage] ];
351 ApiResult::setIndexedTagName( $arr['aliases'], 'alias' );
352 $data[] = $arr;
355 ApiResult::setIndexedTagName( $data, 'specialpage' );
357 return $this->getResult()->addValue( 'query', $property, $data );
360 protected function appendMagicWords( $property ) {
361 global $wgContLang;
362 $data = [];
363 foreach ( $wgContLang->getMagicWords() as $magicword => $aliases ) {
364 $caseSensitive = array_shift( $aliases );
365 $arr = [ 'name' => $magicword, 'aliases' => $aliases ];
366 $arr['case-sensitive'] = (bool)$caseSensitive;
367 ApiResult::setIndexedTagName( $arr['aliases'], 'alias' );
368 $data[] = $arr;
370 ApiResult::setIndexedTagName( $data, 'magicword' );
372 return $this->getResult()->addValue( 'query', $property, $data );
375 protected function appendInterwikiMap( $property, $filter ) {
376 $local = null;
377 if ( $filter === 'local' ) {
378 $local = 1;
379 } elseif ( $filter === '!local' ) {
380 $local = 0;
381 } elseif ( $filter ) {
382 ApiBase::dieDebug( __METHOD__, "Unknown filter=$filter" );
385 $params = $this->extractRequestParams();
386 $langCode = isset( $params['inlanguagecode'] ) ? $params['inlanguagecode'] : '';
387 $langNames = Language::fetchLanguageNames( $langCode );
389 $getPrefixes = Interwiki::getAllPrefixes( $local );
390 $extraLangPrefixes = $this->getConfig()->get( 'ExtraInterlanguageLinkPrefixes' );
391 $localInterwikis = $this->getConfig()->get( 'LocalInterwikis' );
392 $data = [];
394 foreach ( $getPrefixes as $row ) {
395 $prefix = $row['iw_prefix'];
396 $val = [];
397 $val['prefix'] = $prefix;
398 if ( isset( $row['iw_local'] ) && $row['iw_local'] == '1' ) {
399 $val['local'] = true;
401 if ( isset( $row['iw_trans'] ) && $row['iw_trans'] == '1' ) {
402 $val['trans'] = true;
405 if ( isset( $langNames[$prefix] ) ) {
406 $val['language'] = $langNames[$prefix];
408 if ( in_array( $prefix, $localInterwikis ) ) {
409 $val['localinterwiki'] = true;
411 if ( in_array( $prefix, $extraLangPrefixes ) ) {
412 $val['extralanglink'] = true;
414 $linktext = wfMessage( "interlanguage-link-$prefix" );
415 if ( !$linktext->isDisabled() ) {
416 $val['linktext'] = $linktext->text();
419 $sitename = wfMessage( "interlanguage-link-sitename-$prefix" );
420 if ( !$sitename->isDisabled() ) {
421 $val['sitename'] = $sitename->text();
425 $val['url'] = wfExpandUrl( $row['iw_url'], PROTO_CURRENT );
426 $val['protorel'] = substr( $row['iw_url'], 0, 2 ) == '//';
427 if ( isset( $row['iw_wikiid'] ) && $row['iw_wikiid'] !== '' ) {
428 $val['wikiid'] = $row['iw_wikiid'];
430 if ( isset( $row['iw_api'] ) && $row['iw_api'] !== '' ) {
431 $val['api'] = $row['iw_api'];
434 $data[] = $val;
437 ApiResult::setIndexedTagName( $data, 'iw' );
439 return $this->getResult()->addValue( 'query', $property, $data );
442 protected function appendDbReplLagInfo( $property, $includeAll ) {
443 $data = [];
444 $lb = wfGetLB();
445 $showHostnames = $this->getConfig()->get( 'ShowHostnames' );
446 if ( $includeAll ) {
447 if ( !$showHostnames ) {
448 $this->dieUsage(
449 'Cannot view all servers info unless $wgShowHostnames is true',
450 'includeAllDenied'
454 $lags = $lb->getLagTimes();
455 foreach ( $lags as $i => $lag ) {
456 $data[] = [
457 'host' => $lb->getServerName( $i ),
458 'lag' => $lag
461 } else {
462 list( , $lag, $index ) = $lb->getMaxLag();
463 $data[] = [
464 'host' => $showHostnames
465 ? $lb->getServerName( $index )
466 : '',
467 'lag' => intval( $lag )
471 ApiResult::setIndexedTagName( $data, 'db' );
473 return $this->getResult()->addValue( 'query', $property, $data );
476 protected function appendStatistics( $property ) {
477 $data = [];
478 $data['pages'] = intval( SiteStats::pages() );
479 $data['articles'] = intval( SiteStats::articles() );
480 $data['edits'] = intval( SiteStats::edits() );
481 $data['images'] = intval( SiteStats::images() );
482 $data['users'] = intval( SiteStats::users() );
483 $data['activeusers'] = intval( SiteStats::activeUsers() );
484 $data['admins'] = intval( SiteStats::numberingroup( 'sysop' ) );
485 $data['jobs'] = intval( SiteStats::jobs() );
487 Hooks::run( 'APIQuerySiteInfoStatisticsInfo', [ &$data ] );
489 return $this->getResult()->addValue( 'query', $property, $data );
492 protected function appendUserGroups( $property, $numberInGroup ) {
493 $config = $this->getConfig();
495 $data = [];
496 $result = $this->getResult();
497 $allGroups = array_values( User::getAllGroups() );
498 foreach ( $config->get( 'GroupPermissions' ) as $group => $permissions ) {
499 $arr = [
500 'name' => $group,
501 'rights' => array_keys( $permissions, true ),
504 if ( $numberInGroup ) {
505 $autopromote = $config->get( 'Autopromote' );
507 if ( $group == 'user' ) {
508 $arr['number'] = SiteStats::users();
509 // '*' and autopromote groups have no size
510 } elseif ( $group !== '*' && !isset( $autopromote[$group] ) ) {
511 $arr['number'] = SiteStats::numberingroup( $group );
515 $groupArr = [
516 'add' => $config->get( 'AddGroups' ),
517 'remove' => $config->get( 'RemoveGroups' ),
518 'add-self' => $config->get( 'GroupsAddToSelf' ),
519 'remove-self' => $config->get( 'GroupsRemoveFromSelf' )
522 foreach ( $groupArr as $type => $rights ) {
523 if ( isset( $rights[$group] ) ) {
524 if ( $rights[$group] === true ) {
525 $groups = $allGroups;
526 } else {
527 $groups = array_intersect( $rights[$group], $allGroups );
529 if ( $groups ) {
530 $arr[$type] = $groups;
531 ApiResult::setArrayType( $arr[$type], 'BCarray' );
532 ApiResult::setIndexedTagName( $arr[$type], 'group' );
537 ApiResult::setIndexedTagName( $arr['rights'], 'permission' );
538 $data[] = $arr;
541 ApiResult::setIndexedTagName( $data, 'group' );
543 return $result->addValue( 'query', $property, $data );
546 protected function appendFileExtensions( $property ) {
547 $data = [];
548 foreach ( array_unique( $this->getConfig()->get( 'FileExtensions' ) ) as $ext ) {
549 $data[] = [ 'ext' => $ext ];
551 ApiResult::setIndexedTagName( $data, 'fe' );
553 return $this->getResult()->addValue( 'query', $property, $data );
556 protected function appendInstalledLibraries( $property ) {
557 global $IP;
558 $path = "$IP/vendor/composer/installed.json";
559 if ( !file_exists( $path ) ) {
560 return true;
563 $data = [];
564 $installed = new ComposerInstalled( $path );
565 foreach ( $installed->getInstalledDependencies() as $name => $info ) {
566 if ( strpos( $info['type'], 'mediawiki-' ) === 0 ) {
567 // Skip any extensions or skins since they'll be listed
568 // in their proper section
569 continue;
571 $data[] = [
572 'name' => $name,
573 'version' => $info['version'],
576 ApiResult::setIndexedTagName( $data, 'library' );
578 return $this->getResult()->addValue( 'query', $property, $data );
582 protected function appendExtensions( $property ) {
583 $data = [];
584 foreach ( $this->getConfig()->get( 'ExtensionCredits' ) as $type => $extensions ) {
585 foreach ( $extensions as $ext ) {
586 $ret = [];
587 $ret['type'] = $type;
588 if ( isset( $ext['name'] ) ) {
589 $ret['name'] = $ext['name'];
591 if ( isset( $ext['namemsg'] ) ) {
592 $ret['namemsg'] = $ext['namemsg'];
594 if ( isset( $ext['description'] ) ) {
595 $ret['description'] = $ext['description'];
597 if ( isset( $ext['descriptionmsg'] ) ) {
598 // Can be a string or [ key, param1, param2, ... ]
599 if ( is_array( $ext['descriptionmsg'] ) ) {
600 $ret['descriptionmsg'] = $ext['descriptionmsg'][0];
601 $ret['descriptionmsgparams'] = array_slice( $ext['descriptionmsg'], 1 );
602 ApiResult::setIndexedTagName( $ret['descriptionmsgparams'], 'param' );
603 } else {
604 $ret['descriptionmsg'] = $ext['descriptionmsg'];
607 if ( isset( $ext['author'] ) ) {
608 $ret['author'] = is_array( $ext['author'] ) ?
609 implode( ', ', $ext['author'] ) : $ext['author'];
611 if ( isset( $ext['url'] ) ) {
612 $ret['url'] = $ext['url'];
614 if ( isset( $ext['version'] ) ) {
615 $ret['version'] = $ext['version'];
617 if ( isset( $ext['path'] ) ) {
618 $extensionPath = dirname( $ext['path'] );
619 $gitInfo = new GitInfo( $extensionPath );
620 $vcsVersion = $gitInfo->getHeadSHA1();
621 if ( $vcsVersion !== false ) {
622 $ret['vcs-system'] = 'git';
623 $ret['vcs-version'] = $vcsVersion;
624 $ret['vcs-url'] = $gitInfo->getHeadViewUrl();
625 $vcsDate = $gitInfo->getHeadCommitDate();
626 if ( $vcsDate !== false ) {
627 $ret['vcs-date'] = wfTimestamp( TS_ISO_8601, $vcsDate );
631 if ( SpecialVersion::getExtLicenseFileName( $extensionPath ) ) {
632 $ret['license-name'] = isset( $ext['license-name'] ) ? $ext['license-name'] : '';
633 $ret['license'] = SpecialPage::getTitleFor(
634 'Version',
635 "License/{$ext['name']}"
636 )->getLinkURL();
639 if ( SpecialVersion::getExtAuthorsFileName( $extensionPath ) ) {
640 $ret['credits'] = SpecialPage::getTitleFor(
641 'Version',
642 "Credits/{$ext['name']}"
643 )->getLinkURL();
646 $data[] = $ret;
650 ApiResult::setIndexedTagName( $data, 'ext' );
652 return $this->getResult()->addValue( 'query', $property, $data );
655 protected function appendRightsInfo( $property ) {
656 $config = $this->getConfig();
657 $rightsPage = $config->get( 'RightsPage' );
658 if ( is_string( $rightsPage ) ) {
659 $title = Title::newFromText( $rightsPage );
660 $url = wfExpandUrl( $title, PROTO_CURRENT );
661 } else {
662 $title = false;
663 $url = $config->get( 'RightsUrl' );
665 $text = $config->get( 'RightsText' );
666 if ( !$text && $title ) {
667 $text = $title->getPrefixedText();
670 $data = [
671 'url' => $url ?: '',
672 'text' => $text ?: ''
675 return $this->getResult()->addValue( 'query', $property, $data );
678 protected function appendRestrictions( $property ) {
679 $config = $this->getConfig();
680 $data = [
681 'types' => $config->get( 'RestrictionTypes' ),
682 'levels' => $config->get( 'RestrictionLevels' ),
683 'cascadinglevels' => $config->get( 'CascadingRestrictionLevels' ),
684 'semiprotectedlevels' => $config->get( 'SemiprotectedRestrictionLevels' ),
687 ApiResult::setArrayType( $data['types'], 'BCarray' );
688 ApiResult::setArrayType( $data['levels'], 'BCarray' );
689 ApiResult::setArrayType( $data['cascadinglevels'], 'BCarray' );
690 ApiResult::setArrayType( $data['semiprotectedlevels'], 'BCarray' );
692 ApiResult::setIndexedTagName( $data['types'], 'type' );
693 ApiResult::setIndexedTagName( $data['levels'], 'level' );
694 ApiResult::setIndexedTagName( $data['cascadinglevels'], 'level' );
695 ApiResult::setIndexedTagName( $data['semiprotectedlevels'], 'level' );
697 return $this->getResult()->addValue( 'query', $property, $data );
700 public function appendLanguages( $property ) {
701 $params = $this->extractRequestParams();
702 $langCode = isset( $params['inlanguagecode'] ) ? $params['inlanguagecode'] : '';
703 $langNames = Language::fetchLanguageNames( $langCode );
705 $data = [];
707 foreach ( $langNames as $code => $name ) {
708 $lang = [ 'code' => $code ];
709 ApiResult::setContentValue( $lang, 'name', $name );
710 $data[] = $lang;
712 ApiResult::setIndexedTagName( $data, 'lang' );
714 return $this->getResult()->addValue( 'query', $property, $data );
717 public function appendSkins( $property ) {
718 $data = [];
719 $allowed = Skin::getAllowedSkins();
720 $default = Skin::normalizeKey( 'default' );
721 foreach ( Skin::getSkinNames() as $name => $displayName ) {
722 $msg = $this->msg( "skinname-{$name}" );
723 $code = $this->getParameter( 'inlanguagecode' );
724 if ( $code && Language::isValidCode( $code ) ) {
725 $msg->inLanguage( $code );
726 } else {
727 $msg->inContentLanguage();
729 if ( $msg->exists() ) {
730 $displayName = $msg->text();
732 $skin = [ 'code' => $name ];
733 ApiResult::setContentValue( $skin, 'name', $displayName );
734 if ( !isset( $allowed[$name] ) ) {
735 $skin['unusable'] = true;
737 if ( $name === $default ) {
738 $skin['default'] = true;
740 $data[] = $skin;
742 ApiResult::setIndexedTagName( $data, 'skin' );
744 return $this->getResult()->addValue( 'query', $property, $data );
747 public function appendExtensionTags( $property ) {
748 global $wgParser;
749 $wgParser->firstCallInit();
750 $tags = array_map( [ $this, 'formatParserTags' ], $wgParser->getTags() );
751 ApiResult::setArrayType( $tags, 'BCarray' );
752 ApiResult::setIndexedTagName( $tags, 't' );
754 return $this->getResult()->addValue( 'query', $property, $tags );
757 public function appendFunctionHooks( $property ) {
758 global $wgParser;
759 $wgParser->firstCallInit();
760 $hooks = $wgParser->getFunctionHooks();
761 ApiResult::setArrayType( $hooks, 'BCarray' );
762 ApiResult::setIndexedTagName( $hooks, 'h' );
764 return $this->getResult()->addValue( 'query', $property, $hooks );
767 public function appendVariables( $property ) {
768 $variables = MagicWord::getVariableIDs();
769 ApiResult::setArrayType( $variables, 'BCarray' );
770 ApiResult::setIndexedTagName( $variables, 'v' );
772 return $this->getResult()->addValue( 'query', $property, $variables );
775 public function appendProtocols( $property ) {
776 // Make a copy of the global so we don't try to set the _element key of it - bug 45130
777 $protocols = array_values( $this->getConfig()->get( 'UrlProtocols' ) );
778 ApiResult::setArrayType( $protocols, 'BCarray' );
779 ApiResult::setIndexedTagName( $protocols, 'p' );
781 return $this->getResult()->addValue( 'query', $property, $protocols );
784 public function appendDefaultOptions( $property ) {
785 $options = User::getDefaultOptions();
786 $options[ApiResult::META_BC_BOOLS] = array_keys( $options );
787 return $this->getResult()->addValue( 'query', $property, $options );
790 public function appendUploadDialog( $property ) {
791 $config = $this->getConfig()->get( 'UploadDialog' );
792 return $this->getResult()->addValue( 'query', $property, $config );
795 private function formatParserTags( $item ) {
796 return "<{$item}>";
799 public function appendSubscribedHooks( $property ) {
800 $hooks = $this->getConfig()->get( 'Hooks' );
801 $myWgHooks = $hooks;
802 ksort( $myWgHooks );
804 $data = [];
805 foreach ( $myWgHooks as $name => $subscribers ) {
806 $arr = [
807 'name' => $name,
808 'subscribers' => array_map( [ 'SpecialVersion', 'arrayToString' ], $subscribers ),
811 ApiResult::setArrayType( $arr['subscribers'], 'array' );
812 ApiResult::setIndexedTagName( $arr['subscribers'], 's' );
813 $data[] = $arr;
816 ApiResult::setIndexedTagName( $data, 'hook' );
818 return $this->getResult()->addValue( 'query', $property, $data );
821 public function getCacheMode( $params ) {
822 // Messages for $wgExtraInterlanguageLinkPrefixes depend on user language
823 if (
824 count( $this->getConfig()->get( 'ExtraInterlanguageLinkPrefixes' ) ) &&
825 !is_null( $params['prop'] ) &&
826 in_array( 'interwikimap', $params['prop'] )
828 return 'anon-public-user-private';
831 return 'public';
834 public function getAllowedParams() {
835 return [
836 'prop' => [
837 ApiBase::PARAM_DFLT => 'general',
838 ApiBase::PARAM_ISMULTI => true,
839 ApiBase::PARAM_TYPE => [
840 'general',
841 'namespaces',
842 'namespacealiases',
843 'specialpagealiases',
844 'magicwords',
845 'interwikimap',
846 'dbrepllag',
847 'statistics',
848 'usergroups',
849 'libraries',
850 'extensions',
851 'fileextensions',
852 'rightsinfo',
853 'restrictions',
854 'languages',
855 'skins',
856 'extensiontags',
857 'functionhooks',
858 'showhooks',
859 'variables',
860 'protocols',
861 'defaultoptions',
862 'uploaddialog',
864 ApiBase::PARAM_HELP_MSG_PER_VALUE => [],
866 'filteriw' => [
867 ApiBase::PARAM_TYPE => [
868 'local',
869 '!local',
872 'showalldb' => false,
873 'numberingroup' => false,
874 'inlanguagecode' => null,
878 protected function getExamplesMessages() {
879 return [
880 'action=query&meta=siteinfo&siprop=general|namespaces|namespacealiases|statistics'
881 => 'apihelp-query+siteinfo-example-simple',
882 'action=query&meta=siteinfo&siprop=interwikimap&sifilteriw=local'
883 => 'apihelp-query+siteinfo-example-interwiki',
884 'action=query&meta=siteinfo&siprop=dbrepllag&sishowalldb='
885 => 'apihelp-query+siteinfo-example-replag',
889 public function getHelpUrls() {
890 return 'https://www.mediawiki.org/wiki/API:Siteinfo';