Merge "DatabaseMssql: Don't duplicate body of makeList()"
[mediawiki.git] / includes / api / ApiQuerySiteinfo.php
blob5ac10366e5d82bac0cdbde7654a88822ef02918e
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 = array();
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 default:
112 ApiBase::dieDebug( __METHOD__, "Unknown prop=$p" );
114 if ( !$fit ) {
115 // Abuse siprop as a query-continue parameter
116 // and set it to all unprocessed props
117 $this->setContinueEnumParameter( 'prop', implode( '|',
118 array_diff( $params['prop'], $done ) ) );
119 break;
121 $done[] = $p;
125 protected function appendGeneralInfo( $property ) {
126 global $wgContLang;
128 $config = $this->getConfig();
130 $data = array();
131 $mainPage = Title::newMainPage();
132 $data['mainpage'] = $mainPage->getPrefixedText();
133 $data['base'] = wfExpandUrl( $mainPage->getFullURL(), PROTO_CURRENT );
134 $data['sitename'] = $config->get( 'Sitename' );
136 // wgLogo can either be a relative or an absolute path
137 // make sure we always return an absolute path
138 $data['logo'] = wfExpandUrl( $config->get( 'Logo' ), PROTO_RELATIVE );
140 $data['generator'] = "MediaWiki {$config->get( 'Version' )}";
142 $data['phpversion'] = PHP_VERSION;
143 $data['phpsapi'] = PHP_SAPI;
144 if ( defined( 'HHVM_VERSION' ) ) {
145 $data['hhvmversion'] = HHVM_VERSION;
147 $data['dbtype'] = $config->get( 'DBtype' );
148 $data['dbversion'] = $this->getDB()->getServerVersion();
150 $allowFrom = array( '' );
151 $allowException = true;
152 if ( !$config->get( 'AllowExternalImages' ) ) {
153 if ( $config->get( 'EnableImageWhitelist' ) ) {
154 $data['imagewhitelistenabled'] = '';
156 $allowFrom = $config->get( 'AllowExternalImagesFrom' );
157 $allowException = !empty( $allowFrom );
159 if ( $allowException ) {
160 $data['externalimages'] = (array)$allowFrom;
161 $this->getResult()->setIndexedTagName( $data['externalimages'], 'prefix' );
164 if ( !$config->get( 'DisableLangConversion' ) ) {
165 $data['langconversion'] = '';
168 if ( !$config->get( 'DisableTitleConversion' ) ) {
169 $data['titleconversion'] = '';
172 if ( $wgContLang->linkPrefixExtension() ) {
173 $linkPrefixCharset = $wgContLang->linkPrefixCharset();
174 $data['linkprefixcharset'] = $linkPrefixCharset;
175 // For backwards compatibility
176 $data['linkprefix'] = "/^((?>.*[^$linkPrefixCharset]|))(.+)$/sDu";
177 } else {
178 $data['linkprefixcharset'] = '';
179 $data['linkprefix'] = '';
182 $linktrail = $wgContLang->linkTrail();
183 if ( $linktrail ) {
184 $data['linktrail'] = $linktrail;
185 } else {
186 $data['linktrail'] = '';
189 $data['legaltitlechars'] = Title::legalChars();
191 global $IP;
192 $git = SpecialVersion::getGitHeadSha1( $IP );
193 if ( $git ) {
194 $data['git-hash'] = $git;
195 $data['git-branch'] =
196 SpecialVersion::getGitCurrentBranch( $GLOBALS['IP'] );
197 } else {
198 $svn = SpecialVersion::getSvnRevision( $IP );
199 if ( $svn ) {
200 $data['rev'] = $svn;
204 // 'case-insensitive' option is reserved for future
205 $data['case'] = $config->get( 'CapitalLinks' ) ? 'first-letter' : 'case-sensitive';
206 $data['lang'] = $config->get( 'LanguageCode' );
208 $fallbacks = array();
209 foreach ( $wgContLang->getFallbackLanguages() as $code ) {
210 $fallbacks[] = array( 'code' => $code );
212 $data['fallback'] = $fallbacks;
213 $this->getResult()->setIndexedTagName( $data['fallback'], 'lang' );
215 if ( $wgContLang->hasVariants() ) {
216 $variants = array();
217 foreach ( $wgContLang->getVariants() as $code ) {
218 $variants[] = array(
219 'code' => $code,
220 'name' => $wgContLang->getVariantname( $code ),
223 $data['variants'] = $variants;
224 $this->getResult()->setIndexedTagName( $data['variants'], 'lang' );
227 if ( $wgContLang->isRTL() ) {
228 $data['rtl'] = '';
230 $data['fallback8bitEncoding'] = $wgContLang->fallback8bitEncoding();
232 if ( wfReadOnly() ) {
233 $data['readonly'] = '';
234 $data['readonlyreason'] = wfReadOnlyReason();
236 if ( $config->get( 'EnableWriteAPI' ) ) {
237 $data['writeapi'] = '';
240 $tz = $config->get( 'Localtimezone' );
241 $offset = $config->get( 'LocalTZoffset' );
242 if ( is_null( $tz ) ) {
243 $tz = 'UTC';
244 $offset = 0;
245 } elseif ( is_null( $offset ) ) {
246 $offset = 0;
248 $data['timezone'] = $tz;
249 $data['timeoffset'] = intval( $offset );
250 $data['articlepath'] = $config->get( 'ArticlePath' );
251 $data['scriptpath'] = $config->get( 'ScriptPath' );
252 $data['script'] = $config->get( 'Script' );
253 $data['variantarticlepath'] = $config->get( 'VariantArticlePath' );
254 $data['server'] = $config->get( 'Server' );
255 $data['servername'] = $config->get( 'ServerName' );
256 $data['wikiid'] = wfWikiID();
257 $data['time'] = wfTimestamp( TS_ISO_8601, time() );
259 if ( $config->get( 'MiserMode' ) ) {
260 $data['misermode'] = '';
263 $data['maxuploadsize'] = UploadBase::getMaxUploadSize();
265 $data['thumblimits'] = $config->get( 'ThumbLimits' );
266 $this->getResult()->setIndexedTagName( $data['thumblimits'], 'limit' );
267 $data['imagelimits'] = array();
268 $this->getResult()->setIndexedTagName( $data['imagelimits'], 'limit' );
269 foreach ( $config->get( 'ImageLimits' ) as $k => $limit ) {
270 $data['imagelimits'][$k] = array( 'width' => $limit[0], 'height' => $limit[1] );
273 $favicon = $config->get( 'Favicon' );
274 if ( !empty( $favicon ) ) {
275 // wgFavicon can either be a relative or an absolute path
276 // make sure we always return an absolute path
277 $data['favicon'] = wfExpandUrl( $favicon, PROTO_RELATIVE );
280 Hooks::run( 'APIQuerySiteInfoGeneralInfo', array( $this, &$data ) );
282 return $this->getResult()->addValue( 'query', $property, $data );
285 protected function appendNamespaces( $property ) {
286 global $wgContLang;
287 $data = array();
288 foreach ( $wgContLang->getFormattedNamespaces() as $ns => $title ) {
289 $data[$ns] = array(
290 'id' => intval( $ns ),
291 'case' => MWNamespace::isCapitalized( $ns ) ? 'first-letter' : 'case-sensitive',
293 ApiResult::setContent( $data[$ns], $title );
294 $canonical = MWNamespace::getCanonicalName( $ns );
296 if ( MWNamespace::hasSubpages( $ns ) ) {
297 $data[$ns]['subpages'] = '';
300 if ( $canonical ) {
301 $data[$ns]['canonical'] = strtr( $canonical, '_', ' ' );
304 if ( MWNamespace::isContent( $ns ) ) {
305 $data[$ns]['content'] = '';
308 if ( MWNamespace::isNonincludable( $ns ) ) {
309 $data[$ns]['nonincludable'] = '';
312 $contentmodel = MWNamespace::getNamespaceContentModel( $ns );
313 if ( $contentmodel ) {
314 $data[$ns]['defaultcontentmodel'] = $contentmodel;
318 $this->getResult()->setIndexedTagName( $data, 'ns' );
320 return $this->getResult()->addValue( 'query', $property, $data );
323 protected function appendNamespaceAliases( $property ) {
324 global $wgContLang;
325 $aliases = array_merge( $this->getConfig()->get( 'NamespaceAliases' ),
326 $wgContLang->getNamespaceAliases() );
327 $namespaces = $wgContLang->getNamespaces();
328 $data = array();
329 foreach ( $aliases as $title => $ns ) {
330 if ( $namespaces[$ns] == $title ) {
331 // Don't list duplicates
332 continue;
334 $item = array(
335 'id' => intval( $ns )
337 ApiResult::setContent( $item, strtr( $title, '_', ' ' ) );
338 $data[] = $item;
341 sort( $data );
343 $this->getResult()->setIndexedTagName( $data, 'ns' );
345 return $this->getResult()->addValue( 'query', $property, $data );
348 protected function appendSpecialPageAliases( $property ) {
349 global $wgContLang;
350 $data = array();
351 $aliases = $wgContLang->getSpecialPageAliases();
352 foreach ( SpecialPageFactory::getNames() as $specialpage ) {
353 if ( isset( $aliases[$specialpage] ) ) {
354 $arr = array( 'realname' => $specialpage, 'aliases' => $aliases[$specialpage] );
355 $this->getResult()->setIndexedTagName( $arr['aliases'], 'alias' );
356 $data[] = $arr;
359 $this->getResult()->setIndexedTagName( $data, 'specialpage' );
361 return $this->getResult()->addValue( 'query', $property, $data );
364 protected function appendMagicWords( $property ) {
365 global $wgContLang;
366 $data = array();
367 foreach ( $wgContLang->getMagicWords() as $magicword => $aliases ) {
368 $caseSensitive = array_shift( $aliases );
369 $arr = array( 'name' => $magicword, 'aliases' => $aliases );
370 if ( $caseSensitive ) {
371 $arr['case-sensitive'] = '';
373 $this->getResult()->setIndexedTagName( $arr['aliases'], 'alias' );
374 $data[] = $arr;
376 $this->getResult()->setIndexedTagName( $data, 'magicword' );
378 return $this->getResult()->addValue( 'query', $property, $data );
381 protected function appendInterwikiMap( $property, $filter ) {
382 $local = null;
383 if ( $filter === 'local' ) {
384 $local = 1;
385 } elseif ( $filter === '!local' ) {
386 $local = 0;
387 } elseif ( $filter ) {
388 ApiBase::dieDebug( __METHOD__, "Unknown filter=$filter" );
391 $params = $this->extractRequestParams();
392 $langCode = isset( $params['inlanguagecode'] ) ? $params['inlanguagecode'] : '';
393 $langNames = Language::fetchLanguageNames( $langCode );
395 $getPrefixes = Interwiki::getAllPrefixes( $local );
396 $extraLangPrefixes = $this->getConfig()->get( 'ExtraInterlanguageLinkPrefixes' );
397 $localInterwikis = $this->getConfig()->get( 'LocalInterwikis' );
398 $data = array();
400 foreach ( $getPrefixes as $row ) {
401 $prefix = $row['iw_prefix'];
402 $val = array();
403 $val['prefix'] = $prefix;
404 if ( isset( $row['iw_local'] ) && $row['iw_local'] == '1' ) {
405 $val['local'] = '';
407 if ( isset( $row['iw_trans'] ) && $row['iw_trans'] == '1' ) {
408 $val['trans'] = '';
411 if ( isset( $langNames[$prefix] ) ) {
412 $val['language'] = $langNames[$prefix];
414 if ( in_array( $prefix, $localInterwikis ) ) {
415 $val['localinterwiki'] = '';
417 if ( in_array( $prefix, $extraLangPrefixes ) ) {
418 $val['extralanglink'] = '';
420 $linktext = wfMessage( "interlanguage-link-$prefix" );
421 if ( !$linktext->isDisabled() ) {
422 $val['linktext'] = $linktext->text();
425 $sitename = wfMessage( "interlanguage-link-sitename-$prefix" );
426 if ( !$sitename->isDisabled() ) {
427 $val['sitename'] = $sitename->text();
431 $val['url'] = wfExpandUrl( $row['iw_url'], PROTO_CURRENT );
432 if ( substr( $row['iw_url'], 0, 2 ) == '//' ) {
433 $val['protorel'] = '';
435 if ( isset( $row['iw_wikiid'] ) && $row['iw_wikiid'] !== '' ) {
436 $val['wikiid'] = $row['iw_wikiid'];
438 if ( isset( $row['iw_api'] ) && $row['iw_api'] !== '' ) {
439 $val['api'] = $row['iw_api'];
442 $data[] = $val;
445 $this->getResult()->setIndexedTagName( $data, 'iw' );
447 return $this->getResult()->addValue( 'query', $property, $data );
450 protected function appendDbReplLagInfo( $property, $includeAll ) {
451 $data = array();
452 $lb = wfGetLB();
453 $showHostnames = $this->getConfig()->get( 'ShowHostnames' );
454 if ( $includeAll ) {
455 if ( !$showHostnames ) {
456 $this->dieUsage(
457 'Cannot view all servers info unless $wgShowHostnames is true',
458 'includeAllDenied'
462 $lags = $lb->getLagTimes();
463 foreach ( $lags as $i => $lag ) {
464 $data[] = array(
465 'host' => $lb->getServerName( $i ),
466 'lag' => $lag
469 } else {
470 list( , $lag, $index ) = $lb->getMaxLag();
471 $data[] = array(
472 'host' => $showHostnames
473 ? $lb->getServerName( $index )
474 : '',
475 'lag' => intval( $lag )
479 $result = $this->getResult();
480 $result->setIndexedTagName( $data, 'db' );
482 return $this->getResult()->addValue( 'query', $property, $data );
485 protected function appendStatistics( $property ) {
486 $data = array();
487 $data['pages'] = intval( SiteStats::pages() );
488 $data['articles'] = intval( SiteStats::articles() );
489 $data['edits'] = intval( SiteStats::edits() );
490 $data['images'] = intval( SiteStats::images() );
491 $data['users'] = intval( SiteStats::users() );
492 $data['activeusers'] = intval( SiteStats::activeUsers() );
493 $data['admins'] = intval( SiteStats::numberingroup( 'sysop' ) );
494 $data['jobs'] = intval( SiteStats::jobs() );
496 Hooks::run( 'APIQuerySiteInfoStatisticsInfo', array( &$data ) );
498 return $this->getResult()->addValue( 'query', $property, $data );
501 protected function appendUserGroups( $property, $numberInGroup ) {
502 $config = $this->getConfig();
504 $data = array();
505 $result = $this->getResult();
506 $allGroups = User::getAllGroups();
507 foreach ( $config->get( 'GroupPermissions' ) as $group => $permissions ) {
508 $arr = array(
509 'name' => $group,
510 'rights' => array_keys( $permissions, true ),
513 if ( $numberInGroup ) {
514 $autopromote = $config->get( 'Autopromote' );
516 if ( $group == 'user' ) {
517 $arr['number'] = SiteStats::users();
518 // '*' and autopromote groups have no size
519 } elseif ( $group !== '*' && !isset( $autopromote[$group] ) ) {
520 $arr['number'] = SiteStats::numberInGroup( $group );
524 $groupArr = array(
525 'add' => $config->get( 'AddGroups' ),
526 'remove' => $config->get( 'RemoveGroups' ),
527 'add-self' => $config->get( 'GroupsAddToSelf' ),
528 'remove-self' => $config->get( 'GroupsRemoveFromSelf' )
531 foreach ( $groupArr as $type => $rights ) {
532 if ( isset( $rights[$group] ) ) {
533 $groups = array_intersect( $rights[$group], $allGroups );
534 if ( $groups ) {
535 $arr[$type] = $groups;
536 $result->setIndexedTagName( $arr[$type], 'group' );
541 $result->setIndexedTagName( $arr['rights'], 'permission' );
542 $data[] = $arr;
545 $result->setIndexedTagName( $data, 'group' );
547 return $result->addValue( 'query', $property, $data );
550 protected function appendFileExtensions( $property ) {
551 $data = array();
552 foreach ( array_unique( $this->getConfig()->get( 'FileExtensions' ) ) as $ext ) {
553 $data[] = array( 'ext' => $ext );
555 $this->getResult()->setIndexedTagName( $data, 'fe' );
557 return $this->getResult()->addValue( 'query', $property, $data );
560 protected function appendInstalledLibraries( $property ) {
561 global $IP;
562 $path = "$IP/composer.lock";
563 if ( !file_exists( $path ) ) {
564 // Maybe they're using mediawiki/vendor?
565 $path = "$IP/vendor/composer.lock";
566 if ( !file_exists( $path ) ) {
567 return true;
571 $data = array();
572 $lock = new ComposerLock( $path );
573 foreach ( $lock->getInstalledDependencies() as $name => $info ) {
574 if ( strpos( $info['type'], 'mediawiki-' ) === 0 ) {
575 // Skip any extensions or skins since they'll be listed
576 // in their proper section
577 continue;
579 $data[] = array(
580 'name' => $name,
581 'version' => $info['version'],
584 $this->getResult()->setIndexedTagName( $data, 'library' );
586 return $this->getResult()->addValue( 'query', $property, $data );
590 protected function appendExtensions( $property ) {
591 $data = array();
592 foreach ( $this->getConfig()->get( 'ExtensionCredits' ) as $type => $extensions ) {
593 foreach ( $extensions as $ext ) {
594 $ret = array();
595 $ret['type'] = $type;
596 if ( isset( $ext['name'] ) ) {
597 $ret['name'] = $ext['name'];
599 if ( isset( $ext['namemsg'] ) ) {
600 $ret['namemsg'] = $ext['namemsg'];
602 if ( isset( $ext['description'] ) ) {
603 $ret['description'] = $ext['description'];
605 if ( isset( $ext['descriptionmsg'] ) ) {
606 // Can be a string or array( key, param1, param2, ... )
607 if ( is_array( $ext['descriptionmsg'] ) ) {
608 $ret['descriptionmsg'] = $ext['descriptionmsg'][0];
609 $ret['descriptionmsgparams'] = array_slice( $ext['descriptionmsg'], 1 );
610 $this->getResult()->setIndexedTagName( $ret['descriptionmsgparams'], 'param' );
611 } else {
612 $ret['descriptionmsg'] = $ext['descriptionmsg'];
615 if ( isset( $ext['author'] ) ) {
616 $ret['author'] = is_array( $ext['author'] ) ?
617 implode( ', ', $ext['author'] ) : $ext['author'];
619 if ( isset( $ext['url'] ) ) {
620 $ret['url'] = $ext['url'];
622 if ( isset( $ext['version'] ) ) {
623 $ret['version'] = $ext['version'];
624 } elseif ( isset( $ext['svn-revision'] ) &&
625 preg_match( '/\$(?:Rev|LastChangedRevision|Revision): *(\d+)/',
626 $ext['svn-revision'], $m )
628 $ret['version'] = 'r' . $m[1];
630 if ( isset( $ext['path'] ) ) {
631 $extensionPath = dirname( $ext['path'] );
632 $gitInfo = new GitInfo( $extensionPath );
633 $vcsVersion = $gitInfo->getHeadSHA1();
634 if ( $vcsVersion !== false ) {
635 $ret['vcs-system'] = 'git';
636 $ret['vcs-version'] = $vcsVersion;
637 $ret['vcs-url'] = $gitInfo->getHeadViewUrl();
638 $vcsDate = $gitInfo->getHeadCommitDate();
639 if ( $vcsDate !== false ) {
640 $ret['vcs-date'] = wfTimestamp( TS_ISO_8601, $vcsDate );
642 } else {
643 $svnInfo = SpecialVersion::getSvnInfo( $extensionPath );
644 if ( $svnInfo !== false ) {
645 $ret['vcs-system'] = 'svn';
646 $ret['vcs-version'] = $svnInfo['checkout-rev'];
647 $ret['vcs-url'] = isset( $svnInfo['viewvc-url'] ) ? $svnInfo['viewvc-url'] : '';
651 if ( SpecialVersion::getExtLicenseFileName( $extensionPath ) ) {
652 $ret['license-name'] = isset( $ext['license-name'] ) ? $ext['license-name'] : '';
653 $ret['license'] = SpecialPage::getTitleFor(
654 'Version',
655 "License/{$ext['name']}"
656 )->getLinkURL();
659 if ( SpecialVersion::getExtAuthorsFileName( $extensionPath ) ) {
660 $ret['credits'] = SpecialPage::getTitleFor(
661 'Version',
662 "Credits/{$ext['name']}"
663 )->getLinkURL();
666 $data[] = $ret;
670 $this->getResult()->setIndexedTagName( $data, 'ext' );
672 return $this->getResult()->addValue( 'query', $property, $data );
675 protected function appendRightsInfo( $property ) {
676 $config = $this->getConfig();
677 $title = Title::newFromText( $config->get( 'RightsPage' ) );
678 $url = $title ? wfExpandUrl( $title->getFullURL(), PROTO_CURRENT ) : $config->get( 'RightsUrl' );
679 $text = $config->get( 'RightsText' );
680 if ( !$text && $title ) {
681 $text = $title->getPrefixedText();
684 $data = array(
685 'url' => $url ? $url : '',
686 'text' => $text ? $text : ''
689 return $this->getResult()->addValue( 'query', $property, $data );
692 protected function appendRestrictions( $property ) {
693 $config = $this->getConfig();
694 $data = array(
695 'types' => $config->get( 'RestrictionTypes' ),
696 'levels' => $config->get( 'RestrictionLevels' ),
697 'cascadinglevels' => $config->get( 'CascadingRestrictionLevels' ),
698 'semiprotectedlevels' => $config->get( 'SemiprotectedRestrictionLevels' ),
701 $this->getResult()->setIndexedTagName( $data['types'], 'type' );
702 $this->getResult()->setIndexedTagName( $data['levels'], 'level' );
703 $this->getResult()->setIndexedTagName( $data['cascadinglevels'], 'level' );
704 $this->getResult()->setIndexedTagName( $data['semiprotectedlevels'], 'level' );
706 return $this->getResult()->addValue( 'query', $property, $data );
709 public function appendLanguages( $property ) {
710 $params = $this->extractRequestParams();
711 $langCode = isset( $params['inlanguagecode'] ) ? $params['inlanguagecode'] : '';
712 $langNames = Language::fetchLanguageNames( $langCode );
714 $data = array();
716 foreach ( $langNames as $code => $name ) {
717 $lang = array( 'code' => $code );
718 ApiResult::setContent( $lang, $name );
719 $data[] = $lang;
721 $this->getResult()->setIndexedTagName( $data, 'lang' );
723 return $this->getResult()->addValue( 'query', $property, $data );
726 public function appendSkins( $property ) {
727 $data = array();
728 $allowed = Skin::getAllowedSkins();
729 $default = Skin::normalizeKey( 'default' );
730 foreach ( Skin::getSkinNames() as $name => $displayName ) {
731 $msg = $this->msg( "skinname-{$name}" );
732 $code = $this->getParameter( 'inlanguagecode' );
733 if ( $code && Language::isValidCode( $code ) ) {
734 $msg->inLanguage( $code );
735 } else {
736 $msg->inContentLanguage();
738 if ( $msg->exists() ) {
739 $displayName = $msg->text();
741 $skin = array( 'code' => $name );
742 ApiResult::setContent( $skin, $displayName );
743 if ( !isset( $allowed[$name] ) ) {
744 $skin['unusable'] = '';
746 if ( $name === $default ) {
747 $skin['default'] = '';
749 $data[] = $skin;
751 $this->getResult()->setIndexedTagName( $data, 'skin' );
753 return $this->getResult()->addValue( 'query', $property, $data );
756 public function appendExtensionTags( $property ) {
757 global $wgParser;
758 $wgParser->firstCallInit();
759 $tags = array_map( array( $this, 'formatParserTags' ), $wgParser->getTags() );
760 $this->getResult()->setIndexedTagName( $tags, 't' );
762 return $this->getResult()->addValue( 'query', $property, $tags );
765 public function appendFunctionHooks( $property ) {
766 global $wgParser;
767 $wgParser->firstCallInit();
768 $hooks = $wgParser->getFunctionHooks();
769 $this->getResult()->setIndexedTagName( $hooks, 'h' );
771 return $this->getResult()->addValue( 'query', $property, $hooks );
774 public function appendVariables( $property ) {
775 $variables = MagicWord::getVariableIDs();
776 $this->getResult()->setIndexedTagName( $variables, 'v' );
778 return $this->getResult()->addValue( 'query', $property, $variables );
781 public function appendProtocols( $property ) {
782 // Make a copy of the global so we don't try to set the _element key of it - bug 45130
783 $protocols = array_values( $this->getConfig()->get( 'UrlProtocols' ) );
784 $this->getResult()->setIndexedTagName( $protocols, 'p' );
786 return $this->getResult()->addValue( 'query', $property, $protocols );
789 public function appendDefaultOptions( $property ) {
790 return $this->getResult()->addValue( 'query', $property, User::getDefaultOptions() );
793 private function formatParserTags( $item ) {
794 return "<{$item}>";
797 public function appendSubscribedHooks( $property ) {
798 $hooks = $this->getConfig()->get( 'Hooks' );
799 $myWgHooks = $hooks;
800 ksort( $myWgHooks );
802 $data = array();
803 foreach ( $myWgHooks as $name => $subscribers ) {
804 $arr = array(
805 'name' => $name,
806 'subscribers' => array_map( array( 'SpecialVersion', 'arrayToString' ), $subscribers ),
809 $this->getResult()->setIndexedTagName( $arr['subscribers'], 's' );
810 $data[] = $arr;
813 $this->getResult()->setIndexedTagName( $data, 'hook' );
815 return $this->getResult()->addValue( 'query', $property, $data );
818 public function getCacheMode( $params ) {
819 // Messages for $wgExtraInterlanguageLinkPrefixes depend on user language
820 if (
821 count( $this->getConfig()->get( 'ExtraInterlanguageLinkPrefixes' ) ) &&
822 !is_null( $params['prop'] ) &&
823 in_array( 'interwikimap', $params['prop'] )
825 return 'anon-public-user-private';
828 return 'public';
831 public function getAllowedParams() {
832 return array(
833 'prop' => array(
834 ApiBase::PARAM_DFLT => 'general',
835 ApiBase::PARAM_ISMULTI => true,
836 ApiBase::PARAM_TYPE => array(
837 'general',
838 'namespaces',
839 'namespacealiases',
840 'specialpagealiases',
841 'magicwords',
842 'interwikimap',
843 'dbrepllag',
844 'statistics',
845 'usergroups',
846 'libraries',
847 'extensions',
848 'fileextensions',
849 'rightsinfo',
850 'restrictions',
851 'languages',
852 'skins',
853 'extensiontags',
854 'functionhooks',
855 'showhooks',
856 'variables',
857 'protocols',
858 'defaultoptions',
861 'filteriw' => array(
862 ApiBase::PARAM_TYPE => array(
863 'local',
864 '!local',
867 'showalldb' => false,
868 'numberingroup' => false,
869 'inlanguagecode' => null,
873 protected function getExamplesMessages() {
874 return array(
875 'action=query&meta=siteinfo&siprop=general|namespaces|namespacealiases|statistics'
876 => 'apihelp-query+siteinfo-example-simple',
877 'action=query&meta=siteinfo&siprop=interwikimap&sifilteriw=local'
878 => 'apihelp-query+siteinfo-example-interwiki',
879 'action=query&meta=siteinfo&siprop=dbrepllag&sishowalldb='
880 => 'apihelp-query+siteinfo-example-replag',
884 public function getHelpUrls() {
885 return 'https://www.mediawiki.org/wiki/API:Meta#siteinfo_.2F_si';