}
}
+
+if( !function_exists( 'mb_strpos' ) ) {
+ /**
+ * Fallback implementation of mb_strpos, hardcoded to UTF-8.
+ * @param string $haystack
+ * @param string $needle
+ * @param string $offset optional start position
+ * @param string $encoding optional encoding; ignored
+ * @return int
+ */
+ function mb_strpos( $haystack, $needle, $offset = 0, $encoding="" ) {
+ $needle = preg_quote( $needle, '/' );
+
+ $ar = array();
+ preg_match( '/'.$needle.'/u', $haystack, $ar, PREG_OFFSET_CAPTURE, $offset );
+
+ if( isset( $ar[0][1] ) ) {
+ return $ar[0][1];
+ } else {
+ return false;
+ }
+ }
+}
+
+if( !function_exists( 'mb_strrpos' ) ) {
+ /**
+ * Fallback implementation of mb_strrpos, hardcoded to UTF-8.
+ * @param string $haystack
+ * @param string $needle
+ * @param string $offset optional start position
+ * @param string $encoding optional encoding; ignored
+ * @return int
+ */
+ function mb_strrpos( $haystack, $needle, $offset = 0, $encoding = "" ) {
+ $needle = preg_quote( $needle, '/' );
+
+ $ar = array();
+ preg_match_all( '/'.$needle.'/u', $haystack, $ar, PREG_OFFSET_CAPTURE, $offset );
+
+ if( isset( $ar[0] ) && count( $ar[0] ) > 0 &&
+ isset( $ar[0][count($ar[0])-1][1] ) ) {
+ return $ar[0][count($ar[0])-1][1];
+ } else {
+ return false;
+ }
+ }
+}
+
if ( !function_exists( 'array_diff_key' ) ) {
/**
* Exists in PHP 5.1.0+
* @param $forContent Boolean
* @return String: the requested message.
*/
-function wfMsgReal( $key, $args, $useDB = true, $forContent=false, $transform = true ) {
- global $wgMessageCache;
+function wfMsgReal( $key, $args, $useDB = true, $forContent = false, $transform = true ) {
wfProfileIn( __METHOD__ );
- $message = wfMsgGetKey( $key, $useDB, $forContent, false );
+ $message = wfMsgGetKey( $key, $useDB, $forContent, $transform );
$message = wfMsgReplaceArgs( $message, $args );
- if( $transform && is_object( $wgMessageCache ) ) {
- $message = $wgMessageCache->transform( $message, !$forContent );
- }
wfProfileOut( __METHOD__ );
return $message;
}
* This function provides the message source for messages to be edited which are *not* stored in the database.
* @param $key String:
*/
-function wfMsgWeirdKey ( $key ) {
+function wfMsgWeirdKey( $key ) {
$source = wfMsgGetKey( $key, false, true, false );
if ( wfEmptyMsg( $key, $source ) )
return "";
foreach( $options as $arrayKey => $option ) {
if( !preg_match( '/^[0-9]+|language$/', $arrayKey ) ) {
# An unknown index, neither numeric nor "language"
- trigger_error( "wfMsgExt called with incorrect parameter key $arrayKey", E_USER_WARNING );
+ wfWarn( "wfMsgExt called with incorrect parameter key $arrayKey", 1, E_USER_WARNING );
} elseif( preg_match( '/^[0-9]+$/', $arrayKey ) && !in_array( $option,
array( 'parse', 'parseinline', 'escape', 'escapenoentities',
'replaceafter', 'parsemag', 'content' ) ) ) {
# A numeric index with unknown value
- trigger_error( "wfMsgExt called with incorrect parameter $option", E_USER_WARNING );
+ wfWarn( "wfMsgExt called with incorrect parameter $option", 1, E_USER_WARNING );
}
}
function wfViewPrevNext( $offset, $limit, $link, $query = '', $atend = false ) {
global $wgLang;
$fmtLimit = $wgLang->formatNum( $limit );
+ // FIXME: Why on earth this needs one message for the text and another one for tooltip??
# Get prev/next link display text
- $prev = wfMsgHtml( 'prevn', $fmtLimit );
- $next = wfMsgHtml( 'nextn', $fmtLimit );
+ $prev = wfMsgExt( 'prevn', array('parsemag','escape'), $fmtLimit );
+ $next = wfMsgExt( 'nextn', array('parsemag','escape'), $fmtLimit );
# Get prev/next link title text
$pTitle = wfMsgExt( 'prevn-title', array('parsemag','escape'), $fmtLimit );
$nTitle = wfMsgExt( 'nextn-title', array('parsemag','escape'), $fmtLimit );
wfNumLink( $offset, 250, $title, $query ),
wfNumLink( $offset, 500, $title, $query )
) );
- return wfMsg( 'viewprevnext', $plink, $nlink, $nums );
+ return wfMsgHtml( 'viewprevnext', $plink, $nlink, $nums );
}
/**
if ( '' != $cgi ) {
$cgi .= '&';
}
- if(is_array($value))
- {
+ if ( is_array( $value ) ) {
$firstTime = true;
- foreach($value as $v)
- {
- $cgi .= ($firstTime ? '' : '&') .
+ foreach ( $value as $v ) {
+ $cgi .= ( $firstTime ? '' : '&') .
urlencode( $key . '[]' ) . '=' .
urlencode( $v );
$firstTime = false;
}
- }
- else
+ } else {
+ if ( is_object( $value ) ) {
+ $value = $value->__toString();
+ }
$cgi .= urlencode( $key ) . '=' .
urlencode( $value );
+ }
}
}
return $cgi;
* have query string parameters already. If so, they will be combined.
*
* @param string $url
- * @param string $query
+ * @param mixed $query String or associative array
* @return string
*/
function wfAppendQuery( $url, $query ) {
+ if ( is_array( $query ) ) {
+ $query = wfArrayToCGI( $query );
+ }
if( $query != '' ) {
if( false === strpos( $url, '?' ) ) {
$url .= '?';
* @return string Unified diff of $before and $after
*/
function wfDiff( $before, $after, $params = '-u' ) {
+ if ($before == $after) {
+ return '';
+ }
+
global $wgDiff;
# This check may also protect against code injection in
} elseif (preg_match('/^\d{1,13}$/D',$ts)) {
# TS_UNIX
$uts = $ts;
- } elseif (preg_match('/^\d{1,2}-...-\d\d(?:\d\d)? \d\d\.\d\d\.\d\d/', $ts)) {
- # TS_ORACLE
+ } elseif (preg_match('/^\d{2}-\d{2}-\d{4} \d{2}:\d{2}:\d{2}.\d{6}$/', $ts)) {
+ # TS_ORACLE // session altered to DD-MM-YYYY HH24:MI:SS.FF6
$uts = strtotime(preg_replace('/(\d\d)\.(\d\d)\.(\d\d)(\.(\d+))?/', "$1:$2:$3",
str_replace("+00:00", "UTC", $ts)));
} elseif (preg_match('/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.*\d*)?Z$/', $ts, $da)) {
case TS_RFC2822:
return gmdate( 'D, d M Y H:i:s', $uts ) . ' GMT';
case TS_ORACLE:
- return gmdate( 'd-M-y h.i.s A', $uts) . ' +00:00';
+ return gmdate( 'd-m-Y H:i:s.000000', $uts);
+ //return gmdate( 'd-M-y h.i.s A', $uts) . ' +00:00';
case TS_POSTGRES:
return gmdate( 'Y-m-d H:i:s', $uts) . ' GMT';
case TS_DB2:
*
* @param string $dir Full path to directory to create
* @param int $mode Chmod value to use, default is $wgDirectoryMode
+ * @param string $caller Optional caller param for debugging.
* @return bool
*/
-function wfMkdirParents( $dir, $mode = null ) {
+function wfMkdirParents( $dir, $mode = null, $caller = null ) {
global $wgDirectoryMode;
+ if ( !is_null( $caller ) ) {
+ wfDebug( "$caller: called wfMkdirParents($dir)" );
+ }
+
if( strval( $dir ) === '' || file_exists( $dir ) )
return true;
+ $dir = str_replace( array( '\\', '/' ), DIRECTORY_SEPARATOR, $dir );
+
if ( is_null( $mode ) )
$mode = $wgDirectoryMode;
- if ( !is_writable( $dir ) ) {
- return false;
- }
return mkdir( $dir, $mode, true ); // PHP5 <3
}
}
return $output;
}
-
+/**
+ * Executes a shell command in the background. Passes back the PID of the operation
+ *
+ * @param string $cmd
+ */
+function wfShellBackgroundExec( $cmd ){
+ wfDebug( "wfShellBackgroundExec: $cmd\n" );
+
+ if ( ! wfShellExecEnabled() ) {
+ return "Unable to run external programs";
+ }
+
+ $pid = shell_exec( "nohup $cmd > /dev/null & echo $!" );
+ return $pid;
+}
+/**
+ * Checks if the current instance can execute a shell command
+ *
+ */
+function wfShellExecEnabled(){
+ if( wfIniGetBool( 'safe_mode' ) ) {
+ wfDebug( "wfShellExec can't run in safe_mode, PHP's exec functions are too broken.\n" );
+ return false;
+ }
+ $functions = explode( ',', ini_get( 'disable_functions' ) );
+ $functions = array_map( 'trim', $functions );
+ $functions = array_map( 'strtolower', $functions );
+ if ( in_array( 'passthru', $functions ) ) {
+ wfDebug( "passthru is in disabled_functions\n" );
+ return false;
+ }
+ return true;
+}
/**
* Workaround for http://bugs.php.net/bug.php?id=45132
* escapeshellarg() destroys non-ASCII characters if LANG is not a UTF-8 locale
* Alias for modularized function
* @deprecated Use Http::get() instead
*/
-function wfGetHTTP( $url, $timeout = 'default' ) {
+function wfGetHTTP( $url ) {
wfDeprecated(__FUNCTION__);
- return Http::get( $url, $timeout );
+ $status = Http::get( $url );
+ if( $status->isOK() )
+ return $status->value;
+ return null;
}
/**
}
}
}
-
+
return true;
}
* Initialise php session
*/
function wfSetupSession() {
- global $wgSessionsInMemcached, $wgCookiePath, $wgCookieDomain, $wgCookieSecure, $wgCookieHttpOnly;
+ global $wgSessionsInMemcached, $wgCookiePath, $wgCookieDomain,
+ $wgCookieSecure, $wgCookieHttpOnly, $wgSessionHandler;
if( $wgSessionsInMemcached ) {
require_once( 'MemcachedSessions.php' );
- } elseif( 'files' != ini_get( 'session.save_handler' ) ) {
- # If it's left on 'user' or another setting from another
- # application, it will end up failing. Try to recover.
- ini_set ( 'session.save_handler', 'files' );
+ } elseif( $wgSessionHandler && $wgSessionHandler != ini_get( 'session.save_handler' ) ) {
+ # Only set this if $wgSessionHandler isn't null and session.save_handler
+ # hasn't already been set to the desired value (that causes errors)
+ ini_set ( 'session.save_handler', $wgSessionHandler );
}
$httpOnlySafe = wfHttpOnlySafe();
wfDebugLog( 'cookie',
* Get an ASCII string identifying this wiki
* This is used as a prefix in memcached keys
*/
-function wfWikiID( $db = null ) {
- if( $db instanceof Database ) {
- return $db->getWikiID();
- } else {
+function wfWikiID() {
global $wgDBprefix, $wgDBname;
- if ( $wgDBprefix ) {
- return "$wgDBname-$wgDBprefix";
- } else {
- return $wgDBname;
- }
+ if ( $wgDBprefix ) {
+ return "$wgDBname-$wgDBprefix";
+ } else {
+ return $wgDBname;
}
}
/**
* Load an extension messages file
- *
- * @param string $extensionName Name of extension to load messages from\for.
- * @param string $langcode Language to load messages for, or false for default
- * behvaiour (en, content language and user language).
- * @since r24808 (v1.11) Using this method of loading extension messages will not work
- * on MediaWiki prior to that
+ * @deprecated
*/
function wfLoadExtensionMessages( $extensionName, $langcode = false ) {
- global $wgExtensionMessagesFiles, $wgMessageCache, $wgLang, $wgContLang;
-
- #For recording whether extension message files have been loaded in a given language.
- static $loaded = array();
-
- if( !array_key_exists( $extensionName, $loaded ) ) {
- $loaded[$extensionName] = array();
- }
-
- if ( !isset($wgExtensionMessagesFiles[$extensionName]) ) {
- throw new MWException( "Messages file for extensions $extensionName is not defined" );
- }
-
- if( !$langcode && !array_key_exists( '*', $loaded[$extensionName] ) ) {
- # Just do en, content language and user language.
- $wgMessageCache->loadMessagesFile( $wgExtensionMessagesFiles[$extensionName], false );
- # Mark that they have been loaded.
- $loaded[$extensionName]['en'] = true;
- $loaded[$extensionName][$wgLang->getCode()] = true;
- $loaded[$extensionName][$wgContLang->getCode()] = true;
- # Mark that this part has been done to avoid weird if statements.
- $loaded[$extensionName]['*'] = true;
- } elseif( is_string( $langcode ) && !array_key_exists( $langcode, $loaded[$extensionName] ) ) {
- # Load messages for specified language.
- $wgMessageCache->loadMessagesFile( $wgExtensionMessagesFiles[$extensionName], $langcode );
- # Mark that they have been loaded.
- $loaded[$extensionName][$langcode] = true;
- }
}
/**
}
/**
- * Throws an E_USER_NOTICE saying that $function is deprecated
+ * Throws a warning that $function is deprecated
* @param string $function
* @return null
*/
function wfDeprecated( $function ) {
- global $wgDebugLogFile;
- if ( !$wgDebugLogFile ) {
- return;
+ static $functionsWarned = array();
+ if ( !isset( $functionsWarned[$function] ) ) {
+ $functionsWarned[$function] = true;
+ wfWarn( "Use of $function is deprecated.", 2 );
}
+}
+
+function wfWarn( $msg, $callerOffset = 1, $level = E_USER_NOTICE ) {
$callers = wfDebugBacktrace();
- if( isset( $callers[2] ) ){
- $callerfunc = $callers[2];
- $callerfile = $callers[1];
+ if( isset( $callers[$callerOffset+1] ) ){
+ $callerfunc = $callers[$callerOffset+1];
+ $callerfile = $callers[$callerOffset];
if( isset( $callerfile['file'] ) && isset( $callerfile['line'] ) ){
$file = $callerfile['file'] . ' at line ' . $callerfile['line'];
} else {
if( isset( $callerfunc['class'] ) )
$func .= $callerfunc['class'] . '::';
$func .= @$callerfunc['function'];
- $msg = "Use of $function is deprecated. Called from $func in $file";
+ $msg .= " [Called from $func in $file]";
+ }
+
+ global $wgDevelopmentWarnings;
+ if ( $wgDevelopmentWarnings ) {
+ trigger_error( $msg, $level );
} else {
- $msg = "Use of $function is deprecated.";
+ wfDebug( "$msg\n" );
}
- wfDebug( "$msg\n" );
}
/**
flush();
}
+/**
+ * Count down from $n to zero on the terminal, with a one-second pause
+ * between showing each number. For use in command-line scripts.
+ */
+function wfCountDown( $n ) {
+ for ( $i = $n; $i >= 0; $i-- ) {
+ if ( $i != $n ) {
+ echo str_repeat( "\x08", strlen( $i + 1 ) );
+ }
+ echo $i;
+ flush();
+ if ( $i ) {
+ sleep( 1 );
+ }
+ }
+ echo "\n";
+}
+
/** Generate a random 32-character hexadecimal token.
* @param mixed $salt Some sort of salt, if necessary, to add to random characters before hashing.
*/
$name = preg_replace ( "/[^".Title::legalChars()."]|:/", '-', $name );
return $name;
}
+
+/**
+ * Insert array into another array after the specified *KEY*
+ * @param array $array The array.
+ * @param array $insert The array to insert.
+ * @param mixed $after The key to insert after
+ */
+function wfArrayInsertAfter( $array, $insert, $after ) {
+ // Find the offset of the element to insert after.
+ $keys = array_keys($array);
+ $offsetByKey = array_flip( $keys );
+
+ $offset = $offsetByKey[$after];
+
+ // Insert at the specified offset
+ $before = array_slice( $array, 0, $offset + 1, true );
+ $after = array_slice( $array, $offset + 1, count($array)-$offset, true );
+
+ $output = $before + $insert + $after;
+
+ return $output;
+}
+
+/* Recursively converts the parameter (an object) to an array with the same data */
+function wfObjectToArray( $object, $recursive = true ) {
+ $array = array();
+ foreach ( get_object_vars($object) as $key => $value ) {
+ if ( is_object($value) && $recursive ) {
+ $value = wfObjectToArray( $value );
+ }
+
+ $array[$key] = $value;
+ }
+
+ return $array;
+}