mediawiki.Uri: Support names of Object prototypes as keys in query
[mediawiki.git] / includes / api / ApiQuerySiteinfo.php
blobbcd5d9ecc0cdee48f6e15ea78e98f0a424f8a641
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 $data['imagewhitelistenabled'] = (bool)$config->get( 'EnableImageWhitelist' );
154 $allowFrom = $config->get( 'AllowExternalImagesFrom' );
155 $allowException = !empty( $allowFrom );
157 if ( $allowException ) {
158 $data['externalimages'] = (array)$allowFrom;
159 ApiResult::setIndexedTagName( $data['externalimages'], 'prefix' );
162 $data['langconversion'] = !$config->get( 'DisableLangConversion' );
163 $data['titleconversion'] = !$config->get( 'DisableTitleConversion' );
165 if ( $wgContLang->linkPrefixExtension() ) {
166 $linkPrefixCharset = $wgContLang->linkPrefixCharset();
167 $data['linkprefixcharset'] = $linkPrefixCharset;
168 // For backwards compatibility
169 $data['linkprefix'] = "/^((?>.*[^$linkPrefixCharset]|))(.+)$/sDu";
170 } else {
171 $data['linkprefixcharset'] = '';
172 $data['linkprefix'] = '';
175 $linktrail = $wgContLang->linkTrail();
176 $data['linktrail'] = $linktrail ?: '';
178 $data['legaltitlechars'] = Title::legalChars();
179 $data['invalidusernamechars'] = $config->get( 'InvalidUsernameCharacters' );
181 global $IP;
182 $git = SpecialVersion::getGitHeadSha1( $IP );
183 if ( $git ) {
184 $data['git-hash'] = $git;
185 $data['git-branch'] =
186 SpecialVersion::getGitCurrentBranch( $GLOBALS['IP'] );
187 } else {
188 $svn = SpecialVersion::getSvnRevision( $IP );
189 if ( $svn ) {
190 $data['rev'] = $svn;
194 // 'case-insensitive' option is reserved for future
195 $data['case'] = $config->get( 'CapitalLinks' ) ? 'first-letter' : 'case-sensitive';
196 $data['lang'] = $config->get( 'LanguageCode' );
198 $fallbacks = array();
199 foreach ( $wgContLang->getFallbackLanguages() as $code ) {
200 $fallbacks[] = array( 'code' => $code );
202 $data['fallback'] = $fallbacks;
203 ApiResult::setIndexedTagName( $data['fallback'], 'lang' );
205 if ( $wgContLang->hasVariants() ) {
206 $variants = array();
207 foreach ( $wgContLang->getVariants() as $code ) {
208 $variants[] = array(
209 'code' => $code,
210 'name' => $wgContLang->getVariantname( $code ),
213 $data['variants'] = $variants;
214 ApiResult::setIndexedTagName( $data['variants'], 'lang' );
217 $data['rtl'] = $wgContLang->isRTL();
218 $data['fallback8bitEncoding'] = $wgContLang->fallback8bitEncoding();
220 $data['readonly'] = wfReadOnly();
221 if ( $data['readonly'] ) {
222 $data['readonlyreason'] = wfReadOnlyReason();
224 $data['writeapi'] = (bool)$config->get( 'EnableWriteAPI' );
226 $tz = $config->get( 'Localtimezone' );
227 $offset = $config->get( 'LocalTZoffset' );
228 if ( is_null( $tz ) ) {
229 $tz = 'UTC';
230 $offset = 0;
231 } elseif ( is_null( $offset ) ) {
232 $offset = 0;
234 $data['timezone'] = $tz;
235 $data['timeoffset'] = intval( $offset );
236 $data['articlepath'] = $config->get( 'ArticlePath' );
237 $data['scriptpath'] = $config->get( 'ScriptPath' );
238 $data['script'] = $config->get( 'Script' );
239 $data['variantarticlepath'] = $config->get( 'VariantArticlePath' );
240 $data[ApiResult::META_BC_BOOLS][] = 'variantarticlepath';
241 $data['server'] = $config->get( 'Server' );
242 $data['servername'] = $config->get( 'ServerName' );
243 $data['wikiid'] = wfWikiID();
244 $data['time'] = wfTimestamp( TS_ISO_8601, time() );
246 $data['misermode'] = (bool)$config->get( 'MiserMode' );
248 $data['maxuploadsize'] = UploadBase::getMaxUploadSize();
250 $data['thumblimits'] = $config->get( 'ThumbLimits' );
251 ApiResult::setArrayType( $data['thumblimits'], 'BCassoc' );
252 ApiResult::setIndexedTagName( $data['thumblimits'], 'limit' );
253 $data['imagelimits'] = array();
254 ApiResult::setArrayType( $data['imagelimits'], 'BCassoc' );
255 ApiResult::setIndexedTagName( $data['imagelimits'], 'limit' );
256 foreach ( $config->get( 'ImageLimits' ) as $k => $limit ) {
257 $data['imagelimits'][$k] = array( '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 Hooks::run( 'APIQuerySiteInfoGeneralInfo', array( $this, &$data ) );
269 return $this->getResult()->addValue( 'query', $property, $data );
272 protected function appendNamespaces( $property ) {
273 global $wgContLang;
274 $data = array(
275 ApiResult::META_TYPE => 'assoc',
277 foreach ( $wgContLang->getFormattedNamespaces() as $ns => $title ) {
278 $data[$ns] = array(
279 'id' => intval( $ns ),
280 'case' => MWNamespace::isCapitalized( $ns ) ? 'first-letter' : 'case-sensitive',
282 ApiResult::setContentValue( $data[$ns], 'name', $title );
283 $canonical = MWNamespace::getCanonicalName( $ns );
285 $data[$ns]['subpages'] = MWNamespace::hasSubpages( $ns );
287 if ( $canonical ) {
288 $data[$ns]['canonical'] = strtr( $canonical, '_', ' ' );
291 $data[$ns]['content'] = MWNamespace::isContent( $ns );
292 $data[$ns]['nonincludable'] = MWNamespace::isNonincludable( $ns );
294 $contentmodel = MWNamespace::getNamespaceContentModel( $ns );
295 if ( $contentmodel ) {
296 $data[$ns]['defaultcontentmodel'] = $contentmodel;
300 ApiResult::setArrayType( $data, 'assoc' );
301 ApiResult::setIndexedTagName( $data, 'ns' );
303 return $this->getResult()->addValue( 'query', $property, $data );
306 protected function appendNamespaceAliases( $property ) {
307 global $wgContLang;
308 $aliases = array_merge( $this->getConfig()->get( 'NamespaceAliases' ),
309 $wgContLang->getNamespaceAliases() );
310 $namespaces = $wgContLang->getNamespaces();
311 $data = array();
312 foreach ( $aliases as $title => $ns ) {
313 if ( $namespaces[$ns] == $title ) {
314 // Don't list duplicates
315 continue;
317 $item = array(
318 'id' => intval( $ns )
320 ApiResult::setContentValue( $item, 'alias', strtr( $title, '_', ' ' ) );
321 $data[] = $item;
324 sort( $data );
326 ApiResult::setIndexedTagName( $data, 'ns' );
328 return $this->getResult()->addValue( 'query', $property, $data );
331 protected function appendSpecialPageAliases( $property ) {
332 global $wgContLang;
333 $data = array();
334 $aliases = $wgContLang->getSpecialPageAliases();
335 foreach ( SpecialPageFactory::getNames() as $specialpage ) {
336 if ( isset( $aliases[$specialpage] ) ) {
337 $arr = array( 'realname' => $specialpage, 'aliases' => $aliases[$specialpage] );
338 ApiResult::setIndexedTagName( $arr['aliases'], 'alias' );
339 $data[] = $arr;
342 ApiResult::setIndexedTagName( $data, 'specialpage' );
344 return $this->getResult()->addValue( 'query', $property, $data );
347 protected function appendMagicWords( $property ) {
348 global $wgContLang;
349 $data = array();
350 foreach ( $wgContLang->getMagicWords() as $magicword => $aliases ) {
351 $caseSensitive = array_shift( $aliases );
352 $arr = array( 'name' => $magicword, 'aliases' => $aliases );
353 $arr['case-sensitive'] = (bool)$caseSensitive;
354 ApiResult::setIndexedTagName( $arr['aliases'], 'alias' );
355 $data[] = $arr;
357 ApiResult::setIndexedTagName( $data, 'magicword' );
359 return $this->getResult()->addValue( 'query', $property, $data );
362 protected function appendInterwikiMap( $property, $filter ) {
363 $local = null;
364 if ( $filter === 'local' ) {
365 $local = 1;
366 } elseif ( $filter === '!local' ) {
367 $local = 0;
368 } elseif ( $filter ) {
369 ApiBase::dieDebug( __METHOD__, "Unknown filter=$filter" );
372 $params = $this->extractRequestParams();
373 $langCode = isset( $params['inlanguagecode'] ) ? $params['inlanguagecode'] : '';
374 $langNames = Language::fetchLanguageNames( $langCode );
376 $getPrefixes = Interwiki::getAllPrefixes( $local );
377 $extraLangPrefixes = $this->getConfig()->get( 'ExtraInterlanguageLinkPrefixes' );
378 $localInterwikis = $this->getConfig()->get( 'LocalInterwikis' );
379 $data = array();
381 foreach ( $getPrefixes as $row ) {
382 $prefix = $row['iw_prefix'];
383 $val = array();
384 $val['prefix'] = $prefix;
385 if ( isset( $row['iw_local'] ) && $row['iw_local'] == '1' ) {
386 $val['local'] = true;
388 if ( isset( $row['iw_trans'] ) && $row['iw_trans'] == '1' ) {
389 $val['trans'] = true;
392 if ( isset( $langNames[$prefix] ) ) {
393 $val['language'] = $langNames[$prefix];
395 if ( in_array( $prefix, $localInterwikis ) ) {
396 $val['localinterwiki'] = true;
398 if ( in_array( $prefix, $extraLangPrefixes ) ) {
399 $val['extralanglink'] = true;
401 $linktext = wfMessage( "interlanguage-link-$prefix" );
402 if ( !$linktext->isDisabled() ) {
403 $val['linktext'] = $linktext->text();
406 $sitename = wfMessage( "interlanguage-link-sitename-$prefix" );
407 if ( !$sitename->isDisabled() ) {
408 $val['sitename'] = $sitename->text();
412 $val['url'] = wfExpandUrl( $row['iw_url'], PROTO_CURRENT );
413 $val['protorel'] = substr( $row['iw_url'], 0, 2 ) == '//';
414 if ( isset( $row['iw_wikiid'] ) && $row['iw_wikiid'] !== '' ) {
415 $val['wikiid'] = $row['iw_wikiid'];
417 if ( isset( $row['iw_api'] ) && $row['iw_api'] !== '' ) {
418 $val['api'] = $row['iw_api'];
421 $data[] = $val;
424 ApiResult::setIndexedTagName( $data, 'iw' );
426 return $this->getResult()->addValue( 'query', $property, $data );
429 protected function appendDbReplLagInfo( $property, $includeAll ) {
430 $data = array();
431 $lb = wfGetLB();
432 $showHostnames = $this->getConfig()->get( 'ShowHostnames' );
433 if ( $includeAll ) {
434 if ( !$showHostnames ) {
435 $this->dieUsage(
436 'Cannot view all servers info unless $wgShowHostnames is true',
437 'includeAllDenied'
441 $lags = $lb->getLagTimes();
442 foreach ( $lags as $i => $lag ) {
443 $data[] = array(
444 'host' => $lb->getServerName( $i ),
445 'lag' => $lag
448 } else {
449 list( , $lag, $index ) = $lb->getMaxLag();
450 $data[] = array(
451 'host' => $showHostnames
452 ? $lb->getServerName( $index )
453 : '',
454 'lag' => intval( $lag )
458 $result = $this->getResult();
459 ApiResult::setIndexedTagName( $data, 'db' );
461 return $this->getResult()->addValue( 'query', $property, $data );
464 protected function appendStatistics( $property ) {
465 $data = array();
466 $data['pages'] = intval( SiteStats::pages() );
467 $data['articles'] = intval( SiteStats::articles() );
468 $data['edits'] = intval( SiteStats::edits() );
469 $data['images'] = intval( SiteStats::images() );
470 $data['users'] = intval( SiteStats::users() );
471 $data['activeusers'] = intval( SiteStats::activeUsers() );
472 $data['admins'] = intval( SiteStats::numberingroup( 'sysop' ) );
473 $data['jobs'] = intval( SiteStats::jobs() );
475 Hooks::run( 'APIQuerySiteInfoStatisticsInfo', array( &$data ) );
477 return $this->getResult()->addValue( 'query', $property, $data );
480 protected function appendUserGroups( $property, $numberInGroup ) {
481 $config = $this->getConfig();
483 $data = array();
484 $result = $this->getResult();
485 $allGroups = User::getAllGroups();
486 foreach ( $config->get( 'GroupPermissions' ) as $group => $permissions ) {
487 $arr = array(
488 'name' => $group,
489 'rights' => array_keys( $permissions, true ),
492 if ( $numberInGroup ) {
493 $autopromote = $config->get( 'Autopromote' );
495 if ( $group == 'user' ) {
496 $arr['number'] = SiteStats::users();
497 // '*' and autopromote groups have no size
498 } elseif ( $group !== '*' && !isset( $autopromote[$group] ) ) {
499 $arr['number'] = SiteStats::numberInGroup( $group );
503 $groupArr = array(
504 'add' => $config->get( 'AddGroups' ),
505 'remove' => $config->get( 'RemoveGroups' ),
506 'add-self' => $config->get( 'GroupsAddToSelf' ),
507 'remove-self' => $config->get( 'GroupsRemoveFromSelf' )
510 foreach ( $groupArr as $type => $rights ) {
511 if ( isset( $rights[$group] ) ) {
512 $groups = array_intersect( $rights[$group], $allGroups );
513 if ( $groups ) {
514 $arr[$type] = $groups;
515 ApiResult::setArrayType( $arr[$type], 'BCarray' );
516 ApiResult::setIndexedTagName( $arr[$type], 'group' );
521 ApiResult::setIndexedTagName( $arr['rights'], 'permission' );
522 $data[] = $arr;
525 ApiResult::setIndexedTagName( $data, 'group' );
527 return $result->addValue( 'query', $property, $data );
530 protected function appendFileExtensions( $property ) {
531 $data = array();
532 foreach ( array_unique( $this->getConfig()->get( 'FileExtensions' ) ) as $ext ) {
533 $data[] = array( 'ext' => $ext );
535 ApiResult::setIndexedTagName( $data, 'fe' );
537 return $this->getResult()->addValue( 'query', $property, $data );
540 protected function appendInstalledLibraries( $property ) {
541 global $IP;
542 $path = "$IP/composer.lock";
543 if ( !file_exists( $path ) ) {
544 // Maybe they're using mediawiki/vendor?
545 $path = "$IP/vendor/composer.lock";
546 if ( !file_exists( $path ) ) {
547 return true;
551 $data = array();
552 $lock = new ComposerLock( $path );
553 foreach ( $lock->getInstalledDependencies() as $name => $info ) {
554 if ( strpos( $info['type'], 'mediawiki-' ) === 0 ) {
555 // Skip any extensions or skins since they'll be listed
556 // in their proper section
557 continue;
559 $data[] = array(
560 'name' => $name,
561 'version' => $info['version'],
564 ApiResult::setIndexedTagName( $data, 'library' );
566 return $this->getResult()->addValue( 'query', $property, $data );
570 protected function appendExtensions( $property ) {
571 $data = array();
572 foreach ( $this->getConfig()->get( 'ExtensionCredits' ) as $type => $extensions ) {
573 foreach ( $extensions as $ext ) {
574 $ret = array();
575 $ret['type'] = $type;
576 if ( isset( $ext['name'] ) ) {
577 $ret['name'] = $ext['name'];
579 if ( isset( $ext['namemsg'] ) ) {
580 $ret['namemsg'] = $ext['namemsg'];
582 if ( isset( $ext['description'] ) ) {
583 $ret['description'] = $ext['description'];
585 if ( isset( $ext['descriptionmsg'] ) ) {
586 // Can be a string or array( key, param1, param2, ... )
587 if ( is_array( $ext['descriptionmsg'] ) ) {
588 $ret['descriptionmsg'] = $ext['descriptionmsg'][0];
589 $ret['descriptionmsgparams'] = array_slice( $ext['descriptionmsg'], 1 );
590 ApiResult::setIndexedTagName( $ret['descriptionmsgparams'], 'param' );
591 } else {
592 $ret['descriptionmsg'] = $ext['descriptionmsg'];
595 if ( isset( $ext['author'] ) ) {
596 $ret['author'] = is_array( $ext['author'] ) ?
597 implode( ', ', $ext['author'] ) : $ext['author'];
599 if ( isset( $ext['url'] ) ) {
600 $ret['url'] = $ext['url'];
602 if ( isset( $ext['version'] ) ) {
603 $ret['version'] = $ext['version'];
604 } elseif ( isset( $ext['svn-revision'] ) &&
605 preg_match( '/\$(?:Rev|LastChangedRevision|Revision): *(\d+)/',
606 $ext['svn-revision'], $m )
608 $ret['version'] = 'r' . $m[1];
610 if ( isset( $ext['path'] ) ) {
611 $extensionPath = dirname( $ext['path'] );
612 $gitInfo = new GitInfo( $extensionPath );
613 $vcsVersion = $gitInfo->getHeadSHA1();
614 if ( $vcsVersion !== false ) {
615 $ret['vcs-system'] = 'git';
616 $ret['vcs-version'] = $vcsVersion;
617 $ret['vcs-url'] = $gitInfo->getHeadViewUrl();
618 $vcsDate = $gitInfo->getHeadCommitDate();
619 if ( $vcsDate !== false ) {
620 $ret['vcs-date'] = wfTimestamp( TS_ISO_8601, $vcsDate );
622 } else {
623 $svnInfo = SpecialVersion::getSvnInfo( $extensionPath );
624 if ( $svnInfo !== false ) {
625 $ret['vcs-system'] = 'svn';
626 $ret['vcs-version'] = $svnInfo['checkout-rev'];
627 $ret['vcs-url'] = isset( $svnInfo['viewvc-url'] ) ? $svnInfo['viewvc-url'] : '';
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 = array(
671 'url' => $url ? $url : '',
672 'text' => $text ? $text : ''
675 return $this->getResult()->addValue( 'query', $property, $data );
678 protected function appendRestrictions( $property ) {
679 $config = $this->getConfig();
680 $data = array(
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 = array();
707 foreach ( $langNames as $code => $name ) {
708 $lang = array( '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 = array();
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 = array( '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( array( $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 private function formatParserTags( $item ) {
791 return "<{$item}>";
794 public function appendSubscribedHooks( $property ) {
795 $hooks = $this->getConfig()->get( 'Hooks' );
796 $myWgHooks = $hooks;
797 ksort( $myWgHooks );
799 $data = array();
800 foreach ( $myWgHooks as $name => $subscribers ) {
801 $arr = array(
802 'name' => $name,
803 'subscribers' => array_map( array( 'SpecialVersion', 'arrayToString' ), $subscribers ),
806 ApiResult::setArrayType( $arr['subscribers'], 'BCarray' );
807 ApiResult::setIndexedTagName( $arr['subscribers'], 's' );
808 $data[] = $arr;
811 ApiResult::setIndexedTagName( $data, 'hook' );
813 return $this->getResult()->addValue( 'query', $property, $data );
816 public function getCacheMode( $params ) {
817 // Messages for $wgExtraInterlanguageLinkPrefixes depend on user language
818 if (
819 count( $this->getConfig()->get( 'ExtraInterlanguageLinkPrefixes' ) ) &&
820 !is_null( $params['prop'] ) &&
821 in_array( 'interwikimap', $params['prop'] )
823 return 'anon-public-user-private';
826 return 'public';
829 public function getAllowedParams() {
830 return array(
831 'prop' => array(
832 ApiBase::PARAM_DFLT => 'general',
833 ApiBase::PARAM_ISMULTI => true,
834 ApiBase::PARAM_TYPE => array(
835 'general',
836 'namespaces',
837 'namespacealiases',
838 'specialpagealiases',
839 'magicwords',
840 'interwikimap',
841 'dbrepllag',
842 'statistics',
843 'usergroups',
844 'libraries',
845 'extensions',
846 'fileextensions',
847 'rightsinfo',
848 'restrictions',
849 'languages',
850 'skins',
851 'extensiontags',
852 'functionhooks',
853 'showhooks',
854 'variables',
855 'protocols',
856 'defaultoptions',
858 ApiBase::PARAM_HELP_MSG_PER_VALUE => array(),
860 'filteriw' => array(
861 ApiBase::PARAM_TYPE => array(
862 'local',
863 '!local',
866 'showalldb' => false,
867 'numberingroup' => false,
868 'inlanguagecode' => null,
872 protected function getExamplesMessages() {
873 return array(
874 'action=query&meta=siteinfo&siprop=general|namespaces|namespacealiases|statistics'
875 => 'apihelp-query+siteinfo-example-simple',
876 'action=query&meta=siteinfo&siprop=interwikimap&sifilteriw=local'
877 => 'apihelp-query+siteinfo-example-interwiki',
878 'action=query&meta=siteinfo&siprop=dbrepllag&sishowalldb='
879 => 'apihelp-query+siteinfo-example-replag',
883 public function getHelpUrls() {
884 return 'https://www.mediawiki.org/wiki/API:Siteinfo';