* This queues an extension to be loaded through
* the ExtensionRegistry system.
*
- * @param string $name Name of the extension to load
+ * @param string $ext Name of the extension to load
* @param string|null $path Absolute path of where to find the extension.json file
*/
-function wfLoadExtension( $name, $path = null ) {
+function wfLoadExtension( $ext, $path = null ) {
if ( !$path ) {
- global $IP;
- $path = "$IP/extensions/$name/extension.json";
+ global $wgExtensionDirectory;
+ $path = "$wgExtensionDirectory/$ext/extension.json";
}
ExtensionRegistry::getInstance()->queue( $path );
}
* @param string[] $exts Array of extension names to load
*/
function wfLoadExtensions( array $exts ) {
- global $IP;
+ global $wgExtensionDirectory;
$registry = ExtensionRegistry::getInstance();
foreach ( $exts as $ext ) {
- $registry->queue( "$IP/extensions/$ext/extension.json" );
+ $registry->queue( "$wgExtensionDirectory/$ext/extension.json" );
}
}
* Load a skin
*
* @see wfLoadExtension
- * @param string $name Name of the extension to load
+ * @param string $skin Name of the extension to load
* @param string|null $path Absolute path of where to find the skin.json file
*/
-function wfLoadSkin( $name, $path = null ) {
+function wfLoadSkin( $skin, $path = null ) {
if ( !$path ) {
- global $IP;
- $path = "$IP/skins/$name/skin.json";
+ global $wgStyleDirectory;
+ $path = "$wgStyleDirectory/$skin/skin.json";
}
ExtensionRegistry::getInstance()->queue( $path );
}
* @param string[] $skins Array of extension names to load
*/
function wfLoadSkins( array $skins ) {
- global $IP;
+ global $wgStyleDirectory;
$registry = ExtensionRegistry::getInstance();
foreach ( $skins as $skin ) {
- $registry->queue( "$IP/skins/$skin/skin.json" );
+ $registry->queue( "$wgStyleDirectory/$skin/skin.json" );
}
}
*
* ;:@&=$-_.+!*'(),
*
+ * RFC 1738 says ~ is unsafe, however RFC 3986 considers it an unreserved
+ * character which should not be encoded. More importantly, google chrome
+ * always converts %7E back to ~, and converting it in this function can
+ * cause a redirect loop (T105265).
+ *
* But + is not safe because it's used to indicate a space; &= are only safe in
* paths and not in queries (and we don't distinguish here); ' seems kind of
* scary; and urlencode() doesn't touch -_. to begin with. Plus, although /
* is reserved, we don't care. So the list we unescape is:
*
- * ;:@$!*(),/
+ * ;:@$!*(),/~
*
* However, IIS7 redirects fail when the url contains a colon (Bug 22709),
* so no fancy : for IIS7.
}
if ( is_null( $needle ) ) {
- $needle = array( '%3B', '%40', '%24', '%21', '%2A', '%28', '%29', '%2C', '%2F' );
+ $needle = array( '%3B', '%40', '%24', '%21', '%2A', '%28', '%29', '%2C', '%2F', '%7E' );
if ( !isset( $_SERVER['SERVER_SOFTWARE'] ) ||
( strpos( $_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS/7' ) === false )
) {
$s = urlencode( $s );
$s = str_ireplace(
$needle,
- array( ';', '@', '$', '!', '*', '(', ')', ',', '/', ':' ),
+ array( ';', '@', '$', '!', '*', '(', ')', ',', '/', '~', ':' ),
$s
);
if ( $wasRelative ) {
$url = "http:$url";
}
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$bits = parse_url( $url );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
// parse_url() returns an array without scheme for some invalid URLs, e.g.
// parse_url("%0Ahttp://example.com") == array( 'host' => '%0Ahttp', 'path' => 'example.com' )
if ( !$bits || !isset( $bits['scheme'] ) ) {
$profiler->logData();
$config = $context->getConfig();
- if ( $config->has( 'StatsdServer' ) ) {
+ if ( $config->get( 'StatsdServer' ) ) {
$statsdServer = explode( ':', $config->get( 'StatsdServer' ) );
$statsdHost = $statsdServer[0];
$statsdPort = isset( $statsdServer[1] ) ? $statsdServer[1] : 8125;
}
// Callers use this method to be aware that data presented to a user
// may be very stale and thus allowing submissions can be problematic.
- if ( $wgReadOnly === false && wfGetLB()->getLaggedSlaveMode() ) {
+ try {
+ if ( $wgReadOnly === false && wfGetLB()->getLaggedSlaveMode() ) {
+ $wgReadOnly = 'The database has been automatically locked ' .
+ 'while the slave database servers catch up to the master';
+ }
+ } catch ( DBConnectionError $e ) {
$wgReadOnly = 'The database has been automatically locked ' .
- 'while the slave database servers catch up to the master';
+ 'until the slave database servers become available';
}
}
*
* This function replaces all old wfMsg* functions.
*
- * @param string|string[] $key Message key, or array of keys
+ * @param string|string[]|MessageSpecifier $key Message key, or array of keys, or a MessageSpecifier
* @param mixed $params,... Normal message parameters
* @return Message
*
}
if ( in_array( 'escape', $options, true ) ) {
- $string = htmlspecialchars ( $string );
+ $string = htmlspecialchars( $string );
} elseif ( in_array( 'escapenoentities', $options, true ) ) {
$string = Sanitizer::escapeHtmlAllowEntities( $string );
}
*/
function wfHttpError( $code, $label, $desc ) {
global $wgOut;
- header( "HTTP/1.0 $code $label" );
- header( "Status: $code $label" );
+ HttpStatus::header( $code );
if ( $wgOut ) {
$wgOut->disable();
$wgOut->sendCacheControl();
}
header( 'Content-type: text/html; charset=utf-8' );
- print "<!doctype html>" .
+ print '<!DOCTYPE html>' .
'<html><head><title>' .
htmlspecialchars( $label ) .
'</title></head><body><h1>' .
/**
* Reference-counted warning suppression
*
+ * @deprecated since 1.26, use MediaWiki\suppressWarnings() directly
* @param bool $end
*/
function wfSuppressWarnings( $end = false ) {
- static $suppressCount = 0;
- static $originalLevel = false;
-
- if ( $end ) {
- if ( $suppressCount ) {
- --$suppressCount;
- if ( !$suppressCount ) {
- error_reporting( $originalLevel );
- }
- }
- } else {
- if ( !$suppressCount ) {
- $originalLevel = error_reporting( E_ALL & ~(
- E_WARNING |
- E_NOTICE |
- E_USER_WARNING |
- E_USER_NOTICE |
- E_DEPRECATED |
- E_USER_DEPRECATED |
- E_STRICT
- ) );
- }
- ++$suppressCount;
- }
+ MediaWiki\suppressWarnings( $end );
}
/**
+ * @deprecated since 1.26, use MediaWiki\restoreWarnings() directly
* Restore error level to previous value
*/
function wfRestoreWarnings() {
- wfSuppressWarnings( true );
+ MediaWiki\suppressWarnings( true );
}
# Autodetect, convert and provide timestamps of various types
function wfIsWindows() {
static $isWindows = null;
if ( $isWindows === null ) {
- $isWindows = substr( php_uname(), 0, 7 ) == 'Windows';
+ $isWindows = strtoupper( substr( PHP_OS, 0, 3 ) ) === 'WIN';
}
return $isWindows;
}
return defined( 'HHVM_VERSION' );
}
-/**
- * Swap two variables
- *
- * @deprecated since 1.24
- * @param mixed $x
- * @param mixed $y
- */
-function swap( &$x, &$y ) {
- wfDeprecated( __FUNCTION__, '1.24' );
- $z = $x;
- $x = $y;
- $y = $z;
-}
-
/**
* Tries to get the system directory for temporary files. First
* $wgTmpDirectory is checked, and then the TMPDIR, TMP, and TEMP
wfDebug( "$caller: called wfMkdirParents($dir)\n" );
}
- if ( strval( $dir ) === '' || ( file_exists( $dir ) && is_dir( $dir ) ) ) {
+ if ( strval( $dir ) === '' || is_dir( $dir ) ) {
return true;
}
}
// Turn off the normal warning, we're doing our own below
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$ok = mkdir( $dir, $mode, true ); // PHP5 <3
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( !$ok ) {
//directory may have been created on another request since we last checked
$useLogPipe = false;
if ( is_executable( '/bin/bash' ) ) {
- $time = intval ( isset( $limits['time'] ) ? $limits['time'] : $wgMaxShellTime );
+ $time = intval( isset( $limits['time'] ) ? $limits['time'] : $wgMaxShellTime );
if ( isset( $limits['walltime'] ) ) {
$wallTime = intval( $limits['walltime'] );
} elseif ( isset( $limits['time'] ) ) {
} else {
$wallTime = intval( $wgMaxShellWallClockTime );
}
- $mem = intval ( isset( $limits['memory'] ) ? $limits['memory'] : $wgMaxShellMemory );
- $filesize = intval ( isset( $limits['filesize'] ) ? $limits['filesize'] : $wgMaxShellFileSize );
+ $mem = intval( isset( $limits['memory'] ) ? $limits['memory'] : $wgMaxShellMemory );
+ $filesize = intval( isset( $limits['filesize'] ) ? $limits['filesize'] : $wgMaxShellFileSize );
if ( $time > 0 || $mem > 0 || $filesize > 0 || $wallTime > 0 ) {
$cmd = '/bin/bash ' . escapeshellarg( "$IP/includes/limit.sh" ) . ' ' .
# This check may also protect against code injection in
# case of broken installations.
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$haveDiff3 = $wgDiff3 && file_exists( $wgDiff3 );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( !$haveDiff3 ) {
wfDebug( "diff3 not found\n" );
}
global $wgDiff;
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$haveDiff = $wgDiff && file_exists( $wgDiff );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
# This check may also protect against code injection in
# case of broken installations.
// Removing leading zeros works around broken base detection code in
// some PHP versions (see <https://bugs.php.net/bug.php?id=50175> and
// <https://bugs.php.net/bug.php?id=55398>).
- $result = gmp_strval( gmp_init( ltrim( $input, '0' ), $sourceBase ), $destBase );
+ $result = gmp_strval( gmp_init( ltrim( $input, '0' ) ?: '0', $sourceBase ), $destBase );
} elseif ( extension_loaded( 'bcmath' ) && ( $engine == 'auto' || $engine == 'bcmath' ) ) {
$decimal = '0';
foreach ( str_split( strtolower( $input ) ) as $char ) {
} else {
wfFixSessionID();
}
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
session_start();
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
}
/**
}
/**
- * Get a cache key
+ * Make a cache key for the local wiki.
*
* @param string $args,...
* @return string
$prefix = $wgCachePrefix === false ? wfWikiID() : $wgCachePrefix;
$args = func_get_args();
$key = $prefix . ':' . implode( ':', $args );
- $key = str_replace( ' ', '_', $key );
- return $key;
+ return strtr( $key, ' ', '_' );
}
/**
- * Get a cache key for a foreign DB
+ * Make a cache key for a foreign DB.
+ *
+ * Must match what wfMemcKey() would produce in context of the foreign wiki.
*
* @param string $db
* @param string $prefix
function wfForeignMemcKey( $db, $prefix /*...*/ ) {
$args = array_slice( func_get_args(), 2 );
if ( $prefix ) {
+ // Match wfWikiID() logic
$key = "$db-$prefix:" . implode( ':', $args );
} else {
$key = $db . ':' . implode( ':', $args );
}
- return str_replace( ' ', '_', $key );
+ return strtr( $key, ' ', '_' );
+}
+
+/**
+ * Make a cache key with database-agnostic prefix.
+ *
+ * Doesn't have a wiki-specific namespace. Uses a generic 'global' prefix
+ * instead. Must have a prefix as otherwise keys that use a database name
+ * in the first segment will clash with wfMemcKey/wfForeignMemcKey.
+ *
+ * @since 1.26
+ * @param string $args,...
+ * @return string
+ */
+function wfGlobalCacheKey( /*...*/ ) {
+ $args = func_get_args();
+ $key = 'global:' . implode( ':', $args );
+ return strtr( $key, ' ', '_' );
}
/**
}
// Figure out which clusters need to be checked
+ /** @var LoadBalancer[] $lbs */
$lbs = array();
if ( $cluster === '*' ) {
wfGetLBFactory()->forEachLB( function ( LoadBalancer $lb ) use ( &$lbs ) {
// time needed to wait on the next clusters.
$masterPositions = array_fill( 0, count( $lbs ), false );
foreach ( $lbs as $i => $lb ) {
- // bug 27975 - Don't try to wait for slaves if there are none
- // Prevents permission error when getting master position
- if ( $lb->getServerCount() > 1 ) {
- if ( $ifWritesSince && !$lb->hasMasterConnection() ) {
- continue; // assume no writes done
- }
- // Use the empty string to not trigger selectDB() since the connection
- // may have been to a server that does not have a DB for the current wiki.
- $dbw = $lb->getConnection( DB_MASTER, array(), '' );
- if ( $ifWritesSince && $dbw->lastDoneWrites() < $ifWritesSince ) {
- continue; // no writes since the last wait
- }
- $masterPositions[$i] = $dbw->getMasterPos();
+ if ( $lb->getServerCount() <= 1 ) {
+ // Bug 27975 - Don't try to wait for slaves if there are none
+ // Prevents permission error when getting master position
+ continue;
+ } elseif ( $ifWritesSince && $lb->lastMasterChangeTimestamp() < $ifWritesSince ) {
+ continue; // no writes since the last wait
}
+ $masterPositions[$i] = $lb->getMasterPos();
}
$ok = true;
$conflimit = wfShorthandToInteger( $wgMemoryLimit );
if ( $conflimit == -1 ) {
wfDebug( "Removing PHP's memory limit\n" );
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
ini_set( 'memory_limit', $conflimit );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
return $conflimit;
} elseif ( $conflimit > $memlimit ) {
wfDebug( "Raising PHP's memory limit to $conflimit bytes\n" );
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
ini_set( 'memory_limit', $conflimit );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
return $conflimit;
}
}
}
}
- wfSuppressWarnings();
+ MediaWiki\suppressWarnings();
$result = unpack( $format, $data );
- wfRestoreWarnings();
+ MediaWiki\restoreWarnings();
if ( $result === false ) {
// If it cannot extract the packed data.
*
* @since 1.17
*/
-class Message implements MessageSpecifier {
+class Message implements MessageSpecifier, Serializable {
/**
* In which language to get this message. True, which is the default,
/**
* @since 1.17
*
- * @param string|string[] $key Message key or array of message keys to try and use the first
- * non-empty message for.
+ * @param string|string[]|MessageSpecifier $key Message key, or array of
+ * message keys to try and use the first non-empty message for, or a
+ * MessageSpecifier to copy from.
* @param array $params Message parameters.
* @param Language $language Optional language of the message, defaults to $wgLang.
*
public function __construct( $key, $params = array(), Language $language = null ) {
global $wgLang;
+ if ( $key instanceof MessageSpecifier ) {
+ if ( $params ) {
+ throw new InvalidArgumentException(
+ '$params must be empty if $key is a MessageSpecifier'
+ );
+ }
+ $params = $key->getParams();
+ $key = $key->getKey();
+ }
+
if ( !is_string( $key ) && !is_array( $key ) ) {
throw new InvalidArgumentException( '$key must be a string or an array' );
}
$this->language = $language ?: $wgLang;
}
+ /**
+ * @see Serializable::serialize()
+ * @since 1.26
+ * @return string
+ */
+ public function serialize() {
+ return serialize( array(
+ 'interface' => $this->interface,
+ 'language' => $this->language->getCode(),
+ 'key' => $this->key,
+ 'keysToTry' => $this->keysToTry,
+ 'parameters' => $this->parameters,
+ 'format' => $this->format,
+ 'useDatabase' => $this->useDatabase,
+ 'title' => $this->title,
+ ) );
+ }
+
+ /**
+ * @see Serializable::unserialize()
+ * @since 1.26
+ * @param string $serialized
+ */
+ public function unserialize( $serialized ) {
+ $data = unserialize( $serialized );
+ $this->interface = $data['interface'];
+ $this->key = $data['key'];
+ $this->keysToTry = $data['keysToTry'];
+ $this->parameters = $data['parameters'];
+ $this->format = $data['format'];
+ $this->useDatabase = $data['useDatabase'];
+ $this->language = Language::factory( $data['language'] );
+ $this->title = $data['title'];
+ }
+
/**
* @since 1.24
*
*
* @since 1.17
*
- * @param string|string[] $key Message key or array of keys.
+ * @param string|string[]|MessageSpecifier $key
* @param mixed $param,... Parameters as strings.
*
* @return Message
return new self( $keys );
}
+ /**
+ * Get a title object for a mediawiki message, where it can be found in the mediawiki namespace.
+ * The title will be for the current language, if the message key is in
+ * $wgForceUIMsgAsContentMsg it will be append with the language code (except content
+ * language), because Message::inContentLanguage will also return in user language.
+ *
+ * @see $wgForceUIMsgAsContentMsg
+ * @return Title
+ * @since 1.26
+ */
+ public function getTitle() {
+ global $wgContLang, $wgForceUIMsgAsContentMsg;
+
+ $code = $this->language->getCode();
+ $title = $this->key;
+ if (
+ $wgContLang->getCode() !== $code
+ && in_array( $this->key, (array)$wgForceUIMsgAsContentMsg )
+ ) {
+ $title .= '/' . $code;
+ }
+
+ return Title::makeTitle( NS_MEDIAWIKI, $wgContLang->ucfirst( strtr( $title, ' ', '_' ) ) );
+ }
+
/**
* Adds parameters to the parameter list of this message.
*
if ( $lang instanceof Language || $lang instanceof StubUserLang ) {
$this->language = $lang;
} elseif ( is_string( $lang ) ) {
- if ( $this->language->getCode() != $lang ) {
+ if ( !$this->language instanceof Language || $this->language->getCode() != $lang ) {
$this->language = Language::factory( $lang );
}
} else {