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