Merge "Revert "Toolbar: Only show on WikiText pages""
[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::getList() as $specialpage => $stuff ) {
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 ( $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 if ( !$this->getConfig()->get( 'DisableCounters' ) ) {
485 $data['views'] = intval( SiteStats::views() );
486 }
487 $data['edits'] = intval( SiteStats::edits() );
488 $data['images'] = intval( SiteStats::images() );
489 $data['users'] = intval( SiteStats::users() );
490 $data['activeusers'] = intval( SiteStats::activeUsers() );
491 $data['admins'] = intval( SiteStats::numberingroup( 'sysop' ) );
492 $data['jobs'] = intval( SiteStats::jobs() );
493
494 wfRunHooks( 'APIQuerySiteInfoStatisticsInfo', array( &$data ) );
495
496 return $this->getResult()->addValue( 'query', $property, $data );
497 }
498
499 protected function appendUserGroups( $property, $numberInGroup ) {
500 $config = $this->getConfig();
501
502 $data = array();
503 $result = $this->getResult();
504 foreach ( $config->get( 'GroupPermissions' ) as $group => $permissions ) {
505 $arr = array(
506 'name' => $group,
507 'rights' => array_keys( $permissions, true ),
508 );
509
510 if ( $numberInGroup ) {
511 $autopromote = $config->get( 'Autopromote' );
512
513 if ( $group == 'user' ) {
514 $arr['number'] = SiteStats::users();
515 // '*' and autopromote groups have no size
516 } elseif ( $group !== '*' && !isset( $autopromote[$group] ) ) {
517 $arr['number'] = SiteStats::numberInGroup( $group );
518 }
519 }
520
521 $groupArr = array(
522 'add' => $config->get( 'AddGroups' ),
523 'remove' => $config->get( 'RemoveGroups' ),
524 'add-self' => $config->get( 'GroupsAddToSelf' ),
525 'remove-self' => $config->get( 'GroupsRemoveFromSelf' )
526 );
527
528 foreach ( $groupArr as $type => $rights ) {
529 if ( isset( $rights[$group] ) ) {
530 $arr[$type] = $rights[$group];
531 $result->setIndexedTagName( $arr[$type], 'group' );
532 }
533 }
534
535 $result->setIndexedTagName( $arr['rights'], 'permission' );
536 $data[] = $arr;
537 }
538
539 $result->setIndexedTagName( $data, 'group' );
540
541 return $result->addValue( 'query', $property, $data );
542 }
543
544 protected function appendFileExtensions( $property ) {
545 $data = array();
546 foreach ( array_unique( $this->getConfig()->get( 'FileExtensions' ) ) as $ext ) {
547 $data[] = array( 'ext' => $ext );
548 }
549 $this->getResult()->setIndexedTagName( $data, 'fe' );
550
551 return $this->getResult()->addValue( 'query', $property, $data );
552 }
553
554 protected function appendExtensions( $property ) {
555 $data = array();
556 foreach ( $this->getConfig()->get( 'ExtensionCredits' ) as $type => $extensions ) {
557 foreach ( $extensions as $ext ) {
558 $ret = array();
559 $ret['type'] = $type;
560 if ( isset( $ext['name'] ) ) {
561 $ret['name'] = $ext['name'];
562 }
563 if ( isset( $ext['namemsg'] ) ) {
564 $ret['namemsg'] = $ext['namemsg'];
565 }
566 if ( isset( $ext['description'] ) ) {
567 $ret['description'] = $ext['description'];
568 }
569 if ( isset( $ext['descriptionmsg'] ) ) {
570 // Can be a string or array( key, param1, param2, ... )
571 if ( is_array( $ext['descriptionmsg'] ) ) {
572 $ret['descriptionmsg'] = $ext['descriptionmsg'][0];
573 $ret['descriptionmsgparams'] = array_slice( $ext['descriptionmsg'], 1 );
574 $this->getResult()->setIndexedTagName( $ret['descriptionmsgparams'], 'param' );
575 } else {
576 $ret['descriptionmsg'] = $ext['descriptionmsg'];
577 }
578 }
579 if ( isset( $ext['author'] ) ) {
580 $ret['author'] = is_array( $ext['author'] ) ?
581 implode( ', ', $ext['author'] ) : $ext['author'];
582 }
583 if ( isset( $ext['url'] ) ) {
584 $ret['url'] = $ext['url'];
585 }
586 if ( isset( $ext['version'] ) ) {
587 $ret['version'] = $ext['version'];
588 } elseif ( isset( $ext['svn-revision'] ) &&
589 preg_match( '/\$(?:Rev|LastChangedRevision|Revision): *(\d+)/',
590 $ext['svn-revision'], $m )
591 ) {
592 $ret['version'] = 'r' . $m[1];
593 }
594 if ( isset( $ext['path'] ) ) {
595 $extensionPath = dirname( $ext['path'] );
596 $gitInfo = new GitInfo( $extensionPath );
597 $vcsVersion = $gitInfo->getHeadSHA1();
598 if ( $vcsVersion !== false ) {
599 $ret['vcs-system'] = 'git';
600 $ret['vcs-version'] = $vcsVersion;
601 $ret['vcs-url'] = $gitInfo->getHeadViewUrl();
602 $vcsDate = $gitInfo->getHeadCommitDate();
603 if ( $vcsDate !== false ) {
604 $ret['vcs-date'] = wfTimestamp( TS_ISO_8601, $vcsDate );
605 }
606 } else {
607 $svnInfo = SpecialVersion::getSvnInfo( $extensionPath );
608 if ( $svnInfo !== false ) {
609 $ret['vcs-system'] = 'svn';
610 $ret['vcs-version'] = $svnInfo['checkout-rev'];
611 $ret['vcs-url'] = isset( $svnInfo['viewvc-url'] ) ? $svnInfo['viewvc-url'] : '';
612 }
613 }
614
615 if ( SpecialVersion::getExtLicenseFileName( $extensionPath ) ) {
616 $ret['license-name'] = isset( $ext['license-name'] ) ? $ext['license-name'] : '';
617 $ret['license'] = SpecialPage::getTitleFor(
618 'Version',
619 "License/{$ext['name']}"
620 )->getLinkURL();
621 }
622
623 if ( SpecialVersion::getExtAuthorsFileName( $extensionPath ) ) {
624 $ret['credits'] = SpecialPage::getTitleFor(
625 'Version',
626 "Credits/{$ext['name']}"
627 )->getLinkURL();
628 }
629 }
630 $data[] = $ret;
631 }
632 }
633
634 $this->getResult()->setIndexedTagName( $data, 'ext' );
635
636 return $this->getResult()->addValue( 'query', $property, $data );
637 }
638
639 protected function appendRightsInfo( $property ) {
640 $config = $this->getConfig();
641 $title = Title::newFromText( $config->get( 'RightsPage' ) );
642 $url = $title ? wfExpandUrl( $title->getFullURL(), PROTO_CURRENT ) : $config->get( 'RightsUrl' );
643 $text = $config->get( 'RightsText' );
644 if ( !$text && $title ) {
645 $text = $title->getPrefixedText();
646 }
647
648 $data = array(
649 'url' => $url ? $url : '',
650 'text' => $text ? $text : ''
651 );
652
653 return $this->getResult()->addValue( 'query', $property, $data );
654 }
655
656 protected function appendRestrictions( $property ) {
657 $config = $this->getConfig();
658 $data = array(
659 'types' => $config->get( 'RestrictionTypes' ),
660 'levels' => $config->get( 'RestrictionLevels' ),
661 'cascadinglevels' => $config->get( 'CascadingRestrictionLevels' ),
662 'semiprotectedlevels' => $config->get( 'SemiprotectedRestrictionLevels' ),
663 );
664
665 $this->getResult()->setIndexedTagName( $data['types'], 'type' );
666 $this->getResult()->setIndexedTagName( $data['levels'], 'level' );
667 $this->getResult()->setIndexedTagName( $data['cascadinglevels'], 'level' );
668 $this->getResult()->setIndexedTagName( $data['semiprotectedlevels'], 'level' );
669
670 return $this->getResult()->addValue( 'query', $property, $data );
671 }
672
673 public function appendLanguages( $property ) {
674 $params = $this->extractRequestParams();
675 $langCode = isset( $params['inlanguagecode'] ) ? $params['inlanguagecode'] : '';
676 $langNames = Language::fetchLanguageNames( $langCode );
677
678 $data = array();
679
680 foreach ( $langNames as $code => $name ) {
681 $lang = array( 'code' => $code );
682 ApiResult::setContent( $lang, $name );
683 $data[] = $lang;
684 }
685 $this->getResult()->setIndexedTagName( $data, 'lang' );
686
687 return $this->getResult()->addValue( 'query', $property, $data );
688 }
689
690 public function appendSkins( $property ) {
691 $data = array();
692 $allowed = Skin::getAllowedSkins();
693 $default = Skin::normalizeKey( 'default' );
694 foreach ( Skin::getSkinNames() as $name => $displayName ) {
695 $skin = array( 'code' => $name );
696 ApiResult::setContent( $skin, $displayName );
697 if ( !isset( $allowed[$name] ) ) {
698 $skin['unusable'] = '';
699 }
700 if ( $name === $default ) {
701 $skin['default'] = '';
702 }
703 $data[] = $skin;
704 }
705 $this->getResult()->setIndexedTagName( $data, 'skin' );
706
707 return $this->getResult()->addValue( 'query', $property, $data );
708 }
709
710 public function appendExtensionTags( $property ) {
711 global $wgParser;
712 $wgParser->firstCallInit();
713 $tags = array_map( array( $this, 'formatParserTags' ), $wgParser->getTags() );
714 $this->getResult()->setIndexedTagName( $tags, 't' );
715
716 return $this->getResult()->addValue( 'query', $property, $tags );
717 }
718
719 public function appendFunctionHooks( $property ) {
720 global $wgParser;
721 $wgParser->firstCallInit();
722 $hooks = $wgParser->getFunctionHooks();
723 $this->getResult()->setIndexedTagName( $hooks, 'h' );
724
725 return $this->getResult()->addValue( 'query', $property, $hooks );
726 }
727
728 public function appendVariables( $property ) {
729 $variables = MagicWord::getVariableIDs();
730 $this->getResult()->setIndexedTagName( $variables, 'v' );
731
732 return $this->getResult()->addValue( 'query', $property, $variables );
733 }
734
735 public function appendProtocols( $property ) {
736 // Make a copy of the global so we don't try to set the _element key of it - bug 45130
737 $protocols = array_values( $this->getConfig()->get( 'UrlProtocols' ) );
738 $this->getResult()->setIndexedTagName( $protocols, 'p' );
739
740 return $this->getResult()->addValue( 'query', $property, $protocols );
741 }
742
743 public function appendDefaultOptions( $property ) {
744 return $this->getResult()->addValue( 'query', $property, User::getDefaultOptions() );
745 }
746
747 private function formatParserTags( $item ) {
748 return "<{$item}>";
749 }
750
751 public function appendSubscribedHooks( $property ) {
752 $hooks = $this->getConfig()->get( 'Hooks' );
753 $myWgHooks = $hooks;
754 ksort( $myWgHooks );
755
756 $data = array();
757 foreach ( $myWgHooks as $name => $subscribers ) {
758 $arr = array(
759 'name' => $name,
760 'subscribers' => array_map( array( 'SpecialVersion', 'arrayToString' ), $subscribers ),
761 );
762
763 $this->getResult()->setIndexedTagName( $arr['subscribers'], 's' );
764 $data[] = $arr;
765 }
766
767 $this->getResult()->setIndexedTagName( $data, 'hook' );
768
769 return $this->getResult()->addValue( 'query', $property, $data );
770 }
771
772 public function getCacheMode( $params ) {
773 // Messages for $wgExtraInterlanguageLinkPrefixes depend on user language
774 if (
775 count( $this->getConfig()->get( 'ExtraInterlanguageLinkPrefixes' ) ) &&
776 !is_null( $params['prop'] ) &&
777 in_array( 'interwikimap', $params['prop'] )
778 ) {
779 return 'anon-public-user-private';
780 }
781
782 return 'public';
783 }
784
785 public function getAllowedParams() {
786 return array(
787 'prop' => array(
788 ApiBase::PARAM_DFLT => 'general',
789 ApiBase::PARAM_ISMULTI => true,
790 ApiBase::PARAM_TYPE => array(
791 'general',
792 'namespaces',
793 'namespacealiases',
794 'specialpagealiases',
795 'magicwords',
796 'interwikimap',
797 'dbrepllag',
798 'statistics',
799 'usergroups',
800 'extensions',
801 'fileextensions',
802 'rightsinfo',
803 'restrictions',
804 'languages',
805 'skins',
806 'extensiontags',
807 'functionhooks',
808 'showhooks',
809 'variables',
810 'protocols',
811 'defaultoptions',
812 )
813 ),
814 'filteriw' => array(
815 ApiBase::PARAM_TYPE => array(
816 'local',
817 '!local',
818 )
819 ),
820 'showalldb' => false,
821 'numberingroup' => false,
822 'inlanguagecode' => null,
823 );
824 }
825
826 public function getParamDescription() {
827 $p = $this->getModulePrefix();
828
829 return array(
830 'prop' => array(
831 'Which sysinfo properties to get:',
832 ' general - Overall system information',
833 ' namespaces - List of registered namespaces and their canonical names',
834 ' namespacealiases - List of registered namespace aliases',
835 ' specialpagealiases - List of special page aliases',
836 ' magicwords - List of magic words and their aliases',
837 ' statistics - Returns site statistics',
838 ' interwikimap - Returns interwiki map ' .
839 "(optionally filtered, (optionally localised by using {$p}inlanguagecode))",
840 ' dbrepllag - Returns database server with the highest replication lag',
841 ' usergroups - Returns user groups and the associated permissions',
842 ' extensions - Returns extensions installed on the wiki',
843 ' fileextensions - Returns list of file extensions allowed to be uploaded',
844 ' rightsinfo - Returns wiki rights (license) information if available',
845 ' restrictions - Returns information on available restriction (protection) types',
846 ' languages - Returns a list of languages MediaWiki supports' .
847 "(optionally localised by using {$p}inlanguagecode)",
848 ' skins - Returns a list of all enabled skins',
849 ' extensiontags - Returns a list of parser extension tags',
850 ' functionhooks - Returns a list of parser function hooks',
851 ' showhooks - Returns a list of all subscribed hooks (contents of $wgHooks)',
852 ' variables - Returns a list of variable IDs',
853 ' protocols - Returns a list of protocols that are allowed in external links.',
854 ' defaultoptions - Returns the default values for user preferences.',
855 ),
856 'filteriw' => 'Return only local or only nonlocal entries of the interwiki map',
857 'showalldb' => 'List all database servers, not just the one lagging the most',
858 'numberingroup' => 'Lists the number of users in user groups',
859 'inlanguagecode' => 'Language code for localised language names ' .
860 '(best effort, use CLDR extension)',
861 );
862 }
863
864 public function getDescription() {
865 return 'Return general information about the site.';
866 }
867
868 public function getExamples() {
869 return array(
870 'api.php?action=query&meta=siteinfo&siprop=general|namespaces|namespacealiases|statistics',
871 'api.php?action=query&meta=siteinfo&siprop=interwikimap&sifilteriw=local',
872 'api.php?action=query&meta=siteinfo&siprop=dbrepllag&sishowalldb=',
873 );
874 }
875
876 public function getHelpUrls() {
877 return 'https://www.mediawiki.org/wiki/API:Meta#siteinfo_.2F_si';
878 }
879 }