MediaWiki  master
WikiMap.php
Go to the documentation of this file.
1 <?php
22 
25 use MediaWikiSite;
27 
31 class WikiMap {
32 
39  public static function getWiki( $wikiID ) {
40  $wikiReference = self::getWikiReferenceFromWgConf( $wikiID );
41  if ( $wikiReference ) {
42  return $wikiReference;
43  }
44 
45  // Try sites, if $wgConf failed
46  return self::getWikiWikiReferenceFromSites( $wikiID );
47  }
48 
53  private static function getWikiReferenceFromWgConf( $wikiID ) {
54  global $wgConf;
55  '@phan-var \MediaWiki\Config\SiteConfiguration $wgConf';
56 
57  $wgConf->loadFullData();
58 
59  [ $major, $minor ] = $wgConf->siteFromDB( $wikiID );
60  if ( $major === null ) {
61  return null;
62  }
63  $server = $wgConf->get( 'wgServer', $wikiID, $major,
64  [ 'lang' => $minor, 'site' => $major ] );
65 
66  $canonicalServer = $wgConf->get( 'wgCanonicalServer', $wikiID, $major,
67  [ 'lang' => $minor, 'site' => $major ] );
68  if ( $canonicalServer === false || $canonicalServer === null ) {
69  $canonicalServer = $server;
70  }
71 
72  $path = $wgConf->get( 'wgArticlePath', $wikiID, $major,
73  [ 'lang' => $minor, 'site' => $major ] );
74 
75  // If we don't have a canonical server or a path containing $1, the
76  // WikiReference isn't going to function properly. Just return null in
77  // that case.
78  if ( !is_string( $canonicalServer ) || !is_string( $path ) || strpos( $path, '$1' ) === false ) {
79  return null;
80  }
81 
82  return new WikiReference( $canonicalServer, $path, $server );
83  }
84 
89  private static function getWikiWikiReferenceFromSites( $wikiID ) {
90  $siteLookup = MediaWikiServices::getInstance()->getSiteLookup();
91  $site = $siteLookup->getSite( $wikiID );
92 
93  if ( !$site instanceof MediaWikiSite ) {
94  // Abort if not a MediaWikiSite, as this is about Wikis
95  return null;
96  }
97 
98  $urlParts = wfParseUrl( $site->getPageUrl() );
99  if ( $urlParts === false || !isset( $urlParts['path'] ) || !isset( $urlParts['host'] ) ) {
100  // We can't create a meaningful WikiReference without URLs
101  return null;
102  }
103 
104  // XXX: Check whether path contains a $1?
105  $path = $urlParts['path'];
106  if ( isset( $urlParts['query'] ) ) {
107  $path .= '?' . $urlParts['query'];
108  }
109 
110  $canonicalServer = $urlParts['scheme'] ?? 'http';
111  $canonicalServer .= '://' . $urlParts['host'];
112  if ( isset( $urlParts['port'] ) ) {
113  $canonicalServer .= ':' . $urlParts['port'];
114  }
115 
116  return new WikiReference( $canonicalServer, $path );
117  }
118 
126  public static function getWikiName( $wikiID ) {
127  $wiki = self::getWiki( $wikiID );
128  return $wiki ? $wiki->getDisplayName() : $wikiID;
129  }
130 
139  public static function foreignUserLink( $wikiID, $user, $text = null ) {
140  return self::makeForeignLink( $wikiID, "User:$user", $text );
141  }
142 
151  public static function makeForeignLink( $wikiID, $page, $text = null ) {
152  if ( !$text ) {
153  $text = $page;
154  }
155 
156  $url = self::getForeignURL( $wikiID, $page );
157  if ( $url === false ) {
158  return false;
159  }
160 
161  return Linker::makeExternalLink( $url, $text );
162  }
163 
173  public static function getForeignURL( $wikiID, $page, $fragmentId = null ) {
174  $wiki = self::getWiki( $wikiID );
175 
176  if ( $wiki ) {
177  return $wiki->getFullUrl( $page, $fragmentId );
178  }
179 
180  return false;
181  }
182 
190  public static function getCanonicalServerInfoForAllWikis() {
191  $cache = MediaWikiServices::getInstance()->getLocalServerObjectCache();
192 
193  return $cache->getWithSetCallback(
194  $cache->makeGlobalKey( 'wikimap-canonical-urls' ),
195  $cache::TTL_DAY,
196  static function () {
198 
199  $infoMap = [];
200  // Make sure at least the current wiki is set, for simple configurations.
201  // This also makes it the first in the map, which is useful for common cases.
202  $wikiId = self::getCurrentWikiId();
203  $infoMap[$wikiId] = [
204  'url' => $wgCanonicalServer,
205  'parts' => wfParseUrl( $wgCanonicalServer )
206  ];
207 
208  foreach ( $wgLocalDatabases as $wikiId ) {
209  $wikiReference = self::getWiki( $wikiId );
210  if ( $wikiReference ) {
211  $url = $wikiReference->getCanonicalServer();
212  $infoMap[$wikiId] = [ 'url' => $url, 'parts' => wfParseUrl( $url ) ];
213  }
214  }
215 
216  return $infoMap;
217  }
218  );
219  }
220 
226  public static function getWikiFromUrl( $url ) {
227  global $wgCanonicalServer;
228 
229  if ( strpos( $url, "$wgCanonicalServer/" ) === 0 ) {
230  // Optimisation: Handle the common case.
231  // (Duplicates self::getCanonicalServerInfoForAllWikis)
232  return self::getCurrentWikiId();
233  }
234 
235  $urlPartsCheck = wfParseUrl( $url );
236  if ( $urlPartsCheck === false ) {
237  return false;
238  }
239 
240  static $relevantKeys = [ 'host' => 1, 'port' => 1 ];
241  $urlPartsCheck = array_intersect_key( $urlPartsCheck, $relevantKeys );
242 
243  foreach ( self::getCanonicalServerInfoForAllWikis() as $wikiId => $info ) {
244  $urlParts = $info['parts'];
245  if ( $urlParts === false ) {
246  continue;
247  }
248 
249  $urlParts = array_intersect_key( $urlParts, $relevantKeys );
250  if ( $urlParts == $urlPartsCheck ) {
251  return $wikiId;
252  }
253  }
254 
255  return false;
256  }
257 
271  public static function getWikiIdFromDbDomain( $domain ) {
272  $domain = DatabaseDomain::newFromId( $domain );
273  // Since the schema was not always part of the wiki ID, try to maintain backwards
274  // compatibility with some common cases. Assume that if the DB domain schema is just
275  // the installer default then it is probably the case that the schema is the same for
276  // all wikis in the farm. Historically, any wiki farm had to make the database/prefix
277  // combination unique per wiki. Omit the schema if it does not seem wiki specific.
278  if ( !in_array( $domain->getSchema(), [ null, 'mediawiki' ], true ) ) {
279  // This means a site admin may have specifically tailored the schemas.
280  // Domain IDs might use the form <DB>-<project>- or <DB>-<project>-<language>_,
281  // meaning that the schema portion must be accounted for to disambiguate wikis.
282  return "{$domain->getDatabase()}-{$domain->getSchema()}-{$domain->getTablePrefix()}";
283  }
284  // Note that if this wiki ID is passed as a domain ID to LoadBalancer, then it can
285  // handle the schema by assuming the generic "mediawiki" schema if needed.
286  return strlen( $domain->getTablePrefix() )
287  ? "{$domain->getDatabase()}-{$domain->getTablePrefix()}"
288  : (string)$domain->getDatabase();
289  }
290 
295  public static function getCurrentWikiDbDomain() {
297  // Avoid invoking LBFactory to avoid any chance of recursion
298  return new DatabaseDomain( $wgDBname, $wgDBmwschema, (string)$wgDBprefix );
299  }
300 
305  public static function getCurrentWikiId() {
306  return self::getWikiIdFromDbDomain( self::getCurrentWikiDbDomain() );
307  }
308 
314  public static function isCurrentWikiDbDomain( $domain ) {
315  return self::getCurrentWikiDbDomain()->equals( $domain );
316  }
317 
323  public static function isCurrentWikiId( $wikiId ) {
324  return ( self::getCurrentWikiId() === $wikiId );
325  }
326 }
327 
331 class_alias( WikiMap::class, 'WikiMap' );
wfParseUrl( $url)
parse_url() work-alike, but non-broken.
$wgConf
$wgConf hold the site configuration.
Definition: Setup.php:144
Class representing a MediaWiki site.
Some internal bits split of from Skin.php.
Definition: Linker.php:65
static makeExternalLink( $url, $text, $escape=true, $linktype='', $attribs=[], $title=null)
Make an external link.
Definition: Linker.php:1136
Service locator for MediaWiki core services.
static getInstance()
Returns the global default instance of the top level service locator.
Tools for dealing with other locally-hosted wikis.
Definition: WikiMap.php:31
static getWikiFromUrl( $url)
Definition: WikiMap.php:226
static getCanonicalServerInfoForAllWikis()
Get canonical server info for all local wikis in the map that have one.
Definition: WikiMap.php:190
static isCurrentWikiDbDomain( $domain)
Definition: WikiMap.php:314
static isCurrentWikiId( $wikiId)
Definition: WikiMap.php:323
static foreignUserLink( $wikiID, $user, $text=null)
Convenience to get a link to a user page on a foreign wiki.
Definition: WikiMap.php:139
static getCurrentWikiDbDomain()
Definition: WikiMap.php:295
static getForeignURL( $wikiID, $page, $fragmentId=null)
Convenience to get a url to a page on a foreign wiki.
Definition: WikiMap.php:173
static makeForeignLink( $wikiID, $page, $text=null)
Convenience to get a link to a page on a foreign wiki.
Definition: WikiMap.php:151
static getWiki( $wikiID)
Get a WikiReference object for $wikiID.
Definition: WikiMap.php:39
static getWikiIdFromDbDomain( $domain)
Get the wiki ID of a database domain.
Definition: WikiMap.php:271
static getWikiName( $wikiID)
Convenience to get the wiki's display name.
Definition: WikiMap.php:126
Class to handle database/schema/prefix specifications for IDatabase.
$wgDBprefix
Config variable stub for the DBprefix setting, for use by phpdoc and IDEs.
$wgLocalDatabases
Config variable stub for the LocalDatabases setting, for use by phpdoc and IDEs.
$wgDBmwschema
Config variable stub for the DBmwschema setting, for use by phpdoc and IDEs.
$wgDBname
Config variable stub for the DBname setting, for use by phpdoc and IDEs.
$wgCanonicalServer
Config variable stub for the CanonicalServer setting, for use by phpdoc and IDEs.
Definition: config-vars.php:31