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