MediaWiki REL1_37
ApiQuerySiteinfo.php
Go to the documentation of this file.
1<?php
32
39
42
45
48
51
54
57
60
63
65 private $parser;
66
69
72
74 private $skinFactory;
75
78
81
100 public function __construct(
101 ApiQuery $query,
102 $moduleName,
104 UserGroupManager $userGroupManager,
105 LanguageConverterFactory $languageConverterFactory,
106 LanguageFactory $languageFactory,
107 LanguageNameUtils $languageNameUtils,
108 Language $contentLanguage,
109 NamespaceInfo $namespaceInfo,
110 InterwikiLookup $interwikiLookup,
111 Parser $parser,
112 MagicWordFactory $magicWordFactory,
113 SpecialPageFactory $specialPageFactory,
114 SkinFactory $skinFactory,
115 ILoadBalancer $loadBalancer,
116 ReadOnlyMode $readOnlyMode
117 ) {
118 parent::__construct( $query, $moduleName, 'si' );
119 $this->userOptionsLookup = $userOptionsLookup;
120 $this->userGroupManager = $userGroupManager;
121 $this->languageConverterFactory = $languageConverterFactory;
122 $this->languageFactory = $languageFactory;
123 $this->languageNameUtils = $languageNameUtils;
124 $this->contentLanguage = $contentLanguage;
125 $this->namespaceInfo = $namespaceInfo;
126 $this->interwikiLookup = $interwikiLookup;
127 $this->parser = $parser;
128 $this->magicWordFactory = $magicWordFactory;
129 $this->specialPageFactory = $specialPageFactory;
130 $this->skinFactory = $skinFactory;
131 $this->loadBalancer = $loadBalancer;
132 $this->readOnlyMode = $readOnlyMode;
133 }
134
135 public function execute() {
136 $params = $this->extractRequestParams();
137 $done = [];
138 $fit = false;
139 foreach ( $params['prop'] as $p ) {
140 switch ( $p ) {
141 case 'general':
142 $fit = $this->appendGeneralInfo( $p );
143 break;
144 case 'namespaces':
145 $fit = $this->appendNamespaces( $p );
146 break;
147 case 'namespacealiases':
148 $fit = $this->appendNamespaceAliases( $p );
149 break;
150 case 'specialpagealiases':
151 $fit = $this->appendSpecialPageAliases( $p );
152 break;
153 case 'magicwords':
154 $fit = $this->appendMagicWords( $p );
155 break;
156 case 'interwikimap':
157 $fit = $this->appendInterwikiMap( $p, $params['filteriw'] );
158 break;
159 case 'dbrepllag':
160 $fit = $this->appendDbReplLagInfo( $p, $params['showalldb'] );
161 break;
162 case 'statistics':
163 $fit = $this->appendStatistics( $p );
164 break;
165 case 'usergroups':
166 $fit = $this->appendUserGroups( $p, $params['numberingroup'] );
167 break;
168 case 'libraries':
169 $fit = $this->appendInstalledLibraries( $p );
170 break;
171 case 'extensions':
172 $fit = $this->appendExtensions( $p );
173 break;
174 case 'fileextensions':
175 $fit = $this->appendFileExtensions( $p );
176 break;
177 case 'rightsinfo':
178 $fit = $this->appendRightsInfo( $p );
179 break;
180 case 'restrictions':
181 $fit = $this->appendRestrictions( $p );
182 break;
183 case 'languages':
184 $fit = $this->appendLanguages( $p );
185 break;
186 case 'languagevariants':
187 $fit = $this->appendLanguageVariants( $p );
188 break;
189 case 'skins':
190 $fit = $this->appendSkins( $p );
191 break;
192 case 'extensiontags':
193 $fit = $this->appendExtensionTags( $p );
194 break;
195 case 'functionhooks':
196 $fit = $this->appendFunctionHooks( $p );
197 break;
198 case 'showhooks':
199 $fit = $this->appendSubscribedHooks( $p );
200 break;
201 case 'variables':
202 $fit = $this->appendVariables( $p );
203 break;
204 case 'protocols':
205 $fit = $this->appendProtocols( $p );
206 break;
207 case 'defaultoptions':
208 $fit = $this->appendDefaultOptions( $p );
209 break;
210 case 'uploaddialog':
211 $fit = $this->appendUploadDialog( $p );
212 break;
213 default:
214 ApiBase::dieDebug( __METHOD__, "Unknown prop=$p" ); // @codeCoverageIgnore
215 }
216 if ( !$fit ) {
217 // Abuse siprop as a query-continue parameter
218 // and set it to all unprocessed props
219 $this->setContinueEnumParameter( 'prop', implode( '|',
220 array_diff( $params['prop'], $done ) ) );
221 break;
222 }
223 $done[] = $p;
224 }
225 }
226
227 protected function appendGeneralInfo( $property ) {
228 $config = $this->getConfig();
229
230 $data = [];
231 $mainPage = Title::newMainPage();
232 $data['mainpage'] = $mainPage->getPrefixedText();
233 $data['base'] = wfExpandUrl( $mainPage->getFullURL(), PROTO_CURRENT );
234 $data['sitename'] = $config->get( 'Sitename' );
235 $data['mainpageisdomainroot'] = (bool)$config->get( 'MainPageIsDomainRoot' );
236
237 // A logo can either be a relative or an absolute path
238 // make sure we always return an absolute path
240 $data['logo'] = wfExpandUrl( $logo['1x'], PROTO_RELATIVE );
241
242 $data['generator'] = 'MediaWiki ' . MW_VERSION;
243
244 $data['phpversion'] = PHP_VERSION;
245 $data['phpsapi'] = PHP_SAPI;
246 $data['dbtype'] = $config->get( 'DBtype' );
247 $data['dbversion'] = $this->getDB()->getServerVersion();
248
249 $allowFrom = [ '' ];
250 $allowException = true;
251 if ( !$config->get( 'AllowExternalImages' ) ) {
252 $data['imagewhitelistenabled'] = (bool)$config->get( 'EnableImageWhitelist' );
253 $allowFrom = $config->get( 'AllowExternalImagesFrom' );
254 $allowException = !empty( $allowFrom );
255 }
256 if ( $allowException ) {
257 $data['externalimages'] = (array)$allowFrom;
258 ApiResult::setIndexedTagName( $data['externalimages'], 'prefix' );
259 }
260
261 $data['langconversion'] = !$this->languageConverterFactory->isConversionDisabled();
262 $data['linkconversion'] = !$this->languageConverterFactory->isLinkConversionDisabled();
263 // For backwards compatibility (soft deprecated since MW 1.36)
264 $data['titleconversion'] = $data['linkconversion'];
265
266 $contLangConverter = $this->languageConverterFactory->getLanguageConverter( $this->contentLanguage );
267 if ( $this->contentLanguage->linkPrefixExtension() ) {
268 $linkPrefixCharset = $this->contentLanguage->linkPrefixCharset();
269 $data['linkprefixcharset'] = $linkPrefixCharset;
270 // For backwards compatibility
271 $data['linkprefix'] = "/^((?>.*[^$linkPrefixCharset]|))(.+)$/sDu";
272 } else {
273 $data['linkprefixcharset'] = '';
274 $data['linkprefix'] = '';
275 }
276
277 $linktrail = $this->contentLanguage->linkTrail();
278 $data['linktrail'] = $linktrail ?: '';
279
280 $data['legaltitlechars'] = Title::legalChars();
281 $data['invalidusernamechars'] = $config->get( 'InvalidUsernameCharacters' );
282
283 $data['allunicodefixes'] = (bool)$config->get( 'AllUnicodeFixes' );
284 $data['fixarabicunicode'] = true; // Config removed in 1.35, always true
285 $data['fixmalayalamunicode'] = true; // Config removed in 1.35, always true
286
287 global $IP;
289 if ( $git ) {
290 $data['git-hash'] = $git;
291 $data['git-branch'] =
292 SpecialVersion::getGitCurrentBranch( $GLOBALS['IP'] );
293 }
294
295 // 'case-insensitive' option is reserved for future
296 $data['case'] = $config->get( 'CapitalLinks' ) ? 'first-letter' : 'case-sensitive';
297 $data['lang'] = $config->get( 'LanguageCode' );
298
299 $fallbacks = [];
300 foreach ( $this->contentLanguage->getFallbackLanguages() as $code ) {
301 $fallbacks[] = [ 'code' => $code ];
302 }
303 $data['fallback'] = $fallbacks;
304 ApiResult::setIndexedTagName( $data['fallback'], 'lang' );
305
306 if ( $contLangConverter->hasVariants() ) {
307 $variants = [];
308 foreach ( $contLangConverter->getVariants() as $code ) {
309 $variants[] = [
310 'code' => $code,
311 'name' => $this->contentLanguage->getVariantname( $code ),
312 ];
313 }
314 $data['variants'] = $variants;
315 ApiResult::setIndexedTagName( $data['variants'], 'lang' );
316 }
317
318 $data['rtl'] = $this->contentLanguage->isRTL();
319 $data['fallback8bitEncoding'] = $this->contentLanguage->fallback8bitEncoding();
320
321 $data['readonly'] = $this->readOnlyMode->isReadOnly();
322 if ( $data['readonly'] ) {
323 $data['readonlyreason'] = $this->readOnlyMode->getReason();
324 }
325 $data['writeapi'] = true; // Deprecated since MW 1.32
326
327 $data['maxarticlesize'] = $config->get( 'MaxArticleSize' ) * 1024;
328
329 $tz = $config->get( 'Localtimezone' );
330 $offset = $config->get( 'LocalTZoffset' );
331 $data['timezone'] = $tz;
332 $data['timeoffset'] = (int)$offset;
333 $data['articlepath'] = $config->get( 'ArticlePath' );
334 $data['scriptpath'] = $config->get( 'ScriptPath' );
335 $data['script'] = $config->get( 'Script' );
336 $data['variantarticlepath'] = $config->get( 'VariantArticlePath' );
337 $data[ApiResult::META_BC_BOOLS][] = 'variantarticlepath';
338 $data['server'] = $config->get( 'Server' );
339 $data['servername'] = $config->get( 'ServerName' );
340 $data['wikiid'] = WikiMap::getCurrentWikiId();
341 $data['time'] = wfTimestamp( TS_ISO_8601, time() );
342
343 $data['misermode'] = (bool)$config->get( 'MiserMode' );
344
345 $data['uploadsenabled'] = UploadBase::isEnabled();
346 $data['maxuploadsize'] = UploadBase::getMaxUploadSize();
347 $data['minuploadchunksize'] = ApiUpload::getMinUploadChunkSize( $config );
348
349 $data['galleryoptions'] = $config->get( 'GalleryOptions' );
350
351 $data['thumblimits'] = $config->get( 'ThumbLimits' );
352 ApiResult::setArrayType( $data['thumblimits'], 'BCassoc' );
353 ApiResult::setIndexedTagName( $data['thumblimits'], 'limit' );
354 $data['imagelimits'] = [];
355 ApiResult::setArrayType( $data['imagelimits'], 'BCassoc' );
356 ApiResult::setIndexedTagName( $data['imagelimits'], 'limit' );
357 foreach ( $config->get( 'ImageLimits' ) as $k => $limit ) {
358 $data['imagelimits'][$k] = [ 'width' => $limit[0], 'height' => $limit[1] ];
359 }
360
361 $favicon = $config->get( 'Favicon' );
362 if ( !empty( $favicon ) ) {
363 // wgFavicon can either be a relative or an absolute path
364 // make sure we always return an absolute path
365 $data['favicon'] = wfExpandUrl( $favicon, PROTO_RELATIVE );
366 }
367
368 $data['centralidlookupprovider'] = $config->get( 'CentralIdLookupProvider' );
369 $providerIds = array_keys( $config->get( 'CentralIdLookupProviders' ) );
370 $data['allcentralidlookupproviders'] = $providerIds;
371
372 $data['interwikimagic'] = (bool)$config->get( 'InterwikiMagic' );
373 $data['magiclinks'] = $config->get( 'EnableMagicLinks' );
374
375 $data['categorycollation'] = $config->get( 'CategoryCollation' );
376
377 $this->getHookRunner()->onAPIQuerySiteInfoGeneralInfo( $this, $data );
378
379 return $this->getResult()->addValue( 'query', $property, $data );
380 }
381
382 protected function appendNamespaces( $property ) {
383 $nsProtection = $this->getConfig()->get( 'NamespaceProtection' );
384
385 $data = [
386 ApiResult::META_TYPE => 'assoc',
387 ];
388 foreach (
389 $this->contentLanguage->getFormattedNamespaces()
390 as $ns => $title
391 ) {
392 $data[$ns] = [
393 'id' => (int)$ns,
394 'case' => $this->namespaceInfo->isCapitalized( $ns ) ? 'first-letter' : 'case-sensitive',
395 ];
396 ApiResult::setContentValue( $data[$ns], 'name', $title );
397 $canonical = $this->namespaceInfo->getCanonicalName( $ns );
398
399 $data[$ns]['subpages'] = $this->namespaceInfo->hasSubpages( $ns );
400
401 if ( $canonical ) {
402 $data[$ns]['canonical'] = strtr( $canonical, '_', ' ' );
403 }
404
405 $data[$ns]['content'] = $this->namespaceInfo->isContent( $ns );
406 $data[$ns]['nonincludable'] = $this->namespaceInfo->isNonincludable( $ns );
407
408 if ( isset( $nsProtection[$ns] ) ) {
409 if ( is_array( $nsProtection[$ns] ) ) {
410 $specificNs = implode( "|", array_filter( $nsProtection[$ns] ) );
411 } elseif ( $nsProtection[$ns] !== '' ) {
412 $specificNs = $nsProtection[$ns];
413 }
414 if ( isset( $specificNs ) && $specificNs !== '' ) {
415 $data[$ns]['namespaceprotection'] = $specificNs;
416 }
417 }
418
419 $contentmodel = $this->namespaceInfo->getNamespaceContentModel( $ns );
420 if ( $contentmodel ) {
421 $data[$ns]['defaultcontentmodel'] = $contentmodel;
422 }
423 }
424
425 ApiResult::setArrayType( $data, 'assoc' );
426 ApiResult::setIndexedTagName( $data, 'ns' );
427
428 return $this->getResult()->addValue( 'query', $property, $data );
429 }
430
431 protected function appendNamespaceAliases( $property ) {
432 $aliases = $this->contentLanguage->getNamespaceAliases();
433 $namespaces = $this->contentLanguage->getNamespaces();
434 $data = [];
435 foreach ( $aliases as $title => $ns ) {
436 if ( $namespaces[$ns] == $title ) {
437 // Don't list duplicates
438 continue;
439 }
440 $item = [
441 'id' => (int)$ns
442 ];
443 ApiResult::setContentValue( $item, 'alias', strtr( $title, '_', ' ' ) );
444 $data[] = $item;
445 }
446
447 sort( $data );
448
449 ApiResult::setIndexedTagName( $data, 'ns' );
450
451 return $this->getResult()->addValue( 'query', $property, $data );
452 }
453
454 protected function appendSpecialPageAliases( $property ) {
455 $data = [];
456 $aliases = $this->contentLanguage->getSpecialPageAliases();
457 foreach ( $this->specialPageFactory->getNames() as $specialpage ) {
458 if ( isset( $aliases[$specialpage] ) ) {
459 $arr = [ 'realname' => $specialpage, 'aliases' => $aliases[$specialpage] ];
460 ApiResult::setIndexedTagName( $arr['aliases'], 'alias' );
461 $data[] = $arr;
462 }
463 }
464 ApiResult::setIndexedTagName( $data, 'specialpage' );
465
466 return $this->getResult()->addValue( 'query', $property, $data );
467 }
468
469 protected function appendMagicWords( $property ) {
470 $data = [];
471 foreach (
472 $this->contentLanguage->getMagicWords()
473 as $magicword => $aliases
474 ) {
475 $caseSensitive = array_shift( $aliases );
476 $arr = [ 'name' => $magicword, 'aliases' => $aliases ];
477 $arr['case-sensitive'] = (bool)$caseSensitive;
478 ApiResult::setIndexedTagName( $arr['aliases'], 'alias' );
479 $data[] = $arr;
480 }
481 ApiResult::setIndexedTagName( $data, 'magicword' );
482
483 return $this->getResult()->addValue( 'query', $property, $data );
484 }
485
486 protected function appendInterwikiMap( $property, $filter ) {
487 if ( $filter === 'local' ) {
488 $local = 1;
489 } elseif ( $filter === '!local' ) {
490 $local = 0;
491 } else {
492 // $filter === null
493 $local = null;
494 }
495
496 $params = $this->extractRequestParams();
497 $langCode = $params['inlanguagecode'] ?? '';
498 $interwikiMagic = $this->getConfig()->get( 'InterwikiMagic' );
499
500 if ( $interwikiMagic ) {
501 $langNames = $this->languageNameUtils->getLanguageNames( $langCode );
502 }
503
504 $getPrefixes = $this->interwikiLookup->getAllPrefixes( $local );
505 $extraLangPrefixes = $this->getConfig()->get( 'ExtraInterlanguageLinkPrefixes' );
506 $localInterwikis = $this->getConfig()->get( 'LocalInterwikis' );
507 $data = [];
508
509 foreach ( $getPrefixes as $row ) {
510 $prefix = $row['iw_prefix'];
511 $val = [];
512 $val['prefix'] = $prefix;
513 if ( isset( $row['iw_local'] ) && $row['iw_local'] == '1' ) {
514 $val['local'] = true;
515 }
516 if ( isset( $row['iw_trans'] ) && $row['iw_trans'] == '1' ) {
517 $val['trans'] = true;
518 }
519
520 if ( $interwikiMagic && isset( $langNames[$prefix] ) ) {
521 $val['language'] = $langNames[$prefix];
522 }
523 if ( in_array( $prefix, $localInterwikis ) ) {
524 $val['localinterwiki'] = true;
525 }
526 if ( $interwikiMagic && in_array( $prefix, $extraLangPrefixes ) ) {
527 $val['extralanglink'] = true;
528
529 $linktext = wfMessage( "interlanguage-link-$prefix" );
530 if ( !$linktext->isDisabled() ) {
531 $val['linktext'] = $linktext->text();
532 }
533
534 $sitename = wfMessage( "interlanguage-link-sitename-$prefix" );
535 if ( !$sitename->isDisabled() ) {
536 $val['sitename'] = $sitename->text();
537 }
538 }
539
540 $val['url'] = wfExpandUrl( $row['iw_url'], PROTO_CURRENT );
541 $val['protorel'] = substr( $row['iw_url'], 0, 2 ) == '//';
542 if ( isset( $row['iw_wikiid'] ) && $row['iw_wikiid'] !== '' ) {
543 $val['wikiid'] = $row['iw_wikiid'];
544 }
545 if ( isset( $row['iw_api'] ) && $row['iw_api'] !== '' ) {
546 $val['api'] = $row['iw_api'];
547 }
548
549 $data[] = $val;
550 }
551
552 ApiResult::setIndexedTagName( $data, 'iw' );
553
554 return $this->getResult()->addValue( 'query', $property, $data );
555 }
556
557 protected function appendDbReplLagInfo( $property, $includeAll ) {
558 $data = [];
559 $showHostnames = $this->getConfig()->get( 'ShowHostnames' );
560 if ( $includeAll ) {
561 if ( !$showHostnames ) {
562 $this->dieWithError( 'apierror-siteinfo-includealldenied', 'includeAllDenied' );
563 }
564
565 $lags = $this->loadBalancer->getLagTimes();
566 foreach ( $lags as $i => $lag ) {
567 $data[] = [
568 'host' => $this->loadBalancer->getServerName( $i ),
569 'lag' => $lag
570 ];
571 }
572 } else {
573 list( , $lag, $index ) = $this->loadBalancer->getMaxLag();
574 $data[] = [
575 'host' => $showHostnames
576 ? $this->loadBalancer->getServerName( $index )
577 : '',
578 'lag' => $lag
579 ];
580 }
581
582 ApiResult::setIndexedTagName( $data, 'db' );
583
584 return $this->getResult()->addValue( 'query', $property, $data );
585 }
586
587 protected function appendStatistics( $property ) {
588 $data = [];
589 $data['pages'] = (int)SiteStats::pages();
590 $data['articles'] = (int)SiteStats::articles();
591 $data['edits'] = (int)SiteStats::edits();
592 $data['images'] = (int)SiteStats::images();
593 $data['users'] = (int)SiteStats::users();
594 $data['activeusers'] = (int)SiteStats::activeUsers();
595 $data['admins'] = (int)SiteStats::numberingroup( 'sysop' );
596 $data['jobs'] = (int)SiteStats::jobs();
597
598 $this->getHookRunner()->onAPIQuerySiteInfoStatisticsInfo( $data );
599
600 return $this->getResult()->addValue( 'query', $property, $data );
601 }
602
603 protected function appendUserGroups( $property, $numberInGroup ) {
604 $config = $this->getConfig();
605
606 $data = [];
607 $result = $this->getResult();
608 $allGroups = array_values( $this->userGroupManager->listAllGroups() );
609 foreach ( $config->get( 'GroupPermissions' ) as $group => $permissions ) {
610 $arr = [
611 'name' => $group,
612 'rights' => array_keys( $permissions, true ),
613 ];
614
615 if ( $numberInGroup ) {
616 $autopromote = $config->get( 'Autopromote' );
617
618 if ( $group == 'user' ) {
619 $arr['number'] = SiteStats::users();
620 // '*' and autopromote groups have no size
621 } elseif ( $group !== '*' && !isset( $autopromote[$group] ) ) {
622 $arr['number'] = SiteStats::numberingroup( $group );
623 }
624 }
625
626 $groupArr = [
627 'add' => $config->get( 'AddGroups' ),
628 'remove' => $config->get( 'RemoveGroups' ),
629 'add-self' => $config->get( 'GroupsAddToSelf' ),
630 'remove-self' => $config->get( 'GroupsRemoveFromSelf' )
631 ];
632
633 foreach ( $groupArr as $type => $rights ) {
634 if ( isset( $rights[$group] ) ) {
635 if ( $rights[$group] === true ) {
636 $groups = $allGroups;
637 } else {
638 $groups = array_intersect( $rights[$group], $allGroups );
639 }
640 if ( $groups ) {
641 $arr[$type] = $groups;
642 ApiResult::setArrayType( $arr[$type], 'BCarray' );
643 ApiResult::setIndexedTagName( $arr[$type], 'group' );
644 }
645 }
646 }
647
648 ApiResult::setIndexedTagName( $arr['rights'], 'permission' );
649 $data[] = $arr;
650 }
651
652 ApiResult::setIndexedTagName( $data, 'group' );
653
654 return $result->addValue( 'query', $property, $data );
655 }
656
657 protected function appendFileExtensions( $property ) {
658 $data = [];
659 foreach ( array_unique( $this->getConfig()->get( 'FileExtensions' ) ) as $ext ) {
660 $data[] = [ 'ext' => $ext ];
661 }
662 ApiResult::setIndexedTagName( $data, 'fe' );
663
664 return $this->getResult()->addValue( 'query', $property, $data );
665 }
666
667 protected function appendInstalledLibraries( $property ) {
668 global $IP;
669 $path = "$IP/vendor/composer/installed.json";
670 if ( !file_exists( $path ) ) {
671 return true;
672 }
673
674 $data = [];
675 $installed = new ComposerInstalled( $path );
676 foreach ( $installed->getInstalledDependencies() as $name => $info ) {
677 if ( strpos( $info['type'], 'mediawiki-' ) === 0 ) {
678 // Skip any extensions or skins since they'll be listed
679 // in their proper section
680 continue;
681 }
682 $data[] = [
683 'name' => $name,
684 'version' => $info['version'],
685 ];
686 }
687 ApiResult::setIndexedTagName( $data, 'library' );
688
689 return $this->getResult()->addValue( 'query', $property, $data );
690 }
691
692 protected function appendExtensions( $property ) {
693 $data = [];
695 ExtensionRegistry::getInstance(),
696 $this->getConfig()
697 );
698 foreach ( $credits as $type => $extensions ) {
699 foreach ( $extensions as $ext ) {
700 $ret = [];
701 $ret['type'] = $type;
702 if ( isset( $ext['name'] ) ) {
703 $ret['name'] = $ext['name'];
704 }
705 if ( isset( $ext['namemsg'] ) ) {
706 $ret['namemsg'] = $ext['namemsg'];
707 }
708 if ( isset( $ext['description'] ) ) {
709 $ret['description'] = $ext['description'];
710 }
711 if ( isset( $ext['descriptionmsg'] ) ) {
712 // Can be a string or [ key, param1, param2, ... ]
713 if ( is_array( $ext['descriptionmsg'] ) ) {
714 $ret['descriptionmsg'] = $ext['descriptionmsg'][0];
715 $ret['descriptionmsgparams'] = array_slice( $ext['descriptionmsg'], 1 );
716 ApiResult::setIndexedTagName( $ret['descriptionmsgparams'], 'param' );
717 } else {
718 $ret['descriptionmsg'] = $ext['descriptionmsg'];
719 }
720 }
721 if ( isset( $ext['author'] ) ) {
722 $ret['author'] = is_array( $ext['author'] ) ?
723 implode( ', ', $ext['author'] ) : $ext['author'];
724 }
725 if ( isset( $ext['url'] ) ) {
726 $ret['url'] = $ext['url'];
727 }
728 if ( isset( $ext['version'] ) ) {
729 $ret['version'] = $ext['version'];
730 }
731 if ( isset( $ext['path'] ) ) {
732 $extensionPath = dirname( $ext['path'] );
733 $gitInfo = new GitInfo( $extensionPath );
734 $vcsVersion = $gitInfo->getHeadSHA1();
735 if ( $vcsVersion !== false ) {
736 $ret['vcs-system'] = 'git';
737 $ret['vcs-version'] = $vcsVersion;
738 $ret['vcs-url'] = $gitInfo->getHeadViewUrl();
739 $vcsDate = $gitInfo->getHeadCommitDate();
740 if ( $vcsDate !== false ) {
741 $ret['vcs-date'] = wfTimestamp( TS_ISO_8601, $vcsDate );
742 }
743 }
744
745 if ( ExtensionInfo::getLicenseFileNames( $extensionPath ) ) {
746 $ret['license-name'] = $ext['license-name'] ?? '';
747 $ret['license'] = SpecialPage::getTitleFor(
748 'Version',
749 "License/{$ext['name']}"
750 )->getLinkURL();
751 }
752
753 if ( ExtensionInfo::getAuthorsFileName( $extensionPath ) ) {
754 $ret['credits'] = SpecialPage::getTitleFor(
755 'Version',
756 "Credits/{$ext['name']}"
757 )->getLinkURL();
758 }
759 }
760 $data[] = $ret;
761 }
762 }
763
764 ApiResult::setIndexedTagName( $data, 'ext' );
765
766 return $this->getResult()->addValue( 'query', $property, $data );
767 }
768
769 protected function appendRightsInfo( $property ) {
770 $config = $this->getConfig();
771 $rightsPage = $config->get( 'RightsPage' );
772 // The default value is null, but the installer sets it to empty string
773 if ( strlen( (string)$rightsPage ) ) {
774 $title = Title::newFromText( $rightsPage );
775 $url = wfExpandUrl( $title->getLinkURL(), PROTO_CURRENT );
776 } else {
777 $title = false;
778 $url = $config->get( 'RightsUrl' );
779 }
780 $text = $config->get( 'RightsText' );
781 if ( $title && !strlen( (string)$text ) ) {
782 $text = $title->getPrefixedText();
783 }
784
785 $data = [
786 'url' => (string)$url,
787 'text' => (string)$text,
788 ];
789
790 return $this->getResult()->addValue( 'query', $property, $data );
791 }
792
793 protected function appendRestrictions( $property ) {
794 $config = $this->getConfig();
795 $data = [
796 'types' => $config->get( 'RestrictionTypes' ),
797 'levels' => $config->get( 'RestrictionLevels' ),
798 'cascadinglevels' => $config->get( 'CascadingRestrictionLevels' ),
799 'semiprotectedlevels' => $config->get( 'SemiprotectedRestrictionLevels' ),
800 ];
801
802 ApiResult::setArrayType( $data['types'], 'BCarray' );
803 ApiResult::setArrayType( $data['levels'], 'BCarray' );
804 ApiResult::setArrayType( $data['cascadinglevels'], 'BCarray' );
805 ApiResult::setArrayType( $data['semiprotectedlevels'], 'BCarray' );
806
807 ApiResult::setIndexedTagName( $data['types'], 'type' );
808 ApiResult::setIndexedTagName( $data['levels'], 'level' );
809 ApiResult::setIndexedTagName( $data['cascadinglevels'], 'level' );
810 ApiResult::setIndexedTagName( $data['semiprotectedlevels'], 'level' );
811
812 return $this->getResult()->addValue( 'query', $property, $data );
813 }
814
815 public function appendLanguages( $property ) {
816 $params = $this->extractRequestParams();
817 $langCode = $params['inlanguagecode'] ?? '';
818 $langNames = $this->languageNameUtils->getLanguageNames( $langCode );
819
820 $data = [];
821
822 foreach ( $langNames as $code => $name ) {
823 $lang = [
824 'code' => $code,
825 'bcp47' => LanguageCode::bcp47( $code ),
826 ];
827 ApiResult::setContentValue( $lang, 'name', $name );
828 $data[] = $lang;
829 }
830 ApiResult::setIndexedTagName( $data, 'lang' );
831
832 return $this->getResult()->addValue( 'query', $property, $data );
833 }
834
835 // Export information about which page languages will trigger
836 // language conversion. (T153341)
837 public function appendLanguageVariants( $property ) {
838 $langNames = LanguageConverter::$languagesWithVariants;
839 if ( $this->languageConverterFactory->isConversionDisabled() ) {
840 // Ensure result is empty if language conversion is disabled.
841 $langNames = [];
842 }
843 sort( $langNames );
844
845 $data = [];
846 foreach ( $langNames as $langCode ) {
847 $lang = $this->languageFactory->getLanguage( $langCode );
848 $langConverter = $this->languageConverterFactory->getLanguageConverter( $lang );
849 if ( !$langConverter->hasVariants() ) {
850 // Only languages which have variants should be listed
851 continue;
852 }
853 $data[$langCode] = [];
854 ApiResult::setIndexedTagName( $data[$langCode], 'variant' );
855 ApiResult::setArrayType( $data[$langCode], 'kvp', 'code' );
856
857 $variants = $langConverter->getVariants();
858 sort( $variants );
859 foreach ( $variants as $v ) {
860 $fallbacks = $langConverter->getVariantFallbacks( $v );
861 if ( !is_array( $fallbacks ) ) {
862 $fallbacks = [ $fallbacks ];
863 }
864 $data[$langCode][$v] = [
865 'fallbacks' => $fallbacks,
866 ];
867 ApiResult::setIndexedTagName(
868 $data[$langCode][$v]['fallbacks'], 'variant'
869 );
870 }
871 }
872 ApiResult::setIndexedTagName( $data, 'lang' );
873 ApiResult::setArrayType( $data, 'kvp', 'code' );
874
875 return $this->getResult()->addValue( 'query', $property, $data );
876 }
877
878 public function appendSkins( $property ) {
879 $data = [];
880 $allowed = $this->skinFactory->getAllowedSkins();
881 $default = Skin::normalizeKey( 'default' );
882 $skinNames = $this->skinFactory->getSkinNames();
883
884 foreach ( $skinNames as $name => $displayName ) {
885 $msg = $this->msg( "skinname-{$name}" );
886 $code = $this->getParameter( 'inlanguagecode' );
887 if ( $code && $this->languageNameUtils->isValidCode( $code ) ) {
888 $msg->inLanguage( $code );
889 } else {
890 $msg->inContentLanguage();
891 }
892 if ( $msg->exists() ) {
893 $displayName = $msg->text();
894 }
895 $skin = [ 'code' => $name ];
896 ApiResult::setContentValue( $skin, 'name', $displayName );
897 if ( !isset( $allowed[$name] ) ) {
898 $skin['unusable'] = true;
899 }
900 if ( $name === $default ) {
901 $skin['default'] = true;
902 }
903 $data[] = $skin;
904 }
905 ApiResult::setIndexedTagName( $data, 'skin' );
906
907 return $this->getResult()->addValue( 'query', $property, $data );
908 }
909
910 public function appendExtensionTags( $property ) {
911 $tags = array_map(
912 static function ( $item ) {
913 return "<$item>";
914 },
915 $this->parser->getTags()
916 );
917 ApiResult::setArrayType( $tags, 'BCarray' );
918 ApiResult::setIndexedTagName( $tags, 't' );
919
920 return $this->getResult()->addValue( 'query', $property, $tags );
921 }
922
923 public function appendFunctionHooks( $property ) {
924 $hooks = $this->parser->getFunctionHooks();
925 ApiResult::setArrayType( $hooks, 'BCarray' );
926 ApiResult::setIndexedTagName( $hooks, 'h' );
927
928 return $this->getResult()->addValue( 'query', $property, $hooks );
929 }
930
931 public function appendVariables( $property ) {
932 $variables = $this->magicWordFactory->getVariableIDs();
933 ApiResult::setArrayType( $variables, 'BCarray' );
934 ApiResult::setIndexedTagName( $variables, 'v' );
935
936 return $this->getResult()->addValue( 'query', $property, $variables );
937 }
938
939 public function appendProtocols( $property ) {
940 // Make a copy of the global so we don't try to set the _element key of it - T47130
941 $protocols = array_values( $this->getConfig()->get( 'UrlProtocols' ) );
942 ApiResult::setArrayType( $protocols, 'BCarray' );
943 ApiResult::setIndexedTagName( $protocols, 'p' );
944
945 return $this->getResult()->addValue( 'query', $property, $protocols );
946 }
947
948 public function appendDefaultOptions( $property ) {
949 $options = $this->userOptionsLookup->getDefaultOptions();
950 $options[ApiResult::META_BC_BOOLS] = array_keys( $options );
951 return $this->getResult()->addValue( 'query', $property, $options );
952 }
953
954 public function appendUploadDialog( $property ) {
955 $config = $this->getConfig()->get( 'UploadDialog' );
956 return $this->getResult()->addValue( 'query', $property, $config );
957 }
958
959 public function appendSubscribedHooks( $property ) {
960 $hooks = $this->getConfig()->get( 'Hooks' );
961 $myWgHooks = $hooks;
962 ksort( $myWgHooks );
963
964 $data = [];
965 foreach ( $myWgHooks as $name => $subscribers ) {
966 $arr = [
967 'name' => $name,
968 'subscribers' => array_map( [ SpecialVersion::class, 'arrayToString' ], $subscribers ),
969 ];
970
971 ApiResult::setArrayType( $arr['subscribers'], 'array' );
972 ApiResult::setIndexedTagName( $arr['subscribers'], 's' );
973 $data[] = $arr;
974 }
975
976 ApiResult::setIndexedTagName( $data, 'hook' );
977
978 return $this->getResult()->addValue( 'query', $property, $data );
979 }
980
981 public function getCacheMode( $params ) {
982 // Messages for $wgExtraInterlanguageLinkPrefixes depend on user language
983 if (
984 count( $this->getConfig()->get( 'ExtraInterlanguageLinkPrefixes' ) ) &&
985 $params['prop'] !== null &&
986 in_array( 'interwikimap', $params['prop'] )
987 ) {
988 return 'anon-public-user-private';
989 }
990
991 return 'public';
992 }
993
994 public function getAllowedParams() {
995 return [
996 'prop' => [
997 ApiBase::PARAM_DFLT => 'general',
1000 'general',
1001 'namespaces',
1002 'namespacealiases',
1003 'specialpagealiases',
1004 'magicwords',
1005 'interwikimap',
1006 'dbrepllag',
1007 'statistics',
1008 'usergroups',
1009 'libraries',
1010 'extensions',
1011 'fileextensions',
1012 'rightsinfo',
1013 'restrictions',
1014 'languages',
1015 'languagevariants',
1016 'skins',
1017 'extensiontags',
1018 'functionhooks',
1019 'showhooks',
1020 'variables',
1021 'protocols',
1022 'defaultoptions',
1023 'uploaddialog',
1024 ],
1026 ],
1027 'filteriw' => [
1029 'local',
1030 '!local',
1031 ]
1032 ],
1033 'showalldb' => false,
1034 'numberingroup' => false,
1035 'inlanguagecode' => null,
1036 ];
1037 }
1038
1039 protected function getExamplesMessages() {
1040 return [
1041 'action=query&meta=siteinfo&siprop=general|namespaces|namespacealiases|statistics'
1042 => 'apihelp-query+siteinfo-example-simple',
1043 'action=query&meta=siteinfo&siprop=interwikimap&sifilteriw=local'
1044 => 'apihelp-query+siteinfo-example-interwiki',
1045 'action=query&meta=siteinfo&siprop=dbrepllag&sishowalldb='
1046 => 'apihelp-query+siteinfo-example-replag',
1047 ];
1048 }
1049
1050 public function getHelpUrls() {
1051 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Siteinfo';
1052 }
1053}
getDB()
UserOptionsLookup $userOptionsLookup
const PROTO_CURRENT
Definition Defines.php:195
const MW_VERSION
The running version of MediaWiki.
Definition Defines.php:36
const PROTO_RELATIVE
Definition Defines.php:194
wfExpandUrl( $url, $defaultProto=PROTO_CURRENT)
Expand a potentially local URL to a fully-qualified URL.
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
$linkPrefixCharset
$IP
Definition WebStart.php:49
dieWithError( $msg, $code=null, $data=null, $httpCode=0)
Abort execution with an error.
Definition ApiBase.php:1436
getParameter( $paramName, $parseLimit=true)
Get a value for the given parameter.
Definition ApiBase.php:884
static dieDebug( $method, $message)
Internal code errors should be reported with this method.
Definition ApiBase.php:1633
const PARAM_TYPE
Definition ApiBase.php:81
const PARAM_DFLT
Definition ApiBase.php:73
const PARAM_HELP_MSG_PER_VALUE
((string|array|Message)[]) When PARAM_TYPE is an array, this is an array mapping those values to $msg...
Definition ApiBase.php:195
getResult()
Get the result object.
Definition ApiBase.php:628
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition ApiBase.php:764
getHookRunner()
Get an ApiHookRunner for running core API hooks.
Definition ApiBase.php:710
const PARAM_ISMULTI
Definition ApiBase.php:77
This is a base class for all Query modules.
setContinueEnumParameter( $paramName, $paramValue)
Set a query-continue value.
A query action to return meta information about the wiki site.
appendLanguageVariants( $property)
appendLanguages( $property)
appendInterwikiMap( $property, $filter)
appendGeneralInfo( $property)
LanguageConverterFactory $languageConverterFactory
LanguageFactory $languageFactory
SkinFactory $skinFactory
appendRightsInfo( $property)
NamespaceInfo $namespaceInfo
getExamplesMessages()
Returns usage examples for this module.
appendInstalledLibraries( $property)
appendVariables( $property)
__construct(ApiQuery $query, $moduleName, UserOptionsLookup $userOptionsLookup, UserGroupManager $userGroupManager, LanguageConverterFactory $languageConverterFactory, LanguageFactory $languageFactory, LanguageNameUtils $languageNameUtils, Language $contentLanguage, NamespaceInfo $namespaceInfo, InterwikiLookup $interwikiLookup, Parser $parser, MagicWordFactory $magicWordFactory, SpecialPageFactory $specialPageFactory, SkinFactory $skinFactory, ILoadBalancer $loadBalancer, ReadOnlyMode $readOnlyMode)
MagicWordFactory $magicWordFactory
ILoadBalancer $loadBalancer
appendUserGroups( $property, $numberInGroup)
appendFileExtensions( $property)
UserOptionsLookup $userOptionsLookup
appendNamespaces( $property)
appendDefaultOptions( $property)
LanguageNameUtils $languageNameUtils
appendMagicWords( $property)
getHelpUrls()
Return links to more detailed help pages about the module.
appendExtensions( $property)
ReadOnlyMode $readOnlyMode
getCacheMode( $params)
Get the cache mode for the data generated by this module.
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
appendRestrictions( $property)
appendExtensionTags( $property)
UserGroupManager $userGroupManager
appendUploadDialog( $property)
appendProtocols( $property)
appendStatistics( $property)
appendSpecialPageAliases( $property)
appendDbReplLagInfo( $property, $includeAll)
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
SpecialPageFactory $specialPageFactory
appendSubscribedHooks( $property)
appendFunctionHooks( $property)
appendNamespaceAliases( $property)
InterwikiLookup $interwikiLookup
This is the main query class.
Definition ApiQuery.php:37
static getMinUploadChunkSize(Config $config)
Reads an installed.json file and provides accessors to get what is installed.
msg( $key,... $params)
Get a Message object with context set Parameters are the same as wfMessage()
@newable
Definition GitInfo.php:34
Internationalisation code See https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation for more...
Definition Language.php:42
A factory that stores information about MagicWords, and creates them on demand with caching.
An interface for creating language converters.
Internationalisation code See https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation for more...
A service that provides utilities to do with language names and codes.
Factory for handling the special page list and generating SpecialPage objects.
Provides access to user options.
This is a utility class for dealing with namespaces that encodes all the "magic" behaviors of them ba...
PHP Parser - Processes wiki markup (which uses a more user-friendly syntax, such as "[[link]]" for ma...
Definition Parser.php:91
A service class for fetching the wiki's current read-only mode.
static getAvailableLogos( $conf)
Return an array of all available logos that a skin may use.
static articles()
static jobs()
Total number of jobs in the job queue.
static images()
static edits()
Definition SiteStats.php:94
static users()
static pages()
static numberingroup( $group)
Find the number of users in a given user group.
static activeUsers()
Factory class to create Skin objects.
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name If you don't need a full Title object,...
static getGitHeadSha1( $dir)
static getCredits(ExtensionRegistry $reg, Config $conf)
static getGitCurrentBranch( $dir)
Service interface for looking up Interwiki records.
Database cluster connection, tracking, load balancing, and transaction manager interface.
if(!is_readable( $file)) $ext
Definition router.php:48
if(!isset( $args[0])) $lang