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