Fixed spacing in db/debug/diff/externalstore/objectcache folder
[mediawiki.git] / includes / api / ApiQuerySiteinfo.php
blob37b22f15b0ea73f7ad4effc9a742c4f3bd67dc97
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 case 'variables':
97 $fit = $this->appendVariables( $p );
98 break;
99 case 'protocols':
100 $fit = $this->appendProtocols( $p );
101 break;
102 default:
103 ApiBase::dieDebug( __METHOD__, "Unknown prop=$p" );
105 if ( !$fit ) {
106 // Abuse siprop as a query-continue parameter
107 // and set it to all unprocessed props
108 $this->setContinueEnumParameter( 'prop', implode( '|',
109 array_diff( $params['prop'], $done ) ) );
110 break;
112 $done[] = $p;
116 protected function appendGeneralInfo( $property ) {
117 global $wgContLang,
118 $wgDisableLangConversion,
119 $wgDisableTitleConversion;
121 $data = array();
122 $mainPage = Title::newMainPage();
123 $data['mainpage'] = $mainPage->getPrefixedText();
124 $data['base'] = wfExpandUrl( $mainPage->getFullURL(), PROTO_CURRENT );
125 $data['sitename'] = $GLOBALS['wgSitename'];
126 $data['generator'] = "MediaWiki {$GLOBALS['wgVersion']}";
127 $data['phpversion'] = phpversion();
128 $data['phpsapi'] = PHP_SAPI;
129 $data['dbtype'] = $GLOBALS['wgDBtype'];
130 $data['dbversion'] = $this->getDB()->getServerVersion();
132 if ( !$wgDisableLangConversion ) {
133 $data['langconversion'] = '';
136 if ( !$wgDisableTitleConversion ) {
137 $data['titleconversion'] = '';
140 if ( $wgContLang->linkPrefixExtension() ) {
141 $data['linkprefix'] = wfMessage( 'linkprefix' )->inContentLanguage()->text();
142 } else {
143 $data['linkprefix'] = '';
146 $linktrail = $wgContLang->linkTrail();
147 if ( $linktrail ) {
148 $data['linktrail'] = $linktrail;
149 } else {
150 $data['linktrail'] = '';
153 $git = SpecialVersion::getGitHeadSha1( $GLOBALS['IP'] );
154 if ( $git ) {
155 $data['git-hash'] = $git;
156 } else {
157 $svn = SpecialVersion::getSvnRevision( $GLOBALS['IP'] );
158 if ( $svn ) {
159 $data['rev'] = $svn;
163 // 'case-insensitive' option is reserved for future
164 $data['case'] = $GLOBALS['wgCapitalLinks'] ? 'first-letter' : 'case-sensitive';
166 if ( isset( $GLOBALS['wgRightsCode'] ) ) {
167 $data['rightscode'] = $GLOBALS['wgRightsCode'];
169 $data['rights'] = $GLOBALS['wgRightsText'];
170 $data['lang'] = $GLOBALS['wgLanguageCode'];
172 $fallbacks = array();
173 foreach ( $wgContLang->getFallbackLanguages() as $code ) {
174 $fallbacks[] = array( 'code' => $code );
176 $data['fallback'] = $fallbacks;
177 $this->getResult()->setIndexedTagName( $data['fallback'], 'lang' );
179 if ( $wgContLang->hasVariants() ) {
180 $variants = array();
181 foreach ( $wgContLang->getVariants() as $code ) {
182 $variants[] = array( 'code' => $code );
184 $data['variants'] = $variants;
185 $this->getResult()->setIndexedTagName( $data['variants'], 'lang' );
188 if ( $wgContLang->isRTL() ) {
189 $data['rtl'] = '';
191 $data['fallback8bitEncoding'] = $wgContLang->fallback8bitEncoding();
193 if ( wfReadOnly() ) {
194 $data['readonly'] = '';
195 $data['readonlyreason'] = wfReadOnlyReason();
197 if ( $GLOBALS['wgEnableWriteAPI'] ) {
198 $data['writeapi'] = '';
201 $tz = $GLOBALS['wgLocaltimezone'];
202 $offset = $GLOBALS['wgLocalTZoffset'];
203 if ( is_null( $tz ) ) {
204 $tz = 'UTC';
205 $offset = 0;
206 } elseif ( is_null( $offset ) ) {
207 $offset = 0;
209 $data['timezone'] = $tz;
210 $data['timeoffset'] = intval( $offset );
211 $data['articlepath'] = $GLOBALS['wgArticlePath'];
212 $data['scriptpath'] = $GLOBALS['wgScriptPath'];
213 $data['script'] = $GLOBALS['wgScript'];
214 $data['variantarticlepath'] = $GLOBALS['wgVariantArticlePath'];
215 $data['server'] = $GLOBALS['wgServer'];
216 $data['wikiid'] = wfWikiID();
217 $data['time'] = wfTimestamp( TS_ISO_8601, time() );
219 if ( $GLOBALS['wgMiserMode'] ) {
220 $data['misermode'] = '';
223 $data['maxuploadsize'] = UploadBase::getMaxUploadSize();
225 wfRunHooks( 'APIQuerySiteInfoGeneralInfo', array( $this, &$data ) );
227 return $this->getResult()->addValue( 'query', $property, $data );
230 protected function appendNamespaces( $property ) {
231 global $wgContLang;
232 $data = array();
233 foreach ( $wgContLang->getFormattedNamespaces() as $ns => $title ) {
234 $data[$ns] = array(
235 'id' => intval( $ns ),
236 'case' => MWNamespace::isCapitalized( $ns ) ? 'first-letter' : 'case-sensitive',
238 ApiResult::setContent( $data[$ns], $title );
239 $canonical = MWNamespace::getCanonicalName( $ns );
241 if ( MWNamespace::hasSubpages( $ns ) ) {
242 $data[$ns]['subpages'] = '';
245 if ( $canonical ) {
246 $data[$ns]['canonical'] = strtr( $canonical, '_', ' ' );
249 if ( MWNamespace::isContent( $ns ) ) {
250 $data[$ns]['content'] = '';
253 if ( MWNamespace::isNonincludable( $ns ) ) {
254 $data[$ns]['nonincludable'] = '';
257 $contentmodel = MWNamespace::getNamespaceContentModel( $ns );
258 if ( $contentmodel ) {
259 $data[$ns]['defaultcontentmodel'] = $contentmodel;
263 $this->getResult()->setIndexedTagName( $data, 'ns' );
264 return $this->getResult()->addValue( 'query', $property, $data );
267 protected function appendNamespaceAliases( $property ) {
268 global $wgNamespaceAliases, $wgContLang;
269 $aliases = array_merge( $wgNamespaceAliases, $wgContLang->getNamespaceAliases() );
270 $namespaces = $wgContLang->getNamespaces();
271 $data = array();
272 foreach ( $aliases as $title => $ns ) {
273 if ( $namespaces[$ns] == $title ) {
274 // Don't list duplicates
275 continue;
277 $item = array(
278 'id' => intval( $ns )
280 ApiResult::setContent( $item, strtr( $title, '_', ' ' ) );
281 $data[] = $item;
284 $this->getResult()->setIndexedTagName( $data, 'ns' );
285 return $this->getResult()->addValue( 'query', $property, $data );
288 protected function appendSpecialPageAliases( $property ) {
289 global $wgContLang;
290 $data = array();
291 $aliases = $wgContLang->getSpecialPageAliases();
292 foreach ( SpecialPageFactory::getList() as $specialpage => $stuff ) {
293 if ( isset( $aliases[$specialpage] ) ) {
294 $arr = array( 'realname' => $specialpage, 'aliases' => $aliases[$specialpage] );
295 $this->getResult()->setIndexedTagName( $arr['aliases'], 'alias' );
296 $data[] = $arr;
299 $this->getResult()->setIndexedTagName( $data, 'specialpage' );
300 return $this->getResult()->addValue( 'query', $property, $data );
303 protected function appendMagicWords( $property ) {
304 global $wgContLang;
305 $data = array();
306 foreach ( $wgContLang->getMagicWords() as $magicword => $aliases ) {
307 $caseSensitive = array_shift( $aliases );
308 $arr = array( 'name' => $magicword, 'aliases' => $aliases );
309 if ( $caseSensitive ) {
310 $arr['case-sensitive'] = '';
312 $this->getResult()->setIndexedTagName( $arr['aliases'], 'alias' );
313 $data[] = $arr;
315 $this->getResult()->setIndexedTagName( $data, 'magicword' );
316 return $this->getResult()->addValue( 'query', $property, $data );
319 protected function appendInterwikiMap( $property, $filter ) {
320 $local = null;
321 if ( $filter === 'local' ) {
322 $local = 1;
323 } elseif ( $filter === '!local' ) {
324 $local = 0;
325 } elseif ( $filter ) {
326 ApiBase::dieDebug( __METHOD__, "Unknown filter=$filter" );
329 $params = $this->extractRequestParams();
330 $langCode = isset( $params['inlanguagecode'] ) ? $params['inlanguagecode'] : '';
331 $langNames = Language::fetchLanguageNames( $langCode );
333 $getPrefixes = Interwiki::getAllPrefixes( $local );
334 $data = array();
336 foreach ( $getPrefixes as $row ) {
337 $prefix = $row['iw_prefix'];
338 $val = array();
339 $val['prefix'] = $prefix;
340 if ( $row['iw_local'] == '1' ) {
341 $val['local'] = '';
343 // $val['trans'] = intval( $row['iw_trans'] ); // should this be exposed?
344 if ( isset( $langNames[$prefix] ) ) {
345 $val['language'] = $langNames[$prefix];
347 $val['url'] = wfExpandUrl( $row['iw_url'], PROTO_CURRENT );
348 if ( isset( $row['iw_wikiid'] ) ) {
349 $val['wikiid'] = $row['iw_wikiid'];
351 if ( isset( $row['iw_api'] ) ) {
352 $val['api'] = $row['iw_api'];
355 $data[] = $val;
358 $this->getResult()->setIndexedTagName( $data, 'iw' );
359 return $this->getResult()->addValue( 'query', $property, $data );
362 protected function appendDbReplLagInfo( $property, $includeAll ) {
363 global $wgShowHostnames;
364 $data = array();
365 $lb = wfGetLB();
366 if ( $includeAll ) {
367 if ( !$wgShowHostnames ) {
368 $this->dieUsage( 'Cannot view all servers info unless $wgShowHostnames is true', 'includeAllDenied' );
371 $lags = $lb->getLagTimes();
372 foreach ( $lags as $i => $lag ) {
373 $data[] = array(
374 'host' => $lb->getServerName( $i ),
375 'lag' => $lag
378 } else {
379 list( , $lag, $index ) = $lb->getMaxLag();
380 $data[] = array(
381 'host' => $wgShowHostnames
382 ? $lb->getServerName( $index )
383 : '',
384 'lag' => intval( $lag )
388 $result = $this->getResult();
389 $result->setIndexedTagName( $data, 'db' );
390 return $this->getResult()->addValue( 'query', $property, $data );
393 protected function appendStatistics( $property ) {
394 global $wgDisableCounters;
395 $data = array();
396 $data['pages'] = intval( SiteStats::pages() );
397 $data['articles'] = intval( SiteStats::articles() );
398 if ( !$wgDisableCounters ) {
399 $data['views'] = intval( SiteStats::views() );
401 $data['edits'] = intval( SiteStats::edits() );
402 $data['images'] = intval( SiteStats::images() );
403 $data['users'] = intval( SiteStats::users() );
404 $data['activeusers'] = intval( SiteStats::activeUsers() );
405 $data['admins'] = intval( SiteStats::numberingroup( 'sysop' ) );
406 $data['jobs'] = intval( SiteStats::jobs() );
407 return $this->getResult()->addValue( 'query', $property, $data );
410 protected function appendUserGroups( $property, $numberInGroup ) {
411 global $wgGroupPermissions, $wgAddGroups, $wgRemoveGroups, $wgGroupsAddToSelf, $wgGroupsRemoveFromSelf;
413 $data = array();
414 $result = $this->getResult();
415 foreach ( $wgGroupPermissions as $group => $permissions ) {
416 $arr = array(
417 'name' => $group,
418 'rights' => array_keys( $permissions, true ),
421 if ( $numberInGroup ) {
422 global $wgAutopromote;
424 if ( $group == 'user' ) {
425 $arr['number'] = SiteStats::users();
427 // '*' and autopromote groups have no size
428 } elseif ( $group !== '*' && !isset( $wgAutopromote[$group] ) ) {
429 $arr['number'] = SiteStats::numberInGroup( $group );
433 $groupArr = array(
434 'add' => $wgAddGroups,
435 'remove' => $wgRemoveGroups,
436 'add-self' => $wgGroupsAddToSelf,
437 'remove-self' => $wgGroupsRemoveFromSelf
440 foreach ( $groupArr as $type => $rights ) {
441 if ( isset( $rights[$group] ) ) {
442 $arr[$type] = $rights[$group];
443 $result->setIndexedTagName( $arr[$type], 'group' );
447 $result->setIndexedTagName( $arr['rights'], 'permission' );
448 $data[] = $arr;
451 $result->setIndexedTagName( $data, 'group' );
452 return $result->addValue( 'query', $property, $data );
455 protected function appendFileExtensions( $property ) {
456 global $wgFileExtensions;
458 $data = array();
459 foreach ( $wgFileExtensions as $ext ) {
460 $data[] = array( 'ext' => $ext );
462 $this->getResult()->setIndexedTagName( $data, 'fe' );
463 return $this->getResult()->addValue( 'query', $property, $data );
466 protected function appendExtensions( $property ) {
467 global $wgExtensionCredits;
468 $data = array();
469 foreach ( $wgExtensionCredits as $type => $extensions ) {
470 foreach ( $extensions as $ext ) {
471 $ret = array();
472 $ret['type'] = $type;
473 if ( isset( $ext['name'] ) ) {
474 $ret['name'] = $ext['name'];
476 if ( isset( $ext['description'] ) ) {
477 $ret['description'] = $ext['description'];
479 if ( isset( $ext['descriptionmsg'] ) ) {
480 // Can be a string or array( key, param1, param2, ... )
481 if ( is_array( $ext['descriptionmsg'] ) ) {
482 $ret['descriptionmsg'] = $ext['descriptionmsg'][0];
483 $ret['descriptionmsgparams'] = array_slice( $ext['descriptionmsg'], 1 );
484 $this->getResult()->setIndexedTagName( $ret['descriptionmsgparams'], 'param' );
485 } else {
486 $ret['descriptionmsg'] = $ext['descriptionmsg'];
489 if ( isset( $ext['author'] ) ) {
490 $ret['author'] = is_array( $ext['author'] ) ?
491 implode( ', ', $ext['author'] ) : $ext['author'];
493 if ( isset( $ext['url'] ) ) {
494 $ret['url'] = $ext['url'];
496 if ( isset( $ext['version'] ) ) {
497 $ret['version'] = $ext['version'];
498 } elseif ( isset( $ext['svn-revision'] ) &&
499 preg_match( '/\$(?:Rev|LastChangedRevision|Revision): *(\d+)/',
500 $ext['svn-revision'], $m ) )
502 $ret['version'] = 'r' . $m[1];
504 $data[] = $ret;
508 $this->getResult()->setIndexedTagName( $data, 'ext' );
509 return $this->getResult()->addValue( 'query', $property, $data );
512 protected function appendRightsInfo( $property ) {
513 global $wgRightsPage, $wgRightsUrl, $wgRightsText;
514 $title = Title::newFromText( $wgRightsPage );
515 $url = $title ? wfExpandUrl( $title->getFullURL(), PROTO_CURRENT ) : $wgRightsUrl;
516 $text = $wgRightsText;
517 if ( !$text && $title ) {
518 $text = $title->getPrefixedText();
521 $data = array(
522 'url' => $url ? $url : '',
523 'text' => $text ? $text : ''
526 return $this->getResult()->addValue( 'query', $property, $data );
529 public function appendLanguages( $property ) {
530 $params = $this->extractRequestParams();
531 $langCode = isset( $params['inlanguagecode'] ) ? $params['inlanguagecode'] : '';
532 $langNames = Language::fetchLanguageNames( $langCode );
534 $data = array();
536 foreach ( $langNames as $code => $name ) {
537 $lang = array( 'code' => $code );
538 ApiResult::setContent( $lang, $name );
539 $data[] = $lang;
541 $this->getResult()->setIndexedTagName( $data, 'lang' );
542 return $this->getResult()->addValue( 'query', $property, $data );
545 public function appendSkins( $property ) {
546 $data = array();
547 foreach ( Skin::getSkinNames() as $name => $displayName ) {
548 $skin = array( 'code' => $name );
549 ApiResult::setContent( $skin, $displayName );
550 $data[] = $skin;
552 $this->getResult()->setIndexedTagName( $data, 'skin' );
553 return $this->getResult()->addValue( 'query', $property, $data );
556 public function appendExtensionTags( $property ) {
557 global $wgParser;
558 $wgParser->firstCallInit();
559 $tags = array_map( array( $this, 'formatParserTags' ), $wgParser->getTags() );
560 $this->getResult()->setIndexedTagName( $tags, 't' );
561 return $this->getResult()->addValue( 'query', $property, $tags );
564 public function appendFunctionHooks( $property ) {
565 global $wgParser;
566 $wgParser->firstCallInit();
567 $hooks = $wgParser->getFunctionHooks();
568 $this->getResult()->setIndexedTagName( $hooks, 'h' );
569 return $this->getResult()->addValue( 'query', $property, $hooks );
572 public function appendVariables( $property ) {
573 $variables = MagicWord::getVariableIDs();
574 $this->getResult()->setIndexedTagName( $variables, 'v' );
575 return $this->getResult()->addValue( 'query', $property, $variables );
578 public function appendProtocols( $property ) {
579 global $wgUrlProtocols;
580 // Make a copy of the global so we don't try to set the _element key of it - bug 45130
581 $protocols = array_values( $wgUrlProtocols );
582 $this->getResult()->setIndexedTagName( $protocols, 'p' );
583 return $this->getResult()->addValue( 'query', $property, $protocols );
586 private function formatParserTags( $item ) {
587 return "<{$item}>";
590 public function appendSubscribedHooks( $property ) {
591 global $wgHooks;
592 $myWgHooks = $wgHooks;
593 ksort( $myWgHooks );
595 $data = array();
596 foreach ( $myWgHooks as $hook => $hooks ) {
597 $arr = array(
598 'name' => $hook,
599 'subscribers' => array_map( array( 'SpecialVersion', 'arrayToString' ), $hooks ),
602 $this->getResult()->setIndexedTagName( $arr['subscribers'], 's' );
603 $data[] = $arr;
606 $this->getResult()->setIndexedTagName( $data, 'hook' );
607 return $this->getResult()->addValue( 'query', $property, $data );
610 public function getCacheMode( $params ) {
611 return 'public';
614 public function getAllowedParams() {
615 return array(
616 'prop' => array(
617 ApiBase::PARAM_DFLT => 'general',
618 ApiBase::PARAM_ISMULTI => true,
619 ApiBase::PARAM_TYPE => array(
620 'general',
621 'namespaces',
622 'namespacealiases',
623 'specialpagealiases',
624 'magicwords',
625 'interwikimap',
626 'dbrepllag',
627 'statistics',
628 'usergroups',
629 'extensions',
630 'fileextensions',
631 'rightsinfo',
632 'languages',
633 'skins',
634 'extensiontags',
635 'functionhooks',
636 'showhooks',
637 'variables',
638 'protocols',
641 'filteriw' => array(
642 ApiBase::PARAM_TYPE => array(
643 'local',
644 '!local',
647 'showalldb' => false,
648 'numberingroup' => false,
649 'inlanguagecode' => null,
653 public function getParamDescription() {
654 $p = $this->getModulePrefix();
655 return array(
656 'prop' => array(
657 'Which sysinfo properties to get:',
658 ' general - Overall system information',
659 ' namespaces - List of registered namespaces and their canonical names',
660 ' namespacealiases - List of registered namespace aliases',
661 ' specialpagealiases - List of special page aliases',
662 ' magicwords - List of magic words and their aliases',
663 ' statistics - Returns site statistics',
664 " interwikimap - Returns interwiki map (optionally filtered, (optionally localised by using {$p}inlanguagecode))",
665 ' dbrepllag - Returns database server with the highest replication lag',
666 ' usergroups - Returns user groups and the associated permissions',
667 ' extensions - Returns extensions installed on the wiki',
668 ' fileextensions - Returns list of file extensions allowed to be uploaded',
669 ' rightsinfo - Returns wiki rights (license) information if available',
670 " languages - Returns a list of languages MediaWiki supports (optionally localised by using {$p}inlanguagecode)",
671 ' skins - Returns a list of all enabled skins',
672 ' extensiontags - Returns a list of parser extension tags',
673 ' functionhooks - Returns a list of parser function hooks',
674 ' showhooks - Returns a list of all subscribed hooks (contents of $wgHooks)',
675 ' variables - Returns a list of variable IDs',
676 ' protocols - Returns a list of protocols that are allowed in external links.',
678 'filteriw' => 'Return only local or only nonlocal entries of the interwiki map',
679 'showalldb' => 'List all database servers, not just the one lagging the most',
680 'numberingroup' => 'Lists the number of users in user groups',
681 'inlanguagecode' => 'Language code for localised language names (best effort, use CLDR extension)',
685 public function getDescription() {
686 return 'Return general information about the site';
689 public function getPossibleErrors() {
690 return array_merge( parent::getPossibleErrors(), array(
691 array( 'code' => 'includeAllDenied', 'info' => 'Cannot view all servers info unless $wgShowHostnames is true' ),
692 ) );
695 public function getExamples() {
696 return array(
697 'api.php?action=query&meta=siteinfo&siprop=general|namespaces|namespacealiases|statistics',
698 'api.php?action=query&meta=siteinfo&siprop=interwikimap&sifilteriw=local',
699 'api.php?action=query&meta=siteinfo&siprop=dbrepllag&sishowalldb=',
703 public function getHelpUrls() {
704 return 'https://www.mediawiki.org/wiki/API:Meta#siteinfo_.2F_si';