Indicate whether interwiki links can use protocol-relative URLs.
[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( ApiQuery $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 'restrictions':
82 $fit = $this->appendRestrictions( $p );
83 break;
84 case 'languages':
85 $fit = $this->appendLanguages( $p );
86 break;
87 case 'skins':
88 $fit = $this->appendSkins( $p );
89 break;
90 case 'extensiontags':
91 $fit = $this->appendExtensionTags( $p );
92 break;
93 case 'functionhooks':
94 $fit = $this->appendFunctionHooks( $p );
95 break;
96 case 'showhooks':
97 $fit = $this->appendSubscribedHooks( $p );
98 break;
99 case 'variables':
100 $fit = $this->appendVariables( $p );
101 break;
102 case 'protocols':
103 $fit = $this->appendProtocols( $p );
104 break;
105 case 'defaultoptions':
106 $fit = $this->appendDefaultOptions( $p );
107 break;
108 default:
109 ApiBase::dieDebug( __METHOD__, "Unknown prop=$p" );
110 }
111 if ( !$fit ) {
112 // Abuse siprop as a query-continue parameter
113 // and set it to all unprocessed props
114 $this->setContinueEnumParameter( 'prop', implode( '|',
115 array_diff( $params['prop'], $done ) ) );
116 break;
117 }
118 $done[] = $p;
119 }
120 }
121
122 protected function appendGeneralInfo( $property ) {
123 global $wgContLang, $wgDisableLangConversion, $wgDisableTitleConversion;
124
125 $data = array();
126 $mainPage = Title::newMainPage();
127 $data['mainpage'] = $mainPage->getPrefixedText();
128 $data['base'] = wfExpandUrl( $mainPage->getFullURL(), PROTO_CURRENT );
129 $data['sitename'] = $GLOBALS['wgSitename'];
130
131 // wgLogo can either be a relative or an absolute path
132 // make sure we always return an absolute path
133 $data['logo'] = wfExpandUrl( $GLOBALS['wgLogo'], PROTO_RELATIVE );
134
135 $data['generator'] = "MediaWiki {$GLOBALS['wgVersion']}";
136 $data['phpversion'] = phpversion();
137 $data['phpsapi'] = PHP_SAPI;
138 $data['dbtype'] = $GLOBALS['wgDBtype'];
139 $data['dbversion'] = $this->getDB()->getServerVersion();
140
141 $allowFrom = array( '' );
142 $allowException = true;
143 if ( !$GLOBALS['wgAllowExternalImages'] ) {
144 if ( $GLOBALS['wgEnableImageWhitelist'] ) {
145 $data['imagewhitelistenabled'] = '';
146 }
147 $allowFrom = $GLOBALS['wgAllowExternalImagesFrom'];
148 $allowException = !empty( $allowFrom );
149 }
150 if ( $allowException ) {
151 $data['externalimages'] = (array)$allowFrom;
152 $this->getResult()->setIndexedTagName( $data['externalimages'], 'prefix' );
153 }
154
155 if ( !$wgDisableLangConversion ) {
156 $data['langconversion'] = '';
157 }
158
159 if ( !$wgDisableTitleConversion ) {
160 $data['titleconversion'] = '';
161 }
162
163 if ( $wgContLang->linkPrefixExtension() ) {
164 $linkPrefixCharset = $wgContLang->linkPrefixCharset();
165 $data['linkprefixcharset'] = $linkPrefixCharset;
166 // For backwards compatability
167 $data['linkprefix'] = "/^((?>.*[^$linkPrefixCharset]|))(.+)$/sDu";
168 } else {
169 $data['linkprefixcharset'] = '';
170 $data['linkprefix'] = '';
171 }
172
173 $linktrail = $wgContLang->linkTrail();
174 if ( $linktrail ) {
175 $data['linktrail'] = $linktrail;
176 } else {
177 $data['linktrail'] = '';
178 }
179
180 $git = SpecialVersion::getGitHeadSha1( $GLOBALS['IP'] );
181 if ( $git ) {
182 $data['git-hash'] = $git;
183 $data['git-branch'] =
184 SpecialVersion::getGitCurrentBranch( $GLOBALS['IP'] );
185 } else {
186 $svn = SpecialVersion::getSvnRevision( $GLOBALS['IP'] );
187 if ( $svn ) {
188 $data['rev'] = $svn;
189 }
190 }
191
192 // 'case-insensitive' option is reserved for future
193 $data['case'] = $GLOBALS['wgCapitalLinks'] ? 'first-letter' : 'case-sensitive';
194
195 $data['lang'] = $GLOBALS['wgLanguageCode'];
196
197 $fallbacks = array();
198 foreach ( $wgContLang->getFallbackLanguages() as $code ) {
199 $fallbacks[] = array( 'code' => $code );
200 }
201 $data['fallback'] = $fallbacks;
202 $this->getResult()->setIndexedTagName( $data['fallback'], 'lang' );
203
204 if ( $wgContLang->hasVariants() ) {
205 $variants = array();
206 foreach ( $wgContLang->getVariants() as $code ) {
207 $variants[] = array(
208 'code' => $code,
209 'name' => $wgContLang->getVariantname( $code ),
210 );
211 }
212 $data['variants'] = $variants;
213 $this->getResult()->setIndexedTagName( $data['variants'], 'lang' );
214 }
215
216 if ( $wgContLang->isRTL() ) {
217 $data['rtl'] = '';
218 }
219 $data['fallback8bitEncoding'] = $wgContLang->fallback8bitEncoding();
220
221 if ( wfReadOnly() ) {
222 $data['readonly'] = '';
223 $data['readonlyreason'] = wfReadOnlyReason();
224 }
225 if ( $GLOBALS['wgEnableWriteAPI'] ) {
226 $data['writeapi'] = '';
227 }
228
229 $tz = $GLOBALS['wgLocaltimezone'];
230 $offset = $GLOBALS['wgLocalTZoffset'];
231 if ( is_null( $tz ) ) {
232 $tz = 'UTC';
233 $offset = 0;
234 } elseif ( is_null( $offset ) ) {
235 $offset = 0;
236 }
237 $data['timezone'] = $tz;
238 $data['timeoffset'] = intval( $offset );
239 $data['articlepath'] = $GLOBALS['wgArticlePath'];
240 $data['scriptpath'] = $GLOBALS['wgScriptPath'];
241 $data['script'] = $GLOBALS['wgScript'];
242 $data['variantarticlepath'] = $GLOBALS['wgVariantArticlePath'];
243 $data['server'] = $GLOBALS['wgServer'];
244 $data['servername'] = $GLOBALS['wgServerName'];
245 $data['wikiid'] = wfWikiID();
246 $data['time'] = wfTimestamp( TS_ISO_8601, time() );
247
248 if ( $GLOBALS['wgMiserMode'] ) {
249 $data['misermode'] = '';
250 }
251
252 $data['maxuploadsize'] = UploadBase::getMaxUploadSize();
253
254 $data['thumblimits'] = $GLOBALS['wgThumbLimits'];
255 $this->getResult()->setIndexedTagName( $data['thumblimits'], 'limit' );
256 $data['imagelimits'] = array();
257 $this->getResult()->setIndexedTagName( $data['imagelimits'], 'limit' );
258 foreach ( $GLOBALS['wgImageLimits'] as $k => $limit ) {
259 $data['imagelimits'][$k] = array( 'width' => $limit[0], 'height' => $limit[1] );
260 }
261
262 if ( !empty( $GLOBALS['wgFavicon'] ) ) {
263 // wgFavicon can either be a relative or an absolute path
264 // make sure we always return an absolute path
265 $data['favicon'] = wfExpandUrl( $GLOBALS['wgFavicon'], PROTO_RELATIVE );
266 }
267
268 wfRunHooks( 'APIQuerySiteInfoGeneralInfo', array( $this, &$data ) );
269
270 return $this->getResult()->addValue( 'query', $property, $data );
271 }
272
273 protected function appendNamespaces( $property ) {
274 global $wgContLang;
275 $data = array();
276 foreach ( $wgContLang->getFormattedNamespaces() as $ns => $title ) {
277 $data[$ns] = array(
278 'id' => intval( $ns ),
279 'case' => MWNamespace::isCapitalized( $ns ) ? 'first-letter' : 'case-sensitive',
280 );
281 ApiResult::setContent( $data[$ns], $title );
282 $canonical = MWNamespace::getCanonicalName( $ns );
283
284 if ( MWNamespace::hasSubpages( $ns ) ) {
285 $data[$ns]['subpages'] = '';
286 }
287
288 if ( $canonical ) {
289 $data[$ns]['canonical'] = strtr( $canonical, '_', ' ' );
290 }
291
292 if ( MWNamespace::isContent( $ns ) ) {
293 $data[$ns]['content'] = '';
294 }
295
296 if ( MWNamespace::isNonincludable( $ns ) ) {
297 $data[$ns]['nonincludable'] = '';
298 }
299
300 $contentmodel = MWNamespace::getNamespaceContentModel( $ns );
301 if ( $contentmodel ) {
302 $data[$ns]['defaultcontentmodel'] = $contentmodel;
303 }
304 }
305
306 $this->getResult()->setIndexedTagName( $data, 'ns' );
307
308 return $this->getResult()->addValue( 'query', $property, $data );
309 }
310
311 protected function appendNamespaceAliases( $property ) {
312 global $wgNamespaceAliases, $wgContLang;
313 $aliases = array_merge( $wgNamespaceAliases, $wgContLang->getNamespaceAliases() );
314 $namespaces = $wgContLang->getNamespaces();
315 $data = array();
316 foreach ( $aliases as $title => $ns ) {
317 if ( $namespaces[$ns] == $title ) {
318 // Don't list duplicates
319 continue;
320 }
321 $item = array(
322 'id' => intval( $ns )
323 );
324 ApiResult::setContent( $item, strtr( $title, '_', ' ' ) );
325 $data[] = $item;
326 }
327
328 sort( $data );
329
330 $this->getResult()->setIndexedTagName( $data, 'ns' );
331
332 return $this->getResult()->addValue( 'query', $property, $data );
333 }
334
335 protected function appendSpecialPageAliases( $property ) {
336 global $wgContLang;
337 $data = array();
338 $aliases = $wgContLang->getSpecialPageAliases();
339 foreach ( SpecialPageFactory::getList() as $specialpage => $stuff ) {
340 if ( isset( $aliases[$specialpage] ) ) {
341 $arr = array( 'realname' => $specialpage, 'aliases' => $aliases[$specialpage] );
342 $this->getResult()->setIndexedTagName( $arr['aliases'], 'alias' );
343 $data[] = $arr;
344 }
345 }
346 $this->getResult()->setIndexedTagName( $data, 'specialpage' );
347
348 return $this->getResult()->addValue( 'query', $property, $data );
349 }
350
351 protected function appendMagicWords( $property ) {
352 global $wgContLang;
353 $data = array();
354 foreach ( $wgContLang->getMagicWords() as $magicword => $aliases ) {
355 $caseSensitive = array_shift( $aliases );
356 $arr = array( 'name' => $magicword, 'aliases' => $aliases );
357 if ( $caseSensitive ) {
358 $arr['case-sensitive'] = '';
359 }
360 $this->getResult()->setIndexedTagName( $arr['aliases'], 'alias' );
361 $data[] = $arr;
362 }
363 $this->getResult()->setIndexedTagName( $data, 'magicword' );
364
365 return $this->getResult()->addValue( 'query', $property, $data );
366 }
367
368 protected function appendInterwikiMap( $property, $filter ) {
369 $local = null;
370 if ( $filter === 'local' ) {
371 $local = 1;
372 } elseif ( $filter === '!local' ) {
373 $local = 0;
374 } elseif ( $filter ) {
375 ApiBase::dieDebug( __METHOD__, "Unknown filter=$filter" );
376 }
377
378 $params = $this->extractRequestParams();
379 $langCode = isset( $params['inlanguagecode'] ) ? $params['inlanguagecode'] : '';
380 $langNames = Language::fetchLanguageNames( $langCode );
381
382 $getPrefixes = Interwiki::getAllPrefixes( $local );
383 $data = array();
384
385 foreach ( $getPrefixes as $row ) {
386 $prefix = $row['iw_prefix'];
387 $val = array();
388 $val['prefix'] = $prefix;
389 if ( $row['iw_local'] == '1' ) {
390 $val['local'] = '';
391 }
392 if ( $row['iw_trans'] == '1' ) {
393 $val['trans'] = '';
394 }
395 if ( isset( $langNames[$prefix] ) ) {
396 $val['language'] = $langNames[$prefix];
397 }
398 $val['url'] = wfExpandUrl( $row['iw_url'], PROTO_CURRENT );
399 if (substr( $row['iw_url'], 0, 2) == '//') {
400 $val['protorel'] = true;
401 }
402 if ( isset( $row['iw_wikiid'] ) ) {
403 $val['wikiid'] = $row['iw_wikiid'];
404 }
405 if ( isset( $row['iw_api'] ) ) {
406 $val['api'] = $row['iw_api'];
407 }
408
409 $data[] = $val;
410 }
411
412 $this->getResult()->setIndexedTagName( $data, 'iw' );
413
414 return $this->getResult()->addValue( 'query', $property, $data );
415 }
416
417 protected function appendDbReplLagInfo( $property, $includeAll ) {
418 global $wgShowHostnames;
419 $data = array();
420 $lb = wfGetLB();
421 if ( $includeAll ) {
422 if ( !$wgShowHostnames ) {
423 $this->dieUsage(
424 'Cannot view all servers info unless $wgShowHostnames is true',
425 'includeAllDenied'
426 );
427 }
428
429 $lags = $lb->getLagTimes();
430 foreach ( $lags as $i => $lag ) {
431 $data[] = array(
432 'host' => $lb->getServerName( $i ),
433 'lag' => $lag
434 );
435 }
436 } else {
437 list( , $lag, $index ) = $lb->getMaxLag();
438 $data[] = array(
439 'host' => $wgShowHostnames
440 ? $lb->getServerName( $index )
441 : '',
442 'lag' => intval( $lag )
443 );
444 }
445
446 $result = $this->getResult();
447 $result->setIndexedTagName( $data, 'db' );
448
449 return $this->getResult()->addValue( 'query', $property, $data );
450 }
451
452 protected function appendStatistics( $property ) {
453 global $wgDisableCounters;
454 $data = array();
455 $data['pages'] = intval( SiteStats::pages() );
456 $data['articles'] = intval( SiteStats::articles() );
457 if ( !$wgDisableCounters ) {
458 $data['views'] = intval( SiteStats::views() );
459 }
460 $data['edits'] = intval( SiteStats::edits() );
461 $data['images'] = intval( SiteStats::images() );
462 $data['users'] = intval( SiteStats::users() );
463 $data['activeusers'] = intval( SiteStats::activeUsers() );
464 $data['admins'] = intval( SiteStats::numberingroup( 'sysop' ) );
465 $data['jobs'] = intval( SiteStats::jobs() );
466
467 wfRunHooks( 'APIQuerySiteInfoStatisticsInfo', array( &$data ) );
468
469 return $this->getResult()->addValue( 'query', $property, $data );
470 }
471
472 protected function appendUserGroups( $property, $numberInGroup ) {
473 global $wgGroupPermissions, $wgAddGroups, $wgRemoveGroups;
474 global $wgGroupsAddToSelf, $wgGroupsRemoveFromSelf;
475
476 $data = array();
477 $result = $this->getResult();
478 foreach ( $wgGroupPermissions as $group => $permissions ) {
479 $arr = array(
480 'name' => $group,
481 'rights' => array_keys( $permissions, true ),
482 );
483
484 if ( $numberInGroup ) {
485 global $wgAutopromote;
486
487 if ( $group == 'user' ) {
488 $arr['number'] = SiteStats::users();
489 // '*' and autopromote groups have no size
490 } elseif ( $group !== '*' && !isset( $wgAutopromote[$group] ) ) {
491 $arr['number'] = SiteStats::numberInGroup( $group );
492 }
493 }
494
495 $groupArr = array(
496 'add' => $wgAddGroups,
497 'remove' => $wgRemoveGroups,
498 'add-self' => $wgGroupsAddToSelf,
499 'remove-self' => $wgGroupsRemoveFromSelf
500 );
501
502 foreach ( $groupArr as $type => $rights ) {
503 if ( isset( $rights[$group] ) ) {
504 $arr[$type] = $rights[$group];
505 $result->setIndexedTagName( $arr[$type], 'group' );
506 }
507 }
508
509 $result->setIndexedTagName( $arr['rights'], 'permission' );
510 $data[] = $arr;
511 }
512
513 $result->setIndexedTagName( $data, 'group' );
514
515 return $result->addValue( 'query', $property, $data );
516 }
517
518 protected function appendFileExtensions( $property ) {
519 global $wgFileExtensions;
520
521 $data = array();
522 foreach ( array_unique( $wgFileExtensions ) as $ext ) {
523 $data[] = array( 'ext' => $ext );
524 }
525 $this->getResult()->setIndexedTagName( $data, 'fe' );
526
527 return $this->getResult()->addValue( 'query', $property, $data );
528 }
529
530 protected function appendExtensions( $property ) {
531 global $wgExtensionCredits;
532 $data = array();
533 foreach ( $wgExtensionCredits as $type => $extensions ) {
534 foreach ( $extensions as $ext ) {
535 $ret = array();
536 $ret['type'] = $type;
537 if ( isset( $ext['name'] ) ) {
538 $ret['name'] = $ext['name'];
539 }
540 if ( isset( $ext['description'] ) ) {
541 $ret['description'] = $ext['description'];
542 }
543 if ( isset( $ext['descriptionmsg'] ) ) {
544 // Can be a string or array( key, param1, param2, ... )
545 if ( is_array( $ext['descriptionmsg'] ) ) {
546 $ret['descriptionmsg'] = $ext['descriptionmsg'][0];
547 $ret['descriptionmsgparams'] = array_slice( $ext['descriptionmsg'], 1 );
548 $this->getResult()->setIndexedTagName( $ret['descriptionmsgparams'], 'param' );
549 } else {
550 $ret['descriptionmsg'] = $ext['descriptionmsg'];
551 }
552 }
553 if ( isset( $ext['author'] ) ) {
554 $ret['author'] = is_array( $ext['author'] ) ?
555 implode( ', ', $ext['author'] ) : $ext['author'];
556 }
557 if ( isset( $ext['url'] ) ) {
558 $ret['url'] = $ext['url'];
559 }
560 if ( isset( $ext['version'] ) ) {
561 $ret['version'] = $ext['version'];
562 } elseif ( isset( $ext['svn-revision'] ) &&
563 preg_match( '/\$(?:Rev|LastChangedRevision|Revision): *(\d+)/',
564 $ext['svn-revision'], $m )
565 ) {
566 $ret['version'] = 'r' . $m[1];
567 }
568 if ( isset( $ext['path'] ) ) {
569 $extensionPath = dirname( $ext['path'] );
570 $gitInfo = new GitInfo( $extensionPath );
571 $vcsVersion = $gitInfo->getHeadSHA1();
572 if ( $vcsVersion !== false ) {
573 $ret['vcs-system'] = 'git';
574 $ret['vcs-version'] = $vcsVersion;
575 $ret['vcs-url'] = $gitInfo->getHeadViewUrl();
576 $vcsDate = $gitInfo->getHeadCommitDate();
577 if ( $vcsDate !== false ) {
578 $ret['vcs-date'] = wfTimestamp( TS_ISO_8601, $vcsDate );
579 }
580 } else {
581 $svnInfo = SpecialVersion::getSvnInfo( $extensionPath );
582 if ( $svnInfo !== false ) {
583 $ret['vcs-system'] = 'svn';
584 $ret['vcs-version'] = $svnInfo['checkout-rev'];
585 $ret['vcs-url'] = isset( $svnInfo['viewvc-url'] ) ? $svnInfo['viewvc-url'] : '';
586 }
587 }
588
589 if ( SpecialVersion::getExtLicenseFileName( $extensionPath ) ) {
590 $ret['license-name'] = isset( $ext['license-name'] ) ? $ext['license-name'] : '';
591 $ret['license'] = SpecialPage::getTitleFor(
592 'Version',
593 "License/{$ext['name']}"
594 )->getLinkURL();
595 }
596
597 if ( SpecialVersion::getExtAuthorsFileName( $extensionPath ) ) {
598 $ret['credits'] = SpecialPage::getTitleFor(
599 'Version',
600 "Credits/{$ext['name']}"
601 )->getLinkURL();
602 }
603 }
604 $data[] = $ret;
605 }
606 }
607
608 $this->getResult()->setIndexedTagName( $data, 'ext' );
609
610 return $this->getResult()->addValue( 'query', $property, $data );
611 }
612
613 protected function appendRightsInfo( $property ) {
614 global $wgRightsPage, $wgRightsUrl, $wgRightsText;
615 $title = Title::newFromText( $wgRightsPage );
616 $url = $title ? wfExpandUrl( $title->getFullURL(), PROTO_CURRENT ) : $wgRightsUrl;
617 $text = $wgRightsText;
618 if ( !$text && $title ) {
619 $text = $title->getPrefixedText();
620 }
621
622 $data = array(
623 'url' => $url ? $url : '',
624 'text' => $text ? $text : ''
625 );
626
627 return $this->getResult()->addValue( 'query', $property, $data );
628 }
629
630 protected function appendRestrictions( $property ) {
631 global $wgRestrictionTypes, $wgRestrictionLevels,
632 $wgCascadingRestrictionLevels, $wgSemiprotectedRestrictionLevels;
633
634 $data = array(
635 'types' => $wgRestrictionTypes,
636 'levels' => $wgRestrictionLevels,
637 'cascadinglevels' => $wgCascadingRestrictionLevels,
638 'semiprotectedlevels' => $wgSemiprotectedRestrictionLevels,
639 );
640
641 $this->getResult()->setIndexedTagName( $data['types'], 'type' );
642 $this->getResult()->setIndexedTagName( $data['levels'], 'level' );
643 $this->getResult()->setIndexedTagName( $data['cascadinglevels'], 'level' );
644 $this->getResult()->setIndexedTagName( $data['semiprotectedlevels'], 'level' );
645
646 return $this->getResult()->addValue( 'query', $property, $data );
647 }
648
649 public function appendLanguages( $property ) {
650 $params = $this->extractRequestParams();
651 $langCode = isset( $params['inlanguagecode'] ) ? $params['inlanguagecode'] : '';
652 $langNames = Language::fetchLanguageNames( $langCode );
653
654 $data = array();
655
656 foreach ( $langNames as $code => $name ) {
657 $lang = array( 'code' => $code );
658 ApiResult::setContent( $lang, $name );
659 $data[] = $lang;
660 }
661 $this->getResult()->setIndexedTagName( $data, 'lang' );
662
663 return $this->getResult()->addValue( 'query', $property, $data );
664 }
665
666 public function appendSkins( $property ) {
667 $data = array();
668 $allowed = Skin::getAllowedSkins();
669 $default = Skin::normalizeKey( 'default' );
670 foreach ( Skin::getSkinNames() as $name => $displayName ) {
671 $skin = array( 'code' => $name );
672 ApiResult::setContent( $skin, $displayName );
673 if ( !isset( $allowed[$name] ) ) {
674 $skin['unusable'] = '';
675 }
676 if ( $name === $default ) {
677 $skin['default'] = '';
678 }
679 $data[] = $skin;
680 }
681 $this->getResult()->setIndexedTagName( $data, 'skin' );
682
683 return $this->getResult()->addValue( 'query', $property, $data );
684 }
685
686 public function appendExtensionTags( $property ) {
687 global $wgParser;
688 $wgParser->firstCallInit();
689 $tags = array_map( array( $this, 'formatParserTags' ), $wgParser->getTags() );
690 $this->getResult()->setIndexedTagName( $tags, 't' );
691
692 return $this->getResult()->addValue( 'query', $property, $tags );
693 }
694
695 public function appendFunctionHooks( $property ) {
696 global $wgParser;
697 $wgParser->firstCallInit();
698 $hooks = $wgParser->getFunctionHooks();
699 $this->getResult()->setIndexedTagName( $hooks, 'h' );
700
701 return $this->getResult()->addValue( 'query', $property, $hooks );
702 }
703
704 public function appendVariables( $property ) {
705 $variables = MagicWord::getVariableIDs();
706 $this->getResult()->setIndexedTagName( $variables, 'v' );
707
708 return $this->getResult()->addValue( 'query', $property, $variables );
709 }
710
711 public function appendProtocols( $property ) {
712 global $wgUrlProtocols;
713 // Make a copy of the global so we don't try to set the _element key of it - bug 45130
714 $protocols = array_values( $wgUrlProtocols );
715 $this->getResult()->setIndexedTagName( $protocols, 'p' );
716
717 return $this->getResult()->addValue( 'query', $property, $protocols );
718 }
719
720 public function appendDefaultOptions( $property ) {
721 return $this->getResult()->addValue( 'query', $property, User::getDefaultOptions() );
722 }
723
724 private function formatParserTags( $item ) {
725 return "<{$item}>";
726 }
727
728 public function appendSubscribedHooks( $property ) {
729 global $wgHooks;
730 $myWgHooks = $wgHooks;
731 ksort( $myWgHooks );
732
733 $data = array();
734 foreach ( $myWgHooks as $hook => $hooks ) {
735 $arr = array(
736 'name' => $hook,
737 'subscribers' => array_map( array( 'SpecialVersion', 'arrayToString' ), $hooks ),
738 );
739
740 $this->getResult()->setIndexedTagName( $arr['subscribers'], 's' );
741 $data[] = $arr;
742 }
743
744 $this->getResult()->setIndexedTagName( $data, 'hook' );
745
746 return $this->getResult()->addValue( 'query', $property, $data );
747 }
748
749 public function getCacheMode( $params ) {
750 return 'public';
751 }
752
753 public function getAllowedParams() {
754 return array(
755 'prop' => array(
756 ApiBase::PARAM_DFLT => 'general',
757 ApiBase::PARAM_ISMULTI => true,
758 ApiBase::PARAM_TYPE => array(
759 'general',
760 'namespaces',
761 'namespacealiases',
762 'specialpagealiases',
763 'magicwords',
764 'interwikimap',
765 'dbrepllag',
766 'statistics',
767 'usergroups',
768 'extensions',
769 'fileextensions',
770 'rightsinfo',
771 'restrictions',
772 'languages',
773 'skins',
774 'extensiontags',
775 'functionhooks',
776 'showhooks',
777 'variables',
778 'protocols',
779 'defaultoptions',
780 )
781 ),
782 'filteriw' => array(
783 ApiBase::PARAM_TYPE => array(
784 'local',
785 '!local',
786 )
787 ),
788 'showalldb' => false,
789 'numberingroup' => false,
790 'inlanguagecode' => null,
791 );
792 }
793
794 public function getParamDescription() {
795 $p = $this->getModulePrefix();
796
797 return array(
798 'prop' => array(
799 'Which sysinfo properties to get:',
800 ' general - Overall system information',
801 ' namespaces - List of registered namespaces and their canonical names',
802 ' namespacealiases - List of registered namespace aliases',
803 ' specialpagealiases - List of special page aliases',
804 ' magicwords - List of magic words and their aliases',
805 ' statistics - Returns site statistics',
806 ' interwikimap - Returns interwiki map ' .
807 "(optionally filtered, (optionally localised by using {$p}inlanguagecode))",
808 ' dbrepllag - Returns database server with the highest replication lag',
809 ' usergroups - Returns user groups and the associated permissions',
810 ' extensions - Returns extensions installed on the wiki',
811 ' fileextensions - Returns list of file extensions allowed to be uploaded',
812 ' rightsinfo - Returns wiki rights (license) information if available',
813 ' restrictions - Returns information on available restriction (protection) types',
814 ' languages - Returns a list of languages MediaWiki supports' .
815 "(optionally localised by using {$p}inlanguagecode)",
816 ' skins - Returns a list of all enabled skins',
817 ' extensiontags - Returns a list of parser extension tags',
818 ' functionhooks - Returns a list of parser function hooks',
819 ' showhooks - Returns a list of all subscribed hooks (contents of $wgHooks)',
820 ' variables - Returns a list of variable IDs',
821 ' protocols - Returns a list of protocols that are allowed in external links.',
822 ' defaultoptions - Returns the default values for user preferences.',
823 ),
824 'filteriw' => 'Return only local or only nonlocal entries of the interwiki map',
825 'showalldb' => 'List all database servers, not just the one lagging the most',
826 'numberingroup' => 'Lists the number of users in user groups',
827 'inlanguagecode' => 'Language code for localised language names ' .
828 '(best effort, use CLDR extension)',
829 );
830 }
831
832 public function getDescription() {
833 return 'Return general information about the site.';
834 }
835
836 public function getPossibleErrors() {
837 return array_merge( parent::getPossibleErrors(), array( array(
838 'code' => 'includeAllDenied',
839 'info' => 'Cannot view all servers info unless $wgShowHostnames is true'
840 ), ) );
841 }
842
843 public function getExamples() {
844 return array(
845 'api.php?action=query&meta=siteinfo&siprop=general|namespaces|namespacealiases|statistics',
846 'api.php?action=query&meta=siteinfo&siprop=interwikimap&sifilteriw=local',
847 'api.php?action=query&meta=siteinfo&siprop=dbrepllag&sishowalldb=',
848 );
849 }
850
851 public function getHelpUrls() {
852 return 'https://www.mediawiki.org/wiki/API:Meta#siteinfo_.2F_si';
853 }
854 }