*/
require_once dirname(__FILE__) . '/normal/UtfNormalUtil.php';
-require_once dirname(__FILE__) . '/XmlFunctions.php';
// Hide compatibility functions from Doxygen
/// @cond
}
}
-if ( !function_exists( 'array_diff_key' ) ) {
- /**
- * Exists in PHP 5.1.0+
- * Not quite compatible, two-argument version only
- * Null values will cause problems due to this use of isset()
- */
- function array_diff_key( $left, $right ) {
- $result = $left;
- foreach ( $left as $key => $unused ) {
- if ( isset( $right[$key] ) ) {
- unset( $result[$key] );
- }
- }
- return $result;
- }
-}
-
// Support for Wietse Venema's taint feature
if ( !function_exists( 'istainted' ) ) {
function istainted( $var ) {
}
}
-/**
- * Wrapper for clone(), for compatibility with PHP4-friendly extensions.
- * PHP 5 won't let you declare a 'clone' function, even conditionally,
- * so it has to be a wrapper with a different name.
- */
-function wfClone( $object ) {
- return clone( $object );
-}
-
/**
* Seed Mersenne Twister
* No-op for compatibility; only necessary in PHP < 4.2.0
*
* ;:@$!*(),/
*
+ * However, IIS7 redirects fail when the url contains a colon (Bug 22709),
+ * so no fancy : for IIS7.
+ *
* %2F in the page titles seems to fatally break for some reason.
*
* @param $s String:
* @return string
*/
function wfUrlencode( $s ) {
+ static $needle;
+ if ( is_null( $needle ) ) {
+ $needle = array( '%3B','%40','%24','%21','%2A','%28','%29','%2C','%2F' );
+ if (! isset($_SERVER['SERVER_SOFTWARE']) || ( strpos($_SERVER['SERVER_SOFTWARE'], "Microsoft-IIS/7") === false)) {
+ $needle[] = '%3A';
+ }
+ }
+
$s = urlencode( $s );
$s = str_ireplace(
- array( '%3B','%3A','%40','%24','%21','%2A','%28','%29','%2C','%2F' ),
- array( ';', ':', '@', '$', '!', '*', '(', ')', ',', '/' ),
+ $needle,
+ array( ';', '@', '$', '!', '*', '(', ')', ',', '/', ':' ),
$s
);
static $recursion = 0;
static $cache = array(); // Cache of unoutputted messages
+ $text = wfDebugTimer() . $text;
# Check for raw action using $_GET not $wgRequest, since the latter might not be initialised yet
if ( isset( $_GET['action'] ) && $_GET['action'] == 'raw' && !$wgDebugRawPage ) {
}
}
+function wfDebugTimer() {
+ global $wgDebugTimestamps;
+ if ( !$wgDebugTimestamps ) return '';
+ static $start = null;
+
+ if ( $start === null ) {
+ $start = microtime( true );
+ $prefix = "\n$start";
+ } else {
+ $prefix = sprintf( "%6.4f", microtime( true ) - $start );
+ }
+
+ return $prefix . ' ';
+}
+
/**
* Send a line giving PHP memory usage.
* @param $exact Bool: print exact values instead of kilobytes (default: false)
global $wgRequestTime, $wgDebugLogFile, $wgDebugRawPage, $wgRequest;
global $wgProfiler, $wgProfileLimit, $wgUser;
# Profiling must actually be enabled...
- if( !isset( $wgProfiler ) ) return;
+ if( is_null( $wgProfiler ) ) return;
# Get total page request time
$now = wfTime();
$elapsed = $now - $wgRequestTime;
* functionality), or if it is true then use the wikis
* @return Language object
*/
-function wfGetLangObj( $langcode = false ){
+function wfGetLangObj( $langcode = false ) {
# Identify which language to get or create a language object for.
- if( $langcode instanceof Language )
- # Great, we already have the object!
+ # Using is_object here due to Stub objects.
+ if( is_object( $langcode ) ) {
+ # Great, we already have the object (hopefully)!
return $langcode;
+ }
- global $wgContLang;
- if( $langcode === $wgContLang->getCode() || $langcode === true )
+ global $wgContLang, $wgLanguageCode;
+ if( $langcode === true || $langcode === $wgLanguageCode ) {
# $langcode is the language code of the wikis content language object.
# or it is a boolean and value is true
return $wgContLang;
+ }
global $wgLang;
- if( $langcode === $wgLang->getCode() || $langcode === false )
+ if( $langcode === false || $langcode === $wgLang->getCode() ) {
# $langcode is the language code of user language object.
# or it was a boolean and value is false
return $wgLang;
+ }
$validCodes = array_keys( Language::getLanguageNames() );
- if( in_array( $langcode, $validCodes ) )
+ if( in_array( $langcode, $validCodes ) ) {
# $langcode corresponds to a valid language.
return Language::factory( $langcode );
+ }
# $langcode is a string, but not a valid language code; use content language.
wfDebug( "Invalid language code passed to wfGetLangObj, falling back to content language.\n" );
return $wgContLang;
}
+function wfUILang() {
+ global $wgBetterDirectionality;
+ return wfGetLangObj( $wgBetterDirectionality ? false: true );
+}
+
/**
* Get a message from anywhere, for the current user language.
*
*
* Be wary of this distinction: If you use wfMsg() where you should
* use wfMsgForContent(), a user of the software may have to
- * customize over 70 messages in order to, e.g., fix a link in every
- * possible language.
+ * customize potentially hundreds of messages in
+ * order to, e.g., fix a link in every possible language.
*
* @param $key String: lookup key for the message, usually
* defined in languages/Language.php
* @param $key String: key to get.
* @param $args
* @param $useDB Boolean
- * @param $transform Boolean: Whether or not to transform the message.
* @param $forContent Mixed: Language code, or false for user lang, true for content lang.
+ * @param $transform Boolean: Whether or not to transform the message.
* @return String: the requested message.
*/
function wfMsgReal( $key, $args, $useDB = true, $forContent = false, $transform = true ) {
* behaves as a content language switch if it is a boolean.
* @param $transform Boolean: whether to parse magic words, etc.
* @return string
- * @private
*/
function wfMsgGetKey( $key, $useDB, $langCode = false, $transform = true ) {
global $wgContLang, $wgMessageCache;
wfRunHooks('NormalizeMessageKey', array(&$key, &$useDB, &$langCode, &$transform));
- # If $wgMessageCache isn't initialised yet, try to return something sensible.
- if( is_object( $wgMessageCache ) ) {
- $message = $wgMessageCache->get( $key, $useDB, $langCode );
- if ( $transform ) {
- $message = $wgMessageCache->transform( $message );
- }
- } else {
- $lang = wfGetLangObj( $langCode );
-
- # MessageCache::get() does this already, Language::getMessage() doesn't
- # ISSUE: Should we try to handle "message/lang" here too?
- $key = str_replace( ' ' , '_' , $wgContLang->lcfirst( $key ) );
-
- if( is_object( $lang ) ) {
- $message = $lang->getMessage( $key );
- } else {
- $message = false;
- }
+ if ( !is_object( $wgMessageCache ) ) {
+ throw new MWException( "Trying to get message before message cache is initialised" );
}
+ $message = $wgMessageCache->get( $key, $useDB, $langCode );
+ if( $message === false ){
+ $message = '<' . htmlspecialchars( $key ) . '>';
+ } elseif ( $transform ) {
+ $message = $wgMessageCache->transform( $message );
+ }
return $message;
}
* <i>parseinline</i>: parses wikitext to html and removes the surrounding
* p's added by parser or tidy
* <i>escape</i>: filters message through htmlspecialchars
- * <i>escapenoentities</i>: same, but allows entity references like through
+ * <i>escapenoentities</i>: same, but allows entity references like   through
* <i>replaceafter</i>: parameters are substituted after parsing or escaping
* <i>parsemag</i>: transform the message using magic phrases
* <i>content</i>: fetch message for content language instead of interface
* @return bool Whereas client accept gzip compression
*/
function wfClientAcceptsGzip() {
- global $wgUseGzip;
- if( $wgUseGzip ) {
+ if( isset( $_SERVER['HTTP_ACCEPT_ENCODING'] ) ) {
# FIXME: we may want to blacklist some broken browsers
$m = array();
if( preg_match(
/**
* Expand a potentially local URL to a fully-qualified URL. Assumes $wgServer
- * is correct. Also doesn't handle any type of relative URL except one
- * starting with a single "/": this won't work with current-path-relative URLs
- * like "subdir/foo.html", protocol-relative URLs like
- * "//en.wikipedia.org/wiki/", etc. TODO: improve this!
+ * and $wgProto are correct.
+ *
+ * @todo this won't work with current-path-relative URLs
+ * like "subdir/foo.html", etc.
*
* @param $url String: either fully-qualified or a local path + query
* @return string Fully-qualified URL
*/
function wfExpandUrl( $url ) {
- if( substr( $url, 0, 1 ) == '/' ) {
+ if( substr( $url, 0, 2 ) == '//' ) {
+ global $wgProto;
+ return $wgProto . ':' . $url;
+ } elseif( substr( $url, 0, 1 ) == '/' ) {
global $wgServer;
return $wgServer . $url;
} else {
}
$delim = !$delim;
}
+
// Double the backslashes before the end of the string, because
// we will soon add a quote
$m = array();
if ( preg_match( '/^(.*?)(\\\\+)$/', $arg, $m ) ) {
$arg = $m[1] . str_replace( '\\', '\\\\', $m[2] );
}
-
+
+ // The caret is also an special character
+ $arg = str_replace( "^", "^^", $arg );
+
// Add surrounding quotes
$retVal .= '"' . $arg . '"';
} else {
pclose( $handle );
unlink( $mytextName ); unlink( $oldtextName ); unlink( $yourtextName );
- if ( $result === '' && $old !== '' && $conflict == false ) {
+ if ( $result === '' && $old !== '' && !$conflict ) {
wfDebug( "Unexpected null result from diff3. Command: $cmd\n" );
$conflict = true;
}
}
} else {
if ( !$suppressCount ) {
- $originalLevel = error_reporting( E_ALL & ~( E_WARNING | E_NOTICE ) );
+ $originalLevel = error_reporting( E_ALL & ~( E_WARNING | E_NOTICE | E_USER_WARNING | E_USER_NOTICE ) );
}
++$suppressCount;
}
$notice = '';
}
}
-
+ $notice = '<div id="localNotice">'.$notice.'</div>';
wfProfileOut( $fname );
return $notice;
}
* @deprecated
*/
function &wfGetMimeMagic() {
+ wfDeprecated( __FUNCTION__ );
return MimeMagic::singleton();
}
/**
- * Tries to get the system directory for temporary files.
- * The TMPDIR, TMP, and TEMP environment variables are checked in sequence,
- * and if none are set /tmp is returned as the generic Unix default.
+ * Tries to get the system directory for temporary files. For PHP >= 5.2.1,
+ * we'll use sys_get_temp_dir(). The TMPDIR, TMP, and TEMP environment
+ * variables are then checked in sequence, and if none are set /tmp is
+ * returned as the generic Unix default.
*
* NOTE: When possible, use the tempfile() function to create temporary
* files to avoid race conditions on file creation, etc.
* @return String
*/
function wfTempDir() {
+ if( function_exists( 'sys_get_temp_dir' ) ) {
+ return sys_get_temp_dir();
+ }
foreach( array( 'TMPDIR', 'TMP', 'TEMP' ) as $var ) {
$tmp = getenv( $var );
if( $tmp && file_exists( $tmp ) && is_dir( $tmp ) && is_writable( $tmp ) ) {
if ( is_null( $mode ) )
$mode = $wgDirectoryMode;
+ // Turn off the normal warning, we're doing our own below
+ wfSuppressWarnings();
$ok = mkdir( $dir, $mode, true ); // PHP5 <3
+ wfRestoreWarnings();
+
if( !$ok ) {
// PHP doesn't report the path in its warning message, so add our own to aid in diagnosis.
trigger_error( __FUNCTION__ . ": failed to mkdir \"$dir\" mode $mode", E_USER_WARNING );
* looked up didn't exist but a XHTML string, this function checks for the
* nonexistance of messages by looking at wfMsg() output
*
- * @param $msg String: the message key looked up
- * @param $wfMsgOut String: the output of wfMsg*()
- * @return Boolean
+ * @param $key String: the message key looked up
+ * @return Boolean True if the message *doesn't* exist.
*/
-function wfEmptyMsg( $msg, $wfMsgOut ) {
- return $wfMsgOut === htmlspecialchars( "<$msg>" );
+function wfEmptyMsg( $key ) {
+ global $wgMessageCache;
+ return $wgMessageCache->get( $key, /*useDB*/true, /*content*/false ) === false;
}
/**
*/
function wfUrlProtocols() {
global $wgUrlProtocols;
-
- // This function is called a lot, cache its return value
- // TODO: Cache this in memcached instead?
+
static $retval = null;
if ( !is_null( $retval ) )
return $retval;
} else {
$retval = $wgUrlProtocols;
}
-
return $retval;
}
|| preg_match( "/^\s*[+-]?0*[1-9]/", $val ); // approx C atoi() function
}
+/**
+ * Wrapper function for PHP's dl(). This doesn't work in most situations from
+ * PHP 5.3 onward, and is usually disabled in shared environments anyway.
+ *
+ * @param $extension String A PHP extension. The file suffix (.so or .dll)
+ * should be omitted
+ * @return Bool - Whether or not the extension is loaded
+ */
+function wfDl( $extension ) {
+ if( extension_loaded( $extension ) ) {
+ return true;
+ }
+
+ $canDl = ( function_exists( 'dl' ) && is_callable( 'dl' )
+ && wfIniGetBool( 'enable_dl' ) && !wfIniGetBool( 'safe_mode' ) );
+
+ if( $canDl ) {
+ wfSuppressWarnings();
+ dl( $extension . '.' . PHP_SHLIB_SUFFIX );
+ wfRestoreWarnings();
+ }
+ return extension_loaded( $extension );
+}
+
/**
* Execute a shell command, with time and memory limits mirrored from the PHP
* configuration if supported.
throw new MWException( "MediaWiki $req_ver required--this is only $wgVersion" );
}
-/**
- * @deprecated use StringUtils::escapeRegexReplacement
- */
-function wfRegexReplacement( $string ) {
- return StringUtils::escapeRegexReplacement( $string );
-}
-
/**
* Return the final portion of a pathname.
* Reimplemented because PHP5's basename() is buggy with multibyte text.
* array( 'y' )
* )
*/
-function wfMergeErrorArrays(/*...*/) {
+function wfMergeErrorArrays( /*...*/ ) {
$args = func_get_args();
$out = array();
foreach ( $args as $errors ) {
foreach ( $errors as $params ) {
+ # FIXME: sometimes get nested arrays for $params,
+ # which leads to E_NOTICEs
$spec = implode( "\t", $params );
$out[$spec] = $params;
}
$wgPostCommitUpdateList = array();
}
-/**
- * @deprecated use StringUtils::explodeMarkup
- */
-function wfExplodeMarkup( $separator, $text ) {
- return StringUtils::explodeMarkup( $separator, $text );
-}
-
/**
* Convert an arbitrarily-long digit string from one numeric base
* to another, optionally zero-padding to a minimum column width.
}
}
-/**
- * Alias for modularized function
- * @deprecated Use Http::get() instead
- */
-function wfGetHTTP( $url ) {
- wfDeprecated(__FUNCTION__);
- return Http::get( $url );
-}
-
-/**
- * Alias for modularized function
- * @deprecated Use Http::isLocalURL() instead
- */
-function wfIsLocalURL( $url ) {
- wfDeprecated(__FUNCTION__);
- return Http::isLocalURL( $url );
-}
-
function wfHttpOnlySafe() {
global $wgHttpOnlyBlacklist;
if( !version_compare("5.2", PHP_VERSION, "<") )
}
/**
- * Return a string consisting all callers in stack, somewhat useful sometimes
- * for profiling specific points
+ * Return a string consisting of callers in the stack. Useful sometimes
+ * for profiling specific points.
+ *
+ * @param $limit The maximum depth of the stack frame to return, or false for
+ * the entire stack.
*/
-function wfGetAllCallers() {
- return implode('/', array_map('wfFormatStackFrame',array_reverse(wfDebugBacktrace())));
+function wfGetAllCallers( $limit = 3 ) {
+ $trace = array_reverse( wfDebugBacktrace() );
+ if ( !$limit || $limit > count( $trace ) - 1 ) {
+ $limit = count( $trace ) - 1;
+ }
+ $trace = array_slice( $trace, -$limit - 1, $limit );
+ return implode( '/', array_map( 'wfFormatStackFrame', $trace ) );
}
/**
/**
* Find a file.
* Shortcut for RepoGroup::singleton()->findFile()
+ * @param $title Either a string or Title object
* @param $options Associative array of options:
* time: requested time for an archived image, or false for the
* current version. An image object will be returned which was
/**
* Get an object referring to a locally registered file.
* Returns a valid placeholder object if the file does not exist.
+ * @param $title Either a string or Title object
+ * @return File, or null if passed an invalid Title
*/
function wfLocalFile( $title ) {
return RepoGroup::singleton()->getLocalRepo()->newFile( $title );
/**
* Load an extension messages file
- * @deprecated
+ * @deprecated in 1.16 (warnings in 1.18, removed in ?)
*/
function wfLoadExtensionMessages( $extensionName, $langcode = false ) {
}
$langCode = implode ( '-' , $codeBCP );
return $langCode;
}
+
+function wfArrayMap( $function, $input ) {
+ $ret = array_map( $function, $input );
+ foreach ( $ret as $key => $value ) {
+ $taint = istainted( $input[$key] );
+ if ( $taint ) {
+ taint( $ret[$key], $taint );
+ }
+ }
+ return $ret;
+}