Merge "Update migrateUserGroup to deal with primary key issue"
[lhc/web/wiklou.git] / includes / api / ApiQuerySiteinfo.php
1 <?php
2 /**
3 *
4 *
5 * Created on Sep 25, 2006
6 *
7 * Copyright © 2006 Yuri Astrakhan "<Firstname><Lastname>@gmail.com"
8 *
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.
13 *
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.
18 *
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
23 *
24 * @file
25 */
26
27 /**
28 * A query action to return meta information about the wiki site.
29 *
30 * @ingroup API
31 */
32 class ApiQuerySiteinfo extends ApiQueryBase {
33
34 public function __construct( $query, $moduleName ) {
35 parent::__construct( $query, $moduleName, 'si' );
36 }
37
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 default:
100 ApiBase::dieDebug( __METHOD__, "Unknown prop=$p" );
101 }
102 if ( !$fit ) {
103 // Abuse siprop as a query-continue parameter
104 // and set it to all unprocessed props
105 $this->setContinueEnumParameter( 'prop', implode( '|',
106 array_diff( $params['prop'], $done ) ) );
107 break;
108 }
109 $done[] = $p;
110 }
111 }
112
113 protected function appendGeneralInfo( $property ) {
114 global $wgContLang;
115
116 $data = array();
117 $mainPage = Title::newMainPage();
118 $data['mainpage'] = $mainPage->getPrefixedText();
119 $data['base'] = wfExpandUrl( $mainPage->getFullUrl(), PROTO_CURRENT );
120 $data['sitename'] = $GLOBALS['wgSitename'];
121 $data['generator'] = "MediaWiki {$GLOBALS['wgVersion']}";
122 $data['phpversion'] = phpversion();
123 $data['phpsapi'] = php_sapi_name();
124 $data['dbtype'] = $GLOBALS['wgDBtype'];
125 $data['dbversion'] = $this->getDB()->getServerVersion();
126
127 $git = SpecialVersion::getGitHeadSha1( $GLOBALS['IP'] );
128 if ( $git ) {
129 $data['git-hash'] = $git;
130 } else {
131 $svn = SpecialVersion::getSvnRevision( $GLOBALS['IP'] );
132 if ( $svn ) {
133 $data['rev'] = $svn;
134 }
135 }
136
137 // 'case-insensitive' option is reserved for future
138 $data['case'] = $GLOBALS['wgCapitalLinks'] ? 'first-letter' : 'case-sensitive';
139
140 if ( isset( $GLOBALS['wgRightsCode'] ) ) {
141 $data['rightscode'] = $GLOBALS['wgRightsCode'];
142 }
143 $data['rights'] = $GLOBALS['wgRightsText'];
144 $data['lang'] = $GLOBALS['wgLanguageCode'];
145
146 $fallbacks = array();
147 foreach( $wgContLang->getFallbackLanguages() as $code ) {
148 $fallbacks[] = array( 'code' => $code );
149 }
150 $data['fallback'] = $fallbacks;
151 $this->getResult()->setIndexedTagName( $data['fallback'], 'lang' );
152
153 if( $wgContLang->hasVariants() ) {
154 $variants = array();
155 foreach( $wgContLang->getVariants() as $code ) {
156 $variants[] = array( 'code' => $code );
157 }
158 $data['variants'] = $variants;
159 $this->getResult()->setIndexedTagName( $data['variants'], 'lang' );
160 }
161
162 if ( $wgContLang->isRTL() ) {
163 $data['rtl'] = '';
164 }
165 $data['fallback8bitEncoding'] = $wgContLang->fallback8bitEncoding();
166
167 if ( wfReadOnly() ) {
168 $data['readonly'] = '';
169 $data['readonlyreason'] = wfReadOnlyReason();
170 }
171 if ( $GLOBALS['wgEnableWriteAPI'] ) {
172 $data['writeapi'] = '';
173 }
174
175 $tz = $GLOBALS['wgLocaltimezone'];
176 $offset = $GLOBALS['wgLocalTZoffset'];
177 if ( is_null( $tz ) ) {
178 $tz = 'UTC';
179 $offset = 0;
180 } elseif ( is_null( $offset ) ) {
181 $offset = 0;
182 }
183 $data['timezone'] = $tz;
184 $data['timeoffset'] = intval( $offset );
185 $data['articlepath'] = $GLOBALS['wgArticlePath'];
186 $data['scriptpath'] = $GLOBALS['wgScriptPath'];
187 $data['script'] = $GLOBALS['wgScript'];
188 $data['variantarticlepath'] = $GLOBALS['wgVariantArticlePath'];
189 $data['server'] = $GLOBALS['wgServer'];
190 $data['wikiid'] = wfWikiID();
191 $data['time'] = wfTimestamp( TS_ISO_8601, time() );
192
193 if ( $GLOBALS['wgMiserMode'] ) {
194 $data['misermode'] = '';
195 }
196
197 $data['maxuploadsize'] = UploadBase::getMaxUploadSize();
198
199 wfRunHooks( 'APIQuerySiteInfoGeneralInfo', array( $this, &$data ) );
200
201 return $this->getResult()->addValue( 'query', $property, $data );
202 }
203
204 protected function appendNamespaces( $property ) {
205 global $wgContLang;
206 $data = array();
207 foreach ( $wgContLang->getFormattedNamespaces() as $ns => $title ) {
208 $data[$ns] = array(
209 'id' => intval( $ns ),
210 'case' => MWNamespace::isCapitalized( $ns ) ? 'first-letter' : 'case-sensitive',
211 );
212 ApiResult::setContent( $data[$ns], $title );
213 $canonical = MWNamespace::getCanonicalName( $ns );
214
215 if ( MWNamespace::hasSubpages( $ns ) ) {
216 $data[$ns]['subpages'] = '';
217 }
218
219 if ( $canonical ) {
220 $data[$ns]['canonical'] = strtr( $canonical, '_', ' ' );
221 }
222
223 if ( MWNamespace::isContent( $ns ) ) {
224 $data[$ns]['content'] = '';
225 }
226
227 if ( MWNamespace::isNonincludable( $ns ) ) {
228 $data[$ns]['nonincludable'] = '';
229 }
230 }
231
232 $this->getResult()->setIndexedTagName( $data, 'ns' );
233 return $this->getResult()->addValue( 'query', $property, $data );
234 }
235
236 protected function appendNamespaceAliases( $property ) {
237 global $wgNamespaceAliases, $wgContLang;
238 $aliases = array_merge( $wgNamespaceAliases, $wgContLang->getNamespaceAliases() );
239 $namespaces = $wgContLang->getNamespaces();
240 $data = array();
241 foreach ( $aliases as $title => $ns ) {
242 if ( $namespaces[$ns] == $title ) {
243 // Don't list duplicates
244 continue;
245 }
246 $item = array(
247 'id' => intval( $ns )
248 );
249 ApiResult::setContent( $item, strtr( $title, '_', ' ' ) );
250 $data[] = $item;
251 }
252
253 $this->getResult()->setIndexedTagName( $data, 'ns' );
254 return $this->getResult()->addValue( 'query', $property, $data );
255 }
256
257 protected function appendSpecialPageAliases( $property ) {
258 global $wgContLang;
259 $data = array();
260 $aliases = $wgContLang->getSpecialPageAliases();
261 foreach ( SpecialPageFactory::getList() as $specialpage => $stuff ) {
262 if ( isset( $aliases[$specialpage] ) ) {
263 $arr = array( 'realname' => $specialpage, 'aliases' => $aliases[$specialpage] );
264 $this->getResult()->setIndexedTagName( $arr['aliases'], 'alias' );
265 $data[] = $arr;
266 }
267 }
268 $this->getResult()->setIndexedTagName( $data, 'specialpage' );
269 return $this->getResult()->addValue( 'query', $property, $data );
270 }
271
272 protected function appendMagicWords( $property ) {
273 global $wgContLang;
274 $data = array();
275 foreach ( $wgContLang->getMagicWords() as $magicword => $aliases ) {
276 $caseSensitive = array_shift( $aliases );
277 $arr = array( 'name' => $magicword, 'aliases' => $aliases );
278 if ( $caseSensitive ) {
279 $arr['case-sensitive'] = '';
280 }
281 $this->getResult()->setIndexedTagName( $arr['aliases'], 'alias' );
282 $data[] = $arr;
283 }
284 $this->getResult()->setIndexedTagName( $data, 'magicword' );
285 return $this->getResult()->addValue( 'query', $property, $data );
286 }
287
288 protected function appendInterwikiMap( $property, $filter ) {
289 $local = null;
290 if ( $filter === 'local' ) {
291 $local = 1;
292 } elseif ( $filter === '!local' ) {
293 $local = 0;
294 } elseif ( $filter ) {
295 ApiBase::dieDebug( __METHOD__, "Unknown filter=$filter" );
296 }
297
298 $params = $this->extractRequestParams();
299 $langCode = isset( $params['inlanguagecode'] ) ? $params['inlanguagecode'] : '';
300 $langNames = Language::fetchLanguageNames( $langCode );
301
302 $getPrefixes = Interwiki::getAllPrefixes( $local );
303 $data = array();
304
305 foreach ( $getPrefixes as $row ) {
306 $prefix = $row['iw_prefix'];
307 $val = array();
308 $val['prefix'] = $prefix;
309 if ( $row['iw_local'] == '1' ) {
310 $val['local'] = '';
311 }
312 // $val['trans'] = intval( $row['iw_trans'] ); // should this be exposed?
313 if ( isset( $langNames[$prefix] ) ) {
314 $val['language'] = $langNames[$prefix];
315 }
316 $val['url'] = wfExpandUrl( $row['iw_url'], PROTO_CURRENT );
317 if( isset( $row['iw_wikiid'] ) ) {
318 $val['wikiid'] = $row['iw_wikiid'];
319 }
320 if( isset( $row['iw_api'] ) ) {
321 $val['api'] = $row['iw_api'];
322 }
323
324 $data[] = $val;
325 }
326
327 $this->getResult()->setIndexedTagName( $data, 'iw' );
328 return $this->getResult()->addValue( 'query', $property, $data );
329 }
330
331 protected function appendDbReplLagInfo( $property, $includeAll ) {
332 global $wgShowHostnames;
333 $data = array();
334 $lb = wfGetLB();
335 if ( $includeAll ) {
336 if ( !$wgShowHostnames ) {
337 $this->dieUsage( 'Cannot view all servers info unless $wgShowHostnames is true', 'includeAllDenied' );
338 }
339
340 $lags = $lb->getLagTimes();
341 foreach ( $lags as $i => $lag ) {
342 $data[] = array(
343 'host' => $lb->getServerName( $i ),
344 'lag' => $lag
345 );
346 }
347 } else {
348 list( $host, $lag, $index ) = $lb->getMaxLag();
349 $data[] = array(
350 'host' => $wgShowHostnames
351 ? $lb->getServerName( $index )
352 : '',
353 'lag' => intval( $lag )
354 );
355 }
356
357 $result = $this->getResult();
358 $result->setIndexedTagName( $data, 'db' );
359 return $this->getResult()->addValue( 'query', $property, $data );
360 }
361
362 protected function appendStatistics( $property ) {
363 global $wgDisableCounters;
364 $data = array();
365 $data['pages'] = intval( SiteStats::pages() );
366 $data['articles'] = intval( SiteStats::articles() );
367 if ( !$wgDisableCounters ) {
368 $data['views'] = intval( SiteStats::views() );
369 }
370 $data['edits'] = intval( SiteStats::edits() );
371 $data['images'] = intval( SiteStats::images() );
372 $data['users'] = intval( SiteStats::users() );
373 $data['activeusers'] = intval( SiteStats::activeUsers() );
374 $data['admins'] = intval( SiteStats::numberingroup( 'sysop' ) );
375 $data['jobs'] = intval( SiteStats::jobs() );
376 return $this->getResult()->addValue( 'query', $property, $data );
377 }
378
379 protected function appendUserGroups( $property, $numberInGroup ) {
380 global $wgGroupPermissions, $wgAddGroups, $wgRemoveGroups, $wgGroupsAddToSelf, $wgGroupsRemoveFromSelf;
381
382 $data = array();
383 $result = $this->getResult();
384 foreach ( $wgGroupPermissions as $group => $permissions ) {
385 $arr = array(
386 'name' => $group,
387 'rights' => array_keys( $permissions, true ),
388 );
389
390 if ( $numberInGroup ) {
391 global $wgAutopromote;
392
393 if ( $group == 'user' ) {
394 $arr['number'] = SiteStats::users();
395
396 // '*' and autopromote groups have no size
397 } elseif ( $group !== '*' && !isset( $wgAutopromote[$group] ) ) {
398 $arr['number'] = SiteStats::numberInGroup( $group );
399 }
400 }
401
402 $groupArr = array(
403 'add' => $wgAddGroups,
404 'remove' => $wgRemoveGroups,
405 'add-self' => $wgGroupsAddToSelf,
406 'remove-self' => $wgGroupsRemoveFromSelf
407 );
408
409 foreach ( $groupArr as $type => $rights ) {
410 if ( isset( $rights[$group] ) ) {
411 $arr[$type] = $rights[$group];
412 $result->setIndexedTagName( $arr[$type], 'group' );
413 }
414 }
415
416 $result->setIndexedTagName( $arr['rights'], 'permission' );
417 $data[] = $arr;
418 }
419
420 $result->setIndexedTagName( $data, 'group' );
421 return $result->addValue( 'query', $property, $data );
422 }
423
424 protected function appendFileExtensions( $property ) {
425 global $wgFileExtensions;
426
427 $data = array();
428 foreach ( $wgFileExtensions as $ext ) {
429 $data[] = array( 'ext' => $ext );
430 }
431 $this->getResult()->setIndexedTagName( $data, 'fe' );
432 return $this->getResult()->addValue( 'query', $property, $data );
433 }
434
435 protected function appendExtensions( $property ) {
436 global $wgExtensionCredits;
437 $data = array();
438 foreach ( $wgExtensionCredits as $type => $extensions ) {
439 foreach ( $extensions as $ext ) {
440 $ret = array();
441 $ret['type'] = $type;
442 if ( isset( $ext['name'] ) ) {
443 $ret['name'] = $ext['name'];
444 }
445 if ( isset( $ext['description'] ) ) {
446 $ret['description'] = $ext['description'];
447 }
448 if ( isset( $ext['descriptionmsg'] ) ) {
449 // Can be a string or array( key, param1, param2, ... )
450 if ( is_array( $ext['descriptionmsg'] ) ) {
451 $ret['descriptionmsg'] = $ext['descriptionmsg'][0];
452 $ret['descriptionmsgparams'] = array_slice( $ext['descriptionmsg'], 1 );
453 $this->getResult()->setIndexedTagName( $ret['descriptionmsgparams'], 'param' );
454 } else {
455 $ret['descriptionmsg'] = $ext['descriptionmsg'];
456 }
457 }
458 if ( isset( $ext['author'] ) ) {
459 $ret['author'] = is_array( $ext['author'] ) ?
460 implode( ', ', $ext['author' ] ) : $ext['author'];
461 }
462 if ( isset( $ext['url'] ) ) {
463 $ret['url'] = $ext['url'];
464 }
465 if ( isset( $ext['version'] ) ) {
466 $ret['version'] = $ext['version'];
467 } elseif ( isset( $ext['svn-revision'] ) &&
468 preg_match( '/\$(?:Rev|LastChangedRevision|Revision): *(\d+)/',
469 $ext['svn-revision'], $m ) )
470 {
471 $ret['version'] = 'r' . $m[1];
472 }
473 $data[] = $ret;
474 }
475 }
476
477 $this->getResult()->setIndexedTagName( $data, 'ext' );
478 return $this->getResult()->addValue( 'query', $property, $data );
479 }
480
481 protected function appendRightsInfo( $property ) {
482 global $wgRightsPage, $wgRightsUrl, $wgRightsText;
483 $title = Title::newFromText( $wgRightsPage );
484 $url = $title ? wfExpandUrl( $title->getFullURL(), PROTO_CURRENT ) : $wgRightsUrl;
485 $text = $wgRightsText;
486 if ( !$text && $title ) {
487 $text = $title->getPrefixedText();
488 }
489
490 $data = array(
491 'url' => $url ? $url : '',
492 'text' => $text ? $text : ''
493 );
494
495 return $this->getResult()->addValue( 'query', $property, $data );
496 }
497
498 public function appendLanguages( $property ) {
499 $params = $this->extractRequestParams();
500 $langCode = isset( $params['inlanguagecode'] ) ? $params['inlanguagecode'] : '';
501 $langNames = Language::fetchLanguageNames( $langCode );
502
503 $data = array();
504
505 foreach ( $langNames as $code => $name ) {
506 $lang = array( 'code' => $code );
507 ApiResult::setContent( $lang, $name );
508 $data[] = $lang;
509 }
510 $this->getResult()->setIndexedTagName( $data, 'lang' );
511 return $this->getResult()->addValue( 'query', $property, $data );
512 }
513
514 public function appendSkins( $property ) {
515 $data = array();
516 foreach ( Skin::getSkinNames() as $name => $displayName ) {
517 $skin = array( 'code' => $name );
518 ApiResult::setContent( $skin, $displayName );
519 $data[] = $skin;
520 }
521 $this->getResult()->setIndexedTagName( $data, 'skin' );
522 return $this->getResult()->addValue( 'query', $property, $data );
523 }
524
525 public function appendExtensionTags( $property ) {
526 global $wgParser;
527 $wgParser->firstCallInit();
528 $tags = array_map( array( $this, 'formatParserTags'), $wgParser->getTags() );
529 $this->getResult()->setIndexedTagName( $tags, 't' );
530 return $this->getResult()->addValue( 'query', $property, $tags );
531 }
532
533 public function appendFunctionHooks( $property ) {
534 global $wgParser;
535 $wgParser->firstCallInit();
536 $hooks = $wgParser->getFunctionHooks();
537 $this->getResult()->setIndexedTagName( $hooks, 'h' );
538 return $this->getResult()->addValue( 'query', $property, $hooks );
539 }
540
541 public function appendVariables( $property ) {
542 $variables = MagicWord::getVariableIDs();
543 $this->getResult()->setIndexedTagName( $variables, 'v' );
544 return $this->getResult()->addValue( 'query', $property, $variables );
545 }
546
547 private function formatParserTags( $item ) {
548 return "<{$item}>";
549 }
550
551 public function appendSubscribedHooks( $property ) {
552 global $wgHooks;
553 $myWgHooks = $wgHooks;
554 ksort( $myWgHooks );
555
556 $data = array();
557 foreach ( $myWgHooks as $hook => $hooks ) {
558 $arr = array(
559 'name' => $hook,
560 'subscribers' => array_map( array( 'SpecialVersion', 'arrayToString' ), $hooks ),
561 );
562
563 $this->getResult()->setIndexedTagName( $arr['subscribers'], 's' );
564 $data[] = $arr;
565 }
566
567 $this->getResult()->setIndexedTagName( $data, 'hook' );
568 return $this->getResult()->addValue( 'query', $property, $data );
569 }
570
571 public function getCacheMode( $params ) {
572 return 'public';
573 }
574
575 public function getAllowedParams() {
576 return array(
577 'prop' => array(
578 ApiBase::PARAM_DFLT => 'general',
579 ApiBase::PARAM_ISMULTI => true,
580 ApiBase::PARAM_TYPE => array(
581 'general',
582 'namespaces',
583 'namespacealiases',
584 'specialpagealiases',
585 'magicwords',
586 'interwikimap',
587 'dbrepllag',
588 'statistics',
589 'usergroups',
590 'extensions',
591 'fileextensions',
592 'rightsinfo',
593 'languages',
594 'skins',
595 'extensiontags',
596 'functionhooks',
597 'showhooks',
598 'variables',
599 )
600 ),
601 'filteriw' => array(
602 ApiBase::PARAM_TYPE => array(
603 'local',
604 '!local',
605 )
606 ),
607 'showalldb' => false,
608 'numberingroup' => false,
609 'inlanguagecode' => null,
610 );
611 }
612
613 public function getParamDescription() {
614 $p = $this->getModulePrefix();
615 return array(
616 'prop' => array(
617 'Which sysinfo properties to get:',
618 ' general - Overall system information',
619 ' namespaces - List of registered namespaces and their canonical names',
620 ' namespacealiases - List of registered namespace aliases',
621 ' specialpagealiases - List of special page aliases',
622 ' magicwords - List of magic words and their aliases',
623 ' statistics - Returns site statistics',
624 " interwikimap - Returns interwiki map (optionally filtered, (optionally localised by using {$p}inlanguagecode))",
625 ' dbrepllag - Returns database server with the highest replication lag',
626 ' usergroups - Returns user groups and the associated permissions',
627 ' extensions - Returns extensions installed on the wiki',
628 ' fileextensions - Returns list of file extensions allowed to be uploaded',
629 ' rightsinfo - Returns wiki rights (license) information if available',
630 " languages - Returns a list of languages MediaWiki supports (optionally localised by using {$p}inlanguagecode)",
631 ' skins - Returns a list of all enabled skins',
632 ' extensiontags - Returns a list of parser extension tags',
633 ' functionhooks - Returns a list of parser function hooks',
634 ' showhooks - Returns a list of all subscribed hooks (contents of $wgHooks)',
635 ' variables - Returns a list of variable IDs',
636 ),
637 'filteriw' => 'Return only local or only nonlocal entries of the interwiki map',
638 'showalldb' => 'List all database servers, not just the one lagging the most',
639 'numberingroup' => 'Lists the number of users in user groups',
640 'inlanguagecode' => 'Language code for localised language names (best effort, use CLDR extension)',
641 );
642 }
643
644 public function getDescription() {
645 return 'Return general information about the site';
646 }
647
648 public function getPossibleErrors() {
649 return array_merge( parent::getPossibleErrors(), array(
650 array( 'code' => 'includeAllDenied', 'info' => 'Cannot view all servers info unless $wgShowHostnames is true' ),
651 ) );
652 }
653
654 public function getExamples() {
655 return array(
656 'api.php?action=query&meta=siteinfo&siprop=general|namespaces|namespacealiases|statistics',
657 'api.php?action=query&meta=siteinfo&siprop=interwikimap&sifilteriw=local',
658 'api.php?action=query&meta=siteinfo&siprop=dbrepllag&sishowalldb=',
659 );
660 }
661
662 public function getHelpUrls() {
663 return 'https://www.mediawiki.org/wiki/API:Meta#siteinfo_.2F_si';
664 }
665
666 public function getVersion() {
667 return __CLASS__ . ': $Id$';
668 }
669 }