summaryrefslogtreecommitdiff
path: root/www/wiki/includes/WikiMap.php
diff options
context:
space:
mode:
Diffstat (limited to 'www/wiki/includes/WikiMap.php')
-rw-r--r--www/wiki/includes/WikiMap.php294
1 files changed, 294 insertions, 0 deletions
diff --git a/www/wiki/includes/WikiMap.php b/www/wiki/includes/WikiMap.php
new file mode 100644
index 00000000..9cc308d2
--- /dev/null
+++ b/www/wiki/includes/WikiMap.php
@@ -0,0 +1,294 @@
+<?php
+/**
+ * Tools for dealing with other locally-hosted wikis.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+use MediaWiki\MediaWikiServices;
+use Wikimedia\Rdbms\DatabaseDomain;
+
+/**
+ * Helper tools for dealing with other locally-hosted wikis.
+ */
+class WikiMap {
+
+ /**
+ * Get a WikiReference object for $wikiID
+ *
+ * @param string $wikiID Wiki'd id (generally database name)
+ * @return WikiReference|null WikiReference object or null if the wiki was not found
+ */
+ public static function getWiki( $wikiID ) {
+ $wikiReference = self::getWikiReferenceFromWgConf( $wikiID );
+ if ( $wikiReference ) {
+ return $wikiReference;
+ }
+
+ // Try sites, if $wgConf failed
+ return self::getWikiWikiReferenceFromSites( $wikiID );
+ }
+
+ /**
+ * @param string $wikiID
+ * @return WikiReference|null WikiReference object or null if the wiki was not found
+ */
+ private static function getWikiReferenceFromWgConf( $wikiID ) {
+ global $wgConf;
+
+ $wgConf->loadFullData();
+
+ list( $major, $minor ) = $wgConf->siteFromDB( $wikiID );
+ if ( $major === null ) {
+ return null;
+ }
+ $server = $wgConf->get( 'wgServer', $wikiID, $major,
+ [ 'lang' => $minor, 'site' => $major ] );
+
+ $canonicalServer = $wgConf->get( 'wgCanonicalServer', $wikiID, $major,
+ [ 'lang' => $minor, 'site' => $major ] );
+ if ( $canonicalServer === false || $canonicalServer === null ) {
+ $canonicalServer = $server;
+ }
+
+ $path = $wgConf->get( 'wgArticlePath', $wikiID, $major,
+ [ 'lang' => $minor, 'site' => $major ] );
+
+ // If we don't have a canonical server or a path containing $1, the
+ // WikiReference isn't going to function properly. Just return null in
+ // that case.
+ if ( !is_string( $canonicalServer ) || !is_string( $path ) || strpos( $path, '$1' ) === false ) {
+ return null;
+ }
+
+ return new WikiReference( $canonicalServer, $path, $server );
+ }
+
+ /**
+ * @param string $wikiID
+ * @return WikiReference|null WikiReference object or null if the wiki was not found
+ */
+ private static function getWikiWikiReferenceFromSites( $wikiID ) {
+ $siteLookup = MediaWikiServices::getInstance()->getSiteLookup();
+ $site = $siteLookup->getSite( $wikiID );
+
+ if ( !$site instanceof MediaWikiSite ) {
+ // Abort if not a MediaWikiSite, as this is about Wikis
+ return null;
+ }
+
+ $urlParts = wfParseUrl( $site->getPageUrl() );
+ if ( $urlParts === false || !isset( $urlParts['path'] ) || !isset( $urlParts['host'] ) ) {
+ // We can't create a meaningful WikiReference without URLs
+ return null;
+ }
+
+ // XXX: Check whether path contains a $1?
+ $path = $urlParts['path'];
+ if ( isset( $urlParts['query'] ) ) {
+ $path .= '?' . $urlParts['query'];
+ }
+
+ $canonicalServer = isset( $urlParts['scheme'] ) ? $urlParts['scheme'] : 'http';
+ $canonicalServer .= '://' . $urlParts['host'];
+
+ return new WikiReference( $canonicalServer, $path );
+ }
+
+ /**
+ * Convenience to get the wiki's display name
+ *
+ * @todo We can give more info than just the wiki id!
+ * @param string $wikiID Wiki'd id (generally database name)
+ * @return string|int Wiki's name or $wiki_id if the wiki was not found
+ */
+ public static function getWikiName( $wikiID ) {
+ $wiki = self::getWiki( $wikiID );
+
+ if ( $wiki ) {
+ return $wiki->getDisplayName();
+ }
+ return $wikiID;
+ }
+
+ /**
+ * Convenience to get a link to a user page on a foreign wiki
+ *
+ * @param string $wikiID Wiki'd id (generally database name)
+ * @param string $user User name (must be normalised before calling this function!)
+ * @param string $text Link's text; optional, default to "User:$user"
+ * @return string HTML link or false if the wiki was not found
+ */
+ public static function foreignUserLink( $wikiID, $user, $text = null ) {
+ return self::makeForeignLink( $wikiID, "User:$user", $text );
+ }
+
+ /**
+ * Convenience to get a link to a page on a foreign wiki
+ *
+ * @param string $wikiID Wiki'd id (generally database name)
+ * @param string $page Page name (must be normalised before calling this function!)
+ * @param string $text Link's text; optional, default to $page
+ * @return string|false HTML link or false if the wiki was not found
+ */
+ public static function makeForeignLink( $wikiID, $page, $text = null ) {
+ if ( !$text ) {
+ $text = $page;
+ }
+
+ $url = self::getForeignURL( $wikiID, $page );
+ if ( $url === false ) {
+ return false;
+ }
+
+ return Linker::makeExternalLink( $url, $text );
+ }
+
+ /**
+ * Convenience to get a url to a page on a foreign wiki
+ *
+ * @param string $wikiID Wiki'd id (generally database name)
+ * @param string $page Page name (must be normalised before calling this function!)
+ * @param string|null $fragmentId
+ *
+ * @return string|bool URL or false if the wiki was not found
+ */
+ public static function getForeignURL( $wikiID, $page, $fragmentId = null ) {
+ $wiki = self::getWiki( $wikiID );
+
+ if ( $wiki ) {
+ return $wiki->getFullUrl( $page, $fragmentId );
+ }
+
+ return false;
+ }
+
+ /**
+ * Get canonical server info for all local wikis in the map that have one
+ *
+ * @return array Map of (local wiki ID => map of (url,parts))
+ * @since 1.30
+ */
+ public static function getCanonicalServerInfoForAllWikis() {
+ $cache = MediaWikiServices::getInstance()->getLocalServerObjectCache();
+
+ return $cache->getWithSetCallback(
+ $cache->makeGlobalKey( 'wikimap', 'canonical-urls' ),
+ $cache::TTL_DAY,
+ function () {
+ global $wgLocalDatabases, $wgCanonicalServer;
+
+ $infoMap = [];
+ // Make sure at least the current wiki is set, for simple configurations.
+ // This also makes it the first in the map, which is useful for common cases.
+ $infoMap[wfWikiID()] = [
+ 'url' => $wgCanonicalServer,
+ 'parts' => wfParseUrl( $wgCanonicalServer )
+ ];
+
+ foreach ( $wgLocalDatabases as $wikiId ) {
+ $wikiReference = self::getWiki( $wikiId );
+ if ( $wikiReference ) {
+ $url = $wikiReference->getCanonicalServer();
+ $infoMap[$wikiId] = [ 'url' => $url, 'parts' => wfParseUrl( $url ) ];
+ }
+ }
+
+ return $infoMap;
+ }
+ );
+ }
+
+ /**
+ * @param string $url
+ * @return bool|string Wiki ID or false
+ * @since 1.30
+ */
+ public static function getWikiFromUrl( $url ) {
+ $urlPartsCheck = wfParseUrl( $url );
+ if ( $urlPartsCheck === false ) {
+ return false;
+ }
+
+ $urlPartsCheck = array_intersect_key( $urlPartsCheck, [ 'host' => 1, 'port' => 1 ] );
+ foreach ( self::getCanonicalServerInfoForAllWikis() as $wikiId => $info ) {
+ $urlParts = $info['parts'];
+ if ( $urlParts === false ) {
+ continue; // sanity
+ }
+
+ $urlParts = array_intersect_key( $urlParts, [ 'host' => 1, 'port' => 1 ] );
+ if ( $urlParts == $urlPartsCheck ) {
+ return $wikiId;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Get the wiki ID of a database domain
+ *
+ * This is like DatabaseDomain::getId() without encoding (for legacy reasons)
+ *
+ * @param string|DatabaseDomain $domain
+ * @return string
+ */
+ public static function getWikiIdFromDomain( $domain ) {
+ if ( !( $domain instanceof DatabaseDomain ) ) {
+ $domain = DatabaseDomain::newFromId( $domain );
+ }
+
+ return strlen( $domain->getTablePrefix() )
+ ? "{$domain->getDatabase()}-{$domain->getTablePrefix()}"
+ : $domain->getDatabase();
+ }
+
+ /**
+ * @param DatabaseDomain|string $domain
+ * @return bool Whether $domain has the same DB/prefix as the current wiki
+ * @since 1.33
+ */
+ public static function isCurrentWikiDbDomain( $domain ) {
+ $domain = DatabaseDomain::newFromId( $domain );
+ $curDomain = self::getCurrentWikiDbDomain();
+
+ if ( !in_array( $curDomain->getSchema(), [ null, 'mediawiki' ], true ) ) {
+ // Include the schema if it is set and is not the default placeholder.
+ // This means a site admin may have specifically taylored the schemas.
+ // Domain IDs might use the form <DB>-<project>-<language>, meaning that
+ // the schema portion must be accounted for to disambiguate wikis.
+ return $curDomain->equals( $domain );
+ }
+
+ return (
+ $curDomain->getDatabase() === $domain->getDatabase() &&
+ $curDomain->getTablePrefix() === $domain->getTablePrefix()
+ );
+ }
+
+ /**
+ * @return DatabaseDomain Database domain of the current wiki
+ * @since 1.33
+ */
+ public static function getCurrentWikiDbDomain() {
+ global $wgDBname, $wgDBmwschema, $wgDBprefix;
+ // Avoid invoking LBFactory to avoid any chance of recursion
+ return new DatabaseDomain( $wgDBname, $wgDBmwschema, (string)$wgDBprefix );
+ }
+}