Localisation updates from http://translatewiki.net.
[mediawiki.git] / includes / api / ApiQuerySiteinfo.php
blobfc5d7bb365a66b843166714a744908f092739aa6
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( $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 'extensions':
73 $fit = $this->appendExtensions( $p );
74 break;
75 case 'fileextensions':
76 $fit = $this->appendFileExtensions( $p );
77 break;
78 case 'rightsinfo':
79 $fit = $this->appendRightsInfo( $p );
80 break;
81 case 'languages':
82 $fit = $this->appendLanguages( $p );
83 break;
84 case 'skins':
85 $fit = $this->appendSkins( $p );
86 break;
87 case 'extensiontags':
88 $fit = $this->appendExtensionTags( $p );
89 break;
90 case 'functionhooks':
91 $fit = $this->appendFunctionHooks( $p );
92 break;
93 case 'showhooks':
94 $fit = $this->appendSubscribedHooks( $p );
95 break;
96 default:
97 ApiBase::dieDebug( __METHOD__, "Unknown prop=$p" );
99 if ( !$fit ) {
100 // Abuse siprop as a query-continue parameter
101 // and set it to all unprocessed props
102 $this->setContinueEnumParameter( 'prop', implode( '|',
103 array_diff( $params['prop'], $done ) ) );
104 break;
106 $done[] = $p;
110 protected function appendGeneralInfo( $property ) {
111 global $wgContLang;
113 $data = array();
114 $mainPage = Title::newMainPage();
115 $data['mainpage'] = $mainPage->getPrefixedText();
116 $data['base'] = wfExpandUrl( $mainPage->getFullUrl(), PROTO_CURRENT );
117 $data['sitename'] = $GLOBALS['wgSitename'];
118 $data['generator'] = "MediaWiki {$GLOBALS['wgVersion']}";
119 $data['phpversion'] = phpversion();
120 $data['phpsapi'] = php_sapi_name();
121 $data['dbtype'] = $GLOBALS['wgDBtype'];
122 $data['dbversion'] = $this->getDB()->getServerVersion();
124 $svn = SpecialVersion::getSvnRevision( $GLOBALS['IP'] );
125 if ( $svn ) {
126 $data['rev'] = $svn;
129 // 'case-insensitive' option is reserved for future
130 $data['case'] = $GLOBALS['wgCapitalLinks'] ? 'first-letter' : 'case-sensitive';
132 if ( isset( $GLOBALS['wgRightsCode'] ) ) {
133 $data['rightscode'] = $GLOBALS['wgRightsCode'];
135 $data['rights'] = $GLOBALS['wgRightsText'];
136 $data['lang'] = $GLOBALS['wgLanguageCode'];
138 $fallbacks = array();
139 foreach( $wgContLang->getFallbackLanguages() as $code ) {
140 $fallbacks[] = array( 'code' => $code );
142 $data['fallback'] = $fallbacks;
143 $this->getResult()->setIndexedTagName( $data['fallback'], 'lang' );
145 if( $wgContLang->hasVariants() ) {
146 $variants = array();
147 foreach( $wgContLang->getVariants() as $code ) {
148 $variants[] = array( 'code' => $code );
150 $data['variants'] = $variants;
151 $this->getResult()->setIndexedTagName( $data['variants'], 'lang' );
154 if ( $wgContLang->isRTL() ) {
155 $data['rtl'] = '';
157 $data['fallback8bitEncoding'] = $wgContLang->fallback8bitEncoding();
159 if ( wfReadOnly() ) {
160 $data['readonly'] = '';
161 $data['readonlyreason'] = wfReadOnlyReason();
163 if ( $GLOBALS['wgEnableWriteAPI'] ) {
164 $data['writeapi'] = '';
167 $tz = $GLOBALS['wgLocaltimezone'];
168 $offset = $GLOBALS['wgLocalTZoffset'];
169 if ( is_null( $tz ) ) {
170 $tz = 'UTC';
171 $offset = 0;
172 } elseif ( is_null( $offset ) ) {
173 $offset = 0;
175 $data['timezone'] = $tz;
176 $data['timeoffset'] = intval( $offset );
177 $data['articlepath'] = $GLOBALS['wgArticlePath'];
178 $data['scriptpath'] = $GLOBALS['wgScriptPath'];
179 $data['script'] = $GLOBALS['wgScript'];
180 $data['variantarticlepath'] = $GLOBALS['wgVariantArticlePath'];
181 $data['server'] = $GLOBALS['wgServer'];
182 $data['wikiid'] = wfWikiID();
183 $data['time'] = wfTimestamp( TS_ISO_8601, time() );
185 if ( $GLOBALS['wgMiserMode'] ) {
186 $data['misermode'] = '';
189 $data['maxuploadsize'] = UploadBase::getMaxUploadSize();
191 wfRunHooks( 'APIQuerySiteInfoGeneralInfo', array( $this, &$data ) );
193 return $this->getResult()->addValue( 'query', $property, $data );
196 protected function appendNamespaces( $property ) {
197 global $wgContLang;
198 $data = array();
199 foreach ( $wgContLang->getFormattedNamespaces() as $ns => $title ) {
200 $data[$ns] = array(
201 'id' => intval( $ns ),
202 'case' => MWNamespace::isCapitalized( $ns ) ? 'first-letter' : 'case-sensitive',
204 ApiResult::setContent( $data[$ns], $title );
205 $canonical = MWNamespace::getCanonicalName( $ns );
207 if ( MWNamespace::hasSubpages( $ns ) ) {
208 $data[$ns]['subpages'] = '';
211 if ( $canonical ) {
212 $data[$ns]['canonical'] = strtr( $canonical, '_', ' ' );
215 if ( MWNamespace::isContent( $ns ) ) {
216 $data[$ns]['content'] = '';
219 if ( MWNamespace::isNonincludableNamespace( $ns ) ) {
220 $data[$ns]['nonincludable'] = '';
224 $this->getResult()->setIndexedTagName( $data, 'ns' );
225 return $this->getResult()->addValue( 'query', $property, $data );
228 protected function appendNamespaceAliases( $property ) {
229 global $wgNamespaceAliases, $wgContLang;
230 $aliases = array_merge( $wgNamespaceAliases, $wgContLang->getNamespaceAliases() );
231 $namespaces = $wgContLang->getNamespaces();
232 $data = array();
233 foreach ( $aliases as $title => $ns ) {
234 if ( $namespaces[$ns] == $title ) {
235 // Don't list duplicates
236 continue;
238 $item = array(
239 'id' => intval( $ns )
241 ApiResult::setContent( $item, strtr( $title, '_', ' ' ) );
242 $data[] = $item;
245 $this->getResult()->setIndexedTagName( $data, 'ns' );
246 return $this->getResult()->addValue( 'query', $property, $data );
249 protected function appendSpecialPageAliases( $property ) {
250 global $wgContLang;
251 $data = array();
252 foreach ( $wgContLang->getSpecialPageAliases() as $specialpage => $aliases ) {
253 $arr = array( 'realname' => $specialpage, 'aliases' => $aliases );
254 $this->getResult()->setIndexedTagName( $arr['aliases'], 'alias' );
255 $data[] = $arr;
257 $this->getResult()->setIndexedTagName( $data, 'specialpage' );
258 return $this->getResult()->addValue( 'query', $property, $data );
261 protected function appendMagicWords( $property ) {
262 global $wgContLang;
263 $data = array();
264 foreach ( $wgContLang->getMagicWords() as $magicword => $aliases ) {
265 $caseSensitive = array_shift( $aliases );
266 $arr = array( 'name' => $magicword, 'aliases' => $aliases );
267 if ( $caseSensitive ) {
268 $arr['case-sensitive'] = '';
270 $this->getResult()->setIndexedTagName( $arr['aliases'], 'alias' );
271 $data[] = $arr;
273 $this->getResult()->setIndexedTagName( $data, 'magicword' );
274 return $this->getResult()->addValue( 'query', $property, $data );
277 protected function appendInterwikiMap( $property, $filter ) {
278 $local = null;
279 if ( $filter === 'local' ) {
280 $local = 1;
281 } elseif ( $filter === '!local' ) {
282 $local = 0;
283 } elseif ( $filter ) {
284 ApiBase::dieDebug( __METHOD__, "Unknown filter=$filter" );
287 $params = $this->extractRequestParams();
288 $langCode = isset( $params['inlanguagecode'] ) ? $params['inlanguagecode'] : '';
289 $langNames = Language::fetchLanguageNames( $langCode );
291 $getPrefixes = Interwiki::getAllPrefixes( $local );
292 $data = array();
294 foreach ( $getPrefixes as $row ) {
295 $prefix = $row['iw_prefix'];
296 $val = array();
297 $val['prefix'] = $prefix;
298 if ( $row['iw_local'] == '1' ) {
299 $val['local'] = '';
301 // $val['trans'] = intval( $row['iw_trans'] ); // should this be exposed?
302 if ( isset( $langNames[$prefix] ) ) {
303 $val['language'] = $langNames[$prefix];
305 $val['url'] = wfExpandUrl( $row['iw_url'], PROTO_CURRENT );
306 if( isset( $row['iw_wikiid'] ) ) {
307 $val['wikiid'] = $row['iw_wikiid'];
309 if( isset( $row['iw_api'] ) ) {
310 $val['api'] = $row['iw_api'];
313 $data[] = $val;
316 $this->getResult()->setIndexedTagName( $data, 'iw' );
317 return $this->getResult()->addValue( 'query', $property, $data );
320 protected function appendDbReplLagInfo( $property, $includeAll ) {
321 global $wgShowHostnames;
322 $data = array();
323 $lb = wfGetLB();
324 if ( $includeAll ) {
325 if ( !$wgShowHostnames ) {
326 $this->dieUsage( 'Cannot view all servers info unless $wgShowHostnames is true', 'includeAllDenied' );
329 $lags = $lb->getLagTimes();
330 foreach ( $lags as $i => $lag ) {
331 $data[] = array(
332 'host' => $lb->getServerName( $i ),
333 'lag' => $lag
336 } else {
337 list( $host, $lag, $index ) = $lb->getMaxLag();
338 $data[] = array(
339 'host' => $wgShowHostnames
340 ? $lb->getServerName( $index )
341 : '',
342 'lag' => intval( $lag )
346 $result = $this->getResult();
347 $result->setIndexedTagName( $data, 'db' );
348 return $this->getResult()->addValue( 'query', $property, $data );
351 protected function appendStatistics( $property ) {
352 global $wgDisableCounters;
353 $data = array();
354 $data['pages'] = intval( SiteStats::pages() );
355 $data['articles'] = intval( SiteStats::articles() );
356 if ( !$wgDisableCounters ) {
357 $data['views'] = intval( SiteStats::views() );
359 $data['edits'] = intval( SiteStats::edits() );
360 $data['images'] = intval( SiteStats::images() );
361 $data['users'] = intval( SiteStats::users() );
362 $data['activeusers'] = intval( SiteStats::activeUsers() );
363 $data['admins'] = intval( SiteStats::numberingroup( 'sysop' ) );
364 $data['jobs'] = intval( SiteStats::jobs() );
365 return $this->getResult()->addValue( 'query', $property, $data );
368 protected function appendUserGroups( $property, $numberInGroup ) {
369 global $wgGroupPermissions, $wgAddGroups, $wgRemoveGroups, $wgGroupsAddToSelf, $wgGroupsRemoveFromSelf;
371 $data = array();
372 $result = $this->getResult();
373 foreach ( $wgGroupPermissions as $group => $permissions ) {
374 $arr = array(
375 'name' => $group,
376 'rights' => array_keys( $permissions, true ),
379 if ( $numberInGroup ) {
380 global $wgAutopromote;
382 if ( $group == 'user' ) {
383 $arr['number'] = SiteStats::users();
385 // '*' and autopromote groups have no size
386 } elseif ( $group !== '*' && !isset( $wgAutopromote[$group] ) ) {
387 $arr['number'] = SiteStats::numberInGroup( $group );
391 $groupArr = array(
392 'add' => $wgAddGroups,
393 'remove' => $wgRemoveGroups,
394 'add-self' => $wgGroupsAddToSelf,
395 'remove-self' => $wgGroupsRemoveFromSelf
398 foreach ( $groupArr as $type => $rights ) {
399 if ( isset( $rights[$group] ) ) {
400 $arr[$type] = $rights[$group];
401 $result->setIndexedTagName( $arr[$type], 'group' );
405 $result->setIndexedTagName( $arr['rights'], 'permission' );
406 $data[] = $arr;
409 $result->setIndexedTagName( $data, 'group' );
410 return $result->addValue( 'query', $property, $data );
413 protected function appendFileExtensions( $property ) {
414 global $wgFileExtensions;
416 $data = array();
417 foreach ( $wgFileExtensions as $ext ) {
418 $data[] = array( 'ext' => $ext );
420 $this->getResult()->setIndexedTagName( $data, 'fe' );
421 return $this->getResult()->addValue( 'query', $property, $data );
424 protected function appendExtensions( $property ) {
425 global $wgExtensionCredits;
426 $data = array();
427 foreach ( $wgExtensionCredits as $type => $extensions ) {
428 foreach ( $extensions as $ext ) {
429 $ret = array();
430 $ret['type'] = $type;
431 if ( isset( $ext['name'] ) ) {
432 $ret['name'] = $ext['name'];
434 if ( isset( $ext['description'] ) ) {
435 $ret['description'] = $ext['description'];
437 if ( isset( $ext['descriptionmsg'] ) ) {
438 // Can be a string or array( key, param1, param2, ... )
439 if ( is_array( $ext['descriptionmsg'] ) ) {
440 $ret['descriptionmsg'] = $ext['descriptionmsg'][0];
441 $ret['descriptionmsgparams'] = array_slice( $ext['descriptionmsg'], 1 );
442 $this->getResult()->setIndexedTagName( $ret['descriptionmsgparams'], 'param' );
443 } else {
444 $ret['descriptionmsg'] = $ext['descriptionmsg'];
447 if ( isset( $ext['author'] ) ) {
448 $ret['author'] = is_array( $ext['author'] ) ?
449 implode( ', ', $ext['author' ] ) : $ext['author'];
451 if ( isset( $ext['url'] ) ) {
452 $ret['url'] = $ext['url'];
454 if ( isset( $ext['version'] ) ) {
455 $ret['version'] = $ext['version'];
456 } elseif ( isset( $ext['svn-revision'] ) &&
457 preg_match( '/\$(?:Rev|LastChangedRevision|Revision): *(\d+)/',
458 $ext['svn-revision'], $m ) )
460 $ret['version'] = 'r' . $m[1];
462 $data[] = $ret;
466 $this->getResult()->setIndexedTagName( $data, 'ext' );
467 return $this->getResult()->addValue( 'query', $property, $data );
470 protected function appendRightsInfo( $property ) {
471 global $wgRightsPage, $wgRightsUrl, $wgRightsText;
472 $title = Title::newFromText( $wgRightsPage );
473 $url = $title ? wfExpandUrl( $title->getFullURL(), PROTO_CURRENT ) : $wgRightsUrl;
474 $text = $wgRightsText;
475 if ( !$text && $title ) {
476 $text = $title->getPrefixedText();
479 $data = array(
480 'url' => $url ? $url : '',
481 'text' => $text ? $text : ''
484 return $this->getResult()->addValue( 'query', $property, $data );
487 public function appendLanguages( $property ) {
488 $params = $this->extractRequestParams();
489 $langCode = isset( $params['inlanguagecode'] ) ? $params['inlanguagecode'] : '';
490 $langNames = Language::fetchLanguageNames( $langCode );
492 $data = array();
494 foreach ( $langNames as $code => $name ) {
495 $lang = array( 'code' => $code );
496 ApiResult::setContent( $lang, $name );
497 $data[] = $lang;
499 $this->getResult()->setIndexedTagName( $data, 'lang' );
500 return $this->getResult()->addValue( 'query', $property, $data );
503 public function appendSkins( $property ) {
504 $data = array();
505 foreach ( Skin::getSkinNames() as $name => $displayName ) {
506 $skin = array( 'code' => $name );
507 ApiResult::setContent( $skin, $displayName );
508 $data[] = $skin;
510 $this->getResult()->setIndexedTagName( $data, 'skin' );
511 return $this->getResult()->addValue( 'query', $property, $data );
514 public function appendExtensionTags( $property ) {
515 global $wgParser;
516 $wgParser->firstCallInit();
517 $tags = array_map( array( $this, 'formatParserTags'), $wgParser->getTags() );
518 $this->getResult()->setIndexedTagName( $tags, 't' );
519 return $this->getResult()->addValue( 'query', $property, $tags );
522 public function appendFunctionHooks( $property ) {
523 global $wgParser;
524 $wgParser->firstCallInit();
525 $hooks = $wgParser->getFunctionHooks();
526 $this->getResult()->setIndexedTagName( $hooks, 'h' );
527 return $this->getResult()->addValue( 'query', $property, $hooks );
530 private function formatParserTags( $item ) {
531 return "<{$item}>";
534 public function appendSubscribedHooks( $property ) {
535 global $wgHooks;
536 $myWgHooks = $wgHooks;
537 ksort( $myWgHooks );
539 $data = array();
540 foreach ( $myWgHooks as $hook => $hooks ) {
541 $arr = array(
542 'name' => $hook,
543 'subscribers' => array_map( array( 'SpecialVersion', 'arrayToString' ), $hooks ),
546 $this->getResult()->setIndexedTagName( $arr['subscribers'], 's' );
547 $data[] = $arr;
550 $this->getResult()->setIndexedTagName( $data, 'hook' );
551 return $this->getResult()->addValue( 'query', $property, $data );
554 public function getCacheMode( $params ) {
555 return 'public';
558 public function getAllowedParams() {
559 return array(
560 'prop' => array(
561 ApiBase::PARAM_DFLT => 'general',
562 ApiBase::PARAM_ISMULTI => true,
563 ApiBase::PARAM_TYPE => array(
564 'general',
565 'namespaces',
566 'namespacealiases',
567 'specialpagealiases',
568 'magicwords',
569 'interwikimap',
570 'dbrepllag',
571 'statistics',
572 'usergroups',
573 'extensions',
574 'fileextensions',
575 'rightsinfo',
576 'languages',
577 'skins',
578 'extensiontags',
579 'functionhooks',
580 'showhooks',
583 'filteriw' => array(
584 ApiBase::PARAM_TYPE => array(
585 'local',
586 '!local',
589 'showalldb' => false,
590 'numberingroup' => false,
591 'inlanguagecode' => null,
595 public function getParamDescription() {
596 $p = $this->getModulePrefix();
597 return array(
598 'prop' => array(
599 'Which sysinfo properties to get:',
600 ' general - Overall system information',
601 ' namespaces - List of registered namespaces and their canonical names',
602 ' namespacealiases - List of registered namespace aliases',
603 ' specialpagealiases - List of special page aliases',
604 ' magicwords - List of magic words and their aliases',
605 ' statistics - Returns site statistics',
606 " interwikimap - Returns interwiki map (optionally filtered, (optionally localised by using {$p}inlanguagecode))",
607 ' dbrepllag - Returns database server with the highest replication lag',
608 ' usergroups - Returns user groups and the associated permissions',
609 ' extensions - Returns extensions installed on the wiki',
610 ' fileextensions - Returns list of file extensions allowed to be uploaded',
611 ' rightsinfo - Returns wiki rights (license) information if available',
612 " languages - Returns a list of languages MediaWiki supports (optionally localised by using {$p}inlanguagecode)",
613 ' skins - Returns a list of all enabled skins',
614 ' extensiontags - Returns a list of parser extension tags',
615 ' functionhooks - Returns a list of parser function hooks',
616 ' showhooks - Returns a list of all subscribed hooks (contents of $wgHooks)'
618 'filteriw' => 'Return only local or only nonlocal entries of the interwiki map',
619 'showalldb' => 'List all database servers, not just the one lagging the most',
620 'numberingroup' => 'Lists the number of users in user groups',
621 'inlanguagecode' => 'Language code for localised language names (best effort, use CLDR extension)',
625 public function getDescription() {
626 return 'Return general information about the site';
629 public function getPossibleErrors() {
630 return array_merge( parent::getPossibleErrors(), array(
631 array( 'code' => 'includeAllDenied', 'info' => 'Cannot view all servers info unless $wgShowHostnames is true' ),
632 ) );
635 public function getExamples() {
636 return array(
637 'api.php?action=query&meta=siteinfo&siprop=general|namespaces|namespacealiases|statistics',
638 'api.php?action=query&meta=siteinfo&siprop=interwikimap&sifilteriw=local',
639 'api.php?action=query&meta=siteinfo&siprop=dbrepllag&sishowalldb=',
643 public function getHelpUrls() {
644 return 'https://www.mediawiki.org/wiki/API:Meta#siteinfo_.2F_si';
647 public function getVersion() {
648 return __CLASS__ . ': $Id$';