Removed more functions marked for removal in 1.19: wfParseCIDR(), wfRFC822Phrase...
[mediawiki.git] / includes / api / ApiQuerySiteinfo.php
blobed277b90a80d03639a0e1ed7777a829fde814ffc
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 if ( !defined( 'MEDIAWIKI' ) ) {
28 // Eclipse helper - will be ignored in production
29 require_once( 'ApiQueryBase.php' );
32 /**
33 * A query action to return meta information about the wiki site.
35 * @ingroup API
37 class ApiQuerySiteinfo extends ApiQueryBase {
39 public function __construct( $query, $moduleName ) {
40 parent::__construct( $query, $moduleName, 'si' );
43 public function execute() {
44 $params = $this->extractRequestParams();
45 $done = array();
46 foreach ( $params['prop'] as $p ) {
47 switch ( $p ) {
48 case 'general':
49 $fit = $this->appendGeneralInfo( $p );
50 break;
51 case 'namespaces':
52 $fit = $this->appendNamespaces( $p );
53 break;
54 case 'namespacealiases':
55 $fit = $this->appendNamespaceAliases( $p );
56 break;
57 case 'specialpagealiases':
58 $fit = $this->appendSpecialPageAliases( $p );
59 break;
60 case 'magicwords':
61 $fit = $this->appendMagicWords( $p );
62 break;
63 case 'interwikimap':
64 $filteriw = isset( $params['filteriw'] ) ? $params['filteriw'] : false;
65 $fit = $this->appendInterwikiMap( $p, $filteriw );
66 break;
67 case 'dbrepllag':
68 $fit = $this->appendDbReplLagInfo( $p, $params['showalldb'] );
69 break;
70 case 'statistics':
71 $fit = $this->appendStatistics( $p );
72 break;
73 case 'usergroups':
74 $fit = $this->appendUserGroups( $p, $params['numberingroup'] );
75 break;
76 case 'extensions':
77 $fit = $this->appendExtensions( $p );
78 break;
79 case 'fileextensions':
80 $fit = $this->appendFileExtensions( $p );
81 break;
82 case 'rightsinfo':
83 $fit = $this->appendRightsInfo( $p );
84 break;
85 case 'languages':
86 $fit = $this->appendLanguages( $p );
87 break;
88 case 'skins':
89 $fit = $this->appendSkins( $p );
90 break;
91 case 'extensiontags':
92 $fit = $this->appendExtensionTags( $p );
93 break;
94 case 'functionhooks':
95 $fit = $this->appendFunctionHooks( $p );
96 break;
97 case 'showhooks':
98 $fit = $this->appendSubscribedHooks( $p );
99 break;
100 default:
101 ApiBase::dieDebug( __METHOD__, "Unknown prop=$p" );
103 if ( !$fit ) {
104 // Abuse siprop as a query-continue parameter
105 // and set it to all unprocessed props
106 $this->setContinueEnumParameter( 'prop', implode( '|',
107 array_diff( $params['prop'], $done ) ) );
108 break;
110 $done[] = $p;
114 protected function appendGeneralInfo( $property ) {
115 global $wgContLang;
117 $data = array();
118 $mainPage = Title::newMainPage();
119 $data['mainpage'] = $mainPage->getPrefixedText();
120 $data['base'] = $mainPage->getFullUrl();
121 $data['sitename'] = $GLOBALS['wgSitename'];
122 $data['generator'] = "MediaWiki {$GLOBALS['wgVersion']}";
123 $data['phpversion'] = phpversion();
124 $data['phpsapi'] = php_sapi_name();
125 $data['dbtype'] = $GLOBALS['wgDBtype'];
126 $data['dbversion'] = $this->getDB()->getServerVersion();
128 $svn = SpecialVersion::getSvnRevision( $GLOBALS['IP'] );
129 if ( $svn ) {
130 $data['rev'] = $svn;
133 // 'case-insensitive' option is reserved for future
134 $data['case'] = $GLOBALS['wgCapitalLinks'] ? 'first-letter' : 'case-sensitive';
136 if ( isset( $GLOBALS['wgRightsCode'] ) ) {
137 $data['rightscode'] = $GLOBALS['wgRightsCode'];
139 $data['rights'] = $GLOBALS['wgRightsText'];
140 $data['lang'] = $GLOBALS['wgLanguageCode'];
141 if ( $wgContLang->isRTL() ) {
142 $data['rtl'] = '';
144 $data['fallback8bitEncoding'] = $wgContLang->fallback8bitEncoding();
146 if ( wfReadOnly() ) {
147 $data['readonly'] = '';
148 $data['readonlyreason'] = wfReadOnlyReason();
150 if ( $GLOBALS['wgEnableWriteAPI'] ) {
151 $data['writeapi'] = '';
154 $tz = $GLOBALS['wgLocaltimezone'];
155 $offset = $GLOBALS['wgLocalTZoffset'];
156 if ( is_null( $tz ) ) {
157 $tz = 'UTC';
158 $offset = 0;
159 } elseif ( is_null( $offset ) ) {
160 $offset = 0;
162 $data['timezone'] = $tz;
163 $data['timeoffset'] = intval( $offset );
164 $data['articlepath'] = $GLOBALS['wgArticlePath'];
165 $data['scriptpath'] = $GLOBALS['wgScriptPath'];
166 $data['script'] = $GLOBALS['wgScript'];
167 $data['variantarticlepath'] = $GLOBALS['wgVariantArticlePath'];
168 $data['server'] = $GLOBALS['wgServer'];
169 $data['wikiid'] = wfWikiID();
170 $data['time'] = wfTimestamp( TS_ISO_8601, time() );
172 if ( $GLOBALS['wgMiserMode'] ) {
173 $data['misermode'] = '';
176 wfRunHooks( 'APIQuerySiteInfoGeneralInfo', array( $this, &$data ) );
178 return $this->getResult()->addValue( 'query', $property, $data );
181 protected function appendNamespaces( $property ) {
182 global $wgContLang;
183 $data = array();
184 foreach ( $wgContLang->getFormattedNamespaces() as $ns => $title ) {
185 $data[$ns] = array(
186 'id' => intval( $ns ),
187 'case' => MWNamespace::isCapitalized( $ns ) ? 'first-letter' : 'case-sensitive',
189 ApiResult::setContent( $data[$ns], $title );
190 $canonical = MWNamespace::getCanonicalName( $ns );
192 if ( MWNamespace::hasSubpages( $ns ) ) {
193 $data[$ns]['subpages'] = '';
196 if ( $canonical ) {
197 $data[$ns]['canonical'] = strtr( $canonical, '_', ' ' );
200 if ( MWNamespace::isContent( $ns ) ) {
201 $data[$ns]['content'] = '';
205 $this->getResult()->setIndexedTagName( $data, 'ns' );
206 return $this->getResult()->addValue( 'query', $property, $data );
209 protected function appendNamespaceAliases( $property ) {
210 global $wgNamespaceAliases, $wgContLang;
211 $aliases = array_merge( $wgNamespaceAliases, $wgContLang->getNamespaceAliases() );
212 $namespaces = $wgContLang->getNamespaces();
213 $data = array();
214 foreach ( $aliases as $title => $ns ) {
215 if ( $namespaces[$ns] == $title ) {
216 // Don't list duplicates
217 continue;
219 $item = array(
220 'id' => intval( $ns )
222 ApiResult::setContent( $item, strtr( $title, '_', ' ' ) );
223 $data[] = $item;
226 $this->getResult()->setIndexedTagName( $data, 'ns' );
227 return $this->getResult()->addValue( 'query', $property, $data );
230 protected function appendSpecialPageAliases( $property ) {
231 global $wgContLang;
232 $data = array();
233 foreach ( $wgContLang->getSpecialPageAliases() as $specialpage => $aliases ) {
234 $arr = array( 'realname' => $specialpage, 'aliases' => $aliases );
235 $this->getResult()->setIndexedTagName( $arr['aliases'], 'alias' );
236 $data[] = $arr;
238 $this->getResult()->setIndexedTagName( $data, 'specialpage' );
239 return $this->getResult()->addValue( 'query', $property, $data );
242 protected function appendMagicWords( $property ) {
243 global $wgContLang;
244 $data = array();
245 foreach ( $wgContLang->getMagicWords() as $magicword => $aliases ) {
246 $caseSensitive = array_shift( $aliases );
247 $arr = array( 'name' => $magicword, 'aliases' => $aliases );
248 if ( $caseSensitive ) {
249 $arr['case-sensitive'] = '';
251 $this->getResult()->setIndexedTagName( $arr['aliases'], 'alias' );
252 $data[] = $arr;
254 $this->getResult()->setIndexedTagName( $data, 'magicword' );
255 return $this->getResult()->addValue( 'query', $property, $data );
258 protected function appendInterwikiMap( $property, $filter ) {
259 $this->resetQueryParams();
260 $this->addTables( 'interwiki' );
261 $this->addFields( array( 'iw_prefix', 'iw_local', 'iw_url', 'iw_wikiid', 'iw_api' ) );
263 if ( $filter === 'local' ) {
264 $this->addWhere( 'iw_local = 1' );
265 } elseif ( $filter === '!local' ) {
266 $this->addWhere( 'iw_local = 0' );
267 } elseif ( $filter ) {
268 ApiBase::dieDebug( __METHOD__, "Unknown filter=$filter" );
271 $this->addOption( 'ORDER BY', 'iw_prefix' );
273 $res = $this->select( __METHOD__ );
275 $data = array();
276 $langNames = Language::getLanguageNames();
277 foreach ( $res as $row ) {
278 $val = array();
279 $val['prefix'] = $row->iw_prefix;
280 if ( $row->iw_local == '1' ) {
281 $val['local'] = '';
283 // $val['trans'] = intval( $row->iw_trans ); // should this be exposed?
284 if ( isset( $langNames[$row->iw_prefix] ) ) {
285 $val['language'] = $langNames[$row->iw_prefix];
287 $val['url'] = $row->iw_url;
288 $val['wikiid'] = $row->iw_wikiid;
289 $val['api'] = $row->iw_api;
291 $data[] = $val;
294 $this->getResult()->setIndexedTagName( $data, 'iw' );
295 return $this->getResult()->addValue( 'query', $property, $data );
298 protected function appendDbReplLagInfo( $property, $includeAll ) {
299 global $wgShowHostnames;
300 $data = array();
301 if ( $includeAll ) {
302 if ( !$wgShowHostnames ) {
303 $this->dieUsage( 'Cannot view all servers info unless $wgShowHostnames is true', 'includeAllDenied' );
306 $lb = wfGetLB();
307 $lags = $lb->getLagTimes();
308 foreach ( $lags as $i => $lag ) {
309 $data[] = array(
310 'host' => $lb->getServerName( $i ),
311 'lag' => $lag
314 } else {
315 list( $host, $lag ) = wfGetLB()->getMaxLag();
316 $data[] = array(
317 'host' => $wgShowHostnames ? $host : '',
318 'lag' => intval( $lag )
322 $result = $this->getResult();
323 $result->setIndexedTagName( $data, 'db' );
324 return $this->getResult()->addValue( 'query', $property, $data );
327 protected function appendStatistics( $property ) {
328 global $wgDisableCounters;
329 $data = array();
330 $data['pages'] = intval( SiteStats::pages() );
331 $data['articles'] = intval( SiteStats::articles() );
332 if ( !$wgDisableCounters ) {
333 $data['views'] = intval( SiteStats::views() );
335 $data['edits'] = intval( SiteStats::edits() );
336 $data['images'] = intval( SiteStats::images() );
337 $data['users'] = intval( SiteStats::users() );
338 $data['activeusers'] = intval( SiteStats::activeUsers() );
339 $data['admins'] = intval( SiteStats::numberingroup( 'sysop' ) );
340 $data['jobs'] = intval( SiteStats::jobs() );
341 return $this->getResult()->addValue( 'query', $property, $data );
344 protected function appendUserGroups( $property, $numberInGroup ) {
345 global $wgGroupPermissions, $wgAddGroups, $wgRemoveGroups, $wgGroupsAddToSelf, $wgGroupsRemoveFromSelf;
347 $data = array();
348 foreach ( $wgGroupPermissions as $group => $permissions ) {
349 $arr = array(
350 'name' => $group,
351 'rights' => array_keys( $permissions, true ),
354 if ( $numberInGroup ) {
355 global $wgAutopromote;
357 if ( $group == 'user' ) {
358 $arr['number'] = SiteStats::users();
360 // '*' and autopromote groups have no size
361 } elseif ( $group !== '*' && !isset( $wgAutopromote[$group] ) ) {
362 $arr['number'] = SiteStats::numberInGroup( $group );
366 $groupArr = array(
367 'add' => $wgAddGroups,
368 'remove' => $wgRemoveGroups,
369 'add-self' => $wgGroupsAddToSelf,
370 'remove-self' => $wgGroupsRemoveFromSelf
373 foreach ( $groupArr as $type => $rights ) {
374 if ( isset( $rights[$group] ) ) {
375 $arr[$type] = $rights[$group];
376 $this->getResult()->setIndexedTagName( $arr[$type], 'group' );
380 $this->getResult()->setIndexedTagName( $arr['rights'], 'permission' );
381 $data[] = $arr;
384 $this->getResult()->setIndexedTagName( $data, 'group' );
385 return $this->getResult()->addValue( 'query', $property, $data );
388 protected function appendFileExtensions( $property ) {
389 global $wgFileExtensions;
391 $data = array();
392 foreach ( $wgFileExtensions as $ext ) {
393 $data[] = array( 'ext' => $ext );
395 $this->getResult()->setIndexedTagName( $data, 'fe' );
396 return $this->getResult()->addValue( 'query', $property, $data );
399 protected function appendExtensions( $property ) {
400 global $wgExtensionCredits;
401 $data = array();
402 foreach ( $wgExtensionCredits as $type => $extensions ) {
403 foreach ( $extensions as $ext ) {
404 $ret = array();
405 $ret['type'] = $type;
406 if ( isset( $ext['name'] ) ) {
407 $ret['name'] = $ext['name'];
409 if ( isset( $ext['description'] ) ) {
410 $ret['description'] = $ext['description'];
412 if ( isset( $ext['descriptionmsg'] ) ) {
413 // Can be a string or array( key, param1, param2, ... )
414 if ( is_array( $ext['descriptionmsg'] ) ) {
415 $ret['descriptionmsg'] = $ext['descriptionmsg'][0];
416 $ret['descriptionmsgparams'] = array_slice( $ext['descriptionmsg'], 1 );
417 $this->getResult()->setIndexedTagName( $ret['descriptionmsgparams'], 'param' );
418 } else {
419 $ret['descriptionmsg'] = $ext['descriptionmsg'];
422 if ( isset( $ext['author'] ) ) {
423 $ret['author'] = is_array( $ext['author'] ) ?
424 implode( ', ', $ext['author' ] ) : $ext['author'];
426 if ( isset( $ext['url'] ) ) {
427 $ret['url'] = $ext['url'];
429 if ( isset( $ext['version'] ) ) {
430 $ret['version'] = $ext['version'];
431 } elseif ( isset( $ext['svn-revision'] ) &&
432 preg_match( '/\$(?:Rev|LastChangedRevision|Revision): *(\d+)/',
433 $ext['svn-revision'], $m ) )
435 $ret['version'] = 'r' . $m[1];
437 $data[] = $ret;
441 $this->getResult()->setIndexedTagName( $data, 'ext' );
442 return $this->getResult()->addValue( 'query', $property, $data );
445 protected function appendRightsInfo( $property ) {
446 global $wgRightsPage, $wgRightsUrl, $wgRightsText;
447 $title = Title::newFromText( $wgRightsPage );
448 $url = $title ? $title->getFullURL() : $wgRightsUrl;
449 $text = $wgRightsText;
450 if ( !$text && $title ) {
451 $text = $title->getPrefixedText();
454 $data = array(
455 'url' => $url ? $url : '',
456 'text' => $text ? $text : ''
459 return $this->getResult()->addValue( 'query', $property, $data );
462 public function appendLanguages( $property ) {
463 $data = array();
464 foreach ( Language::getLanguageNames() as $code => $name ) {
465 $lang = array( 'code' => $code );
466 ApiResult::setContent( $lang, $name );
467 $data[] = $lang;
469 $this->getResult()->setIndexedTagName( $data, 'lang' );
470 return $this->getResult()->addValue( 'query', $property, $data );
473 public function appendSkins( $property ) {
474 $data = array();
475 foreach ( Skin::getSkinNames() as $name => $displayName ) {
476 $skin = array( 'code' => $name );
477 ApiResult::setContent( $skin, $displayName );
478 $data[] = $skin;
480 $this->getResult()->setIndexedTagName( $data, 'skin' );
481 return $this->getResult()->addValue( 'query', $property, $data );
484 public function appendExtensionTags( $property ) {
485 global $wgParser;
486 $wgParser->firstCallInit();
487 $tags = array_map( array( $this, 'formatParserTags'), $wgParser->getTags() );
488 $this->getResult()->setIndexedTagName( $tags, 't' );
489 return $this->getResult()->addValue( 'query', $property, $tags );
492 public function appendFunctionHooks( $property ) {
493 global $wgParser;
494 $wgParser->firstCallInit();
495 $hooks = $wgParser->getFunctionHooks();
496 $this->getResult()->setIndexedTagName( $hooks, 'h' );
497 return $this->getResult()->addValue( 'query', $property, $hooks );
500 private function formatParserTags( $item ) {
501 return "<{$item}>";
504 public function appendSubscribedHooks( $property ) {
505 global $wgHooks;
506 $myWgHooks = $wgHooks;
507 ksort( $myWgHooks );
509 $data = array();
510 foreach ( $myWgHooks as $hook => $hooks ) {
511 $arr = array(
512 'name' => $hook,
513 'subscribers' => array_map( array( 'SpecialVersion', 'arrayToString' ), $hooks ),
516 $this->getResult()->setIndexedTagName( $arr['subscribers'], 's' );
517 $data[] = $arr;
520 $this->getResult()->setIndexedTagName( $data, 'hook' );
521 return $this->getResult()->addValue( 'query', $property, $data );
524 public function getCacheMode( $params ) {
525 return 'public';
528 public function getAllowedParams() {
529 return array(
530 'prop' => array(
531 ApiBase::PARAM_DFLT => 'general',
532 ApiBase::PARAM_ISMULTI => true,
533 ApiBase::PARAM_TYPE => array(
534 'general',
535 'namespaces',
536 'namespacealiases',
537 'specialpagealiases',
538 'magicwords',
539 'interwikimap',
540 'dbrepllag',
541 'statistics',
542 'usergroups',
543 'extensions',
544 'fileextensions',
545 'rightsinfo',
546 'languages',
547 'skins',
548 'extensiontags',
549 'functionhooks',
550 'showhooks',
553 'filteriw' => array(
554 ApiBase::PARAM_TYPE => array(
555 'local',
556 '!local',
559 'showalldb' => false,
560 'numberingroup' => false,
564 public function getParamDescription() {
565 return array(
566 'prop' => array(
567 'Which sysinfo properties to get:',
568 ' general - Overall system information',
569 ' namespaces - List of registered namespaces and their canonical names',
570 ' namespacealiases - List of registered namespace aliases',
571 ' specialpagealiases - List of special page aliases',
572 ' magicwords - List of magic words and their aliases',
573 ' statistics - Returns site statistics',
574 ' interwikimap - Returns interwiki map (optionally filtered)',
575 ' dbrepllag - Returns database server with the highest replication lag',
576 ' usergroups - Returns user groups and the associated permissions',
577 ' extensions - Returns extensions installed on the wiki',
578 ' fileextensions - Returns list of file extensions allowed to be uploaded',
579 ' rightsinfo - Returns wiki rights (license) information if available',
580 ' languages - Returns a list of languages MediaWiki supports',
581 ' skins - Returns a list of all enabled skins',
582 ' extensiontags - Returns a list of parser extension tags',
583 ' functionhooks - Returns a list of parser function hooks',
584 ' showhooks - Returns a list of all subscribed hooks (contents of $wgHooks)'
586 'filteriw' => 'Return only local or only nonlocal entries of the interwiki map',
587 'showalldb' => 'List all database servers, not just the one lagging the most',
588 'numberingroup' => 'Lists the number of users in user groups',
592 public function getDescription() {
593 return 'Return general information about the site';
596 public function getPossibleErrors() {
597 return array_merge( parent::getPossibleErrors(), array(
598 array( 'code' => 'includeAllDenied', 'info' => 'Cannot view all servers info unless $wgShowHostnames is true' ),
599 ) );
602 protected function getExamples() {
603 return array(
604 'api.php?action=query&meta=siteinfo&siprop=general|namespaces|namespacealiases|statistics',
605 'api.php?action=query&meta=siteinfo&siprop=interwikimap&sifilteriw=local',
606 'api.php?action=query&meta=siteinfo&siprop=dbrepllag&sishowalldb=',
610 public function getVersion() {
611 return __CLASS__ . ': $Id$';